RSA代码演示

RSA实例代码

通过上一篇的RSA算法原理了解之后,这里用一段简易的Java代码进行演示。

  1. 首先我们创建一个类,然后在main方法中通过BigInteger.probablePrime(int bitLength, Random rnd)方法生成两个素数

    System.out.println(BigInteger.probablePrime(10, new Random()));
    System.out.println(BigInteger.probablePrime(10, new Random()));
    // 613
    // 523
    

    这里我生成的两个素数为 613 523,然后将两个素数相乘,613 * 523 = 320599[数字1]

  2. 将两个素数分别减一相乘,612 * 522 = 319464[数字2]

  3. 再通过随机数生成一个公钥 757。这个数不能与两个素数相同且小于数字2

    System.out.println(BigInteger.probablePrime(10, new Random()));
    // 757
    
  4. 再通过下面的 for循环找出私钥。注意:公钥与私钥并非是一对的,也就是说一个公钥可以对应多个私钥。

    for (int i = 0; i < 846216; i++) {
         // 私钥满足条件:公钥产生私钥除以数字2余1
         if (((757 * i) % 319464) == 1) {
             System.out.println("私钥为:" + i); // 95797、415261、734725
    			}
    }
    
  5. 在这里我们得到公钥和私钥后,就可以发送我们所需要发送的东西了

    比如我们发送一个密码,123456。通过模指运算来进行加密和解密。

    System.out.println(new BigInteger("123456").modPow(new BigInteger("757"), new BigInteger("320599"))); // 172243
    // 172243,这就是通过模指运算加密后的
    
    System.out.println(new BigInteger("172243").modPow(new BigInteger("95797"), new BigInteger("320599"))); // 172243解密后就是123456
    

完整代码:

public class RSA {

    public static void main(String[] args) {
        System.out.println(BigInteger.probablePrime(10, new Random()));
        System.out.println(BigInteger.probablePrime(10, new Random()));

        
        for (int i = 0; i < 846216; i++) {
            // 私钥满足条件:公钥产生私钥除以数字2余1
            if (((757 * i) % 319464) == 1) {
                System.out.println("私钥为:" + i); // 95797、415261、734725
            }
        }

      	System.out.println("加密后:");
        System.out.println(new BigInteger("123456").modPow(new BigInteger("757"), new BigInteger("320599"))); // 172243,这就是通过模指运算加密后我们所需发给银行的

      	System.out.println("解密后:");
        System.out.println(new BigInteger("172243").modPow(new BigInteger("95797"), new BigInteger("320599"))); // 172243解密后就是123456
    }
}

标准的RSA算法模拟代码

导入第三方加密库的依赖
<dependencies>
      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.13</version>
      </dependency>
      <!-- 引入第三方加密库 bouncycastle的依赖 -->
      <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16 -->
      <dependency>
          <groupId>org.bouncycastle</groupId>
          <artifactId>bcprov-jdk16</artifactId>
          <version>1.46</version>
      </dependency>
</dependencies>
创建 RSA的公钥和密钥的PSAKeyCreator类
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.*;
import java.util.Base64;

/**
 * Created by wb on 2020/9/4 0004 19:33
 *
 * 创建 RSA的公钥和私钥
 */
public class RSAKeyCreator {

    public static void main(String[] args) {
        createKeyPairs();
    }

