安全加密总结
一、近代密码学
恩尼格玛密码机:(被人工智能之父图灵破解)
核心使用了位移和替换算法,(这种方式的密码可以采用频度分析法进行破解)
二、现代密码学
1、加密方式
(1)流加密
对信息流中的每个元素(一个字母或一个bit)作为基本的处理单元进行加密最后拼接成密文
(2)块加密
先对信息流进行分块,再对每个块进行加密
(3)举例
例如原文为abcd、流加密先对a加密、再对b加密、再对c加密、再对d加密,最后吧加密后的数据拼接组成密文。块加密先对原文分块比如abc 作为第一块、然后d+xx+xx为第二块(xx为补位数据),然后对每个块进行加密,最后拼接组成一个密文
2、加密模式
(1)、ECB模式
需要对加密的消息按照块分为数个块,并对每个块进行独立加密
优点:可以并行处理数据
缺点:同样的原文生成同样的密文,不能很好的保护数据。同时加密,原文是一样的,加密出来的密文也一样的
(2)、CBC模式
密码块链接。每个明文块先与前一个密文块进行异或后,在进行加密。在这种方法中,每个密文块都依赖前一个明文块。
优点:同样的原文生成的密码不一样
缺点:串行处理,速度慢
3、加密算法
1、散列函数(即哈希函数)
常用的有MD5、SHA-1、SHA-256、SHA-512(这种函数加密属于单项加密,不可逆)
MD5可以将任意长度的原文加密生成一个长度为128bit(16字节)的哈希值
SHA-1可以将任意长度的原文加密生成一个长度为160bit(20字节)的哈希值
SHA-256可以将任意长度的原文加密生成一个长度为256bit(32字节)的哈希值
SHA-512可以将任意长度的原文加密生成一个长度为512bit(64字节)的哈希值
2、对称加密(特点密钥相同)
对称加密,加密和解密使用同一把密钥
1)常用算法
常用的有DES、3DES 、AES、DESX、Blowfish、RC4、RC5、RC6。
2)、 DES(已被破解、不推荐使用)
即数据加密标准,是一种加密算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准,并在非密级政府通信中使用。
特点:加密速度快,可以加密大文件。文件可逆
3)、 3DES(速度慢、不推荐使用)
DES升级版
1)、 AES(推荐使用)
高级加密标准,是下一代的加密算法标准,速度快,安全级别高
3、非对称加密(密钥对、最安全加密算法)
非称加密,加密和解密使用不同的密钥密钥,
即使用公钥加密的数据只能使用私钥解密
即使用私钥加密的数据只能使用公钥解密
1)、常用的算法
RSA、ECC(移动设备用)、DSA(数字签名较优)
2)RSA算法
1、参数说明
(1)m 加密数据
(2)N密钥长度 (注意RSA密钥一般是1024位,重要场合则为2048位)
(3)c加密数据
(4)e公钥指数
(5)d私钥指数
(6)符号^表示数学上的指数运算;mod表示模运算,即相除取余数。
2、RSA算法推导
(1)计算得到N
使用欧拉函数
φ(n) = (p-1)(q-1) (注:p和q为两个质数,所为质数即只能被1和它本身整除的数)
例如:7 和11就是两个质数
N=37=21
φ(77)等于26 即12
(2)得到公钥指数e
随机选择一个整数e作为公钥,条件是1< e < φ(n),且e与φ(n) 互质
在1到12之间,随机选择了5作为公钥e。(实际应用中,常常选择65537。)
(3)计算私钥指数d
使得d满足(de) mod φ(21) = 1 即(d5)mod 12=1
通过试算我们找到,当d=5时,e×d mod φ(21) = 1等式成立。因此,可令d=7。从而我们可以设计出一对公私密钥,加密密钥(公钥)为:KU =(e,n)=(5,21),解密密钥(私钥)为:KR =(d,n)=(5,21)。
(4)明文加密
测试两组数据
给字符’c’加密 码值为3
给字符’f’加密 码值为6
m^e mod N=c 即 3^5 mod 21=12
m^e mod N=c 即 6^5 mod 21=6
(5)密文解密
c^d mod N=m 即 12^5 mod 21=3 对应字符‘c’
c^d mod N=m 即 6^5 mod 21=6 对应字符‘f’
3、RSA加密解密公式
1、加密公式:m^e mod N=c
2、解密公式:c^d mod N=m
4、RSA使用注意事项
RSA的分组长度太大,为保证安全性,n至少也要512位以上,使运算代价很高,尤其是速度很慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。
JAVA和lua集成注意问题:
1、密钥对生成N值最好使用512、1024、2048这个数据的大小会决定生成密钥的长度,并且还会影响加密原文的长度,还会意向加密的效率
2、生成密钥对使用的标准是pkcs8,所以用其他语言生成密钥时要注意
Lua其中pkcs1生成如下
Lua其中pkcs8生成如下
填充模式注意事项:
1、两边填充模式不同可能造成加密解密出现乱码。和报错
例如lua中使用PADDING.RSA_PKCS1_PADDING这种填充对应java为PKCS1Padding
还有其他的填充模式可以对照响应语言的API去查看
2、加密解密数据base64加密方式不同造成问题
例如:Lua中使用ngx.encode_base64和ngx.decode_base64加解密时java中使用import sun.misc.BASE64Decoder这个包中的Base进行加解密
3、数据网络传输出现的问题
使用Lua私钥签名加密,调用java公钥验签的时候出现Base加密的数据在传输过程中把+改成了空格,这样在验签的时候数据不一致验签失败,采用下图处理
Lua框架支撑加密解密方式
目前市面上提供的Lua的 rsa框架很少只有一个成熟的lua-resty-rsa
这个框架底层使用C语言进行开发,研究发现C语言使用了Openssl框架实现Openssl是使用C开发,提供了大量的加密算法库
1、方法有生成密钥对方法支持支持的key_type 即标准有PKCS#1和PKCS#8两种
Lua加密
公钥加密(lua)+私钥解密(其他应用)
私钥加密签名(lua)+公钥验签(其他应用)
Lua解密
公钥解密(其他应用)+私钥解密(Lua)
私钥加密(其他应用)+公钥解密(Lua)
3)RSA实现示例
1、Lua 实现使用
1、参考网站 https://github.com/spacewander/lua-resty-rsa
2、说明:lua-resty-rsa是Openresty集成rsa的一个框架
一、lua-resty-rsa集成到Openresty
1、下载
https://github.com/spacewander/lua-resty-rsa到本地
2、复制rsa.lua脚本
3、打开项目的如下目录粘贴rsa.lua
二、lua-resty-rsa集成到Openresty
1、打开gateway项目
复制rsa.lua到lib目录
3、编写脚本例子
1、rsa_test.lua
– Created by IntelliJ IDEA.
– User: admin
– Date: 2021/4/7
– Time: 18:08
– To change this template use File | Settings | File Templates.
ngx.req.read_body()
local body=ngx.req.get_body_data()
local cjson = require(“cjson”);
–local d=cjson.encode(body)
–ngx.log(ngx.INFO,"-------d---------"…body.data)
–http声明
local zhttp = require(“resty.http”)
local httpc = zhttp.new()
httpc:set_timeout(30000)
local rsa_util = require(“rsa_util”)
local url=“http://10.221.100.145:8076/”;
–生成证书
function rsa_init_keyTest()
local ReadAndWriteFile = require(“ReadAndWriteFile”)
local VmPath = require(“VmPath”)
local rsa_public_key1, rsa_priv_key1, err =rsa_util:rsa_init_key(1024);
ReadAndWriteFile:write_file(VmPath.rsa_public_key_path,rsa_public_key1)
ReadAndWriteFile:write_file(VmPath.rsa_priv_key_path,rsa_priv_key1)
ngx.say(rsa_public_key1…"=============="…rsa_priv_key1)
end
–公钥加密
function publicEncryptionTest(data)
local result=rsa_util:publicEncryption(data);
local res, err_ = httpc:request_uri(url…“privateDecryptBnc”, {
method = “POST”,
body= “password=”…result,
headers = {
[“Content-Type”] = “application/x-www-form-urlencoded; charset=utf-8”,
}
})
if res ~= nil then
if res.status == ngx.HTTP_OK then
ngx.log(ngx.DEBUG, "响应:", res.body)
ngx.say(res.body)
return res.body
else
ngx.log(ngx.ERR, "出错")
ngx.exit(res.status)
end
else
ngx.log(ngx.ERR, "出错")
ngx.exit(500)
end
end
–私钥签名
function privSignDataTest(sources)
local result=rsa_util:privSigData(sources);
local res, err_ = httpc:request_uri(url…“publicSignBnc”, {
method = “POST”,
body= “password=”…result…"&sources="…sources,
headers = {
[“Content-Type”] = “application/x-www-form-urlencoded”
}
})
if res ~= nil then
if res.status == ngx.HTTP_OK then
ngx.log(ngx.DEBUG, “响应:”, res.body)
ngx.say(res.body)
return res.body
else
ngx.log(ngx.ERR, “出错”)
ngx.exit(res.status)
end
else
ngx.log(ngx.ERR, “出错”)
ngx.exit(500)
end
end
–私钥解密
function privDecryptDataTest(sources)
local result=rsa_util:privDecryptData(sources);
ngx.say(result)
end
local postargs = ngx.req.get_uri_args()
local type = postargs[“type”]
local data = postargs[“data”]
if typenil or datanil then
local postargs1 = ngx.req.get_post_args()
type = postargs1[“type”]
data = postargs1[“data”]
end
–data=urlDecode(data);
if(type==‘1’)then
rsa_init_keyTest();
elseif (type==‘2’) then
publicEncryptionTest(data)
elseif (type==‘3’) then
privSignDataTest(data);
elseif (type==‘4’) then
privDecryptDataTest(data);
end
2、rsa_util.lua
– Created by IntelliJ IDEA.
– User: lpp
– Date: 2021/4/25
– Time: 13:44
– To change this template use File | Settings | File Templates.
–rsa
local rsa_util={}
local resty_rsa = require “resty.rsa”
local ReadAndWriteFile = require(“ReadAndWriteFile”)
local VmPath = require(“VmPath”)
function rsa_util:rsa_init_key(size)
local rsa_public_key1, rsa_priv_key1, err = resty_rsa:generate_rsa_keys(size,true)
if not rsa_public_key1 then
ngx.say('generate rsa keys err: ', err)
end
return rsa_public_key1, rsa_priv_key1, err
end
–获取公钥key
function rsa_util:rsa_public_key()
–在共享缓存中获取
local rsa_public_key =ngx.shared.dict_sp_rsa_key:get(“rsa_public_key”)
if rsa_public_keynil then
–在文件中获取
rsa_public_key= ReadAndWriteFile:read_file(VmPath.rsa_public_key_path)
ngx.shared.dict_sp_rsa_key:set(“rsa_public_key”,rsa_public_key)
end
return rsa_public_key
end
–获取私钥key
function rsa_util:rsa_priv_key()
–在共享缓存中获取
local rsa_priv_key =ngx.shared.dict_sp_rsa_key:get(“rsa_priv_key”)
if rsa_priv_keynil then
–在文件中获取
rsa_priv_key= ReadAndWriteFile:read_file(VmPath.rsa_priv_key_path)
ngx.shared.dict_sp_rsa_key:set(“rsa_priv_key”,rsa_priv_key)
end
return rsa_priv_key
end
–公钥加密
function rsa_util:publicEncryption(data)
local pub, err =resty_rsa:new({public_key = rsa_util:rsa_public_key(),padding = resty_rsa.PADDING.RSA_PKCS1_PADDING});
if not pub then
ngx.say("new rsa err: ", err)
return
end
local encrypted, err = pub:encrypt(data)
if not encrypted then
ngx.say("failed to encrypt: ", err)
return
end
return ngx.encode_base64(encrypted)
end
–私钥签名
function rsa_util:privSigData(data)
local priv, err = resty_rsa:new({ private_key = rsa_util:rsa_priv_key(),padding = resty_rsa.PADDING.RSA_PKCS1_PADDING,algorithm = “sha256WithRSAEncryption”})
if not priv then
ngx.log(ngx.INFO,"new rsa err: "…err)
return
end
local sig, err = priv:sign(data)
if not sig then
ngx.log(ngx.INFO,“failed to sign:”…err)
return
end
return ngx.encode_base64(sig)
end
–私钥解密
function rsa_util:privDecryptData(data)
local priv, err = resty_rsa:new({ private_key = rsa_util:rsa_priv_key(),padding = resty_rsa.PADDING.RSA_PKCS1_PADDING})
if not priv then
ngx.log(ngx.INFO,“new rsa err: “…err)
return
end
–base64解码
local enc = ngx.decode_base64(data)
local decrypt, err = priv:decrypt(enc)
if not decrypt then
ngx.log(ngx.INFO,“failed to decryp:”…err)
return
end
return decrypt;
end
return rsa_util
3、ReadAndWriteFile.lua
local ReadAndWriteFile={}
–对文件
function ReadAndWriteFile:read_file(file_path)
local file =io.open(file_path,“r”)
local data=file:read(”*a”) --读取整个文件
file:close()
return data
end
function ReadAndWriteFile:write_file(file_path,data)
local file =io.open(file_path,“w+”)
file:write(data) --读取整个文件
file:close()
end
return ReadAndWriteFile
4、VmPath.lua
local bak=“D:/work/DAma/hjpt/bcp.gateway/Nginx/bak/”;
local VmPath={
rsa_public_key_path=bak…“rsa_public_key.crt”,
rsa_priv_key_path=bak…“rsa_priv_key.crt”
}
return VmPath
2、java实现使用
采用springboot开发
1、pom.xml
4.0.0
<groupId>org.example</groupId>
<artifactId>rsaclient</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 移除嵌入式tomcat插件 -->
<!-- <exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>-->
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.64</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
</dependencies>
2、RsaController.java package com.sihua.rsa.controller;
import com.sihua.rsa.service.SynchronizationService;
import com.sihua.rsa.utils.RSAUtils;
import com.sihua.rsa.utils.RsaJs;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.File;
import java.nio.charset.Charset;
@Controller
public class RsaController {
@Autowired
private SynchronizationService syncservice;
//公钥
@Value("
r
s
a
.
p
u
b
l
i
c
K
e
y
P
a
t
h
"
)
p
r
i
v
a
t
e
S
t
r
i
n
g
p
u
b
l
i
c
K
e
y
P
a
t
h
;
/
/
私
钥
@
V
a
l
u
e
(
"
{rsa.publicKeyPath}") private String publicKeyPath; //私钥 @Value("
rsa.publicKeyPath")privateStringpublicKeyPath;//私钥@Value("{rsa.privateKeyPath}")
private String privateKeyPath;
/**
* 生成密钥对
* @return
*/
@ResponseBody
@RequestMapping("/initKey")
public String initKey() throws Exception{
RSAUtils.initKey(1024,publicKeyPath,privateKeyPath);
return “key生成成功”;
}
/**
* 公钥加密
* @param password
* @return
*/
@ResponseBody
@RequestMapping("/publicDataBnc")
public String publicDataBnc(String password) throws Exception{
System.out.println("原数据:"+password);
String data = RSAUtils.publicEncrypt(password,publicKeyPath);
System.out.println("公钥加密后数据:"+data);
//调用服务端
String s = syncservice.postSend(data);
return s;
}
/**
* 公钥验签
* @param password
* @return
*/
@ResponseBody
@RequestMapping("/publicSignBnc")
public boolean publicSignBnc(String password,String sources) throws Exception{
password=password.replaceAll(" ", "+");
System.out.println("lua加密数据:"+password);
boolean s = RSAUtils.verify(password,sources,publicKeyPath);
System.out.println("验签结果:"+s);
return s;
}
/**
* 私钥解密
* @param password
* @return
*/
@ResponseBody
@RequestMapping("/privateDecryptBnc")
public String privateDecryptBnc (String password,String a) throws Exception{
password=password.replaceAll(" ", "+");
System.out.println("lua加密数据:"+password);
String s = RSAUtils.privateDecrypt(password,privateKeyPath);
System.out.println("原始数据=========="+s);
return s;
}
/**
* 私钥解密
* @return
*/
@RequestMapping("/getPrivateDecryptJs")
@ResponseBody
public String getPrivateDecryptJs (String password) throws Exception{
String privateKeyStr = FileUtils.readFileToString(new File(privateKeyPath), Charset.forName("utf-8"));
System.out.println("JS加密数据:=="+password);
String publicStr = RsaJs.privateDecryptData(password,privateKeyStr );
System.out.println("解密字符:=="+publicStr);
return publicStr;
}
/**
* 公钥钥解密
* @return
*/
@RequestMapping("/getPublicDecryptJs")
@ResponseBody
public String getPublicDecryptJs (String password) throws Exception{
String publicKeyStr = FileUtils.readFileToString(new File(publicKeyPath), Charset.forName("utf-8"));
System.out.println("JS加密数据:=="+password);
String publicStr = RsaJs.publicDecryptData(password,publicKeyStr);
System.out.println("解密字符:=="+publicStr);
return publicStr;
}
/**
* 测试页面
* @return
*/
@RequestMapping("/test")
public String test (Model model, String data) throws Exception{
model.addAttribute("data",data);
return "/test";
}
}
3、SynchronizationService.java
package com.sihua.rsa.service;
import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
@Service
public interface SynchronizationService {
String postSend(String data) throws UnsupportedEncodingException;
}
4、SynchronizationServiceImpl.java
package com.sihua.rsa.service.impl;
import com.sihua.rsa.service.SynchronizationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.io.UnsupportedEncodingException;
@Service
public class SynchronizationServiceImpl implements SynchronizationService {
@Autowired
private RestTemplate restTemplate;
//发送lua
private String retryUrl=“http://10.221.100.145:8088/rsatest”;
@Override
public String postSend(String data) throws UnsupportedEncodingException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
requestEntity.add(“data”, data);
requestEntity.add(“type”, “4”);
String s = restTemplate.postForObject(retryUrl, requestEntity, String.class);
return s;
}
}
5、RSAUtils.java lua工具类
package com.sihua.rsa.utils;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import sun.plugin.com.Utils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
- RSA 加密工具
- 加密过长的会报错:
Data must not be longer than 245 bytes
原因是应为不同长度的密钥对应可以加密不同最大长度的原文,2048就对应245
解决办法是:
1.分段
2.RSA加密是有长度限制的.单纯用RSA加密较长数据时得使用分段加密,效率低下.用RSA+AES是比较主流的做法:AES加密数据产生密文,RSA加密AES密钥产生加密后的AES密钥,然后将密文和加密后的AES密钥一起传输 - @author hank
- @since 2020/4/28 0028 下午 15:42
*/
public class RSAUtils {
private static final String CHARSET = “UTF-8”;
private static final BASE64Decoder decoder64 = new BASE64Decoder();
private static final BASE64Encoder encoder64 = new BASE64Encoder();
/**
* 生成公私钥
* @param keySize
* @return
* @throws NoSuchAlgorithmException
*/
public static void initKey(int keySize,String publicKeyPath,String privateKeyPath) throws NoSuchAlgorithmException, IOException {
BASE64Encoder encoder64 = new BASE64Encoder();
//生成密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(keySize);
KeyPair pair = keyGen.generateKeyPair();
PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
String rsaPublicKey=encoder64.encode(publicKey.getEncoded());
String rsaPrivateKey=encoder64.encode(privateKey.getEncoded());
//这里可以将密钥对保存到本地
System.out.println("公钥:"+rsaPublicKey);
System.out.println("私钥:"+rsaPrivateKey);
FileUtils.writeStringToFile(new File(publicKeyPath),rsaPublicKey,Charset.forName(CHARSET));
FileUtils.writeStringToFile(new File(privateKeyPath),rsaPrivateKey,Charset.forName(CHARSET));
}
//获取私钥key
public static PrivateKey getPrivateKey(String privateKeyPath) {
try {
String privateKeyStr = FileUtils.readFileToString(new File(privateKeyPath), Charset.forName(CHARSET));
PKCS8EncodedKeySpec pKCS8EncodedKeySpec=new PKCS8EncodedKeySpec(decoder64.decodeBuffer(privateKeyStr));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pKCS8EncodedKeySpec);
return privateKey;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//获取公钥key
public static PublicKey getPublicKey(String publicKeyPath) {
try {
String privateKeyStr = FileUtils.readFileToString(new File(publicKeyPath), Charset.forName(CHARSET));
X509EncodedKeySpec x509EncodedKeySpec=new X509EncodedKeySpec(decoder64.decodeBuffer(privateKeyStr));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
return publicKey;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 私钥加密
* @param data
* @return
* @throws IOException
*/
public static String privateEncrypt(String data,String privateKeyPath) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey(privateKeyPath));
return encoder64.encode(cipher.doFinal(data.getBytes(CHARSET)));
}
/**
* 公钥解密
* @param data
* @param publicKeyPath
* @return
*/
public static String publicDecrypt(String data,String publicKeyPath) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
byte[] encryptDataBytes= decoder64.decodeBuffer(data);
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
//解密
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",provider);
cipher.init(Cipher.DECRYPT_MODE, getPublicKey(publicKeyPath));
byte[] bytes = cipher.doFinal(encryptDataBytes);
String s = new String(bytes, Charset.forName("UTF-8"));
return s;
}
/**
* 公钥验签
* @param data
* @return
*/
public static boolean verify(String data, String sources,String publicKeyPath) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException, SignatureException {
Signature publicSignature = Signature.getInstance("SHA256withRSA");
publicSignature.initVerify(getPublicKey(publicKeyPath));
publicSignature.update(sources.getBytes(Charset.forName("UTF-8")));
byte[] signatureBytes = decoder64.decodeBuffer(data);
return publicSignature.verify(signatureBytes);
}
/**
* 公钥加密
* @param data
* @return
*/
public static String publicEncrypt(String data,String publicKeyPath) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
byte[] encryptDataBytes=new String(data).getBytes(CHARSET);
//解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKeyPath));
String encode = encoder64.encode(cipher.doFinal(encryptDataBytes));
encode=encode.replaceAll("\r\n","");
return encode;
}
/**
* 私钥解密
* @param data
* @return
* @throws IOException
*/
public static String privateDecrypt(String data,String privateKeyPath) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",provider);cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKeyPath));
byte[] bytes = decoder64.decodeBuffer(data);
return new String(cipher.doFinal(bytes),CHARSET);
}
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, IOException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException, InvalidKeySpecException {
initKey(2048,"","");
System.out.println("--------------------------");
System.out.println("私钥加密---公钥解密");
String str1="测试rsa算法1";
System.out.println("原数据:"+str1);
String privateEncrypt = privateEncrypt(str1,"");
System.out.println("密文:"+privateEncrypt);
String publicDecrypt = publicDecrypt(privateEncrypt,"");
System.out.println("解密:"+publicDecrypt);
System.out.println("--------------------------");
System.out.println("--------------------------");
System.out.println("私钥加密---公钥解密");
String str2="测试rsa算法2";
System.out.println("原数据:"+str2);
String publicEncrypt = publicEncrypt(str2,"");
System.out.println("密文:"+publicEncrypt);
String privateDecrypt = privateDecrypt(publicEncrypt,"");
System.out.println("解密:"+privateDecrypt);
}
}
6、RsaJs.java js实现工具类
package com.sihua.rsa.utils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import javax.crypto.Cipher;
import java.nio.charset.Charset;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
public class RsaJs {
final static String publicKeyStr="";
final static String pairKeyStr="";
static String charset = “utf-8”;
public static void main(String[] args) {
}
// KeyPair is a simple holder for a key pair.
private static final KeyPair keyPair = initKey();
/**
* 初始化方法,产生key pair,提供provider和random
* @return KeyPair instance
*/
private static KeyPair initKey() {
try {
// 添加provider
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
// 产生用于安全加密的随机数
SecureRandom random = new SecureRandom();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", provider);
generator.initialize(1024, random);
return generator.generateKeyPair();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取公钥public key
* @return public key字符串
*/
public static String generateBase64PublicKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// encodeBase64(): Encodes binary data using the base64
// algorithm but does not chunk the output.
// getEncoded():返回key的原始编码形式
System.out.println("公钥:==="+new String(Base64.encodeBase64(publicKey.getEncoded())));
System.out.println("私钥:==="+new String(Base64.encodeBase64(privateKey.getEncoded())));
return new String(Base64.encodeBase64(publicKey.getEncoded()));
}
/**
* 公钥解密数据
* @param string 需要解密的字符串
* @return 破解之后的字符串
*/
public static String publicDecryptData(String string,String publicKeyBase) {
// decodeBase64():将Base64数据解码为"八位字节”数据
return new String(publicDecrypt(Base64.decodeBase64(string.getBytes(Charset.forName(charset))),publicKeyBase), Charset.forName(charset));
}
/**
* 私钥解密数据
* @param string 需要解密的字符串
* @return 破解之后的字符串
*/
public static String privateDecryptData(String string,String privateKeyBase) {
// decodeBase64():将Base64数据解码为"八位字节”数据
return new String(privateDecrypt(Base64.decodeBase64(string.getBytes(Charset.forName(charset))),privateKeyBase), Charset.forName(charset));
}
private static byte[] publicDecrypt(byte[] byteArray,String publicKeyBase) {
try {
AsymmetricBlockCipher cipher = new RSAEngine();
//这里也可以从流中读取,从本地导入
byte[] privateInfoByte=Base64.decodeBase64(publicKeyBase);
AsymmetricKeyParameter pubKey = PublicKeyFactory.createKey(privateInfoByte);
//true表示加密
cipher.init(false, pubKey);
//byte[] publicInfoBytes= Base64.decodeBase64(data);
byte[] encryptDataBytes = cipher.processBlock(byteArray
, 0, byteArray.length);
return encryptDataBytes;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/*private static byte[] publicDecrypt(byte[] byteArray,String publicKeyBase) {
try {
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
// Cipher: 提供加密和解密功能的实例
// transformation: "algorithm/mode/padding" RSA/None/PKCS1Padding
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", provider);
byte[] publicInfoByte=Base64.decodeBase64(publicKeyBase);
//PrivateKey privateKey = keyPair.getPrivate();
X509EncodedKeySpec x509EncodedKeySpec=new X509EncodedKeySpec(publicInfoByte);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
// RSAPrivateKeySpec rsaPrivateKeySpec=new RSAPrivateKeySpec();
// 初始化
cipher.init(Cipher.DECRYPT_MODE, publicKey);
// doFinal(): 加密或者解密数据
byte[] plainText = cipher.doFinal(byteArray);
return plainText;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}*/
/*private static byte[] privateDecrypt(byte[] byteArray,String privateKeyBase64) {
try {
AsymmetricBlockCipher cipher = new RSAEngine();
//这里也可以从流中读取,从本地导入
byte[] privateInfoByte=Base64.decodeBase64(privateKeyBase64);
AsymmetricKeyParameter pubKey = PrivateKeyFactory.createKey(privateInfoByte);
//true表示加密
cipher.init(false, pubKey);
//byte[] publicInfoBytes= Base64.decodeBase64(data);
byte[] encryptDataBytes = cipher.processBlock(byteArray
, 0, byteArray.length);
return encryptDataBytes;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}*/
private static byte[] privateDecrypt(byte[] byteArray,String privateKeyBase64) {
try {
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
// Cipher: 提供加密和解密功能的实例
// transformation: "algorithm/mode/padding" RSA/None/PKCS1Padding
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding",provider);
byte[] privateInfoByte=Base64.decodeBase64(privateKeyBase64);
//PrivateKey privateKey = keyPair.getPrivate();
PKCS8EncodedKeySpec pKCS8EncodedKeySpec=new PKCS8EncodedKeySpec(privateInfoByte);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pKCS8EncodedKeySpec);
// RSAPrivateKeySpec rsaPrivateKeySpec=new RSAPrivateKeySpec();
// 初始化
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// doFinal(): 加密或者解密数据
byte[] plainText = cipher.doFinal(byteArray);
return plainText;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
3、JS实现使用
1、test.html
})
</script>
js公钥加密-java私钥解密 结果
js私钥加密-java公钥解密 结果 2、jsencrypt.min.js 下载
4)RSA 验证
http://localhost:8088/rsatest?type=1&data=2 //lua生成证书 (注:要和java联调需要把生成的证书拷贝到java中的resources目录下)
http://localhost:8088/rsatest?type=2&data=2 //lua公钥加密java私钥解密
http://localhost:8088/rsatest?type=3&data=2 //lua私钥签名java公钥验签
http://localhost:8076/publicDataBnc?password=12312 //java公钥加密 lua私钥解密
http://localhost:8076/test?data=1 js加密测试页面
5)RSA 示例源码下载
下载路径:https://pan.baidu.com/s/13kEzM2aSwYCVQKoo6BYjtQ 9ys1