数字签名,顾名思义,就相似于一种写在纸上的普通的物理签名.html
简单说就是将文件内容进行hash散列(消息摘要),信息发送者对散列后的字符串使用私钥加密,获得的最终字符串就是签名。而后将获得的签名字符串添加到文件信息的后面一同发送出去。接收者获取到文件信息和签名后,使用公钥对签名进行解密,就获得文件内容和加密后的hash散列。此时,他能够对获取到的文件内容作hash散列,与签名中的hash散列进行匹对,从而鉴别出最终获取信息的真伪.java
整个过程能够用以下图解理解.git
常见的几种KeyPairGenerator算法算法
KeyPairGenerator
Algorithms(除了指出,这些类建立Key.getAlgorithm()返回标准算法名称的密钥.)apache
生成KeyPairGenerator实例时能够指定本节中的算法名称.数组
Algorithm Name | Description |
---|---|
DiffieHellman | 为Diffie-Hellman密钥协商算法生成密钥对。 注意: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实例时能够指定本节中的算法名称。测试
Algorithm Name | Description |
---|---|
NONEwithRSA | RSA签名算法在执行RSA操做以前不使用摘要算法(例如MD5 /SHA1)。 |
MD2withRSA MD5withRSA |
使用MD2 / MD5摘要算法和RSA来建立和验证 |
SHA1withRSA SHA224withRSA SHA256withRSA SHA384withRSA SHA512withRSA |
使用 SHA- * 的签名算法和OSI Interoperability Workshop中定义的RSA加密算法 |
NONEwithDSA | FIPS PUB 186-2中定义的数字签名算法。 数据长度必须是20个字节。 这个算法也被称为rawDSA。this |
SHA1withDSA SHA224withDSA SHA256withDSA |
DSA签名算法使用SHA-1,SHA-224或SHA-256摘要算法来建立和验证编码 |
NONEwithECDSA SHA1withECDSA SHA224withECDSA SHA256withECDSA SHA384withECDSA SHA512withECDSA (ECDSA) |
ECDSA签名算法。 |
<digest>with<encryption> | 使用这个名称为具备特定消息摘要(如MD2或MD5)和算法(如RSA或DSA)的签名算法建立一个名称,就像本节中明肯定义的标准名称(MD2withRSA等)同样 上) |
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="这是一个测试文本!!!"; public static void main(String[] args) { // localKeyPairMethod(testContent); // localPrivatKeyMethod(testContent); generatorKey(testContent); } /** * 加载本地密钥对 */ public static void localKeyPairMethod(String Content){ try { File file = new File("ca.key"); FileOutputStream fileOutputStream = new FileOutputStream(file); //加载本地KeyPair 密钥对 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("验证签名结果\t"+dataSignaturer.verifySign(Content.getBytes(), sign)); } catch (FileNotFoundException | NoSuchAlgorithmException e) { e.printStackTrace(); } } /** * 加载本地私钥/公钥 对数据实现签名和验证 */ 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); //生成本地密钥 分别存储本地 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("验证签名结果\t"+dataSignaturer.verifySign(Content.getBytes(), sign)); } catch (FileNotFoundException | NoSuchAlgorithmException e) { e.printStackTrace(); } } /** * 使用密钥对 构建公私钥 对数据进行签名和验证 */ 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标准做为密钥规范管理的编码格式 转换成 密钥 // 在 Java 语言中,此类表示基于在 PKCS 8 标准中定义的 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("原文内容:\t"+Content); System.out.println("签名结果:\t"+Hex.encodeHexString(sign)); //建立公钥 ,使用公钥验证签名 X509EncodedKeySpec ASN.1 类型的编码密钥 X509EncodedKeySpec x509encodedkeyspec=new X509EncodedKeySpec(publicKey.getEncoded()); PublicKey generatePublic = keyFactory.generatePublic(x509encodedkeyspec); signature.initVerify(generatePublic); signature.update(Content.getBytes()); System.out.println("原文内容:\t"+Content); System.out.println("验证签名是否经过:\t"+signature.verify(sign)); } catch (NoSuchAlgorithmException | InvalidKeySpecException | SignatureException | InvalidKeyException e) { e.printStackTrace(); } } }
KeyPairUtil(密钥对的生成或者 加载本地密钥文件):
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 秘钥对生成器生成而后保存到本地</br> *或者直接读取本地的密钥文件 *</pre> */ public class KeyPairUtil { // 能够用DSA,也能够用RSA public static final String KEY_ALGORITHM="RSA"; /** * 从输入流中获取KeyPair 秘钥对 对象 * @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 block e.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; } /** * 将整个KeyPair密钥对 对象存在本地文件 * * @param keyPair 公钥私钥对对象 * @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; } /** *将公钥,私钥分开存储在IO流中 * @param keyPair 公钥私钥对对象 * @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流或者密钥对 对象为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公钥私钥对 * * @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(实现签名和验证):
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> * 实现数字签名的类 * X509EncodedKeySpec和PKCS8EncodedKeySpec两个类在加密解密环节中常常会用到。 * 密钥极可能会以二进制方式存储于文件中,由程序来读取。这时候,就须要经过这两个类将文件中的字节数组 * 读出转换为密钥对象。 * </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()); } /** * 进行数字签名 * @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"; // } // 或者为了方便统一使用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; } /** * 验证数字签名 * @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 要加密的数据 * @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 输出:
在使用签名算法对数据进行数据签名和验证时,主要步骤
1.建立Signature对象
Signature verifySign = Signature.getInstance(String algorithm);//algorith为前面表格中的值
2.初始化:
Signature .initVerify(PublicKey publicKey)/Signature .initSign(PrivateKey privateKey)
3.填充数据:
Signature.update(byte[] data);
签名和验证
4.Signature.sign() 和 verify(byte[] signature)方法.
---------------------------------------------------分割线-----------------------------------------------