暗号クラスのガイド
1. 概要
簡単に言えば、暗号化とは、許可されたユーザーのみがメッセージを理解またはアクセスできるようにメッセージをエンコードするプロセスです。
plaintextと呼ばれるメッセージは、暗号化アルゴリズム(cipher)を使用して暗号化され、許可されたユーザーのみが復号化によって読み取ることができるciphertextを生成します。
この記事では、Javaのthe core Cipher class, which provides cryptographic encryption and decryption functionalityについて詳しく説明します。
2. 暗号クラス
Java Cryptography Extension(JCE)は、データの暗号化と復号化、およびプライベートデータのハッシュのための暗号化暗号をアプリケーションに提供するpart of the Java Cryptography Architecture (JCA)です。
javax.cryptoパッケージにあるCipherクラスは、JCEフレームワークのコアを形成し、暗号化と復号化の機能を提供します。
2.1. 暗号のインスタンス化
Cipherオブジェクトをインスタンス化するために、call the static getInstance method, passing the name of the requested transformationを実行します。 オプションで、プロバイダーの名前を指定できます。
Cipherのインスタンス化を示すサンプルクラスを書いてみましょう。
public class Encryptor {
public byte[] encryptMessage(byte[] message, byte[] keyBytes)
throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//...
}
}
変換AES/ECB/PKCS5Paddingは、getInstanceメソッドにCipherオブジェクトをECBmode of operationおよびPKCS5padding schemeを使用してAES暗号としてインスタンス化するように指示します。
変換でアルゴリズムのみを指定することにより、Cipherオブジェクトをインスタンス化することもできます。
Cipher cipher = Cipher.getInstance("AES");
この場合、モードおよびパディング方式のプロバイダー固有のデフォルト値が使用されます。
変換がnull、空、無効な形式の場合、または指定された暗号アルゴリズムの実装が指定されたプロバイダーから利用できない場合、NoSuchAlgorithmExceptionがスローされます。
変換に使用できないパディングスキームが含まれている場合、NoSuchPaddingExceptionがスローされます。
2.2. Keys
Keyインターフェースは、暗号化操作のキーを表します。 キーは、エンコードされたキー、キーのエンコード形式、およびその暗号化アルゴリズムを保持する不透明なコンテナです。
キーは通常、key generators、証明書、またはkey factoryを使用したkey specificationsから取得されます。
指定されたキーバイトから対称Keyを作成しましょう。
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
2.3. 暗号の初期化
We call the init() method to initialize the Cipher objectとKeyまたはCertificate、およびopmodeは暗号の動作モードを示します。
オプションで、we can pass in a source of randomness。 デフォルトでは、インストールされている最も優先度の高いプロバイダーのSecureRandom実装が使用されます。 何も見つからない場合は、システム提供のソースが使用されます。
We can specify a set of algorithm-specific parameters optionally.たとえば、IvParameterSpecをspecify an initialization vectorに渡すことができます。
利用可能な暗号操作モードは次のとおりです。
-
ENCRYPT_MODE:cipherオブジェクトを暗号化モードに初期化します
-
DECRYPT_MODE:cipherオブジェクトを復号化モードに初期化します。
-
WRAP_MODE:cipherオブジェクトをkey-wrappingモードに初期化します。
-
UNWRAP_MODE:cipherオブジェクトをkey-unwrappingモードに初期化します。
Cipherオブジェクトを初期化しましょう:
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// ...
キーの長さ/エンコーディングが無効な場合など、指定されたキーが暗号の初期化に不適切な場合、InvalidKeyExceptionがスローされます。
また、暗号がキーから決定できない特定のアルゴリズムパラメータを必要とする場合、またはキーのキーサイズが最大許容キーサイズ(configured JCE jurisdictionポリシーファイルから決定)を超える場合にもスローされます。
Certificateを使用した例を見てみましょう。
public byte[] encryptMessage(byte[] message, Certificate certificate)
throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, certificate);
// ...
}
Cipherオブジェクトは、getPublicKeyメソッドを呼び出すことにより、証明書からデータ暗号化の公開鍵を取得します。
2.4. 暗号化と復号化
Cipherオブジェクトを初期化した後、doFinal()メソッドを呼び出して、暗号化または復号化操作を実行します。 このメソッドは、暗号化または復号化されたメッセージを含むバイト配列を返します。
doFinal()メソッドは、Cipherオブジェクトを、init()メソッドの呼び出しによって以前に初期化されたときの状態にリセットし、Cipherオブジェクトを追加の暗号化または復号化に使用できるようにします。メッセージ。
encryptMessageメソッドでdoFinalを呼び出しましょう。
public byte[] encryptMessage(byte[] message, byte[] keyBytes)
throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException,
BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(message);
}
復号化操作を実行するには、opmodeをDECRYPT_MODEに変更します。
public byte[] decryptMessage(byte[] encryptedMessage, byte[] keyBytes)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(encryptedMessage);
}
2.5. プロバイダ
provider-based architecture、JCE allows for qualified cryptography libraries such as BouncyCastle to be plugged in as security providers and new algorithms to be added seamlesslyを使用するように設計されています。
それでは、セキュリティプロバイダーとしてBouncyCastleを追加しましょう。 We can add a security provider either statically or dynamically.
<JAVA_HOME>/jre/lib/securityフォルダーにあるTo add BouncyCastle statically, we modify the java.security file。
リストの最後に行を追加します。
...
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider
プロバイダープロパティを追加する場合、プロパティキーはsecurity.provider.Nの形式になります。ここで、番号Nはリストの最後の番号より1つ多くなります。
セキュリティファイルを変更せずにWe can also add the BouncyCastle security provider dynamically:
Security.addProvider(new BouncyCastleProvider());
暗号の初期化中にプロバイダーを指定できるようになりました。
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
BCは、プロバイダーとしてBouncyCastleを指定します。 登録されたプロバイダーのリストは、Security.getProviders()メソッドを介して取得できます。
3. 暗号化と復号化のテスト
メッセージの暗号化と復号化を説明するためのテスト例を書いてみましょう。
このテストでは、128ビットキーでAES暗号化アルゴリズムを使用し、復号化された結果が元のメッセージテキストと等しいことをアサートします。
@Test
public void whenIsEncryptedAndDecrypted_thenDecryptedEqualsOriginal()
throws Exception {
String encryptionKeyString = "thisisa128bitkey";
String originalMessage = "This is a secret message";
byte[] encryptionKeyBytes = encryptionKeyString.getBytes();
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(encryptionKeyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedMessageBytes = cipher.doFinal(message.getBytes());
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedMessageBytes = cipher.doFinal(encryptedMessageBytes);
assertThat(originalMessage).isEqualTo(new String(decryptedMessageBytes));
}
4. 結論
この記事では、Cipherクラスについて説明し、使用例を示しました。 CipherクラスとJCEフレームワークの詳細については、class documentationとJava Cryptography Architecture (JCA) Reference Guideを参照してください。
これらすべての例とコードスニペットの実装can be foundover on Github;これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。