RSA加密解密及数字签名Java实现--转
RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密算法。
RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。
关于RSA算法的原理,这里就不再详加介绍,网上各种资源一大堆。下面就开始介绍RSA加密解密JAVA类的具体实现。
01
|
import java.security.MessageDigest;
|
02
|
03
|
import sun.misc.BASE64Decoder;
|
04
|
import sun.misc.BASE64Encoder;
|
05
|
06
|
public class Coder {
|
07
|
|
08
|
public static final String KEY_SHA= "SHA" ;
|
09
|
public static final String KEY_MD5= "MD5" ;
|
10
|
|
11
|
/**
|
12
|
* BASE64解密
|
13
|
* @param key
|
14
|
* @return
|
15
|
* @throws Exception
|
16
|
*/
|
17
|
public static byte [] decryptBASE64(String key) throws Exception{
|
18
|
return ( new BASE64Decoder()).decodeBuffer(key);
|
19
|
}
|
20
|
|
21
|
/**
|
22
|
* BASE64加密
|
23
|
* @param key
|
24
|
* @return
|
25
|
* @throws Exception
|
26
|
*/
|
27
|
public static String encryptBASE64( byte [] key) throws Exception{
|
28
|
return ( new BASE64Encoder()).encodeBuffer(key);
|
29
|
}
|
30
|
|
31
|
/**
|
32
|
* MD5加密
|
33
|
* @param data
|
34
|
* @return
|
35
|
* @throws Exception
|
36
|
*/
|
37
|
public static byte [] encryptMD5( byte [] data) throws Exception{
|
38
|
MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
|
39
|
md5.update(data);
|
40
|
return md5.digest();
|
41
|
}
|
42
|
|
43
|
/**
|
44
|
* SHA加密
|
45
|
* @param data
|
46
|
* @return
|
47
|
* @throws Exception
|
48
|
*/
|
49
|
public static byte [] encryptSHA( byte [] data) throws Exception{
|
50
|
MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
|
51
|
sha.update(data);
|
52
|
return sha.digest();
|
53
|
}
|
54
|
}
|
先提供Coder编码类,该类封装了基本的Base64、md5和SHA加密解密算法。Java对这些算法的实现提供了很好的API封装,开发人员只需调用这些API就可很简单方便的实现数据的加密与解密。
下面提供RSA加密解密类,该类为Coder类子类,因为其中对RSA公私密钥的保存进行了一层Base64加密处理。
RSA加密解密类静态常量
1
|
public static final String KEY_ALGORTHM= "RSA" ; //
|
2
|
public static final String SIGNATURE_ALGORITHM= "MD5withRSA" ;
|
3
|
4
|
public static final String PUBLIC_KEY = "RSAPublicKey" ; //公钥
|
5
|
public static final String PRIVATE_KEY = "RSAPrivateKey" ; //私钥
|
RSA加密解密的实现,需要有一对公私密钥,公私密钥的初始化如下:
01
|
/**
|
02
|
* 初始化密钥
|
03
|
* @return
|
04
|
* @throws Exception
|
05
|
*/
|
06
|
public static Map<String,Object> initKey() throws Exception{
|
07
|
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORTHM);
|
08
|
keyPairGenerator.initialize( 1024 );
|
09
|
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
10
|
|
11
|
//公钥
|
12
|
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
13
|
//私钥
|
14
|
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
|
15
|
|
16
|
Map<String,Object> keyMap = new HashMap<String, Object>( 2 );
|
17
|
keyMap.put(PUBLIC_KEY, publicKey);
|
18
|
keyMap.put(PRIVATE_KEY, privateKey);
|
19
|
|
20
|
return keyMap;
|
21
|
}
|
从代码中可以看出密钥的初始化长度为1024位,密钥的长度越长,安全性就越好,但是加密解密所用的时间就会越多。而一次能加密的密文长度也与密钥的长度成正比。一次能加密的密文长度为:密钥的长度/8-11。所以1024bit长度的密钥一次可以加密的密文为1024/8-11=117bit。所以非对称加密一般都用于加密对称加密算法的密钥,而不是直接加密内容。对于小文件可以使用RSA加密,但加密过程仍可能会使用分段加密。
从map中获取公钥、私钥
01
|
/**
|
02
|
* 取得公钥,并转化为String类型
|
03
|
* @param keyMap
|
04
|
* @return
|
05
|
* @throws Exception
|
06
|
*/
|
07
|
public static String getPublicKey(Map<String, Object> keyMap) throws Exception{
|
08
|
Key key = (Key) keyMap.get(PUBLIC_KEY);
|
09
|
return encryptBASE64(key.getEncoded());
|
10
|
}
|
11
|
12
|
/**
|
13
|
* 取得私钥,并转化为String类型
|
14
|
* @param keyMap
|
15
|
* @return
|
16
|
* @throws Exception
|
17
|
*/
|
18
|
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception{
|
19
|
Key key = (Key) keyMap.get(PRIVATE_KEY);
|
20
|
return encryptBASE64(key.getEncoded());
|
21
|
}
|
对于RSA产生的公钥、私钥,我们可以有两种方式可以对信息进行加密解密。私钥加密-公钥解密 和 公钥加密-私钥解密。
私钥加密
01
|
/**
|
02
|
* 用私钥加密
|
03
|
* @param data 加密数据
|
04
|
* @param key 密钥
|
05
|
* @return
|
06
|
* @throws Exception
|
07
|
*/
|
08
|
public static byte [] encryptByPrivateKey( byte [] data,String key) throws Exception{
|
09
|
//解密密钥
|
10
|
byte [] keyBytes = decryptBASE64(key);
|
11
|
//取私钥
|
12
|
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
13
|
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
|
14
|
Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
|
15
|
|
16
|
//对数据加密
|
17
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
18
|
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
|
19
|
|
20
|
return cipher.doFinal(data);
|
21
|
}
|
私钥解密
01
|
/**
|
02
|
* 用私钥解密<span style="color:#000000;"></span> * @param data 加密数据
|
03
|
* @param key 密钥
|
04
|
* @return
|
05
|
* @throws Exception
|
06
|
*/
|
07
|
public static byte [] decryptByPrivateKey( byte [] data,String key) throws Exception{
|
08
|
//对私钥解密
|
09
|
byte [] keyBytes = decryptBASE64(key);
|
10
|
|
11
|
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
12
|
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
|
13
|
Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
|
14
|
//对数据解密
|
15
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
16
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
17
|
|
18
|
return cipher.doFinal(data);
|
19
|
}
|
公钥加密
01
|
/**
|
02
|
* 用公钥加密
|
03
|
* @param data 加密数据
|
04
|
* @param key 密钥
|
05
|
* @return
|
06
|
* @throws Exception
|
07
|
*/
|
08
|
public static byte [] encryptByPublicKey( byte [] data,String key) throws Exception{
|
09
|
//对公钥解密
|
10
|
byte [] keyBytes = decryptBASE64(key);
|
11
|
//取公钥
|
12
|
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
|
13
|
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
|
14
|
Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
|
15
|
|
16
|
//对数据解密
|
17
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
18
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
19
|
|
20
|
return cipher.doFinal(data);
|
21
|
}
|
私钥加密
01
|
/**
|
02
|
* 用公钥解密
|
03
|
* @param data 加密数据
|
04
|
* @param key 密钥
|
05
|
* @return
|
06
|
* @throws Exception
|
07
|
*/
|
08
|
public static byte [] decryptByPublicKey( byte [] data,String key) throws Exception{
|
09
|
//对私钥解密
|
10
|
byte [] keyBytes = decryptBASE64(key);
|
11
|
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
|
12
|
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
|
13
|
Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
|
14
|
|
15
|
//对数据解密
|
16
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
17
|
cipher.init(Cipher.DECRYPT_MODE, publicKey);
|
18
|
|
19
|
return cipher.doFinal(data);
|
20
|
}
|
关于数字签名,先了解下何为数字签名。数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。数字签名是非对称密钥加密技术与数字摘要技术的应用。简单地说,所谓数字签名就是附加在数据单元上的一些数据,或是对数据单元所作的密码变换。这种数据或变换允许数据单元的接收者用以确认数据单元的来源和数据单元的完整性并保护数据,防止被人(例如接收者)进行伪造。
数字签名的主要功能如下:
保证信息传输的完整性、发送者的身份认证、防止交易中的抵赖发生。
数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。
数字签名是个加密的过程,数字签名验证是个解密的过程。
3.验证算法。
通过RSA加密解密算法,我们可以实现数字签名的功能。我们可以用私钥对信息生成数字签名,再用公钥来校验数字签名,当然也可以反过来公钥签名,私钥校验。
私钥签名
01
|
/**
|
02
|
* 用私钥对信息生成数字签名
|
03
|
* @param data //加密数据
|
04
|
* @param privateKey //私钥
|
05
|
* @return
|
06
|
* @throws Exception
|
07
|
*/
|
08
|
public static String sign( byte [] data,String privateKey) throws Exception{
|
09
|
//解密私钥
|
10
|
byte [] keyBytes = decryptBASE64(privateKey);
|
11
|
//构造PKCS8EncodedKeySpec对象
|
12
|
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
13
|
//指定加密算法
|
14
|
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
|
15
|
//取私钥匙对象
|
16
|
PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
|
17
|
//用私钥对信息生成数字签名
|
18
|
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
|
19
|
signature.initSign(privateKey2);
|
20
|
signature.update(data);
|
21
|
|
22
|
return encryptBASE64(signature.sign());
|
23
|
}
|
公钥校验
01
|
/**
|
02
|
* 校验数字签名
|
03
|
* @param data 加密数据
|
04
|
* @param publicKey 公钥
|
05
|
* @param sign 数字签名
|
06
|
* @return
|
07
|
* @throws Exception
|
08
|
*/
|
09
|
public static boolean verify( byte [] data,String publicKey,String sign) throws Exception{
|
10
|
//解密公钥
|
11
|
byte [] keyBytes = decryptBASE64(publicKey);
|
12
|
//构造X509EncodedKeySpec对象
|
13
|
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
|
14
|
//指定加密算法
|
15
|
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
|
16
|
//取公钥匙对象
|
17
|
PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec);
|
18
|
|
19
|
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
|
20
|
signature.initVerify(publicKey2);
|
21
|
signature.update(data);
|
22
|
//验证签名是否正常
|
23
|
return signature.verify(decryptBASE64(sign));
|
24
|
|
25
|
}
|
对于RSA如何加密文件、图片等信息,加密的信息又如何保存,怎样保存解密后的信息,以及操作过程中遇到的错误将如何处理,将在后面的文章中介绍给大家。
转载于:https://www.cnblogs.com/davidwang456/p/3922528.html
RSA加密解密及数字签名Java实现--转相关推荐
- RSA加密解密算法的java实现
最近有一个外部合作项目要求在数据传输过程中使用RSA加密算法对数据进行加密,所以需要编写一个加解密的工具类,因为对方不是java语言,所以是各自实现的这个工具,本文主要讨论实现以及双方调试过程中的一些 ...
- Java实现RSA加密解密、数字签名及验签
RSA公钥加密算法是1977年由罗纳德-李维斯特(Ron Rivest).阿迪-萨莫尔(Adi Shamir)和伦纳德-阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院 ...
- C# Java间进行RSA加密解密交互(二)
接着前面一篇文章C# Java间进行RSA加密解密交互,继续探讨这个问题. 在前面,虽然已经实现了C# Java间进行RSA加密解密交互,但是还是与项目中要求的有所出入.在项目中,客户端(Java)的 ...
- RSA加密解密(附源码工程)
一.RSA加密介绍 RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.1987 ...
- C# Java间进行RSA加密解密交互
C# Java间进行RSA加密解密交互 原文:C# Java间进行RSA加密解密交互 这里,讲一下RSA算法加解密在C#和Java之间交互的问题,这两天纠结了很久,也看了很多其他人写的文章,颇受裨益, ...
- Java使用RSA加密解密签名及校验
RSA加密解密类: import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; i ...
- angular和JAVA实现aes、rsa加密解密,前后端交互,前端加解密和后端JAVA加解密实现
今天实现了下AES和RSA加密解密,主要的功能是对前后端交互数据进行加密解密,为什么要用到两个算法呢,首先RSA默认的话加密长度是有限的100多个byte吧大约,并且需要公钥私钥,而AES加密没有限制 ...
- java rsa 验_Java使用RSA加密解密签名及校验
RSA加密解密类: package com.ihep; import java.io.BufferedReader; import java.io.BufferedWriter; import jav ...
- RSA分段加密/解密 nodejs 和java联调
RSA分段加密/解密 nodejs 和java联调 文章目录 RSA分段加密/解密 nodejs 和java联调 1 nodejs 环境 1.1 axios配置 1.2 API接口 1.3 业务 1. ...
最新文章
- 人工智能缺陷与误觉:让机器产生幻觉的「怪异事件」 1
- php 图形用户界面GUI 开发
- 比想象中更旗舰,金立M2017国内首秀堪称完美!
- 施乐s2110进入维修模式_施乐进入维修模式步骤
- gazebo 模型导入
- 二分法求解方程的根java_【数值分析】利用二分法和牛顿公式求解方程的根
- 教你电脑微信多开方法,超级简单_多啦咪
- oracle remap schema,oracle 10g DATA PUMP 的REMAP_SCHEMA和REMAP_TABLESPACE的功能
- 猿创征文 |【算法入门必刷】数据结构-栈(四)
- linux奶瓶U盘使用方法,如何用U盘启动盘奶瓶解除无线WPA加密
- 螃蟹保存方法保存时间_活螃蟹如何保存才能活得时间久(这几个方法简单实用)...
- MD5的加密和解密算法
- 山东大学软件学院项目实训-创新实训-网络安全靶场实验平台(十六)
- 计算机软件系统举例,什么是系统软件应用软件举例说明
- [重磅] 让HTML5达到原生的体验 系列之一 避免切页白屏
- 【菜鸟进阶之路】P2141 珠心算测验 - 洛谷
- 求约数java_最多约数问题(Java)
- ROP Emporium x86_64 1~6题
- 标准查询运算符(SQO)
- 简简单单的一个嵌入式板子项目,笔记
热门文章
- c语言设备管理系统实训答辩,C语言设计(力学实验设备管理系统)1答辩.doc
- java中封装日期加时间_java日期处理简单封装
- python翻译成matlab_matlab语言转译成python
- java 智能家居管理系统_智能家居系统手机客户端应用源码
- java项目中怎么查看用的序列_如何在Java应用程序中使用序列化分类器对...
- mysql在mac下的data目录_Mysql在mac中目录结构用法命令
- StaicArray
- C++中的虚函数与纯虚函数
- 不属于计算机常用软件日常应用的是,综合技能实践+计算机常用应用软件的安装和使用指导 (1)...
- foobar2000 ios版怎么添加音乐_抖音怎么设置说完话后再放音乐 视频先配音后半段添加背景音乐...