RSA加密理解

一、对称加密

通俗来讲,典型的对称加密,比如利用异或重要的性质自反性:“A^B^B=A”,即对给定的数A,用同样的运算因子(B)作两次异或运算后仍得到A本身。

A^B=D,D^B=A 这种对称是加密,即加密解密方式一致,用B加密,用B解密,如1^0^0=1

二、非对称加密

通俗理解非对称加密,比如rsa加密,即,A^B=D,D^C=A,用B加密,用C解密,rsa算法大致理解就是

  • 科学界大佬想出了一种方法,通过两个的互质数得到模mod n(3233),再算得一对数字e(17), d(2753),最终得出公钥n,e(3233,17),私钥n,d(3233,2753)

  • 然后客户想加密明文m(65),通过公式m^e ≡ c (mod n),代入公钥n,e得出密文c(2790)

  • 服务器通想解密密文c(2790),通过公式c^d ≡ m (mod n),代入私钥n,d得出明文m(65)

三、java实现

1. 方法一

java直接使用KeyPair生成的公钥和密钥

KeyPair keyPair=genKeyPair(1024);
        
//获取公钥,并以base64格式打印出来
PublicKey publicKey=keyPair.getPublic();        
System.out.println("公钥:"+new String(Base64.getEncoder().encode(publicKey.getEncoded())));
​
//获取私钥,并以base64格式打印出来
PrivateKey privateKey=keyPair.getPrivate();     
System.out.println("私钥:"+new String(Base64.getEncoder().encode(privateKey.getEncoded())));

具体代码如下

public class RSACryptography {
    
    public static String data="hello world";
 
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        
        KeyPair keyPair=genKeyPair(1024);
        
        //获取公钥,并以base64格式打印出来
        PublicKey publicKey=keyPair.getPublic();        
        System.out.println("公钥:"+new String(Base64.getEncoder().encode(publicKey.getEncoded())));
        
        //获取私钥,并以base64格式打印出来
        PrivateKey privateKey=keyPair.getPrivate();     
        System.out.println("私钥:"+new String(Base64.getEncoder().encode(privateKey.getEncoded())));
        
        //公钥加密
        byte[] encryptedBytes=encrypt(data.getBytes(), publicKey);  
        System.out.println("加密后:"+new String(encryptedBytes));
        
        //私钥解密
        byte[] decryptedBytes=decrypt(encryptedBytes, privateKey);      
        System.out.println("解密后:"+new String(decryptedBytes));
    }
    
    //生成密钥对
    public static KeyPair genKeyPair(int keyLength) throws Exception{
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);      
        return keyPairGenerator.generateKeyPair();
    }
    
    //公钥加密
    public static byte[] encrypt(byte[] content, PublicKey publicKey) throws Exception{
        Cipher cipher=Cipher.getInstance("RSA");//java默认"RSA"="RSA/ECB/PKCS1Padding"
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(content);
    }
    
    //私钥解密
    public static byte[] decrypt(byte[] content, PrivateKey privateKey) throws Exception{
        Cipher cipher=Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(content);
    }
 
}

2. 方法二

上面代码用来生成密钥就OK了,生成的密钥需要保存到本地文件中,一般不会在客户端调用KeyPairGenerator进行密钥的生成操作。

这里,我们可以将密钥保存到文件,下次我们直接读取就可以了。我假设以String的形式保存在文件内,那么接下来直接使用读取到的String生成密钥即可。

//获取公钥 
PublicKey publicKey=getPublicKey(publicKeyString);
        
//获取私钥 
PrivateKey privateKey=getPrivateKey(privateKeyString);

具体代码如下

public class RSACryptography {
    
