web-dev-qa-db-ja.com

Java CBCで256ビットAES暗号化を実装する方法

私は次のスレッドを読み、少し役に立ちましたが、もう少し情報を探しています。

BlackBerryの初期化ベクトルパラメータを使用したAES/CBC/PKCS5Padding暗号化および復号化の記述方法

Java 256ビットAES暗号化

基本的に、私がやっていることは、TCP/IPを介して送信される要求を暗号化し、サーバープログラムによって復号化するプログラムを作成することです。暗号化はAESである必要があり、調査を行ったところ、CBCとPKCS5Paddingを使用する必要があることがわかりました。つまり、基本的に秘密鍵とIVも必要です。

私が開発しているアプリケーションは電話用なので、Javaセキュリティパッケージを使用してサイズを抑えたいと思います。設計は完了しましたが、実装が不明です。 IVと共有キー。

ここにいくつかのコードがあります:

// My user name
byte[] loginId = "login".getBytes();

byte[] preSharedKey128 = "ACME-1234AC".getBytes();
byte[] preSharedKey192 = "ACME-1234ACME-1234A".getBytes();
// 256 bit key
byte[] preSharedKey256 = "ACME-1234ACME-1234ACME-1234".getBytes();
byte[] preSharedKey = preSharedKey256;

// Initialization Vector
// Required for CBC
byte[] iv ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
IvParameterSpec ips = new IvParameterSpec(iv);


byte[] encodedKey = new byte[loginId.length + preSharedKey.length];

System.arraycopy(loginId, 0, encodedKey, 0, loginId.length);
System.arraycopy(preSharedKey, 0, encodedKey, loginId.length, preSharedKey.length);

// The SecretKeySpec provides a mechanism for application-specific generation
// of cryptography keys for consumption by the Java Crypto classes.

// Create a key specification first, based on our key input.
SecretKey aesKey = new SecretKeySpec(encodedKey, "AES");

// Create a Cipher for encrypting the data using the key we created.
Cipher encryptCipher;

encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize the Cipher with key and parameters
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey, ips);

// Our cleartext
String clearString = "33,8244000,9999,411,5012022517,0.00,0,1,V330";
byte[] cleartext = clearString.getBytes();

// Encrypt the cleartext
byte[] ciphertext = encryptCipher.doFinal(cleartext);

// Now decrypt back again...
// Decryption cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize PBE Cipher with key and parameters
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ips);

// Decrypt the cleartext
byte[] deciphertext = decryptCipher.doFinal(ciphertext);

一言で言えば、それがすべきことは、サーバーが電話からキーまたはIVを取得する必要なしに、サーバーによって復号化できるメッセージを暗号化することです。電話のIVとキーを保護し、サーバーにもキーとIVを認識させる方法はありますか?そうでない場合は、もっと明確にするように私に言ってください。

16
Steven

コードにはいくつかの問題があります。まず、秘密鍵を生成するには、鍵ジェネレーターを使用する必要があります。一部のテキストを直接使用するだけで一部のアルゴリズムで機能する場合がありますが、テストが必要な弱いキーなどがあるものもあります。

パスワードベースの暗号化を実行する場合でも、すでに引用した質問に対する my answer に示すように、パスワードを鍵導出アルゴリズムで実行して鍵を生成する必要があります。

また、Stringの引数なしのgetBytes()メソッドを使用しないでください。これはプラットフォームに依存します。エンコードするすべての文字列にUS-ASCII文字セットの文字のみが含まれている場合は、そのエンコードを明示的に指定して明確にします。そうしないと、電話とサーバーのプラットフォームが異なる文字エンコードを使用している場合、キーとIVは同じになりません。

CBCモードの場合、送信するすべてのメッセージに新しいIVを使用するのが最善です。通常、CBCIVはランダムに生成されます。 CFBやOFBrequireのような他のモードでは、メッセージごとに一意のIVが必要です。 IVは通常、暗号文とともに送信されます。IVを秘密にする必要はありませんが、予測可能なIVを使用すると、多くのアルゴリズムが機能しなくなります。

サーバーは、電話から直接シークレットまたはIVを取得する必要はありません。あなたはできます秘密鍵(または秘密鍵の派生元のパスワード)を使用してサーバーを構成できますが、多くのアプリケーションではこれは悪いことです設計。

たとえば、アプリケーションを複数の人の電話に展開する場合、同じ秘密鍵を使用することはお勧めできません。 1人の悪意のあるユーザーがキーを回復し、すべての人のシステムを破壊する可能性があります。

より良いアプローチは、電話で新しい秘密鍵を生成し、鍵共有アルゴリズムを使用してサーバーと鍵を交換することです。これには、Diffie-Hellman鍵共有を使用するか、秘密鍵をRSAで暗号化してサーバーに送信することができます。


更新:

サーバーの公開鍵がアプリケーションに埋め込まれている限り、サーバーから電話への最初のメッセージがなくても、「ephemeral-static」モード(および「static-static」モードも望ましいですが)のDiffie-Hellmanが可能です。 。

サーバーの公開鍵は、電話に共通の秘密鍵を埋め込むのと同じリスクをもたらしません。これは公開鍵であるため、攻撃者が電話を手に入れて(またはリモートでハッキングして)、実際の公開鍵を偽の鍵に置き換えてサーバーになりすますことが脅威になります。

静的-静的モードを使用することもできますが、実際にはもっと複雑で、安全性が少し劣ります。すべての電話には独自のキーペアが必要です。そうしないと、秘密キーの問題に陥ります。少なくとも、サーバーがどの電話にどのキーがあるかを追跡する必要はありません(パスワードなど、アプリケーションレベルで何らかの認証メカニズムがあると仮定します)。

電話の速さはわかりません。私のデスクトップでは、エフェメラルキーペアの生成に約1/3秒かかります。 Diffie-Hellmanパラメーターの生成は非常に遅いです。サーバーキーのパラメーターを再利用することをお勧めします。

12
erickson

以前にミッドレットで同様のプロジェクトを行ったことがありますが、次のアドバイスがあります。

  1. 共有シークレットを電話に保存する安全な方法はありません。使用できますが、これは 隠すことによるセキュリティ というカテゴリに分類されます。それは「マットの下の鍵」のようなセキュリティのようなものです。
  2. 広く利用されていない256ビットAESは使用しないでください。別のJCEをインストールする必要がある場合があります。 128ビットのAESまたはTripleDESは、引き続き安全であると見なされます。 #1を考えると、これについて心配する必要はありません。
  3. パスワード(ユーザーごとに異なる)を使用した暗号化は、はるかに安全です。ただし、例で示しているように、キーとしてパスワードを使用しないでください。 PBEKeySpec(パスワードベースの暗号化)を使用してキーを生成してください。
  4. MITM(man-in-the-middle)攻撃が心配な場合は、SSLを使用してください。
2
ZZ Coder