1. 序章

RSA、つまり Riverst–Shamir–Adleman は、非対称暗号化アルゴリズムです。 DESAESのような対称アルゴリズムとは異なり、2つのキーがあります。 データの暗号化には、誰とでも共有できる公開鍵が使用されます。 そして、私たちが自分たちだけのために保持し、データを復号化するために使用されるプライベートなもの

このチュートリアルでは、JavaでRSAキーを生成、保存、および使用する方法を学習します。

2. RSAキーペアを生成する

実際の暗号化を開始する前に、RSAキーペアを生成する必要があります。 java.securityパッケージのKeyPairGeneratorを使用すると、簡単に実行できます。

KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
KeyPair pair = generator.generateKeyPair();

生成されたキーのサイズは2048ビットになります。

次に、秘密鍵と公開鍵を抽出できます。

PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();

公開鍵を使用してデータを暗号化し、秘密鍵を使用してデータを復号化します。

3. キーをファイルに保存する

キーペアをメモリに保存することは、必ずしも良いオプションではありません。 ほとんどの場合、キーは長期間変更されません。 このような場合は、ファイルに保存する方が便利です。

キーをファイルに保存するには、 getEncoded メソッドを使用できます。このメソッドは、キーの内容をプライマリエンコード形式で返します。

try (FileOutputStream fos = new FileOutputStream("public.key")) {
    fos.write(publicKey.getEncoded());
}

ファイルからキーを読み取るには、最初にコンテンツをバイト配列としてロードする必要があります。

File publicKeyFile = new File("public.key");
byte[] publicKeyBytes = Files.readAllBytes(publicKeyFile.toPath());

次に、 KeyFactory を使用して、実際のインスタンスを再作成します。

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
keyFactory.generatePublic(publicKeySpec);

キーバイトの内容は、EncodedKeySpecクラスでラップする必要があります。 ここでは、ファイルの保存に使用した Key :: getEncodedメソッドのデフォルトアルゴリズムを表すX509EncodedKeySpec、を使用しています。

この例では、公開鍵ファイルのみを保存して読み取りました。 秘密鍵の処理にも同じ手順を使用できます。

アクセスを可能な限り制限して、秘密鍵を使用してファイルを可能な限り安全に保つことを忘れないでください。 不正アクセスはセキュリティの問題を引き起こす可能性があります。

4. 文字列の操作

それでは、単純な文字列を暗号化および復号化する方法を見てみましょう。 まず、使用するデータが必要です。

String secretMessage = "Baeldung secret message";

次に、以前に生成した公開鍵を使用して暗号化するために初期化されたCipherオブジェクトが必要です。

Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);

準備ができたら、doFinalメソッドを呼び出してメッセージを暗号化できます。 バイト配列引数のみを受け入れるため、次の前に文字列を変換する必要があることに注意してください。

byte[] secretMessageBytes = secretMessage.getBytes(StandardCharsets.UTF_8);)
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);

これで、メッセージが正常にエンコードされました。 データベースに保存したり、 REST API 経由で送信したりする場合は、Base64アルファベットエンコードする方が便利です。

String encodedMessage = Base64.getEncoder().encodeToString(encryptedMessageBytes);

これにより、メッセージが読みやすくなり、操作しやすくなります。

それでは、メッセージを元の形式に復号化する方法を見てみましょう。 このために、別のCipherインスタンスが必要になります。 今回は、復号化モードと秘密鍵を使用して初期化します。

Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);

doFinal メソッドを使用して、以前と同じように暗号を呼び出します。

byte[] decryptedMessageBytes = decryptCipher.doFinal(encryptedMessageBytes);
String decryptedMessage = new String(decryptedMessageBytes, StandardCharsets.UTF_8);

最後に、暗号化と復号化のプロセスが正しく行われたかどうかを確認しましょう。

assertEquals(secretMessage, decryptedMessage);

5. ファイルの操作

ファイル全体を暗号化することも可能です。 例として、いくつかのテキストコンテンツを含む一時ファイルを作成しましょう。

Path tempFile = Files.createTempFile("temp", "txt");
Files.writeString(tempFile, "some secret message");

暗号化を開始する前に、その内容をバイト配列に変換する必要があります。

byte[] fileBytes = Files.readAllBytes(tempFile);

これで、暗号化暗号を使用できます。

Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedFileBytes = encryptCipher.doFinal(fileBytes);

そして最後に、新しい暗号化されたコンテンツで上書きできます。

try (FileOutputStream stream = new FileOutputStream(tempFile.toFile())) {
    stream.write(encryptedFileBytes);
}

復号化プロセスは非常によく似ています。 唯一の違いは、秘密鍵を使用して復号化モードで初期化された暗号です。

byte[] encryptedFileBytes = Files.readAllBytes(tempFile);
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedFileBytes = decryptCipher.doFinal(encryptedFileBytes);
try (FileOutputStream stream = new FileOutputStream(tempFile.toFile())) {
    stream.write(decryptedFileBytes);
}

最後のステップとして、ファイルの内容が元の値と一致するかどうかを確認できます。

String fileContent = Files.readString(tempFile);
Assertions.assertEquals("some secret message", fileContent);

6. 概要

この記事では、JavaでRSAキーを作成する方法と、それらを使用してメッセージとファイルを暗号化および復号化する方法を学習しました。 いつものように、すべてのソースコードはGitHub利用できます。