2017-11-30 31 views
0

JSONがPHPのopenssl_encryptで暗号化されているため、JAVAで解読する必要があります。PHPで暗号化してJavaで解読するAES-256-CBC

この$decryptedには、正しいデータが復号化されています。私はすでにのように同様の質問を訪問した

Exception in thread "main" java.security.InvalidKeyException: Invalid AES key length: 370 bytes 
at com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87) 
at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:91) 
at com.sun.crypto.provider.CipherCore.init(CipherCore.java:591) 
at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:346) 
at javax.crypto.Cipher.init(Cipher.java:1394) 
at javax.crypto.Cipher.init(Cipher.java:1327) 
at com.sample.App.main(App.java:70) 

さて、問題は、私はJavaで同じことをしようとすると、それは動作しません:(

String path = "/path/to/secret/saved/in/text"; 
String payload = "...ENCRYPTED DATA..."; 
StringBuilder output = new StringBuilder(); 

String iv = payload.substring(0, 16); 
byte[] secret = Base64.getDecoder().decode(Files.readAllBytes(Paths.get(path))); 
String data = payload.substring(16); 

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
SecretKeySpec secretKeySpec = new SecretKeySpec(secret, "AES"); 
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(), 0, cipher.getBlockSize()); 
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); // This line throws exception : 

cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); 

をここではそれがあります

AES-256 CBC encrypt in php and decrypt in Java or vice-versa

openssl_encrypt 256 CBC raw_data in java

Unable to exchange data encrypted with AES-256 between Java and PHP

とリスト続けて....しかし、そこ

運がところで、これは暗号化はPHP

$secretFile = "/path/to/secret/saved/in/text_file"; 
$secret = base64_decode(file_get_contents($secretFile)); 
$iv = bin2hex(openssl_random_pseudo_bytes(8)); 
$enc = openssl_encrypt($plainText, "aes-256-cbc", $secret, false, $iv); 
return $iv.$enc; 

で行われ、はい、私は私のことを言及するのを忘れている方法ではありませんJREはすでにUnlimitedJCEPolicyにあり、PHPコードを変更することはできません。

私は完全にこの時点で立ち往生しており、前進することはできません。助けてください。スニペットの上

EDIT#1

byte[] payload = ....; 
byte[] iv = ....; 
byte[] secret = ....; // Now 370 bits 
byte[] data = Base64.getDecoder().decode(payload); 

Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); 
SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOfRange(secret, 0, 32), "AES"); 
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv, 0, cipher.getBlockSize()); 

cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); 
byte[] output = cipher.doFinal(data); 

System.out.println(new String(output).trim()); 

openssl_encrypt

EDIT#2

で動作しているようだ私はこれが正しいかどうかわからないけど、次は何ですか私はやっていると両側の暗号化 - 復号化は正常に動作しています。私は完全なソリューションを提供することはありませんが、あなたはの世話をする必要がありますいくつかの違いがあるAES/CBC/PKCS5Padding

+1

32バイトのキーである "AES-256" を、正しい長さのキーを使用。 – zaph

+1

なぜ370バイトのAESキーを使用しようとしていますか? –

+0

^キー生成は私の手にはないので。それはPHPの終わりで行われ、完璧に動作します。 – Raja

答えて

1

PHPでの使用にJAVA、復号化にAES/CBC/NoPadding

暗号化を使用してJAVAでのPHP、復号化で

暗号化

エンコード:

String iv = payload.substring(0, 16); 
String data = payload.substring(16); 

はあなたがIVとデータがJavaとPHPで同じであることを確認してください(IVは文字列ですか?)データが暗号化されている場合は、文字列ではなくバイト配列として扱う必要があります。

IVの場合は、iv.getBytes()を呼び出しますが、ロケールのエンコーディングによって値が破損する可能性があります。文字列は実際に文字列(テキスト)の場合にのみ使用する必要があります。バイナリには文字列を使用しないでください。

単に

鍵の生成[]バイトとしてデータおよびivの治療にOpenSSLによる

AESキーを使用aes-256-cbcのために256ビットの長さを持っている必要があります。物事は - opensslはデフォルトでは提供された秘密をキーとして使用しません(私はそうすることができると信じていますが、PHPでの指定方法はわかりません)。

OpenSSL EVP_BytesToKey issue in Java

を見ると、ここEVP_BytesToKey実装です:https://olabini.com/blog/tag/evp_bytestokey/

あなたはEVP_BytesToKey機能をusging 256ビットの鍵を生成する必要があります(これは、OpenSSLで使用する鍵導出関数です)。

編集:(コメントで)

マーティンは正しいです。 のキーがキーです。 PHP関数が誤解を招くような長さのパラメータを受け付けているようです。いくつかの記事(例えば、http://thefsb.tumblr.com/post/110749271235/using-opensslendecrypt-in-php-instead-of)によれば、キーは、必要な長さに忠実またはパディングされています(370ビットのキーが256ビットの長さに切り捨てられているようです)。

+1

私は最初の部分に同意します。簡単に言えば、現代の暗号は文字列ではなくバイト(または*オクテット文字列*)で動作します。質問の文字列で行われることは、特にJavaでは**間違った**です。 Javaでは 'byte [] 'を操作する必要があります。 PHP **では、エスケープ文字を使用して文字列内に何かをエンコードすることができるので、暗号文は正しいかもしれません。第2の部分は、 'openssl_encrypt' APIの記述を見れば正しくないようです。キーとIV、パスワードと塩は見ないでください。 –

+0

実装を 'byte []'に変更しました。しかし、はい、あなたは何とかPHPは256ビットにこの超過した長さを切り捨てています。私はいくつかの変更を行いましたし、今作業しています – Raja

+0

更新を確認してください。 'openssl_en/decrypt'でキーがデフォルトで切り捨てられていると、これはどういうわけか誤解を招きます。 これは愚かな質問かもしれませんが、2つのキーが同じ初期の256ビットを持つ場合はどうなりますか? – Raja

0

はあなたの例によると、私はPHPとJavaのための完全に動作するコードを書いた:
AesCipherクラス:https://gist.github.com/demisang/716250080d77a7f65e66f4e813e5a636

注:
-ByデフォルトアルゴをAES-128-CBCです。
- デフォルトの初期ベクトルは16バイトです。
- エンコード結果= base64(initVector + aes crypt)。
-エンコードされた/デコードされた結果がそれ自体のオブジェクトとして存在する場合、エンコード/デコード操作後にエラーをチェックし、エラーメッセージを取得し、初期ベクトル値を取得する可能性が高くなります。

PHP:

$secretKey = '26kozQaKwRuNJ24t'; 
$text = 'Some text' 
$encrypted = AesCipher::encrypt($secretKey, $text); 
$decrypted = AesCipher::decrypt($secretKey, $encrypted); 

$encrypted->hasError(); // TRUE if operation failed, FALSE otherwise 
$encrypted->getData(); // Encoded/Decoded result 
$encrypted->getInitVector(); // Get used (random if encode) init vector 
// $decrypted->* has identical methods 

JAVA:

String secretKey = "26kozQaKwRuNJ24t"; 
String text = "Some text"; 

AesCipher encrypted = AesCipher.encrypt(secretKey, text); 
AesCipher decrypted = AesCipher.decrypt(secretKey, encrypted); 

encrypted.hasError(); // TRUE if operation failed, FALSE otherwise 
encrypted.getData(); // Encoded/Decoded result 
encrypted.getInitVector(); // Get used (random if encode) init vector 
// decrypted.* has identical methods 
+0

短い説明を追加し、完全なソリューションにリンクする必要があります –

関連する問題