RSA原理
通过一定的规则,生成公钥和私钥,公钥和私钥总是成对出现。
公钥可以公开出去,任何人都可以知道。
私钥只有自己知道。
RSA算法能保证,公钥加密后的密文,只有对应的私钥才能解密。或者,私钥加密后的密文,只有对应的公钥才能解密。
而且不能通过公钥得到私钥,也不能通过私钥算出公钥。
关于为什么公私钥直接不能互相转换,请看我之前的一篇文章:
非对称加密算法之RSA算法实现
RSA应用场景
RSA加密场景
A给B传一条消息,要保证哪怕消息被截取了,也不能让别人知道消息的真正含义。
1、B生成公钥和私钥,私钥自己保留,把公钥传给A
2、A用公钥加密要传的消息,然后把密文传给B
3、B用私钥解密密文,得到真正的消息。
这样做的好处是,就算有人把中间的密文和公钥都拿到了,他也获取不到明文。
因为RSA的特点就是公钥加密,必须用对应的私钥才能解密。而私钥一直是B保管。
RSA签名场景
同样的,A给B传一条消息,可以明文传输,但要保证,B收到的,就是A发出的,不能被别人恶意修改。
1、B生成公钥和私钥,私钥自己保留,把公钥传给A
2、A用公钥对要传的信息进行签名,形成签名信息。A将签名信息和明文一起传给B
3、B收到明文和签名后,用私钥对签名进行验证,如果验证通过,则证明B收到的明文就是A发出的明文。
这样做的好处是,哪怕中间有人截取到明文和签名,只要修改任意一个,B那里最终都不会验证通过。
RSA加解密和签名算法的java实现
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class TestRsa {
// 私钥对象
private PrivateKey sk;
// 公钥对象
private PublicKey pk;
// 私钥字符串
private String privateKeyStr;
// 公钥字符串
private String publicKeyStr;
// 初始化公钥私钥
public TestRsa() throws NoSuchAlgorithmException {
KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA");
rsa.initialize(1024);
KeyPair keyPair = rsa.generateKeyPair();
sk = keyPair.getPrivate();
pk = keyPair.getPublic();
privateKeyStr = new String(Base64.encodeBase64(sk.getEncoded()));
publicKeyStr = new String(Base64.encodeBase64(pk.getEncoded()));
}
// 公钥加密
public String encrypt(String str, String publicKey) throws Exception {
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
// 私钥解密
public String decrypt(String str, String privateKey) throws Exception {
//64位解码加密后的字符串
byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
//base64编码的私钥
byte[] decoded = Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}
// 私钥签名
public String sign(String str) throws Exception {
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(this.sk);
signature.update(str.getBytes());
byte[] sign = signature.sign();
return new String(Base64.encodeBase64(sign));
}
// 公钥验证
public boolean verify(String str, String sign) throws Exception {
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(this.pk);
signature.update(str.getBytes());
return signature.verify(Base64.decodeBase64(sign.getBytes("UTF-8")));
}
public static void main(String[] args) throws Exception {
String str = "这是加密前的明文";
TestRsa testRsa = new TestRsa();
String encrypt = testRsa.encrypt(str, testRsa.publicKeyStr);
System.out.println("加密后的密文:" + encrypt);
String decrypt = testRsa.decrypt(encrypt, testRsa.privateKeyStr);
System.out.println("解密后的明文:" + decrypt);
// 签名
String sign = testRsa.sign(str);
System.out.println("签名结果:" + sign);
// 验证
boolean verify = testRsa.verify(str, sign);
System.out.println("验证结果:" + verify);// true
// 验证反例
String str2 = "这是被恶意修改过的伪原文";
boolean verify2 = testRsa.verify(str2, sign);
System.out.println("验证结果2:" + verify2);// false
}
}
最终结果:
加密后的密文:Pc/lj5beiojR1BIiEG1O9fooVOmwDgQixN9qX19ofU3Myq5iOViMqEM2lUZ+tmihms3BrLahZze2FeZVR1wrTSk24ZTK5rjKtL1GZLsQI6m/wNXmk9bA5gYbcR6ivZSTEw5a9+77mcAFuAgpeSmSM825NOTAt7epZeUt7i9FPNY=
解密后的明文:这是加密前的明文
签名结果:Oe2XuGCb5mBwE4JTRPcemipOSuXEsw+hxido6r3/FSyDhx371sdg6/iRYQk6C2FuOqOpltWBJ4gA7x+VfJSJoA94+EIu5WxOaupaPumzNrsfhC/ZtYRUw0PfUvR5j232LH5bfA+Dh6pGbo1gu6qMVf8EtS63BoGHi9SYP068uss=
验证结果:true
验证结果2:false
1616

被折叠的 条评论
为什么被折叠?



