Java实现RSA密钥对并在加解密、加签验签中应用的实例
一.项目结构
二.代码具体实现
1.密钥对生成的两种方式:一种生成公钥私文件,一种生成公钥私串
KeyPairGenUtil.java
package com.wangjinxiang.genkey.util; import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import sun.misc.BASE64Encoder; public class KeyPairGenUtil { /** 指定加密算法为RSA */
private static final String ALGORITHM = "RSA";
/** 密钥长度,用来初始化 */
private static final int KEYSIZE = 1024;
/** 指定公钥存放文件 */
private static String PUBLIC_KEY_FILE = "PublicKey";
/** 指定私钥存放文件 */
private static String PRIVATE_KEY_FILE = "PrivateKey"; public static void main(String[] args) throws Exception {
//generateKeyPair();
genKeyPair();
} /**
* 生成密钥对文件
* @throws Exception
*/
private static void generateKeyPair() throws Exception { // /** RSA算法要求有一个可信任的随机数源 */
// SecureRandom secureRandom = new SecureRandom();
/** 为RSA算法创建一个KeyPairGenerator对象 */
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM); /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
// keyPairGenerator.initialize(KEYSIZE, secureRandom);
keyPairGenerator.initialize(KEYSIZE); /** 生成密匙对 */
KeyPair keyPair = keyPairGenerator.generateKeyPair(); /** 得到公钥 */
Key publicKey = keyPair.getPublic(); /** 得到私钥 */
Key privateKey = keyPair.getPrivate(); ObjectOutputStream oos1 = null;
ObjectOutputStream oos2 = null;
try {
/** 用对象流将生成的密钥写入文件 */
oos1 = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE));
oos2 = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE));
oos1.writeObject(publicKey);
oos2.writeObject(privateKey);
} catch (Exception e) {
throw e;
} finally {
/** 清空缓存,关闭文件输出流 */
oos1.close();
oos2.close();
}
} /**
* 生成密钥对
* @throws NoSuchAlgorithmException
*/
private static void genKeyPair() throws NoSuchAlgorithmException { /** RSA算法要求有一个可信任的随机数源 */
SecureRandom secureRandom = new SecureRandom(); /** 为RSA算法创建一个KeyPairGenerator对象 */
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM); /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
keyPairGenerator.initialize(KEYSIZE, secureRandom);
//keyPairGenerator.initialize(KEYSIZE); /** 生成密匙对 */
KeyPair keyPair = keyPairGenerator.generateKeyPair(); /** 得到公钥 */
Key publicKey = keyPair.getPublic(); /** 得到私钥 */
Key privateKey = keyPair.getPrivate(); byte[] publicKeyBytes = publicKey.getEncoded();
byte[] privateKeyBytes = privateKey.getEncoded(); String publicKeyBase64 = new BASE64Encoder().encode(publicKeyBytes);
String privateKeyBase64 = new BASE64Encoder().encode(privateKeyBytes); System.out.println("publicKeyBase64.length():" + publicKeyBase64.length());
System.out.println("publicKeyBase64:" + publicKeyBase64); System.out.println("privateKeyBase64.length():" + privateKeyBase64.length());
System.out.println("privateKeyBase64:" + privateKeyBase64);
}
}
2.将密钥串生成方式的密钥对在常量类里定义,以便后面的应用使用
Constants.java
package com.wangjinxiang.constant; public class Constants { //#priKeyText
public final static String priKeyText = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJg7beoxy+/SCkaz3ut+bEhOOPPmb+yNngmBi88Gz4kfAP9IK/tMkIQpWbhpdMQ9NdGQ3suBSNBOcQYZLUkFjjPKqmeYlx+k3Fal2ADIT/imgwnytxm+qbXgM6M0f7r2bCkh0mTJIe7NQLNC0wnwYbajA1z1+tM6lmjOVxRZsZZ9AgMBAAECgYAoGzAgDTJ/YkTWz7ihLlN00Tbr+v/twHmsY3bj+hVfOM3Yc7kyob9JMmOy1AWxVbcCGTq5PrxiNOhOBQALRu1pivDsGDm2wA+Jb4vSIwL8dFCnIMlFFPMUb5VwtNIdlEZDQdZoLV7185OJ4IEK//GuNTwCklZNIOZ0j0YMEUw7uQJBAN5C3QpRWfwRhDf1S5+RaQPZWKehuc3DU2T67/tIUOKkSnY/KUX4KxPxCXXRsrbzU4mwoW0npBO3mtuOFDsk788CQQCvVzdjz7TZXFcGOjhk1e+id/ElW69/nt6DQmwUnJYyNS4cYfKoGD/RAxN0xaAoXsl6u3FGzY7TjLsuf6Wn3vvzAkAmLGW6d+50lK2YztCGP3tB5fqMEALRjFKubUr6ZZk+0+jWFlMIaW88pZFyYunG8lPOuj9/d+d+W3KFcwmWfumRAkApho1OrSVWiQDvL6CleOk84A0TXOhuYBCwo213YDJOB7w46pWOa9fJR2I3OIqapQAwee3057/YqC64b3CrFiszAkEAttDMWhXlagXMjwZAjEuuHK3CVCqRPNhZlnoX5A5RWIg0+BpHNQDfVSlYBtki361zB8L3HR8YfJIOWk/4S+ORLg=="; //#pubKeyText
public final static String pubKeyText = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYO23qMcvv0gpGs97rfmxITjjz5m/sjZ4JgYvPBs+JHwD/SCv7TJCEKVm4aXTEPTXRkN7LgUjQTnEGGS1JBY4zyqpnmJcfpNxWpdgAyE/4poMJ8rcZvqm14DOjNH+69mwpIdJkySHuzUCzQtMJ8GG2owNc9frTOpZozlcUWbGWfQIDAQAB";
}
DigestUtil.java
package com.wangjinxiang.util; public class DigestUtil { /**
* 字节转为十六进制字符串
* @param字节
* @return 十六进制字符串
*/
public static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (int n = 0; b != null && n < b.length; n++) {
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1)
hs = hs + "0" + stmp;
else
hs = hs + stmp;
}
return hs;
} /**
* 十六进制字符转为字节
* @param 十六进制字符
* @return 字节
*/
public static byte[] hex2byte(byte[] b) {
if ((b.length % 2) != 0)
throw new IllegalArgumentException("byte length is not correct");
byte[] b2 = new byte[b.length / 2];
for (int n = 0; n < b.length; n += 2) {
String item = new String(b, n, 2);
b2[n / 2] = (byte) Integer.parseInt(item, 16);
}
return b2;
} /**
* 字符串转换成十六进制值
* @param bin String 我们看到的要转换成十六进制的字符串
* @return
*/
public static String bin2hex(String bin) {
char[] digital = "0123456789ABCDEF".toCharArray();
StringBuffer sb = new StringBuffer("");
byte[] bs = bin.getBytes();
int bit;
for (int i = 0; i < bs.length; i++) {
bit = (bs[i] & 0x0f0) >> 4;
sb.append(digital[bit]);
bit = bs[i] & 0x0f;
sb.append(digital[bit]);
}
return sb.toString();
}
}
3.加解密应用实例RSAUtil.java
说明:加解密是用公钥加密,用私钥解密
package com.wangjinxiang.util; import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
import com.wangjinxiang.constant.Constants;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder; public class RSAUtil { /** 指定加密算法为RSA */
private static final String ALGORITHM = "RSA"; public static void main(String[] args) throws Exception { String source = "深圳,您好!";// 要加密的字符串
System.out.println("准备用公钥加密的字符串为:" + source); String cryptograph = encrypt(source);// 生成的密文
System.out.print("用公钥加密后的结果为:" + cryptograph);
System.out.println(); String target = decrypt(cryptograph);// 解密密文
System.out.println("用私钥解密后的字符串为:" + target);
System.out.println();
} /**
* 加密方法
* @param source 源数据
* @return
* @throws Exception
*/
public static String encrypt(String source) throws Exception { java.security.spec.X509EncodedKeySpec x509KeySpec = new java.security.spec.X509EncodedKeySpec(Base64.decodeBase64(Constants.pubKeyText));
// RSA算法
java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
// 取公钥匙对象
java.security.PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
// 得到Cipher对象来实现对源数据的RSA加密
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] b = source.getBytes();
/** 执行加密操作 */
byte[] b1 = cipher.doFinal(b);
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(b1);
} /**
* 解密算法
* @param cryptograph 密文
* @return
* @throws Exception
*/
public static String decrypt(String cryptograph) throws Exception { PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(Constants.priKeyText));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyf.generatePrivate(priPKCS8); /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
BASE64Decoder decoder = new BASE64Decoder();
byte[] b1 = decoder.decodeBuffer(cryptograph); /** 执行解密操作 */
byte[] b = cipher.doFinal(b1);
return new String(b);
}
}
运行结果:
准备用公钥加密的字符串为:深圳,您好!
用公钥加密后的结果为:Q5bZjBlIIPII04NOCIwYDPYBGNSC5Hv7XKc8TlkCRbZyAK4M4nm9uYcEded0Nbj7HeLXNZY8XrQD
l2+FsYjfL0DlioCoJQm7bnwlVwYmdNMXOB3bfepywpeFRDSNswJxueLqVtmIKcbuCuXBvdIqrfDq
PVbCVfI59/GhqAcqM6U=
用私钥解密后的字符串为:深圳,您好!
4.加签验签实例SignUtil.java
说明:加签是用私钥,验签是用公钥
package com.wangjinxiang.util; import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import org.apache.commons.codec.binary.Base64;
import com.wangjinxiang.constant.Constants; public class SignUtil { private final static String CHARACTER_ENCODING_UTF_8 = "UTF-8"; public static void main(String[] args) { String signString = "深圳,您好!";
try {
// 加签
String localSignature = SignUtil.sign(Constants.priKeyText.getBytes(CHARACTER_ENCODING_UTF_8), signString);
System.out.println(localSignature);
//验签
boolean verifyResult = SignUtil.verify(Constants.pubKeyText.getBytes(CHARACTER_ENCODING_UTF_8), signString, localSignature);
System.out.println("verifyResult:" + verifyResult);
} catch (Exception e) {
e.printStackTrace();
}
} /**
* RSA私钥加签
* @param priKeyText经过base64处理后的私钥
* @param plainText明文内容
* @return 十六进制的签名字符串
* @throws Exception
*/
public static String sign(byte[] priKeyText, String plainText) throws Exception {
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(priKeyText));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey prikey = keyf.generatePrivate(priPKCS8); // 用私钥对信息生成数字签名
java.security.Signature signet = java.security.Signature.getInstance("SHA256withRSA");
signet.initSign(prikey);
signet.update(plainText.getBytes("UTF-8"));
return DigestUtil.byte2hex(signet.sign());
} catch (Exception e) {
throw e;
}
} /**
* 公钥验签
* @param pubKeyText经过base64处理后的公钥
* @param plainText明文内容
* @param signText十六进制的签名字符串
* @return 验签结果 true验证一致 false验证不一致
*/
public static boolean verify(byte[] pubKeyText, String plainText, String signText) {
try {
// 解密由base64编码的公钥,并构造X509EncodedKeySpec对象
java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(
Base64.decodeBase64(pubKeyText));
// RSA算法
java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
// 取公钥匙对象
java.security.PublicKey pubKey = keyFactory.generatePublic(bobPubKeySpec);
// 十六进制数字签名转为字节
byte[] signed = DigestUtil.hex2byte(signText.getBytes("UTF-8"));
java.security.Signature signatureChecker = java.security.Signature.getInstance("SHA256withRSA");
signatureChecker.initVerify(pubKey);
signatureChecker.update(plainText.getBytes("UTF-8"));
// 验证签名是否正常
return signatureChecker.verify(signed);
} catch (Throwable e) {
return false;
}
}
}
运行结果:
7ef0cd04a3dc41ae1396a90a3d8a8b799c68c65202361823dd3a71a05fc2bf57c09ebe2074ba49008cf58288297267d770137ee267c6c296a784c7d50c607c73e1d78799c7de5dadf183f011d604df7270ce5616e465ddc93a95df9095249702fc265e97ed7ab2adf4535d13237040653d7f000a3080a0c4f11f84bbe48849e7
verifyResult:true
5.从生成的密钥对文件中读取公私钥加解密实例RSAUtil02.java
package com.wangjinxiang.util2; import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.security.Key; import javax.crypto.Cipher; import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder; public class RSAUtil02 { /** 指定加密算法为RSA */
private static final String ALGORITHM = "RSA";
/** 指定公钥存放文件 */
private static String PUBLIC_KEY_FILE = "PublicKey";
/** 指定私钥存放文件 */
private static String PRIVATE_KEY_FILE = "PrivateKey"; public static void main(String[] args) throws Exception { String source = "深圳,您好!";// 要加密的字符串
System.out.println("准备用公钥加密的字符串为:" + source); String cryptograph = encrypt(source);// 生成的密文
System.out.print("用公钥加密后的结果为:" + cryptograph);
System.out.println(); String target = decrypt(cryptograph);// 解密密文
System.out.println("用私钥解密后的字符串为:" + target);
System.out.println();
} /**
* 加密方法
* @param source 源数据
* @return
* @throws Exception
*/
public static String encrypt(String source) throws Exception { Key publicKey = getKey(PUBLIC_KEY_FILE); /** 得到Cipher对象来实现对源数据的RSA加密 */
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] b = source.getBytes();
/** 执行加密操作 */
byte[] b1 = cipher.doFinal(b);
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(b1);
} /**
* 解密算法
* @param cryptograph 密文
* @return
* @throws Exception
*/
public static String decrypt(String cryptograph) throws Exception { Key privateKey = getKey(PRIVATE_KEY_FILE); /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
BASE64Decoder decoder = new BASE64Decoder();
byte[] b1 = decoder.decodeBuffer(cryptograph); /** 执行解密操作 */
byte[] b = cipher.doFinal(b1);
return new String(b);
} private static Key getKey(String fileName) throws Exception, IOException {
Key key;
ObjectInputStream ois = null;
try {
/** 将文件中的私钥对象读出 */
ois = new ObjectInputStream(new FileInputStream(fileName));
key = (Key) ois.readObject();
} catch (Exception e) {
throw e;
} finally {
ois.close();
}
return key;
}
}
运行结果:
准备用公钥加密的字符串为:深圳,您好!
用公钥加密后的结果为:Ep2Y6EstlUWQnmVxsZ0/NIV1NFIPAlg8rJguRdQB+2uBD+/sunrPiVoCm3zbuj317CNG5hwijNBf
qKETmd7HoftpnHxzYwn+lWqlVdUHIO+ZrFn2OB6omlA/aFHCZzIHtKDU72cNuiBiwONxCXyaWq4Z
scDfvzbz3//UYOhlDs4=
用私钥解密后的字符串为:深圳,您好!
Java实现RSA密钥对并在加解密、加签验签中应用的实例的更多相关文章
- RSA - 原理、特点(加解密及签名验签)及公钥和私钥的生成
Wiki - RSA加密演算法 Wiki - 欧拉函数 Wiki - 模反元素 ASN.1 格式标准 RSA算法原理(二) 注意: RSA 加密或签名后的结果是不可读的二进制,使用时经常会转为 BAS ...
- [Python3] RSA的加解密和签名/验签实现 -- 使用pycrytodome
Crypto 包介绍: pycrypto,pycrytodome 和 crypto 是一个东西,crypto 在 python 上面的名字是 pycrypto 它是一个第三方库,但是已经停止更新,所以 ...
- RSA密钥生成、加密解密、签名验签
RSA 非对称加密公钥加密,私钥解密 私钥签名,公钥验签 下面是生成随机密钥对: //随机生成密钥对 KeyPairGenerator keyPairGen = null; try { keyPair ...
- RSA体系 c++/java相互进行加签验签--转
在web开发中,采用RSA公钥密钥体系自制ukey,文件证书登陆时,普遍的做法为:在浏览器端采用c++ activex控件,使用 c++的第三库openssl进行RAS加签操作,在服务器端采用java ...
- RSA加密解密及RSA加签验签
RSA安全性应用场景说明 在刚接触RSA的时候,会混淆RSA加密解密和RSA加签验签的概念.简单来说加密解密是公钥加密私钥解密,持有公钥(多人持有)可以对数据加密,但是只有持有私钥(一人持有)才可以解 ...
- RSA加密解密与加签验签
RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.1987年7月首次在美国公布 ...
- 微信小程序(17)-- RSA加密 解密 加签 验签
RSA加密 解密 加签 验签 /** * 注:区分RSA私钥的类型,有pkcs1和pkcs8.pkcs8格式的私钥主要用于Java中 pkcs1格式: -----BEGIN RSA PRIVATE K ...
- Python rsa公私钥生成 rsa公钥加解密(分段加解密)-私钥加签验签实战
一般现在的SAAS服务提供现在的sdk或api对接服务都涉及到一个身份验证和数据加密的问题.一般现在普遍的做法就是配置使用非对称加密的方式来解决这个问题,你持有SAAS公司的公钥,SAAS公司持有你的 ...
- java RSA 加签验签【转】
引用自: http://blog.csdn.net/wangqiuyun/article/details/42143957/ java RSA 加签验签 package com.testdemo.co ...
随机推荐
- 002 python准备做题的一些准备
在这里,刷刷题,然后,将比较有用的连接粘贴一下在这里.
- 执行Android后台任务的最佳实践
灵活执行后台任务可以帮助提升应用性能,并最小化电量损耗. Android后台任务主题包含以下三个子主题: 1. 在IntentService中执行后台任务: 2. 使用CursorLoader在后台加 ...
- 潭州课堂25班:Ph201805201 tornado 项目 第六课 用户和图片分享的集成(课堂笔记)
tornado 相关说明 改善图片上传功能 ,生成唯一的 ID ,与路径拼接,生成 URL, 这里引用 uuid 的 python 库 在 photo.py 中创建个类,用来 辅助用户上传的图片,生 ...
- 使用第三方插件Gear Tacks 画齿轮
以下介绍第二种方法: 重复再生成一个大的齿轮 两个都保存起来: 再创建一个装配体环境. 接下来就是要达到使两个轮子配合转起来的效果! 步骤如下:
- js 类数组对象arguments
function Add() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } Add( ...
- JavaScript浏览器解析原理
首先,JavaScript的特点是: 1. 跨平台 可以再不同的操作系统上运行. 2. 弱类型 与之相对的是强类型 强类型:在定义变量的时候,需要将变量的数据类型表明.例如:Java 弱类型:定义变量 ...
- JDBC API 可滚动可编辑的结果集
JDBC的API中的链接数据和创建statement并且执行读取ResultSet大家已经很熟悉了,这边介绍设置statement的属性使结果集可以移动并且进行编辑同步回数据库. Statement ...
- 2018-2019-1 20189210 《LInux内核原理与分析》第六周作业
系统调用实验(下): 将第四章的两个实验集成到MenuOS系统中,将其作为MenuOS系统的两个命令,新版本的menu中已经把两个系统调用添加进去了,只需重新克隆一个新版本的menu. 使用make ...
- 什么是Hash?Hash有哪些特性?
Hash 把任意长度的输入通过散列算法变换成固定长度的输出 Hash的特性: 输入域无穷,输出域有限.例如:有无穷多个(在工程中可以具体到多少个,例如1000)输入参数经过hash函数映射后得到有限的 ...
- 表单/iframe与video标签
<form action="所有表单值提交的地址" method="传值的方式默认是GET方式,还有另一种POST方式"> 表单元素</for ...