目录
- RSA原理
- RSA应用场景
- RSA加密场景
- RSA签名场景
- RSA加解密和签名算法的java实现
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