1.RSA算法史:
RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)三位数学家提出。在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
但实际上,在1973年,在英国政府通讯总部工作的数学家克利福德·柯克斯(Clifford Cocks)在一个内部文件中提出了一个相同的算法,但他的发现被列入机密,一直到1997年才被发表。
2.RSA加密简介:
RSA加密是一种非对称加密。可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程,分别称为公钥和私钥。两者之间有数学相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥,公钥是公开的(可能同时多人持有)
3.RSA加密、签名区别:
加密和签名都是为了安全性考虑,但略有不同。常有人问加密和签名是用私钥还是公钥?其实都是对加密和签名的作用有所混淆。简单的说,加密是为了防止信息被泄露,而签名是为了防止信息被篡改。这里举2个例子说明。
4.使用场景
场景一:
第一个场景:战场上,B要给A传递一条消息,内容为某一指令。
RSA的加密过程如下:
@1A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
@2A传递自己的公钥给B,B用A的公钥对消息进行加密。
@3A接收到B加密的消息,利用A自己的私钥对消息进行解密。
在这个过程中,只有2次传递过程,第一次是A传递公钥给B,第二次是B传递加密消息给A,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行解密,防止了消息内容的泄露。
场景二:
第二个场景:A收到B发的消息后,需要进行回复“收到”。
RSA签名的过程如下:
(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
(2)A用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给B。
(3)B收到消息后,在获取A的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是A回复的。
在这个过程中,只有2次传递过程,第一次是A传递加签的消息和消息本身给B,第二次是B获取A的公钥,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带签名的回复给B,防止了消息内容的篡改。
项目案例:
第二个场景:A收到B发的消息后,需要进行回复“收到”。
RSA签名的过程如下:
(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
(2)A用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给B。
(3)B收到消息后,在获取A的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是A回复的。
在这个过程中,只有2次传递过程,第一次是A传递加签的消息和消息本身给B,第二次是B获取A的公钥,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带签名的回复给B,防止了消息内容的篡改。
5.RSA项目中加密流程
RSA是一种常用的非对称加密算法,所谓非对称加密是指使用一对密钥(公钥和私钥)进行加密和解密,公钥人人都可以获得,用于加密数据,私钥保存在服务器中,用于解密数据。加密解密过程如下:
使用RSA进行加密解密,其优点是非常不容易破解,缺点是和对称加密(如AES)相比,加密速度较慢。因此,实际使用中,常常将对称加密和非对称加密结合使用,即使用非对称加密协商对称加密的密钥,使用对称加密密钥加密传输内容。
6.RSA项目中加密源码
6.1生成随机公钥私钥
随机生成公钥和私钥,用于测试RSA加密解密
/**
* 私钥
*/
private static RSAPrivateKey privateKey;
/**
* 公钥
*/
private static RSAPublicKey publicKey;
/**
* 随机生成密钥对
*/
public static void genKeyPair() {
KeyPairGenerator keyPairGen = null;
try {
keyPairGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
keyPairGen.initialize(1024, new SecureRandom());
KeyPair keyPair = keyPairGen.generateKeyPair();
privateKey = (RSAPrivateKey) keyPair.getPrivate();
publicKey = (RSAPublicKey) keyPair.getPublic();
}
6.2加载公钥/私钥
从字符串/文件输入流中加载公钥
/**
* 从字符串中加载公钥
*
* @param publicKeyStr 公钥数据字符串
* @throws Exception 加载公钥时产生的异常
*/
public static void loadPublicKey(String publicKeyStr) throws Exception {
try {
byte[] buffer = EnDecryptionUtil.base64Decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("公钥非法");
} catch (NullPointerException e) {
throw new Exception("公钥数据为空");
}
}
/**
* 从文件输入流中加载公钥
*
* @param in 公钥输入流
* @throws Exception 加载公钥时产生的异常
*/
public static void loadPublicKey(InputStream in) throws Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
loadPublicKey(sb.toString());
} catch (IOException e) {
throw new Exception("公钥数据流读取错误");
} catch (NullPointerException e) {
throw new Exception("公钥输入流为空");
}
}
//从字符串/文件输入流中加载私钥
/**
* 从字符串中加载私钥
* @param privateKeyStr
* @throws Exception
*/
public static void loadPrivateKey(String privateKeyStr) throws Exception {
try {
byte[] buffer = EnDecryptionUtil.base64Decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("私钥非法");
} catch (NullPointerException e) {
throw new Exception("私钥数据为空");
}
}
/**
* 从文件输入流中加载私钥
*
* @param in 私钥输入流
* @return 是否成功
* @throws Exception
*/
public static void loadPrivateKey(InputStream in) throws Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
loadPrivateKey(sb.toString());
} catch (IOException e) {
throw new Exception("私钥数据读取错误");
} catch (NullPointerException e) {
throw new Exception("私钥输入流为空");
}
}
6.3RSA加密数据
/**
* RSA加密过程
*
* @param publicKey 公钥
* @param plainTextData 明文数据
* @return
* @throws Exception 加密过程中的异常信息
*/
public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
if (publicKey == null) {
throw new Exception("加密公钥为空, 请设置");
}
Cipher cipher;
try {
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(plainTextData);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此加密算法");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
return null;
} catch (InvalidKeyException e) {
throw new Exception("加密公钥非法,请检查");
} catch (IllegalBlockSizeException e) {
throw new Exception("明文长度非法");
} catch (BadPaddingException e) {
throw new Exception("明文数据已损坏");
}
}
//加密后获得的byte[]数组一般会进行Base64编码
6.4RSA解密
/**
* RSA解密
*
* @param privateKey 私钥
* @param cipherData 密文数据
* @return 明文
* @throws Exception 解密过程中的异常信息
*/
public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
if (privateKey == null) {
throw new Exception("解密私钥为空, 请设置");
}
Cipher cipher = null;
try {
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(cipherData);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此解密算法");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
return null;
} catch (InvalidKeyException e) {
throw new Exception("解密私钥非法,请检查");
} catch (IllegalBlockSizeException e) {
throw new Exception("密文长度非法");
} catch (BadPaddingException e) {
throw new Exception("密文数据已损坏");
}
}
//如果输入的密文进行过Base64编码,需Base64解码后再进行RSA解密
6.4RSA 运行结果
公钥:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO2TVhB1VIpUhNb5+owamkjmU8dNEMJyTbakBT
b7GysKaA+byMRqJLRAbVPj+eD15erREOkv9A1z4mOMo7i+7hb6J8LuktCDWC5QeusvbwlpOjjIE6
Sq8pETHPnHX5dd+ORFYWPrbd7drSIv0Fbm3R7zi0LhuJn3JWkLf1JEFDywIDAQAB
私钥:MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAM7ZNWEHVUilSE1vn6jBqaSOZTx0
0QwnJNtqQFNvsbKwpoD5vIxGoktEBtU+P54PXl6tEQ6S/0DXPiY4yjuL7uFvonwu6S0INYLlB66y
9vCWk6OMgTpKrykRMc+cdfl1345EVhY+tt3t2tIi/QVubdHvOLQuG4mfclaQt/UkQUPLAgMBAAEC
gYB+M3Xm4iN9dCI95JnDy4ymMp6/mQImaQeKuzPN9Dq1rCOaU0RfTYUdaL7GgfkshXHtT6g1fSgx
NmHbzhBM7l5qoYJNwz/8KQ9rTphdc0JQFzu3ECkDZvOe+yjSKWpuZFGizLsB2j3Og4MF3fOKNfN7
c1ucNNEYpzbGPyOPC23TWQJBAPOU5pLEwMV4VSC3LgJcjorvf5DQqJVpnPYyHRE7MFhsnVHfmbIq
nTBhOcdomwOde+yQjerGIi7W7RIjobgoZdUCQQDZZOLEo5qdIXn319R3ucPsAHLPcTa8kfxpUHLo
rN8INKUj7dR3FtWc9cye5fzWRg+NkBx6OC408l95qeGvBbMfAkEAqQJ7DgFJBHtfDcksOmVAXnSZ
XcD6CFn0l/rjok4gWGpcqi9stGvPD3+WmJ8jV9nQ367ZWbpKg5eLfReOIXqeVQJBAMuxwuVbIoE+
n8kBm1w/XHuig/EpdI9F/oszTSgE6soGggHjU6PuamMy0PLGLp0bcnFDadt/DpSf0aPu8L8NCSMC
QQDvL5cjxQqIPJSP1T+JKktvd+nWPULt7Adir1fab022e0XfEod73Eoo4rp0GmN0hSZUH0VBBvqf
lNY1P23tZP3C
待加密明文:123456
加密后Base64数据:KMzWgXeWLpc31/D3LOv65AYquARkNCoPNVy+vqZd4ASC8hev1iZtBOowmWp5mMr0pYHya9AK6Ang
GZmT2KzS472r+UR6LJxY7u3qthGuWiWcWmZbyH/z2LEB6du60b8BOpa670GE/HB074z85kPTWCWE
3kvBNDbYvDdfjMD/8JY=
待解密Base64密文:KMzWgXeWLpc31/D3LOv65AYquARkNCoPNVy+vqZd4ASC8hev1iZtBOowmWp5mMr0pYHya9AK6Ang
GZmT2KzS472r+UR6LJxY7u3qthGuWiWcWmZbyH/z2LEB6du60b8BOpa670GE/HB074z85kPTWCWE
3kvBNDbYvDdfjMD/8JY=
解密后数据:123456
总结:
公钥加密、私钥解密、私钥签名、公钥验签。
想要源码评论区回复我,给你私发链接
Kotlin基础篇【1】Android Studio 3.0 Kotlin环境配置
Kotlin基础篇【2】初识Kotlin的意义
Kotlin基础篇【3】Kotlin基础语法
=======Kotlin基础篇【4】Kotlin基础语法即将更新=======