RSA加密处理

535 阅读3分钟

基本概念

RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。

RSA是目前最有影响力的公钥加密算法,该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用。

解密者拥有私钥,并且将由私钥计算生成的公钥发布给加密者。加密都使用公钥进行加密,并将密文发送到解密者,解密者用私钥解密将密文解码为明文。

xx.jpg

生成私钥


# 生成rsa私钥,以X509编码,指定生成的密钥的位数: 2048
openssl genrsa -out rsa_private_key_2048.pem 2048

# 将上一步生成的rsa私钥转换成PKCS#8编码
openssl pkcs8 -topk8 -in rsa_private_key_2048.pem -out pkcs8_rsa_private_key_2048.pem -nocrypt

生成公钥


openssl rsa -in rsa_private_key_2048.pem -out rsa_public_key_2048.pem -pubout

依赖


<dependencies>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.68</version>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.6.5</version>
    </dependency>
</dependencies>

工具类



/**
 * <p>
 * RSA加解密工具类
 * <p>
 * 密钥长度 2048 bits
 * 密钥格式 PKCS#8
 * 加密算法 RSA/ECB/PKCS1Padding
 * 签名算法 SHA1withRSA
 *
 * @author 苦瓜不苦
 * @date 2021/6/9 10:22
 **/
public class RSAHelperUtil {


    // 加密算法
    private final static String ENCRYPT_ARITHMETIC = "RSA/ECB/PKCS1Padding";
    // 签名算法
    private final static String SIGN_ARITHMETIC = "SHA1withRSA";

    // 2048 bits 的RSA 密钥对
    private final static int KEY_BIT = 2048;
    // 2048 bits 的RSA 密钥对
    private final static int RESERVE_BYTES = 11;

    // 实例化私钥
    private static PrivateKey privateKey = null;
    // 实例化公钥
    private static PublicKey publicKey = null;

    // 私钥
    private final static String PRIVATE_KEY = "xxxxx";
    // 公钥
    private final static String PUBLIC_KEY = "xxxxx";


    static {
        try {
            Account account = new Account();
            privateKey = RSAHelperUtil.getPrivateKey(account.getPrivateKey());
            publicKey = RSAHelperUtil.getPublicKey(account.getPublicKey());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 实例化公钥
     *
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] publicKeyByte = base64Decoder.decodeBuffer(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyByte);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }


    /**
     * 实例化私钥
     *
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] privateKeyByte = base64Decoder.decodeBuffer(privateKey);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyByte);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }


    /**
     * 公钥分段加密
     *
     * @param text 明文字符串
     * @return 加密密文
     */
    public static String encrypt(String text) {
        try {
            // 2048 bits 的RSA 密钥对, 最大加密明文大小计算公式:  2048 (bits) / 8 - 11(byte) = 245 byte
            int maxEncryptBlock = KEY_BIT / 8 - RESERVE_BYTES;

            Cipher cipher = Cipher.getInstance(ENCRYPT_ARITHMETIC);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            byte[] textBytes = text.getBytes(StandardCharsets.UTF_8);
            int textBytesLength = textBytes.length;

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            // 分段加密
            for (int offset = 0; offset < textBytesLength; offset += maxEncryptBlock) {
                // 字节长度不能超过max_encrypt_block
                int block = textBytesLength - offset;
                if (block > maxEncryptBlock) {
                    block = maxEncryptBlock;
                }
                // 得到分段加密结果
                byte[] encryptBlock = cipher.doFinal(textBytes, offset, block);
                // 追加结果
                outputStream.write(encryptBlock);
            }
            // 关闭流
            outputStream.flush();
            outputStream.close();
            // 获取加密字节
            byte[] encryptBytes = outputStream.toByteArray();
            // Base64编码
            byte[] encode = Base64.getEncoder().encode(encryptBytes);
            return new String(encode, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 私钥分段解密
     *
     * @param text 加密字符串
     * @return 加密明文
     */
    public static String decrypt(String text) {
        try {
            // 2048 bits 的RSA 密钥对, 最大解密明文大小计算公式:  2048 (bits) / 8 = 256 byte
            int maxDecryptBlock = KEY_BIT / 8;

            Cipher cipher = Cipher.getInstance(ENCRYPT_ARITHMETIC);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            byte[] textBytes = Base64.getDecoder().decode(text.getBytes(StandardCharsets.UTF_8));
            int textBytesLength = textBytes.length;
            // 分段解密
            for (int offset = 0; offset < textBytesLength; offset += maxDecryptBlock) {
                // 字节长度不能超过max_decrypt_block
                int block = Math.min(textBytesLength - offset, maxDecryptBlock);
                // 得到分段加密结果
                byte[] encryptBlock = cipher.doFinal(textBytes, offset, block);
                // 追加结果
                outputStream.write(encryptBlock);
            }
            // 关闭流
            outputStream.flush();
            outputStream.close();
            // 获取数据
            return outputStream.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 生成签名
     *
     * @param text 明文数据
     * @return 签名的信息
     */
    public static String generateSign(String text) {
        try {
            // 实例化
            Signature signature = Signature.getInstance(SIGN_ARITHMETIC);
            signature.initSign(privateKey);
            signature.update(text.getBytes(StandardCharsets.UTF_8));
            // 生成签名
            byte[] sign = signature.sign();
            // base64编码
            return new String(Base64.getEncoder().encode(sign), StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }


    /**
     * 验证签名
     *
     * @param text     明文数据
     * @param signText 签名的信息
     * @return
     */
    public static Boolean verifySign(String text, String signText) {
        try {
            Signature signature = Signature.getInstance(SIGN_ARITHMETIC);
            signature.initVerify(publicKey);
            signature.update(text.getBytes(StandardCharsets.UTF_8));
            // base64解码
            byte[] signByte = Base64.getDecoder().decode(signText.getBytes(StandardCharsets.UTF_8));
            // 验证签名
            return signature.verify(signByte);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

}