数字签名的java实现(RSA,DSA)
2019独角兽企业重金招聘Python工程师标准>>>
基本概念:
数字签名,顾名思义,就类似于一种写在纸上的普通的物理签名.
简单说就是将文件内容进行hash散列(消息摘要),信息发送者对散列后的字符串使用私钥加密,得到的最终字符串就是签名。然后将得到的签名字符串添加到文件信息的后面一同发送出去。接收者获取到文件信息和签名后,使用公钥对签名进行解密,就得到文件内容和加密后的hash散列。此时,他可以对获取到的文件内容做hash散列,与签名中的hash散列进行匹对,从而鉴别出最终获取信息的真伪.
整个过程可以用如下图解理解.
算法种类:
常见的几种KeyPairGenerator算法
KeyPairGenerator
Algorithms
(除了指出,这些类创建Key.getAlgorithm()返回标准算法名称的密钥.)
生成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。 |
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等)一样 上) |
code实例:
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 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;}/*** 将整个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)方法.
---------------------------------------------------分割线-----------------------------------------------
参考:https://www.cnblogs.com/huangzijian/p/6347293.html
转载于:https://my.oschina.net/u/3406827/blog/1600595
数字签名的java实现(RSA,DSA)相关推荐
- java RSA/DSA/ECDSA实现数字签名
java RSA/DSA/ECDSA实现数字签名 标签: java RSADSAECDSA实现数字RSADSAECDSA实现数字签名 2015-12-13 14:51 1656人阅读 评论(0) 收藏 ...
- java使用RSA加密方式,实现数字签名
全栈工程师开发手册 (作者:栾鹏) java教程全解 java使用RSA加密方式,实现数字签名.数字签名,使用私钥获取签名,使用公钥校验签名 测试代码 public static void main( ...
- JAVA加密算法(DSA)
DSA DSA-Digital Signature Algorithm 是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard) ...
- dsa java_将Java转换为python DSA签名
有人知道我将如何将java代码转换成python吗?在/** * signs the data for the account account */ private byte[] sign(Strin ...
- 消息摘要和数字签名(Java简单实现)
摘要: 本文主要对数字签名和消息摘要进行简要介绍,并通过java实现基本流程. 概念介绍: 消息摘要 一个消息摘要是一个数据块的数字指纹.即对一个任意长度的一个数据块进行计算,产生一个唯一指印(对于 ...
- Java前端Rsa公钥加密,后端Rsa私钥解密(支持字符和中文)
Base64工具类,可以让rsa编码的乱码变成一串字符序列 package com.utils;import java.io.ByteArrayInputStream; import java.io. ...
- java中RSA数字证书生成,jks文件生成以及读取。
一.Java代码生成cer证书文件: public class GetCertFile { //证书颁发者 static String CertificateIssuer = "C= ...
- java的rsa作用_java 中RSA的方式实现非对称加密的实例
java 中rsa的方式实现非对称加密的实例 rsa通俗理解: 你只要去想:既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密:同理,既然是签名,那肯 ...
- javascript rsa java,用javascript与java执行
RSA加密与解密
用javascript与java执行 RSA加密与解密 2009-12-12 14:58:30 出处:https://www.yqdown.com 这几天一直做安全登录,网上查了好多资料,不尽如意 ...
最新文章
- 大触教你如何调节python内置函数
- vim-addon-manager install youcompleteme
- vtune下载 windows_intel vtune 介绍、安装和使用
- lua调用.so测试
- SQL笛卡尔积结合前后行数据的统计案例
- CSRF 1 (转)
- 使用router-view时组件之间的通信
- 评审专家:基金本子“瘦”点好
- CVPR 2020 | 3D目标检测泛化问题研究
- Android笔记 fragment入门 动态加载fragment demo+ 判断横竖屏
- nodejs在自然语言处理中的一些小应用
- 读嵌入式linux驱动程序设计从入门到精通1
- google 搜索关键字技巧 google darking
- [从源码学设计]蚂蚁金服SOFARegistry之服务上线
- Mysql Buffer Pool
- RSPO棕榈油供应链认证体系
- iPhone软件开发前需认真考虑问题
- Glib之GObject简介(翻译)
- 进程互斥锁,队列,IPC进程间通信,生产者与消费者,线程,线程对象的属性,先行互斥锁...
- Cartov for Mac 1.0.2 无尽旅图