RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。1987年7月首次在美国公布,当时他们三人都在麻省理工学院工作实习。RSA就是他们三人姓氏开头字母拼在一起组成的。

  RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。

  RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。

  在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK。

  基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可以在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。

  RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,截止2017年被普遍认为是最优秀的公钥方案之一。

  SET(Secure Electronic Transaction)协议中要求CA采用2048bits长的密钥,其他实体使用1024比特的密钥。RSA密钥长度随着保密级别提高,增加很快。

  RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。

  我们接下来看下Java中如何实现RSA加密解密与加签验签。我们先来看RSA加密解密。  

 import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.util.Base64;
/**
* RSA加密解密操作步骤
*/
public class Test1 {
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
//先给出一个待加密的字符串
String data="青青子衿,悠悠我心。但为君故,沉吟至今。";
//1.构建公私钥匙对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
KeyPair keyPair = keyPairGenerator.generateKeyPair();
//2.获取钥匙对中的公钥
PublicKey publicKey = keyPair.getPublic();
//3.获取钥匙对中的私钥
PrivateKey privateKey = keyPair.getPrivate();
//4.对待加密的数据进行加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE,publicKey);
byte[] bytesEncrypt = cipher.doFinal(data.getBytes());//产生的是乱码,需要用Base64进行转码
//5.Base64编码
byte[] encodeBase64 = Base64.getEncoder().encode(bytesEncrypt);
System.out.println("加密后的数据:"+new String(encodeBase64));
//6.在解密时,先对用Base64编码的信息进行解码
byte[] bytesDecode = Base64.getDecoder().decode(encodeBase64);
//7.解密
Cipher cipher2=Cipher.getInstance("RSA");
cipher2.init(Cipher.DECRYPT_MODE,privateKey);
byte[] bytesDecrypt = cipher2.doFinal(bytesDecode);
System.out.println("解密后的数据:"+new String(bytesDecrypt));
}
}

  公钥和私钥本身存储的信息是乱码,在实际使用中,我们还可以通过Base64将这些乱码编码为可识别的ASCII码,然后将公钥和私钥信息持久化存储到文件中,在以后需要使用时,可以从文件中读取公钥和私钥信息。为此,我们可以写一个RSA的工具类,从一个储存公钥和私钥信息的文件里读取公钥和私钥信息,然后定义获取公钥和私钥的方法,以及加密和解密数据的方法。首先,我们提供一对公私钥信息,假定公钥信息储存在一个名称为rsa_public_key.pem的文件里,信息如下:

-----BEGIN RSA PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDY90KtriCa4KjNe3mgrGGbDB95
8A2byBKf+wOmPmOopP3gGeg7+DFAPNYCC+tL8h2bpUI3IPKOm2Hon8kM/p628i1J
Z7JjopYVZW6JKqA2ImyneeUEK748FXwXTRAAMCTqQG/7a178BGawTdHi6hk+M6UF
lT0EhL6JA8ULKFoiHwIDAQAB
-----BEGIN RSA PUBLIC KEY-----

  假定私钥信息储存在一个名称为rsa_private_key.pem的文件里,信息如下::

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDY90KtriCa4KjNe3mgrGGbDB958A2byBKf+wOmPmOopP3gGeg7
+DFAPNYCC+tL8h2bpUI3IPKOm2Hon8kM/p628i1JZ7JjopYVZW6JKqA2ImyneeUE
K748FXwXTRAAMCTqQG/7a178BGawTdHi6hk+M6UFlT0EhL6JA8ULKFoiHwIDAQAB
AoGBAIJFhF2wLZeQyQoH13Gnzzs/Pi8C+cjNipFQMFLDJyd9WYoTRCOt1DST0pOM
AI2rJCfuRCHBwKHrnhAE0LzirPxkmvyHTIBXIoz3fHiSkIKkUVG04BcgTYpNKWPB
ISlzdhSaw7CnmJjTthTrD5LLPtpqUl350lUYFEHVNR6Ys9JRAkEA9JUEVxzSvQkV
V6hxhbvlxl0mATbPfiNKDBTPdr48dyYdgluAoGfAPf9rmgoCpdEd2hZBIfdy7xdL
LvP7ztb/rQJBAOMYNC/lZLz9A9cDJ5bibrJnmyRG0SAGAzu4ffYdBoGb0kRRKzTe
5jxfRnbiUPQU4GQXhADfikGn2ogRqbtDsnsCQQCJdp+D3n1LJanLJK75PQv9myjb
EdU4zdi2RZP85xrQ1KlNNORsQyO3NLFjWDD4xTmD83IUByGf43WsJBDoxcnZAkA3
i84IARX42/I6fz0JvOzSmmDqKKAyMwZLbz7wGf1jalet+iSVVAgAsFUt8wFWEl0o
XlAdXpAUqxfavGdFtLNNAkABS576xgLcLmyw51f9hoM9RiamLn+WNzoA5TLOZjGI
dZZnX/A8SoFYGoJoN1O0hp5DxDdl+gjW/mH51+gliEIB
-----END RSA PRIVATE KEY-----

  接下来,我们写一个RSAUtil工具类,代码如下:  

 import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* 工具类
