import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
/**
* RSA非对称加密算法。用法:1 公钥加密,私钥解密;2 私钥签名,公钥验证签名。
*/
public class RSAUtils {
/** 指定加密算法为RSA */
public static final String ALGORITHM = "RSA";
/** 签名算法 */
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
/** 指定key的大小*/
public static final int KEYSIZE = 1024;
/** 加密时支持的最大字节数为【证书位数/8 -11】,1024位的证书加密时最大支持117个字节,2048位的证书加密时最大支持245个字节*/
public static final int MAX_ENCRYPT_SIZE = KEYSIZE / 8 - 11 - 1;
/** 解密是支持的最大字节数为【证书位数/8】,1024位的证书解密时最大支持128个字节,2048位的证书解密时最大支持256个字节*/
public static final int MAX_DECRYPT_SIZE = KEYSIZE / 8;
/** 指定公钥存放文件 */
public static final String PUBLIC_KEY_FILE = "PublicKey";
/** 指定私钥存放文件 */
public static final String PRIVATE_KEY_FILE = "PrivateKey";
/** 字符串编码 */
public static final String CHARSET = "UTF-8";
public static void main(String[] args) throws Exception {
generateKeyPair();
test1("1");
String source = "一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九";//刚刚好117个字符
test1(source);//证书位数为1024时,加密超过117个字符就会报异常:javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes
test2(source + "我可以超过117个字符");
test3(source.getBytes(CHARSET));
}
private static void test1(String source) throws Exception {
String cryptograph = encrypt(source);// 生成的密文
String target = decrypt(cryptograph);// 解密密文
System.out.println("加密前【" + source + "】\n加密后【" + cryptograph + "】\n解密后【" + target + "】\n");
}
private static void test2(String source) throws Exception {
byte[] cryptograph = encrypt(source.getBytes(CHARSET));// 生成的密文
String cryptographStr = Base64.getEncoder().encodeToString(cryptograph);//这里不能用new String()来还原字符串
byte[] target = decrypt(cryptograph);// 解密密文
System.out.println("加密前【" + source + "】\n加密后【" + cryptographStr + "】\n解密后【" + new String(target, CHARSET) + "】\n");
}
private static void test3(byte[] datas) throws Exception {
byte[] signature = sign(datas);
System.out.println("原始数据"+Arrays.toString(datas));
System.out.println("签名数据"+Arrays.toString(signature));
System.out.println("签名是否正确:" + verify(datas, signature));
}
//******************************************************************************************
// 生成密钥
//******************************************************************************************
/**
* 生成并持久化密钥对
*/
public static void generateKeyPair() throws Exception {
/** RSA算法要求有一个可信任的随机数源 */
SecureRandom sr = new SecureRandom();
/** 为RSA算法创建一个KeyPairGenerator对象 */
KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
kpg.initialize(KEYSIZE, sr);
/** 生成密匙对 */
KeyPair kp = kpg.generateKeyPair();
/** 得到公钥 */
Key publicKey = kp.getPublic();
/** 得到私钥 */
Key privateKey = kp.getPrivate();
/** 用对象流将生成的密钥写入文件 */
ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE));
ObjectOutputStream oos2 = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE));
oos1.writeObject(publicKey);
oos2.writeObject(privateKey);
/** 清空缓存,关闭文件输出流 */
oos1.close();
oos2.close();
}
/**
* 获取公钥
*/
public static Key getPublicKey() throws Exception {
/** 将文件中的公钥对象读出 */
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PUBLIC_KEY_FILE));
Key key = (Key) ois.readObject();//直接从持久化对象中获取KEY
ois.close();
return key;
}
/**
* 获取私钥
*/
public static Key getPrivateKey() throws Exception {
/** 将文件中的私钥对象读出 */
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PRIVATE_KEY_FILE));
Key key = (Key) ois.readObject();
ois.close();
return key;
}
//******************************************************************************************
// 加解密
//******************************************************************************************
/**
* 加密
*/
public static String encrypt(String source) throws Exception {
/** 得到Cipher对象来实现对源数据的RSA加密 */
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey());//加密模式
/** 执行加密操作*/
byte[] b1 = cipher.doFinal(source.getBytes(CHARSET));
return Base64.getEncoder().encodeToString(b1);
}
/**
* 解密
*/
public static String decrypt(String cryptograph) throws Exception {
/** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey());//解密模式
byte[] b1 = Base64.getDecoder().decode(cryptograph);
/** 执行解密操作 */
byte[] b = cipher.doFinal(b1);
return new String(b, CHARSET);
}
//******************************************************************************************
// 分段加解密
//******************************************************************************************
/**
* 分段加密
*/
public static byte[] encrypt(byte[] data) throws Exception {
Cipher cipher = Cipher.getInstance(getPublicKey().getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey());
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
for (int i = 0; inputLen - offSet > 0; offSet = i * MAX_ENCRYPT_SIZE) {
byte[] cache;
if (inputLen - offSet > MAX_ENCRYPT_SIZE) cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_SIZE);
else cache = cipher.doFinal(data, offSet, inputLen - offSet);
out.write(cache, 0, cache.length);
++i;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
/**
* 分段解密
*/
public static byte[] decrypt(byte[] encryptedData) throws Exception {
Cipher cipher = Cipher.getInstance(getPrivateKey().getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey());
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
for (int i = 0; inputLen - offSet > 0; offSet = i * MAX_DECRYPT_SIZE) {
byte[] cache;
if (inputLen - offSet > MAX_DECRYPT_SIZE) cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_SIZE);
else cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
out.write(cache, 0, cache.length);
++i;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
//******************************************************************************************
// 签名
//******************************************************************************************
/**
* 用私钥对信息生成数字签名
*/
public static byte[] sign(byte[] data) throws Exception {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign((PrivateKey) getPrivateKey());
signature.update(data);
return signature.sign();
}
/**
* 用公钥校验数字签名
* @param data 已加密数据
* @param sign 数字签名
*/
public static boolean verify(byte[] data, byte[] sign) throws Exception {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify((PublicKey) getPublicKey());
signature.update(data);
return signature.verify(sign);
}
}
测试结果
加密前【1】
加密后【GibdXMLtPXHgw2A0MtESRboqrmAApTpfPAODrcGkzTXgw+gbkdQWU9ICjpFye+w1muh5loatUxL2cDqBvM25UnPhXAkh9QZZfiCfHxGPGyH6Evk1Cw/Jns4usqyz8tv5/gf/AXogIktmrvV70yb/yRga49qDBfJGJ4zTJ3nOR4Q=】
解密后【1】
加密前【一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九】
加密后【ckc7RKtnog1sFI/RmNZ9s3WRBYQ3wPxGSWE4uWDq27pwf4chvEYZv8J2UcSC7yuT1oTHFLqjnr6qW1X/k8SXZSfaqdUyYUgyr4YNE7D7nmt5bYxqFec0PMEOq73GVDeay1c+crXC+HEFGxSs97mo8j5uJG4oT6sDCA1PNdja9ss=】
解密后【一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九】
加密前【一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九我可以超过117个字符】
加密后【O9+kTPKFz311XIQcgoR/fVMp/qVJTjEgXbi5+f8ZhvE4/0NFlc2CYTqZu4XTdIeJEIfBvKUcntKV6z1mf5lkk/mWJoDV8HPkcBgvjATkmbtU5oD2kTEhECyvxKYsfsvC1ybj9iUzWnePm6CLLM2PCV4H2D+cMknn6cbnkapz0TxdjUk1uAlZLM7/hDqRkW/sv5CQIBd5lJqtY3ffFHX2jIw8m9DbMO/tL5nRSTTgrs+fmJQYjAZcik+KTui98SyVbNa7lx9jPN0ySl0ehgKIz2SiS7Pby4Ys3Opa2H/INpjWJY0gkIYg3t1JAhCk7FalG7ZpgXWy7fzc4RnNlYcN1A==】
解密后【一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九我可以超过117个字符】
原始数据[-28, -72, -128, -28, -70, -116, -28, -72, -119, -27, -101, -101, -28, -70, -108, -27, -123, -83, -28, -72, -125, -27, -123, -85, -28, -71, -99, -27, -115, -127, -28, -72, -128, -28, -70, -116, -28, -72, -119, -27, -101, -101, -28, -70, -108, -27, -123, -83, -28, -72, -125, -27, -123, -85, -28, -71, -99, -27, -115, -127, -28, -72, -128, -28, -70, -116, -28, -72, -119, -27, -101, -101, -28, -70, -108, -27, -123, -83, -28, -72, -125, -27, -123, -85, -28, -71, -99, -27, -115, -127, -28, -72, -128, -28, -70, -116, -28, -72, -119, -27, -101, -101, -28, -70, -108, -27, -123, -83, -28, -72, -125, -27, -123, -85, -28, -71, -99]
签名数据[105, -36, 107, -65, 87, -111, 93, -11, -68, 31, 0, 96, 41, -43, 9, -11, 102, 44, 24, 67, 118, -109, 75, -124, -77, -27, -43, -56, -111, -69, 99, 105, -71, -73, 111, 119, 84, -81, 104, -81, 35, -91, -81, 121, -5, -78, 74, 120, 41, 15, 16, -54, -42, -55, 72, 59, -54, -59, -38, -62, 49, 112, -105, 102, -78, -91, 102, -83, 65, -50, -95, -44, 20, -34, -105, -62, 100, -103, -88, -11, -24, 123, -34, -110, 80, 70, 74, -73, -119, -123, -126, -20, -61, 59, -35, -62, -35, 117, -115, -43, 19, 85, 74, 44, -15, -109, -9, -11, -113, 82, -10, 74, 38, 109, 87, 79, 97, 127, -56, 31, -9, -20, 11, 59, -64, -57, 13, -80]
签名是否正确:true
- iOS RSA加解密签名和验证
转自:http://www.jianshu.com/p/81b0b54436b8 Pre:在公司负责了一个项目,需要用到iOS RSA验证签名的功能.后台给我的仅仅是一个公钥的字符串.经过起初的一段时 ...
- 调用OpenSSL实现RSA加解密和签名操作
调用OpenSSL实现RSA加解密和签名操作 RSA公钥可以从证书和公钥文件,RSA私钥可以从私钥文件中提取.OpenSSL使用了一种BIO抽象IO机制读写所用文件,可以打开文件相关联的BIO,通过B ...
- RSA加解密用途简介及java示例
在公司当前版本的中间件通信框架中,为了防止非授权第三方和到期客户端的连接,我们通过AES和RSA两种方式的加解密策略进行认证.对于非对称RSA加解密,因为其性能耗费较大,一般仅用于认证连接,不会用于每 ...
- PHP RSA加解密示例(转)
1.生成密钥和公钥 开始前需要准备openssl环境 linux 需要安装openssl工具包,传送门http://www.openssl.org/source/ window 下需要安装openss ...
- iOS使用Security.framework进行RSA 加密解密签名和验证签名
iOS 上 Security.framework为我们提供了安全方面相关的api: Security框架提供的RSA在iOS上使用的一些小结 支持的RSA keySize 大小有:512,768,10 ...
- 【go语言】RSA加解密
关于go语言的RSA加解密的介绍,这里有一篇文章,已经介绍的很完整了. 对应的go语言的加解密代码,参考git. 因为原文跨语言是跟php,我这里要跟c语言进行交互,所以,这里贴上c语言的例子. 参考 ...
- java RSA加解密以及用途
在公司当前版本的中间件通信框架中,为了防止非授权第三方和到期客户端的连接,我们通过AES和RSA两种方式的加解密策略进行认证.对于非对称RSA加解密,因为其性能耗费较大,一般仅用于认证连接,不会用于每 ...
- 与非java语言使用RSA加解密遇到的问题:algid parse error, not a sequence
遇到的问题 在一个与Ruby语言对接的项目中,决定使用RSA算法来作为数据传输的加密与签名算法.但是,在使用Ruby生成后给我的私钥时,却发生了异常:IOException: algid parse ...
- RSA加解密-2
Java使用RSA加密解密签名及校验 package com.ihep; import java.io.BufferedReader; import java.io.BufferedWriter; ...
随机推荐
- windows相关小知识
获得本机MAC1 快捷键win+R打开运行窗口, 输入cmd回车进入控制台2 输入ipconfig -all 找到本地连接中的物理地址 根据IP获得MAC方法:1 进入cmd控制台,执行:ping ...
- iOS 宏定义_16进制色值转化为RGB返回UIColor类型对象
// 十六进制颜色 #define COLOR_WITH_HEX(hexValue) [UIColor colorWithRed:((float)((hexValue & 0xFF0000) ...
- VC 项目支撑文件解释
1.解决方案文件: a.sln 解决方案.把项目中的所有元素或者多个项目整合到一个解决方案中去. b.suo 解决方案定制项.存储用户级别对解决方案的定制,比如打开状态,断点信息. 这两个文件 ...
- server-send event object
http://jamie-wang.iteye.com/blog/1849193 event -- onmessage, onopen, onerror 不是方法,而是事件 http://school ...
- 为什么用GPU挖比特币?
http://www.leiphone.com/gpubitcoin.html 呵呵,这么红火的东东,不了解就长不了见识. 转一下两个东东,这挖矿机天天在算什么内容,还有,当前为什么GPU比CPU有优 ...
- -AC自动机-题表
2016-07-13 09:59:42
- js页面传参数时,参数值包含特殊字符的处理
js页面传参数时,参数值包含特殊字符应该怎么处理,解决方法就是利用js的escape函数,这个函数在解决中文乱码等方面应用的比较广泛.推荐使用. 工作中遇到的小问题,一个页面中通过window.sho ...
- Keil_C51程序调试过程
调试一般都是在发生错误与意外的情况下使用的.如果程序能正常执行,调试很多时候都是用不上的.所以,最高效率的程序开发还是程序员自己做好规范,而不是指望调试来解决问题. 单片机的程序调试分为两种,一种是使 ...
- 5.JSON
AJAX传递复杂数据如果自己进行格式定义的话会经历组装.解析的过程,因此AJAX中有一个事实上的数据传输标准JSON. JSON将复杂对象序列化为一个字符串,在浏览器端再将字符串反序列化为JavaSc ...
- LeetCode解题报告:Insertion Sort List
Insertion Sort List Sort a linked list using insertion sort. leetcode subject思路:标准的插入排序.考察一下链表的操作. 对 ...