Mã hóa và giải mã RSA trong Java

Trong các hệ thống thực tế, thông tin nhạy cảm như mật khẩu thường không được lưu trữ dưới dạng văn bản thuần túy trong cơ sở dữ liệu. Thay vào đó, chúng cần được mã hóa trước khi lưu trữ. Bài viết này cung cấp một công cụ hỗ trợ mã hóa/giải mã RSA.

Thêm thư viện phụ thuộc

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.8.0</version>
</dependency>

Lớp công cụ xử lý RSA

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;

import org.apache.commons.io.FileUtils;

public class RSACryptoTool {

    private static final String CRYPTO_ALGO = "RSA";
    private static final String PUB_KEY_FILE = "C:\\keys\\pub.key";
    private static final String PRI_KEY_FILE = "C:\\keys\\priv.key";

    /**
     * Tạo cặp khóa và lưu vào tệp
     */
    public static void createAndSaveKeys() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(CRYPTO_ALGO);
        KeyPair pair = generator.generateKeyPair();

        PublicKey pubKey = pair.getPublic();
        PrivateKey privKey = pair.getPrivate();

        String pubStr = Base64.getEncoder().encodeToString(pubKey.getEncoded());
        String privStr = Base64.getEncoder().encodeToString(privKey.getEncoded());

        System.out.println("Public key: " + pubStr);
        System.out.println("Private key: " + privStr);

        FileUtils.writeStringToFile(new File(PUB_KEY_FILE), pubStr, StandardCharsets.UTF_8);
        FileUtils.writeStringToFile(new File(PRI_KEY_FILE), privStr, StandardCharsets.UTF_8);
    }

    /**
     * Giải mã chuỗi đã mã hóa
     */
    public static String decrypt(String privateKeyBase64, String encryptedData) throws Exception {
        byte[] decodedKey = Base64.getDecoder().decode(privateKeyBase64);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        PrivateKey privateKey = KeyFactory.getInstance(CRYPTO_ALGO).generatePrivate(keySpec);

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

        byte[] decodedCipherText = Base64.getDecoder().decode(encryptedData);
        byte[] plainBytes = cipher.doFinal(decodedCipherText);

        return new String(plainBytes, StandardCharsets.UTF_8);
    }

    /**
     * Mã hóa chuỗi đầu vào
     */
    public static String encrypt(String publicKeyBase64, String plainText) throws Exception {
        byte[] decodedKey = Base64.getDecoder().decode(publicKeyBase64);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        PublicKey publicKey = KeyFactory.getInstance(CRYPTO_ALGO).generatePublic(keySpec);

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

        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }
}

Cách sử dụng

Gọi createAndSaveKeys() một lần để tạo và lưu khóa. Sau đó:

  • Mã hóa: RSACryptoTool.encrypt(publicKey, "dữ liệu")
  • Giải mã: RSACryptoTool.decrypt(privateKey, "dữ liệu đã mã hóa")

Xử lý ký tự Unicode (tiếng Việt, tiếng Trung...)

Khi mã hóa văn bản có chứa ký tự Unicode, nên URL-encode trước khi mã hóa và URL-decode sau khi giải mã:

String original = "Xin chào";
String encodedInput = java.net.URLEncoder.encode(original, "UTF-8");
String encrypted = RSACryptoTool.encrypt(publicKey, encodedInput);
String decrypted = RSACryptoTool.decrypt(privateKey, encrypted);
String finalOutput = java.net.URLDecoder.decode(decrypted, "UTF-8");
System.out.println(finalOutput); // "Xin chào"

Lưu ý về Base64 trong Java 7

Lớp java.util.Base64 chỉ có sẵn từ Java 8 trở lên. Nếu chạy trên Java 7, bạn sẽ gặp lỗi NoClassDefFoundError. Có thể khắc phục bằng cách:

  • Nâng cấp lên Java 8+
  • Sao chép mã nguồn Base64 từ JDK 8 vào dự án
  • Hoặc sử dụng thư viện bên thứ ba như Apache Commons Codec

Thẻ: RSA Java cryptography base64 Encryption

Đăng vào ngày 18 tháng 6 lúc 17:59