    /*
     * 生成公钥和私钥
     */
    private static void createKeyPairs() {
        Security.addProvider(new BouncyCastleProvider());
        // KeyPairGenerator 密钥对的生成器
        try {
            // KeyPairGenerator.getInstance(algorithm): 需要放置一个字符串,也就是算法的名称
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");

            // initialize(keysize, random): 密钥的大小,随机数
            generator.initialize(512, new SecureRandom()); // 初始化 generator

            // 这里就可以通过 generator获取到密钥对(公钥、私钥)
            KeyPair pair = generator.generateKeyPair();

            PublicKey publicKey = pair.getPublic(); // 返回一个公钥对象

            PrivateKey privateKey = pair.getPrivate(); // 返回一个私钥对象

            // 接下来就需要将公钥和私钥转换成可识别的字符串,这里就需要进行 Base64的编码
            // 通过 Base64获取到一个编码对象,编码对象里面的一个编码方法就可以获得 publicKey.getEncoded()的字节数组
            // 然后再将字节数组转换成 Base64的字符串
            String strPublicKey = new String(Base64.getEncoder().encode(publicKey.getEncoded())); // 公钥字符串
            String strPrivateKey = new String(Base64.getEncoder().encode(privateKey.getEncoded())); // 私钥字符串

            System.out.println(strPublicKey);
            System.out.println(strPrivateKey);

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}
RSA加密/解密的RSAUtil工具类
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;

/**
 * Created by wb on 2020/9/4 0004 19:33
 *
 * 封装标准的 RSA加密/解密算法的工具类
 */
public class RSAUtil {

    /*
     * RSA公钥加密
     *
     * 参数:第一个是需要加密的明文字符串,第二参数是公钥对象
     */
    public static String publicKeyEncryptData(String data, PublicKey publicKey) {

        try {
            // Cipher密码对象
            Cipher cipher = Cipher.getInstance("RSA");

            // 通过公钥进行加密
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            // 加密后的字节数组
            byte[] encryptData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); // 使用 utf-8字符编码加密

            // 获取加密字符串的结果,并返回
            return Base64.getEncoder().encodeToString(encryptData);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /*
     * RSA私钥解密
     *
     * 参数:第一个是需要加密后的字符串,第二参数是私钥对象
     */
    public static String privateKeyDecryptData(String encryptData, PrivateKey privateKey) {

        try {
            // Cipher密码对象
            Cipher cipher = Cipher.getInstance("RSA");

            // 通过私钥进行解密
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            // 通过 Base64进行解码,然后返回一个字节数组
            byte[] decryptData = cipher.doFinal(Base64.getDecoder().decode(encryptData));

            // 转换成明文的字符串并返回
            return new String(decryptData, StandardCharsets.UTF_8); // 使用 utf-8字符编码解密

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    // 扩展内容
    /*
     * RSA私钥加密
     *
     * 参数:第一个是需要加密的明文字符串,第二参数是私钥对象
     */
    public static String privateKeyEncryptData(String data, PrivateKey privateKey) {

        try {
            // Cipher密码对象
            Cipher cipher = Cipher.getInstance("RSA");

            // 通过公钥进行加密
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);

            // 加密后的字节数组
            byte[] encryptData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); // 使用 utf-8字符编码加密

            // 获取加密字符串的结果,并返回
            return Base64.getEncoder().encodeToString(encryptData);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /*
     * RSA公钥解密
     *
     * 参数:第一个是需要加密后的字符串,第二参数是公钥对象
     */
    public static String publicKeyDecryptData(String encryptData, PublicKey publicKey) {

        try {
            // Cipher密码对象
            Cipher cipher = Cipher.getInstance("RSA");

            // 通过私钥进行解密
            cipher.init(Cipher.DECRYPT_MODE, publicKey);

            // 通过 Base64进行解码,然后返回一个字节数组
            byte[] decryptData = cipher.doFinal(Base64.getDecoder().decode(encryptData));

            // 转换成明文的字符串并返回
            return new String(decryptData, StandardCharsets.UTF_8); // 使用 utf-8字符编码解密

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}
RSA算法测试
import fun.wblog.utils.RSAUtil;

import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * Created by wb on 2020/9/4 0004 20:06
 */
public class RSATest {

    public static void main(String[] args) {

        // 公钥字符串
        String strPublicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJHXc9MzZLGNrs6nAB/PmaDopfOoOaiN9M+4ZSli/JW5XRx/2+DL8VPhOMadWiLUDYwtMjAlHO9YYOmAR+mIDKsCAwEAAQ==";

        // 私钥字符串
        String strPrivateKey = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAkddz0zNksY2uzqcAH8+ZoOil86g5qI30z7hlKWL8lbldHH/b4MvxU+E4xp1aItQNjC0yMCUc71hg6YBH6YgMqwIDAQABAkBOTqYlT+IQJ+glk6vQaNKvgFui4b/bziUV54eB2mGPLkFvbPPz6eEIu0XEvouBxGBxmgp/vMysEjDPzLcL8cIxAiEAzhNpbW5Yt4Hwej2JyHKsbHKPV1NaPp3gb4Cq9eJJMYMCIQC1LGIS+r2+e4hyPDEj4IFbjRxq2dRQ0CnlzHXo76WXuQIgYLTlXdBR29QjqQnl9eYymjXspJteF1J5d3oXQIpvtMcCIQCvu6JRyJdd+ZNLQyljJHQ1KnYDCtGPparONPm1/SZBOQIhAJpjZWIU3G8dAxtcdA7xhUOV4OiL/u8QPiOfSRjWZIjR";

        // 公钥规则对象/公钥说明书对象
        X509EncodedKeySpec x509EncodedKeySpec =
                new X509EncodedKeySpec(Base64.getDecoder().decode(strPublicKey.getBytes()));

        // 私钥规则对象/私钥说明书对象
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
                new PKCS8EncodedKeySpec(Base64.getDecoder().decode(strPrivateKey.getBytes()));

        try {
            // 密钥工厂对象
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            // 通过 x509EncodedKeySpec规则生成公钥
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            // 通过 pkcs8EncodedKeySpec规则生成私钥
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

            // ===================================================================//
            String data = "RSA加密解密算法@###123456%&"; // 明文
            System.out.println("明文是: " + data);

            // 1.调用公钥加密方法
            String encryptData = RSAUtil.publicKeyEncryptData(data, publicKey);
            System.out.println("公钥加密后: " + encryptData);

            // 2.调用私钥解密方法
            String decryptData = RSAUtil.privateKeyDecryptData(encryptData, privateKey);
            System.out.println("私钥解密后: " + decryptData);

            // 扩展内容==========================================================//
            // 3.调用私钥加密方法
            String encryptData2 = RSAUtil.privateKeyEncryptData(data, privateKey);
            System.out.println("私钥加密后: " + encryptData2);

            // 4.调用公钥解密方法
            String decryptData2 = RSAUtil.publicKeyDecryptData(encryptData2, publicKey);
            System.out.println("公钥解密后: " + decryptData2);
            
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
    }
}

https://i.loli.net/2020/09/05/TyZPsoczardQU89.gif
RSA算法演示.gif

总结:

先通过KeyPairGenerator来生成密钥对,然后再去封装加密和解密的方法。

在工具类中最主要的实现加密和解密的关键的对象是靠Cipher密码对象通过getInstance()去找它的这个密码算法,然后实现了这个对象。这个对象的关键一点就是有两个常量,一个常量是ENCRYPT_MODE加密模式,一个常量是DECRYPT_MODE解密模式。

然后在使用的过程再去将我们的公钥和私钥字符串,把它转成一个公钥对象和私钥对象,那么如何将公钥字符串/私钥字符串转成公钥对象/私钥对象呢?那么就要使用到了一个公钥规则对象(公钥说明书X509EncodedKeySpec)/私钥规则对象(私钥说明书PKCS8EncodedKeySpec)。拿到这个说明书对象,我们最终的主要目的就是通过KeyFactory去生成一个公钥对象和私钥对象,这样就可以使用我们之前封装的加密解密工具了。从而对我们的明文进行加密和解密。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值