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; ...
随机推荐
- Uva_11021 Tribles
题目链接 题意: 现在有k只麻球, 每只麻球只能存活一天, 第二天就会死去, 死去之前可能生下x只小麻球(x = 0,1,2,...,n 1), 概率分别为P[0], P[1], ... , P[n ...
- windows下端口被占用的解决方法
1:打开CMD输入:netstat -ano | findstr "80" 找到PID: 2:查看应用名称:tasklist | findstr "2544" ...
- oracle中的一些函数笔记
replace函数 replace(最长的字符串,被替换的字符串,替换字符串) 数学函数 round(n,[m]) 保留m位总共n位长度的数,采用四舍五入的方式. trunc(n,[m])截取数字,不 ...
- Scarborough Fair 绝美天籁
很少见的男声唱法,而且还古色古香: https://www.youtube.com/watch?v=sgbo2QWLBzI https://www.youtube.com/watch?v=-BakWV ...
- StringGrid右击选中表格(发消息给句柄模拟点击,右键点击也是MouseDown)
顺便还把单元格给变了: procedure TFGLGL.StringGrid1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShi ...
- Android Wear 开发入门
大家好,我是陆嘉杰,我是一名Android开发者.我想和大家进行一些技术交流,希望越来越多的人能和我成为好朋友. 大家都知道,智能手表是下一个开发的风口,而这方面的技术又属于前沿,所以和大家分享下An ...
- div+css页面居中代码
普通div和html混写可以这样写,设置 text-align:center, margin:0px auto 最简单的方法就是 把你的body这样设置: <body style="t ...
- java static 执行顺序
先加载类,然后再实例化类. 继承与static 面试题目如下:请写出程序执行完成之后的结果. package extend; public class X { Y y=new Y(); static{ ...
- 优雅的让Fragment监听返回键
转载请注明出处:http://write.blog.csdn.net/postedit/40507387 Activity可以很容易的得到物理返回键的监听事件,而Fragment却不能.假设Fragm ...
- 【HDOJ】3397 Sequence operation
线段树的应用,很不错的一道题目.结点属性包括:(1)n1:1的个数:(2)c1:连续1的最大个数:(3)c0:连续0的最大个数:(4)lc1/lc0:从区间左边开始,连续1/0的最大个数:(5)rc1 ...