    public static String data="hello world";
    public static String publicKeyString="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCISLP98M/56HexX/9FDM8iuIEQozy6kn2JMcbZS5/BhJ+U4PZIChJfggYlWnd8NWn4BYr2kxxyO8Qgvc8rpRZCkN0OSLqLgZGmNvoSlDw80UXq90ZsVHDTOHuSFHw8Bv//B4evUNJBB8g9tpVxr6P5EJ6FMoR/kY2dVFQCQM4+5QIDAQAB";
    public static String privateKeyString="MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIhIs/3wz/nod7Ff/0UMzyK4gRCjPLqSfYkxxtlLn8GEn5Tg9kgKEl+CBiVad3w1afgFivaTHHI7xCC9zyulFkKQ3Q5IuouBkaY2+hKUPDzRRer3RmxUcNM4e5IUfDwG//8Hh69Q0kEHyD22lXGvo/kQnoUyhH+RjZ1UVAJAzj7lAgMBAAECgYAVh26vsggY0Yl/Asw/qztZn837w93HF3cvYiaokxLErl/LVBJz5OtsHQ09f2IaxBFedfmy5CB9R0W/aly851JxrI8WAkx2W2FNllzhha01fmlNlOSumoiRF++JcbsAjDcrcIiR8eSVNuB6ymBCrx/FqhdX3+t/VUbSAFXYT9tsgQJBALsHurnovZS1qjCTl6pkNS0V5qio88SzYP7lzgq0eYGlvfupdlLX8/MrSdi4DherMTcutUcaTzgQU20uAI0EMyECQQC6il1Kdkw8Peeb0JZMHbs+cMCsbGATiAt4pfo1b/i9/BO0QnRgDqYcjt3J9Ux22dPYbDpDtMjMRNrAKFb4BJdFAkBMrdWTZOVc88IL2mcC98SJcII5wdL3YSeyOZto7icmzUH/zLFzM5CTsLq8/HDiqVArNJ4jwZia/q6Fg6e8KO2hAkB0EK1VLF/ox7e5GkK533Hmuu8XGWN6I5bHnbYd06qYQyTbbtHMBrFSaY4UH91Qwd3u9gAWqoCZoGnfT/o03V5lAkBqq8jZd2lHifey+9cf1hsHD5WQbjJKPPIb57CK08hn7vUlX5ePJ02Q8AhdZKETaW+EsqJWpNgsu5wPqsy2UynO";
    
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        
        
        //获取公钥 
        PublicKey publicKey=getPublicKey(publicKeyString);
        
        //获取私钥 
        PrivateKey privateKey=getPrivateKey(privateKeyString);      
        
        //公钥加密
        byte[] encryptedBytes=encrypt(data.getBytes(), publicKey);  
        System.out.println("加密后:"+new String(encryptedBytes));
        
        //私钥解密
        byte[] decryptedBytes=decrypt(encryptedBytes, privateKey);      
        System.out.println("解密后:"+new String(decryptedBytes));
    }
    
    //将base64编码后的公钥字符串转成PublicKey实例
    public static PublicKey getPublicKey(String publicKey) throws Exception{
        byte[ ] keyBytes=Base64.getDecoder().decode(publicKey.getBytes());
        X509EncodedKeySpec keySpec=new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory=KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);  
    }
    
    //将base64编码后的私钥字符串转成PrivateKey实例
    public static PrivateKey getPrivateKey(String privateKey) throws Exception{
        byte[ ] keyBytes=Base64.getDecoder().decode(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec=new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory=KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }
    
    //公钥加密
    public static byte[] encrypt(byte[] content, PublicKey publicKey) throws Exception{
        Cipher cipher=Cipher.getInstance("RSA");//java默认"RSA"="RSA/ECB/PKCS1Padding"
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(content);
    }
    
    //私钥解密
    public static byte[] decrypt(byte[] content, PrivateKey privateKey) throws Exception{
        Cipher cipher=Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(content);
    }
 
}

3. 方法三

为了安全,两个的质数必须足够大,最终得到的公钥和密钥才足够安全,java还可以通过publicKey,privateKey来分别获取n,e,d的值

