--- title: OpenSSLで作成したRSAの鍵を使ってJavaで暗号化・復号するサンプル tags: ["Java", "OpenSSL"] categories: ["Programming", "Java", "java", "security"] date: 2015-03-19T07:55:40Z updated: 2015-03-19T07:55:40Z --- メモ ``` java import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Paths; import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class RSADemo { public static void main(String[] args) { // まずはJava APIで作成したRSAの秘密鍵と公開鍵を使って、Javaで暗復号する例 new RSADemo().generateKeysByJava(); // OpenSSLで作成したRSAの秘密鍵と公開鍵を使って、Javaで暗号化、OpenSSLで復号する例 new RSADemo().useOpenSSLDecryption(); // OpenSSLで作成したRSAの秘密鍵と公開鍵を使って、OpenSSLで暗号化、Javaで復号する例 new RSADemo().useOpenSSLEncryption(); } public void generateKeysByJava() { try { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(2048);// 鍵の長さ(bit) KeyPair keyPair = generator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); byte[] encrypted = encryptByPublicKey("Hello World!", publicKey); System.out.println(Base64.getEncoder().encodeToString(encrypted)); String decrypted = decryptByPrivateKey(encrypted, privateKey); System.out.println(decrypted); } catch (NoSuchAlgorithmException ignored) { throw new IllegalStateException("Should not be happend!", ignored); } } public void useOpenSSLDecryption() { // [プログラム実行前] // DER形式で秘密鍵を生成 // openssl genrsa -out hoge.pem 2048 // 秘密鍵をJavaで読めるように PKCS #8 形式かつ DER 形式に変換 // openssl pkcs8 -topk8 -nocrypt -in hoge.pem -out private.pk8 -outform DER // 秘密鍵からDER形式公開鍵生成 // openssl rsa -pubout -in hoge.pem -out public.der -outform DER // [プログラム実行後] // 秘密鍵で復号 // openssl rsautl -decrypt -inkey hoge.pem -in encryptedByJava.txt try { KeySpec publicKeySpec = new X509EncodedKeySpec(Files .readAllBytes(Paths.get("public.der"))); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); byte[] encrypted = encryptByPublicKey("Hello World!", publicKey); Files.write(Paths.get("encryptedByJava.txt"), encrypted); System.out.println("Please execute the following command:"); System.out .println("openssl rsautl -decrypt -inkey hoge.pem -in encryptedByJava.txt"); } catch (IOException e) { throw new UncheckedIOException(e); } catch (NoSuchAlgorithmException ignored) { throw new IllegalStateException("Should not be happend!", ignored); } catch (InvalidKeySpecException e) { throw new IllegalArgumentException(e); } } public void useOpenSSLEncryption() { // [プログラム実行前] // DER形式で秘密鍵を生成 // openssl genrsa -out hoge.pem 2048 // 秘密鍵をJavaで読めるように PKCS #8 形式かつ DER 形式に変換 // openssl pkcs8 -topk8 -nocrypt -in hoge.pem -out private.pk8 -outform DER // 秘密鍵からDER形式公開鍵生成 // openssl rsa -pubout -in hoge.pem -out public.der -outform DER // 公開鍵で暗号 // echo Hello!! | openssl rsautl -encrypt -keyform DER -pubin -inkey public.der -out ecryptedByOpenSSL.txt try { KeySpec privateKeySpec = new PKCS8EncodedKeySpec(Files .readAllBytes(Paths.get("private.pk8"))); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec); String decrypted = decryptByPrivateKey(Files.readAllBytes(Paths .get("ecryptedByOpenSSL.txt")), privateKey); System.out.println(decrypted); } catch (IOException e) { throw new UncheckedIOException(e); } catch (NoSuchAlgorithmException ignored) { throw new IllegalStateException("Should not be happend!", ignored); } catch (InvalidKeySpecException e) { throw new IllegalArgumentException(e); } } // 暗号化・復号用のメソッド /** * 平文を公開鍵で暗号化し、バイト配列返却 */ public byte[] encryptByPublicKey(String clearText, PublicKey publicKey) { try { // 暗復号のためのCipher生成 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // 暗号化 cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(clearText.getBytes()); } catch (NoSuchAlgorithmException | NoSuchPaddingException ignored) { throw new IllegalStateException("Should not be happened!", ignored); } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { throw new IllegalArgumentException(e); } } /** * バイト配列を秘密鍵で暗号化し、平文を返却 */ public String decryptByPrivateKey(byte[] encrypted, PrivateKey privateKey) { try { // 暗復号のためのCipher生成 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // 暗号化 cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decrypted = cipher.doFinal(encrypted); return new String(decrypted); } catch (NoSuchAlgorithmException | NoSuchPaddingException ignored) { throw new IllegalStateException("Should not be happened!", ignored); } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { throw new IllegalArgumentException(e); } } } ```