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. Android Canvas 绘图

    画布(Canvas)是图形编程中一个很普通的概念,通常由三个基本的绘图组件组成:       Canvas  提供了绘图方法,可以向底层的位图绘制基本图形.       Paint  也称为" ...

  2. BZOJ1856:[SCOI2010]字符串——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=1856 lxhgww最近接到了一个生成字符串的任务,任务需要他把n个1和m个0组成字符串,但是任务还 ...

  3. BZOJ2427:[HAOI2010]软件安装——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=2427 https://www.luogu.org/problemnew/show/P2515 现在 ...

  4. 【并查集】【P1525】关押罪犯

    传送门 Description Input Output Sample Input Sample Output Hint Solution 非常显然的并查集题目,在本题中,对于每个罪犯i,维护两个信息 ...

  5. 在CentOS6.5 下安装并使用Java开发opencv的配置(一)

    1) 安装gcc以及cmake等等乱七八糟的软件 yum install gcc yum install python yum install cmake yum groupinstall " ...

  6. Mac 访问隐藏文件方法! 网上方法在我电脑上都不可用!

    百度的方法: 如果你想打开整个系统的隐藏文件可以在终端下输入以下命令 defaults write com.apple.finder AppleShowAllFiles -bool true 关闭显示 ...

  7. springboot以jar包方式启动、关闭、重启脚本

    springboot以jar包方式启动.关闭.重启脚本 启动 编写启动脚本startup.sh #!/bin/bash echo Starting application nohup java -ja ...

  8. c# 事实证明,abstract类除了不能用new实例化和类没什么区别

    abstract类是抽象类,不能够实例化,大家都知道,abstract类往往和接口interface一块儿使用,针对接口中一些公共的方法进行实现,然后实体类去继承抽象类和接口.虽然abstract类不 ...

  9. 【点分治练习题·不虚就是要AK】点分治

    不虚就是要AK(czyak.c/.cpp/.pas)  2s 128M  by zhb czy很火.因为又有人说他虚了.为了证明他不虚,他决定要在这次比赛AK. 现在他正在和别人玩一个游戏:在一棵树上 ...

  10. CSS(Cascading Style Shee)

    1.CSS是Cascading Style Sheet这个几个英文单词的缩写,翻译成中文是“层叠样式表”的意思 CSS能让网页制作者有效的定制.改善网页的效果. CSS是对HTML的补充,网页设计师曾 ...