RSA加密解密示例程式碼

Ashe|||^_^發表於2024-10-09
import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.io.ByteArrayOutputStream;

public class RSADemo {

    // 加密時每塊的最大位元組數,對於1024位RSA金鑰,通常為117位元組
    private static final int MAX_ENCRYPT_BLOCK = 117;
    // 解密時每塊的最大位元組數,對於1024位RSA金鑰,通常為128位元組
    private static final int MAX_DECRYPT_BLOCK = 128;

    public static void main(String[] args) throws Exception {
        // 生成RSA金鑰對
        KeyPair keyPair = generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        // 原始文字
        String originalText = "Hello, RSA Encryption!";
        // 加密文字
        String encryptedText = encrypt(originalText, publicKey);
        System.out.println("Encrypted Text: " + encryptedText);

        // 解密文字
        String decryptedText = decrypt(encryptedText, privateKey);
        System.out.println("Decrypted Text: " + decryptedText);
    }

    // 生成RSA金鑰對的方法
    private static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        return keyPairGenerator.generateKeyPair();
    }

    // 使用公鑰加密文字
    private static String encrypt(String plainText, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedData = processData(plainText.getBytes(StandardCharsets.UTF_8), cipher, MAX_ENCRYPT_BLOCK);
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    // 使用私鑰解密文字
    private static String decrypt(String encryptedText, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedData = processData(Base64.getDecoder().decode(encryptedText), cipher, MAX_DECRYPT_BLOCK);
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    // 處理加密或解密資料的方法
    private static byte[] processData(byte[] data, Cipher cipher, int maxBlockSize) throws Exception {
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        while (inputLen - offSet > 0) {
            // 確定當前塊的大小
            if (inputLen - offSet > maxBlockSize) {
                cache = cipher.doFinal(data, offSet, maxBlockSize);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            // 將加密或解密後的塊寫入輸出流
            out.write(cache, 0, cache.length);
            offSet += maxBlockSize;
        }
        return out.toByteArray();
    }
}

為什麼加密的分段大小和解密的分段大小不同:

加密分段大小 (MAX_ENCRYPT_BLOCK): 在RSA加密中,由於使用了填充(如PKCS#1 v1.5),可加密的最大資料量小於金鑰長度。對於1024位RSA金鑰,有效載荷大小大約是117位元組,因為需要留出空間給填充和可能的會話金鑰等。

解密分段大小 (MAX_DECRYPT_BLOCK): 解密時,資料塊的大小等於金鑰長度除以8。對於1024位RSA金鑰,這意味著解密塊的大小是128位元組。這是因為在加密過程中新增的填充在解密時被移除,因此解密塊可以容納整個加密資料塊(包括填充)。

如果你已經使用OpenSSL工具生成RSA金鑰對字串(可參考https://www.cnblogs.com/ashet/p/18434822),請使用以下方法生成公鑰、私鑰

// 使用X509EncodedKeySpec載入公鑰
private static PublicKey initPublicKey(String publicKeyStr) throws Exception {
    byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePublic(keySpec);
}

// 使用PKCS8EncodedKeySpec載入私鑰
private static PrivateKey initPrivateKey(String privateKeyStr) throws Exception {
    byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePrivate(keySpec);
}

相關文章