//获取公钥你,
RSAPublicKey publicKey=(RSAPublicKey) getPublicKey(publicKeyString);
BigInteger modulus1=publicKey.getModulus();
BigInteger exponent1=publicKey.getPublicExponent();
​
//获取私钥
RSAPrivateKey privateKey=(RSAPrivateKey) getPrivateKey(privateKeyString);        
BigInteger modulus2=privateKey.getModulus();
BigInteger exponent2=privateKey..getPrivateExponent();

具体代码实现如下

package com.depart.utils;
​
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
​
import javax.crypto.Cipher;
​
/**
 * 
 * @ClassName: RSACryptography 
 * @Description: 
        参考链接
        https://blog.csdn.net/qq_41619796/article/details/118604950
        https://blog.csdn.net/qq_18870023/article/details/52596808
 * @author wangzhen
 * @date 2022年5月13日 下午6:25:31 
 *
 */
public class RSACryptography {
    
    //明文 m
    public static String data="65";
    //模mod n
    public static String modulusString="95701876885335270857822974167577168764621211406341574477817778908798408856077334510496515211568839843884498881589280440763139683446418982307428928523091367233376499779842840789220784202847513854967218444344438545354682865713417516385450114501727182277555013890267914809715178404671863643421619292274848317157";
    //公钥(n,e)中的 e
    public static String publicExponentString="65537";
    //私钥(n,d)中的 d
    public static String privateExponentString="15118200884902819158506511612629910252530988627643229329521452996670429328272100404155979400725883072214721713247384231857130859555987849975263007110480563992945828011871526769689381461965107692102011772019212674436519765580328720044447875477151172925640047963361834004267745612848169871802590337012858580097";
    
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub      
        
        //由n和e获取公钥
        PublicKey publicKey=getPublicKey(modulusString, publicExponentString);
        
        //由n和d获取私钥
        PrivateKey privateKey=getPrivateKey(modulusString, privateExponentString);
        
        //公钥加密,公式 m^e ≡ c (mod n) 得到c
        byte[] encryptedBytes=encrypt(data.getBytes(), publicKey);  
        System.out.println("加密后:"+new String(encryptedBytes));
        
        //私钥解密,公式c^d ≡ m (mod n) 得到m
        byte[] decryptedBytes=decrypt(encryptedBytes, privateKey);      
        System.out.println("解密后:"+new String(decryptedBytes));
    }
    
    //将base64编码后的公钥字符串转成PublicKey实例
    public static PublicKey getPublicKey(String modulusStr, String exponentStr) throws Exception{
        BigInteger modulus=new BigInteger(modulusStr);
        BigInteger exponent=new BigInteger(exponentStr);
        RSAPublicKeySpec publicKeySpec=new RSAPublicKeySpec(modulus, exponent);
        KeyFactory keyFactory=KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(publicKeySpec);
    }
    
    //将base64编码后的私钥字符串转成PrivateKey实例
    public static PrivateKey getPrivateKey(String modulusStr, String exponentStr) throws Exception{
        BigInteger modulus=new BigInteger(modulusStr);
        BigInteger exponent=new BigInteger(exponentStr);
        RSAPrivateKeySpec privateKeySpec=new RSAPrivateKeySpec(modulus, exponent);
        KeyFactory keyFactory=KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(privateKeySpec);
    }
    
    //公钥加密
    public static byte[] encrypt(byte[] content, PublicKey publicKey) throws Exception{
        Cipher cipher=Cipher.getInstance("RSA");//java默认"RSA"="RSA/ECB/PKCS1Padding"
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(content);
    }
    
    //私钥解密
    public static byte[] decrypt(byte[] content, PrivateKey privateKey) throws Exception{
        Cipher cipher=Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(content);
    }
 
}
​

四、参考链接

  参考链接
  https://blog.csdn.net/qq_41619796/article/details/118604950
  https://blog.csdn.net/qq_18870023/article/details/52596808