*/
public class RSAUtil {
/*
读取秘钥数据
*/
public static byte[] readKeyDatas(String keyFilePath){
BufferedReader bufferedReader=null;
try{
bufferedReader = new BufferedReader(new FileReader(keyFilePath));
String str=null;
StringBuilder stringBuilder=new StringBuilder();
while ((str=bufferedReader.readLine())!=null){
if(str.contains("---")){
continue;
}
stringBuilder.append(str);
}
return stringBuilder.toString().getBytes();
}catch (IOException e) {
e.printStackTrace();
}finally {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/*
生成公钥
*/
public static PublicKey getPublicKey(String publicKeyPath){
//1.读取公钥文件,获取公钥数据
byte[] bytesPublicBase64 = readKeyDatas(publicKeyPath);
//2.对读取回来的数据进行Base64解码
byte[] bytesPublic = Base64.getDecoder().decode(bytesPublicBase64);
//3.把解码后的数据,重新封装成一个PublicKey对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytesPublic);
KeyFactory keyFactory=null;
try {
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
/*
生成私钥
*/
public static PrivateKey getPrivateKey(String privateKeyPath){
//1.读取私钥文件,获取私钥数据
byte[] bytesPrivateBase64 = readKeyDatas(privateKeyPath);
//2.对读取回来的数据进行Base64解码
byte[] bytesPrivate = Base64.getDecoder().decode(bytesPrivateBase64);
//3.把解码后的数据,重新封装成一个PrivateKey对象
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytesPrivate);
KeyFactory keyFactory=null;
try {
keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
/*
加密数据
*/
public static String encodeData(PublicKey publicKey,String originData){
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE,publicKey);
byte[] bytesEncrypt = cipher.doFinal(originData.getBytes());
//Base64编码
byte[] bytesEncryptBase64 = Base64.getEncoder().encode(bytesEncrypt);
return new String(bytesEncryptBase64);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return null;
}
/*
解密数据
*/
public static String decodeData(PrivateKey privateKey,String encodeData){
try {
//Base64解码
byte[] bytesEncrypt = Base64.getDecoder().decode(encodeData);
//加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE,privateKey);
byte[] bytesDecrypt = cipher.doFinal(bytesEncrypt);
return new String(bytesDecrypt);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return null;
}
}

  这样的话,以后需要使用公钥和私钥,以及加密解密时,调用上述工具类中的相应方法即可。

  最后,我们再来看用RSA如何对数据进行加签验签,具体代码如下:

 import java.io.UnsupportedEncodingException;
import java.security.*;
/**
* 加签 验签 签名验证:验证数据的合法来源 即验证数据来源的合法性
* 加签:私钥
* 验签:公钥
*/
public class Test2 {
private static String privateKeyPath="储存私钥信息的文件路径";
private static String publicKeyPath="储存公钥信息的文件路径";
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, SignatureException {
String data="验证该数据是否为合法的服务器发送";
/**
* 加签过程
*/
PrivateKey privateKey = RSAUtil.getPrivateKey(privateKeyPath);
Signature signature = Signature.getInstance("Sha1WithRSA");
signature.initSign(privateKey);
signature.update(data.getBytes("UTF-8"));
byte[] signed = signature.sign();
/**
* 验签过程
*/
PublicKey publicKey = RSAUtil.getPublicKey(publicKeyPath);
Signature signature2 = Signature.getInstance("Sha1WithRSA");
signature2.initVerify(publicKey);
signature2.update(data.getBytes("UTF-8"));
boolean verify = signature2.verify(signed);
System.out.println("验签结果:"+verify);
}
}

RSA加密解密与加签验签的更多相关文章

  1. RSA加密解密及RSA加签验签

    RSA安全性应用场景说明 在刚接触RSA的时候,会混淆RSA加密解密和RSA加签验签的概念.简单来说加密解密是公钥加密私钥解密,持有公钥(多人持有)可以对数据加密,但是只有持有私钥(一人持有)才可以解 ...

  2. 微信小程序(17)-- RSA加密 解密 加签 验签

    RSA加密 解密 加签 验签 /** * 注:区分RSA私钥的类型,有pkcs1和pkcs8.pkcs8格式的私钥主要用于Java中 pkcs1格式: -----BEGIN RSA PRIVATE K ...

  3. RSA 加密 解密 公钥 私钥 签名 加签 验签

    http://blog.csdn.net/21aspnet/article/details/7249401# http://www.ruanyifeng.com/blog/2013/06/rsa_al ...

  4. Java实现RSA密钥对并在加解密、加签验签中应用的实例

    一.项目结构 二.代码具体实现 1.密钥对生成的两种方式:一种生成公钥私文件,一种生成公钥私串 KeyPairGenUtil.java package com.wangjinxiang.genkey. ...

  5. Python rsa公私钥生成 rsa公钥加解密(分段加解密)-私钥加签验签实战

    一般现在的SAAS服务提供现在的sdk或api对接服务都涉及到一个身份验证和数据加密的问题.一般现在普遍的做法就是配置使用非对称加密的方式来解决这个问题,你持有SAAS公司的公钥,SAAS公司持有你的 ...

  6. 手摸手带你认识https涉及的知识,并实现https加密解密,加签解签

    目录 http访问流程 https访问流程 证书 加密/解密 加签/验签 Java实现https 拓展 @ 看完整的代码,直接去完整代码实现,看实现完后会遇到的坑,直接去测试过程中的问题,包括经过代理 ...

  7. RSA体系 c++/java相互进行加签验签--转

    在web开发中,采用RSA公钥密钥体系自制ukey,文件证书登陆时,普遍的做法为:在浏览器端采用c++ activex控件,使用 c++的第三库openssl进行RAS加签操作,在服务器端采用java ...

  8. java RSA 加签验签【转】

    引用自: http://blog.csdn.net/wangqiuyun/article/details/42143957/ java RSA 加签验签 package com.testdemo.co ...

  9. .NET RSA解密、签名、验签

    using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Sec ...

随机推荐

  1. [51nod1325]两棵树的问题

    description 题面 solution 点分治+最小割. 点分必选的重心,再在树上dfs判交,转化为最大权闭合子图. 可以做\(k\)棵树的情况. code #include<iostr ...

  2. 【Codeforces Round #405 ( Div 2)】题解

    Bear and Big Brother 签到题,直接模拟就可以了. Bear and Friendship Condition 满足只能是每个朋友圈中每个人和其他人都是朋友,这样的边数的确定的. 然 ...

  3. [BZOJ2961] 共点圆 [cdq分治+凸包]

    题面 BZOJ传送门 思路 首先考虑一个点$(x_0,y_0)$什么时候在一个圆$(x_1,y_1,\sqrt{x_1^2+y_1^2})$内 显然有:$x_1^2+y_1^2\geq (x_0-x_ ...

  4. [POI2007]ZAP-Queries && [HAOI2011]Problem b 莫比乌斯反演

    1,[POI2007]ZAP-Queries ---题面---题解: 首先列出式子:$$ans = \sum_{i = 1}^{n}\sum_{j = 1}^{m}[gcd(i, j) == d]$$ ...

  5. 三个月死磕Python是种什么样的体验?

    3个月的死磕Python后,参加「 楼+ Python实战 · 第4期 」的学员们感想如何?下面带来他们的真实评价. 作为实验楼的网红课程——「 楼+ Python实战 」已经走过了第四期,经过了三个 ...

  6. ZOJ1994 & POJ2396:Budget——题解

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1994 http://poj.org/problem?id=2396 题目大 ...

  7. BZOJ5321 & 洛谷4064 & LOJ2274:[JXOI2017]加法——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5321 https://www.luogu.org/problemnew/show/P4064 ht ...

  8. float,absolute脱离文档流的总结

    dom元素脱离文档流,有如下几种方式: 1. float 脱离文档流,其他dom元素无视他,在其下方布局,但是其未脱离文本流,其他元素的文本会认为他存在,环绕他布局.父元素会无视他,因此无法获取其高度 ...

  9. 读取proc/uptime信息。

    #include <stdio.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h ...

  10. JavaScript随机数生成方法

    实现随机数是各种编程语言都很常见的一个编程任务,下面介绍一下在JavaScript如何实现随机数.第一中方法通过重写Math.random方法实现,第二种方法改自一个C实现,都可以实现编程目的. 直接 ...