数字签名的java实现(RSA,DSA)
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
基本概念:
????數(shù)字簽名,顧名思義,就類似于一種寫在紙上的普通的物理簽名.
????簡單說就是將文件內(nèi)容進(jìn)行hash散列(消息摘要),信息發(fā)送者對(duì)散列后的字符串使用私鑰加密,得到的最終字符串就是簽名。然后將得到的簽名字符串添加到文件信息的后面一同發(fā)送出去。接收者獲取到文件信息和簽名后,使用公鑰對(duì)簽名進(jìn)行解密,就得到文件內(nèi)容和加密后的hash散列。此時(shí),他可以對(duì)獲取到的文件內(nèi)容做hash散列,與簽名中的hash散列進(jìn)行匹對(duì),從而鑒別出最終獲取信息的真?zhèn)?
整個(gè)過程可以用如下圖解理解.
????
????
? ?算法種類:
? ? 常見的幾種KeyPairGenerator算法
KeyPairGenerator Algorithms
(除了指出,這些類創(chuàng)建Key.getAlgorithm()返回標(biāo)準(zhǔn)算法名稱的密鑰.)
生成KeyPairGenerator實(shí)例時(shí)可以指定本節(jié)中的算法名稱.
| DiffieHellman | 為Diffie-Hellman密鑰協(xié)商算法生成密鑰對(duì)。 注意:key.getAlgorithm()將返回“DH”而不是“DiffieHellman”。 |
| DSA | Generates keypairs for the Digital Signature Algorithm. |
| RSA | Generates keypairs for the RSA algorithm (Signature/Cipher). |
| EC | Generates keypairs for the Elliptic Curve algorithm. |
常見的簽名算法
Signature Algorithms
生成Signature實(shí)例時(shí)可以指定本節(jié)中的算法名稱。
| NONEwithRSA | RSA簽名算法在執(zhí)行RSA操作之前不使用摘要算法(例如MD5 /SHA1)。? |
| MD2withRSA MD5withRSA | 使用MD2 / MD5摘要算法和RSA來創(chuàng)建和驗(yàn)證 |
| SHA1withRSA SHA224withRSA SHA256withRSA SHA384withRSA SHA512withRSA | 使用? SHA- *? 的簽名算法和OSI Interoperability Workshop中定義的RSA加密算法 |
| NONEwithDSA | FIPS PUB 186-2中定義的數(shù)字簽名算法。?數(shù)據(jù)長度必須是20個(gè)字節(jié)。?這個(gè)算法也被稱為rawDSA。 |
| SHA1withDSA SHA224withDSA SHA256withDSA | DSA簽名算法使用SHA-1,SHA-224或SHA-256摘要算法來創(chuàng)建和驗(yàn)證 |
| NONEwithECDSA SHA1withECDSA SHA224withECDSA SHA256withECDSA SHA384withECDSA SHA512withECDSA (ECDSA) | ECDSA簽名算法。 |
| <digest>with<encryption> | 使用這個(gè)名稱為具有特定消息摘要(如MD2或MD5)和算法(如RSA或DSA)的簽名算法創(chuàng)建一個(gè)名稱,就像本節(jié)中明確定義的標(biāo)準(zhǔn)名稱(MD2withRSA等)一樣?上) |
code實(shí)例:
DataSecurity:
package com.fitc.soldier.service.common;import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec;import org.apache.commons.codec.binary.Hex;public class DataSecurity {private static String testContent="這是一個(gè)測(cè)試文本!!!";public static void main(String[] args) {// localKeyPairMethod(testContent); // localPrivatKeyMethod(testContent);generatorKey(testContent);}/*** 加載本地密鑰對(duì)*/public static void localKeyPairMethod(String Content){try {File file = new File("ca.key");FileOutputStream fileOutputStream = new FileOutputStream(file);//加載本地KeyPair 密鑰對(duì)KeyPair keyPair = KeyPairUtil.generatorkeyPair();KeyPairUtil.storeKeyPair(keyPair, fileOutputStream);KeyPair localFileKeyPair = KeyPairUtil.localFileKeyPair(new FileInputStream(file));PublicKey publicKey = localFileKeyPair.getPublic();PrivateKey privateKey = localFileKeyPair.getPrivate();DataSignaturer dataSignaturer=new DataSignaturer(privateKey, publicKey);byte[] sign = dataSignaturer.sign(Content.getBytes());System.out.println("簽名:\t"+Hex.encodeHexString(sign));System.out.println("驗(yàn)證簽名結(jié)果\t"+dataSignaturer.verifySign(Content.getBytes(), sign));} catch (FileNotFoundException | NoSuchAlgorithmException e) {e.printStackTrace();}}/*** 加載本地私鑰/公鑰 對(duì)數(shù)據(jù)實(shí)現(xiàn)簽名和驗(yàn)證*/public static void localPrivatKeyMethod(String Content){try {File private_key_File = new File("private_key.key");File public_key_File = new File("public_key.key");FileOutputStream private_keytStream = new FileOutputStream(private_key_File);FileOutputStream public_keyStream = new FileOutputStream(public_key_File);//生成本地密鑰 分別存儲(chǔ)本地 KeyPair keyPair = KeyPairUtil.generatorkeyPair();KeyPairUtil.storeKeyPair(keyPair, private_keytStream, public_keyStream);//加載本地密鑰文件PrivateKey loadFilePrivateKey = KeyPairUtil.loadFilePrivateKey(new FileInputStream(private_key_File));PublicKey loadFilePublicKey = KeyPairUtil.loadFilePublicKey(new FileInputStream(public_key_File));DataSignaturer dataSignaturer=new DataSignaturer(loadFilePrivateKey, loadFilePublicKey);byte[] sign = dataSignaturer.sign(Content.getBytes());System.out.println("簽名:\t"+Hex.encodeHexString(sign));System.out.println("簽名:\t"+StringHelper.encoderBase64(sign));System.out.println("驗(yàn)證簽名結(jié)果\t"+dataSignaturer.verifySign(Content.getBytes(), sign));} catch (FileNotFoundException | NoSuchAlgorithmException e) {e.printStackTrace();}}/*** 使用密鑰對(duì) 構(gòu)建公私鑰 對(duì)數(shù)據(jù)進(jìn)行簽名和驗(yàn)證*/public static void generatorKey(String Content){try {//生成密鑰KeyPair keyPair = KeyPairUtil.generatorkeyPair();PrivateKey privateKey = keyPair.getPrivate();PublicKey publicKey = keyPair.getPublic();KeyFactory keyFactory=KeyFactory.getInstance(KeyPairUtil.KEY_ALGORITHM); // 將生成的密鑰 按照PKCS#8標(biāo)準(zhǔn)作為密鑰規(guī)范管理的編碼格式 轉(zhuǎn)換成 密鑰 // 在 Java 語言中,此類表示基于在 PKCS 8 標(biāo)準(zhǔn)中定義的 ASN.1 類型的編碼密鑰PKCS8EncodedKeySpec pkcs8encodedkeyspec=new PKCS8EncodedKeySpec(privateKey.getEncoded());PrivateKey generatePrivate = keyFactory.generatePrivate(pkcs8encodedkeyspec);//使用密鑰簽名 SHA1withRSA 簽名算法Signature signature=Signature.getInstance("SHA1withRSA");signature.initSign(generatePrivate);signature.update(Content.getBytes());byte[] sign = signature.sign();System.out.println("原文內(nèi)容:\t"+Content);System.out.println("簽名結(jié)果:\t"+Hex.encodeHexString(sign));//創(chuàng)建公鑰 ,使用公鑰驗(yàn)證簽名 X509EncodedKeySpec ASN.1 類型的編碼密鑰X509EncodedKeySpec x509encodedkeyspec=new X509EncodedKeySpec(publicKey.getEncoded());PublicKey generatePublic = keyFactory.generatePublic(x509encodedkeyspec);signature.initVerify(generatePublic);signature.update(Content.getBytes());System.out.println("原文內(nèi)容:\t"+Content);System.out.println("驗(yàn)證簽名是否通過:\t"+signature.verify(sign));} catch (NoSuchAlgorithmException | InvalidKeySpecException | SignatureException | InvalidKeyException e) {e.printStackTrace();}}}KeyPairUtil(密鑰對(duì)的生成或者 加載本地密鑰文件):
package com.fitc.soldier.service.common;import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey;/*** <pre>*公鑰,私鑰生成工具類</br>*可以又 KeyPairGenerator 秘鑰對(duì)生成器生成然后保存到本地</br>*或者直接讀取本地的密鑰文件*</pre>*/public class KeyPairUtil {// 可以用DSA,也可以用RSA public static final String KEY_ALGORITHM="RSA"; /*** 從輸入流中獲取KeyPair 秘鑰對(duì) 對(duì)象* @param keyPairStream 輸入流* @return*/public static KeyPair localFileKeyPair(InputStream keyPairStream){if (keyPairStream==null) {System.out.println("指定的輸入流=null!因此無法讀取KeyPair!");return null;}ObjectInputStream objectInputStream=null;try {objectInputStream=new ObjectInputStream(keyPairStream);KeyPair keyPair =(KeyPair)objectInputStream.readObject();objectInputStream.close();return keyPair;} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}finally {if (objectInputStream!=null) {try {objectInputStream.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}return null;}/*** 從本地文件加載公鑰* @param publicKeyInputStream 輸入流* @return*/public static PublicKey loadFilePublicKey(InputStream publicKeyInputStream){ObjectInputStream objectInputStream=null;try {objectInputStream=new ObjectInputStream(publicKeyInputStream);PublicKey publickey = (PublicKey)objectInputStream.readObject();objectInputStream.close();return publickey;} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}finally {if (objectInputStream!=null) {try {objectInputStream.close();} catch (IOException e) {e.printStackTrace();}}}return null;}/*** 從本地文件加載私鑰* @param PrivateKeyInputStream 輸入流* @return*/public static PrivateKey loadFilePrivateKey(InputStream PrivateKeyInputStream){ObjectInputStream objectInputStream=null;try {objectInputStream=new ObjectInputStream(PrivateKeyInputStream);PrivateKey privatekey = (PrivateKey)objectInputStream.readObject();objectInputStream.close();return privatekey;} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}finally {if (objectInputStream!=null) {try {objectInputStream.close();} catch (IOException e) {e.printStackTrace();}}}return null;}/*** 將整個(gè)KeyPair密鑰對(duì) 對(duì)象存在本地文件* * @param keyPair 公鑰私鑰對(duì)對(duì)象* @param out 輸出流* @return*/public static boolean storeKeyPair(KeyPair keyPair,OutputStream out){if ((keyPair == null) || (out == null)) {System.out.println("keyPair or OutputStream is null ");return false;}ObjectOutputStream objectOutputStream=null;try {objectOutputStream = new ObjectOutputStream(out);objectOutputStream.writeObject(keyPair);objectOutputStream.close();return true;} catch (IOException e) {e.printStackTrace();} finally {if (objectOutputStream != null) {try {objectOutputStream.close();} catch (IOException e) {e.printStackTrace();}}}return false;}/***將公鑰,私鑰分開存儲(chǔ)在IO流中* @param keyPair 公鑰私鑰對(duì)對(duì)象* @param out 輸出流* @return*/public static boolean storeKeyPair(KeyPair keyPair,OutputStream privateKeyOut,OutputStream publicKeyOut){PrivateKey privateKey = keyPair.getPrivate();PublicKey publicKey=keyPair.getPublic();boolean resut=false;if (keyPair==null||privateKeyOut==null||publicKeyOut==null) {System.out.println("指定的IO流或者密鑰對(duì) 對(duì)象為null");return resut;}ObjectOutputStream privateKeyStream = null;ObjectOutputStream publicKeyStream = null;try {privateKeyStream = new ObjectOutputStream(privateKeyOut);privateKeyStream.writeObject(privateKey);publicKeyStream = new ObjectOutputStream(publicKeyOut);publicKeyStream.writeObject(publicKey);resut = true;privateKeyStream.close();publicKeyStream.close();} catch (IOException e) {e.printStackTrace();}finally {if (privateKeyStream!=null&&publicKeyStream!=null) {try {privateKeyStream.close();publicKeyStream.close();} catch (IOException e) {e.printStackTrace();}}}return resut;}/*** 生成KeyPair公鑰私鑰對(duì)* * @return*/public static KeyPair generatorkeyPair(){try {KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);keyPairGenerator.initialize(1024);return keyPairGenerator.generateKeyPair();} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return null;} }DataSignaturer(實(shí)現(xiàn)簽名和驗(yàn)證):
package com.fitc.soldier.service.common;import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec;/**<pre>* 實(shí)現(xiàn)數(shù)字簽名的類* X509EncodedKeySpec和PKCS8EncodedKeySpec兩個(gè)類在加密解密環(huán)節(jié)中經(jīng)常會(huì)用到。* 密鑰很可能會(huì)以二進(jìn)制方式存儲(chǔ)于文件中,由程序來讀取。這時(shí)候,就需要通過這兩個(gè)類將文件中的字節(jié)數(shù)組* 讀出轉(zhuǎn)換為密鑰對(duì)象。* </pre>*/ public class DataSignaturer {/*** 私鑰*/private PrivateKey privateKey;/*** 公鑰*/private PublicKey publicKey;/*** key 工廠*/private KeyFactory keyFactory;public DataSignaturer(PrivateKey privateKey, PublicKey publicKey) throws NoSuchAlgorithmException {super();this.privateKey = privateKey;this.publicKey = publicKey;this.keyFactory=KeyFactory.getInstance(privateKey.getAlgorithm());}/*** 進(jìn)行數(shù)字簽名* @param data* @return*/public byte[] sign(byte[] resoure){if (privateKey==null||publicKey==null) {System.out.println("privateKey or publicKey is null ");return null;}try { // 初始化簽名算法// String signatuureAlgorithm=""; // if (algorithm.equals("RSA")) { // signatuureAlgorithm="MD5withRSA"; // signatuureAlgorithm="SHA1withRSA"; // }else if (algorithm.equals("DSA")) { // signatuureAlgorithm="SHA1withDSA"; // }else { // signatuureAlgorithm="SHA1withECDSA"; // }// 或者為了方便統(tǒng)一使用SHA1with**的簽名算法PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded()); PrivateKey privatekey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);Signature signature=Signature.getInstance("SHA1with"+privateKey.getAlgorithm());signature.initSign(privatekey);signature.update(resoure);return signature.sign();} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) {e.printStackTrace();}return null;}/*** 驗(yàn)證數(shù)字簽名* @param data* @param signature* @return*/public boolean verifySign(byte[] resoure, byte[] signature) {if (privateKey == null || publicKey == null) {System.out.println("privateKey or publicKey is null ");return false;}try {X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec (publicKey.getEncoded());PublicKey publickey = keyFactory.generatePublic(x509EncodedKeySpec);Signature verifySign = Signature.getInstance("SHA1with"+publicKey.getAlgorithm());verifySign.initVerify(publickey);verifySign.update(resoure);return verifySign.verify(signature);} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) {e.printStackTrace();}return false;} }StringHelper(Base64編碼工具類):
package com.fitc.soldier.service.common;import java.io.IOException;import org.apache.commons.lang.StringUtils;import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;/*** *Base64的編解碼*將密鑰編碼成Base64 以便傳輸和查看*/ public class StringHelper {/** * BASE64Encoder 加密 * @param data 要加密的數(shù)據(jù) * @return 加密后的字符串 */ public static String encoderBase64(byte[] data){if (data==null||data.length==0) {return "";}BASE64Encoder base64Encoder = new BASE64Encoder();return base64Encoder.encode(data);}/** * BASE64Decoder 解密 * @param data 要解密的字符串 * @return 解密后的byte[] * @throws Exception */ public static byte[] decoderBase64(String encodeString) throws IOException{if (StringUtils.isEmpty(encodeString)) {return null;}BASE64Decoder base64Encoder = new BASE64Decoder();return base64Encoder.decodeBuffer(encodeString);}}console 輸出:
總結(jié).
在使用簽名算法對(duì)數(shù)據(jù)進(jìn)行數(shù)據(jù)簽名和驗(yàn)證時(shí),主要步驟
1.創(chuàng)建Signature對(duì)象
Signature verifySign = Signature.getInstance(String?algorithm);//algorith為前面表格中的值
2.初始化:
Signature .initVerify(PublicKey?publicKey)/Signature .initSign(PrivateKey?privateKey)
3.填充數(shù)據(jù):
?? ?Signature.update(byte[] data);
簽名和驗(yàn)證
4.Signature.sign() 和 verify(byte[] signature)方法.
---------------------------------------------------分割線-----------------------------------------------
?
?
參考:https://www.cnblogs.com/huangzijian/p/6347293.html
轉(zhuǎn)載于:https://my.oschina.net/u/3406827/blog/1600595
總結(jié)
以上是生活随笔為你收集整理的数字签名的java实现(RSA,DSA)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 增值税为什么不用计提
- 下一篇: 函数与导数题目类型和解法思路的总结