暗号AES暗号化について2日間多くの記事を読んでいるので、私はこれを聞いているだけです。そして、私はそれを手に入れようと思ったとき、私はまったく手に入れていないことに気付きました。
この投稿は私の問題に最も近いものです。私はまったく同じ問題を抱えていますが、未回答です。
CryptoJS AES暗号化とJava AES復号化値の不一致
いろいろとやってみましたが、うまくいきませんでした。
最初のオフ
私はすでに暗号化された文字列を取得しています(彼らがそれをどのようにやっているかを見るためのコードしか手に入れていません)ので、暗号化の方法を変更することはオプションではありません。それが、すべての同様の質問が私にとってそれほど有用ではない理由です。
秒
私は秘密鍵にアクセスでき、それを修正することができます(したがって、長さの調整は必要な場合のオプションです)。
暗号化はCryptoJSで行われ、暗号化された文字列をGETパラメーターとして送信します。
GetParamsForAppUrl.prototype.generateUrlParams = function() {
const self = this;
return new Promise((resolve, reject) => {
const currentDateInMilliseconds = new Date().getTime();
const secret = tokenSecret.secret;
var encrypted = CryptoJS.AES.encrypt(self.authorization, secret);
encrypted = encrypted.toString();
self.urlParams = {
token: encrypted,
time: currentDateInMilliseconds
};
resolve();
});
};
私はCryptoJSを使用してjavascriptでこれを簡単に解読できます:
var decrypted = CryptoJS.AES.decrypt(encrypted_string, secret);
console.log(decrypted.toString(CryptoJS.enc.Utf8));
しかし、セキュリティ上の理由から、Javascriptでこれを行いたくないので、Javaでこれを復号化しようとしています:
String secret = "secret";
byte[] cipherText = encrypted_string.getBytes("UTF8");
SecretKey secKey = new SecretKeySpec(secret.getBytes(), "AES");
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.DECRYPT_MODE, secKey);
byte[] bytePlainText = aesCipher.doFinal(byteCipherText);
String myDecryptedText = = new String(bytePlainText);
自分が何をしているのかわからないうちに、base64デコードを試みて、IVと読んだものをたくさん追加しましたが、どれもうまくいきませんでした。
しかし、私がやっていることを理解し始めた後、上記の簡単なスクリプトを書いて、同じエラーを投稿で受け取りました:Invalid AES key length
ここからどこへ行くべきかわかりません。これについて多くを読んだ後、解決策はハッシュまたはパディングであるように見えますが、暗号化方式を制御できないため、秘密をハッシュしたりパディングしたりすることはできません。
しかし、私が言ったように、特定の長さに一致するように秘密鍵を変更することができ、それを変更しようとしましたが、ここで暗闇で撮影しているので、これが解決策であるかどうかはわかりません。
だから、私の質問は基本的に、暗号化された文字列(最初のスクリプトのようなjavascriptで)と秘密鍵を取得した場合、解読する方法がありますit(in Java)?もしそうなら、それを行う方法は?
CryptoJSは、OpenSSLと同じキー派生関数と同じ形式を実装して、IVを暗号化されたデータに入れます。したがって、OpenSSLでエンコードされたデータを処理するすべてのJavaコードが適用されます。
次のJavascriptコードを考えます:
var text = "The quick brown fox jumps over the lazy dog. ???? ????";
var secret = "René Über";
var encrypted = CryptoJS.AES.encrypt(text, secret);
encrypted = encrypted.toString();
console.log("Cipher text: " + encrypted);
暗号テキストを取得します。
U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hyaQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=
Java側では、
String secret = "René Über";
String cipherText = "U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hyaQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=";
byte[] cipherData = Base64.getDecoder().decode(cipherText);
byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);
MessageDigest md5 = MessageDigest.getInstance("MD5");
final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes(StandardCharsets.UTF_8), md5);
SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);
byte[] encrypted = Arrays.copyOfRange(cipherData, 16, cipherData.length);
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decryptedData = aesCBC.doFinal(encrypted);
String decryptedText = new String(decryptedData, StandardCharsets.UTF_8);
System.out.println(decryptedText);
結果は次のとおりです。
The quick brown fox jumps over the lazy dog. ???? ????
それが私たちが始めたテキストです。また、絵文字、アクセント、ウムラウトも機能します。
GenerateKeyAndIV
は、OpenSSLのキー派生関数を再実装するヘルパー関数ですEVP_BytesToKey
( https://github.com/openssl/openssl/blob/master/crypto/evp/evp_key.c を参照)。
/**
* Generates a key and an initialization vector (IV) with the given salt and password.
* <p>
* This method is equivalent to OpenSSL's EVP_BytesToKey function
* (see https://github.com/openssl/openssl/blob/master/crypto/evp/evp_key.c).
* By default, OpenSSL uses a single iteration, MD5 as the algorithm and UTF-8 encoded password data.
* </p>
* @param keyLength the length of the generated key (in bytes)
* @param ivLength the length of the generated IV (in bytes)
* @param iterations the number of digestion rounds
* @param salt the salt data (8 bytes of data or <code>null</code>)
* @param password the password data (optional)
* @param md the message digest algorithm to use
* @return an two-element array with the generated key and IV
*/
public static byte[][] GenerateKeyAndIV(int keyLength, int ivLength, int iterations, byte[] salt, byte[] password, MessageDigest md) {
int digestLength = md.getDigestLength();
int requiredLength = (keyLength + ivLength + digestLength - 1) / digestLength * digestLength;
byte[] generatedData = new byte[requiredLength];
int generatedLength = 0;
try {
md.reset();
// Repeat process until sufficient data has been generated
while (generatedLength < keyLength + ivLength) {
// Digest data (last digest if available, password data, salt if available)
if (generatedLength > 0)
md.update(generatedData, generatedLength - digestLength, digestLength);
md.update(password);
if (salt != null)
md.update(salt, 0, 8);
md.digest(generatedData, generatedLength, digestLength);
// additional rounds
for (int i = 1; i < iterations; i++) {
md.update(generatedData, generatedLength, digestLength);
md.digest(generatedData, generatedLength, digestLength);
}
generatedLength += digestLength;
}
// Copy key and IV into separate byte arrays
byte[][] result = new byte[2][];
result[0] = Arrays.copyOfRange(generatedData, 0, keyLength);
if (ivLength > 0)
result[1] = Arrays.copyOfRange(generatedData, keyLength, keyLength + ivLength);
return result;
} catch (DigestException e) {
throw new RuntimeException(e);
} finally {
// Clean out temporary data
Arrays.fill(generatedData, (byte)0);
}
}
Java Cryptography Extension(JCE) nlimited Strength Jurisdiction Policy 。をインストールする必要があることに注意してください。 :
Java.security.InvalidKeyException: Illegal key size
更新
Ola Bini's Java code of EVP_BytesToKey
、これは私の回答の最初のバージョンで使用したもので、より慣用的で理解しやすいJavaコード(上記参照)。
Java AESを使用してopensslコマンドで暗号化されたJava $ ===)でファイルを復号化する方法 も参照してください。
あるシステムで暗号化して別のシステムで復号化するとき、システムのデフォルトに翻弄されます。システムのデフォルトが一致しない場合(そしてしばしば一致しない場合)、復号化は失敗します。
すべてがbyte for byte両側で同じでなければなりません。つまり、デフォルトに依存するのではなく、両側ですべてを指定することを意味します。両端で同じシステムを使用している場合にのみ、デフォルトを使用できます。それでも、正確に指定することをお勧めします。
キー、IV、暗号化モード、パディング、および文字列からバイトへの変換はすべて、両端で同じである必要があります。キーバイトが同じであることを確認することは特に価値があります。キー派生関数(KDF)を使用してキーを生成する場合、そのためのすべてのパラメーターは同じである必要があるため、正確に指定する必要があります。
「無効なAESキーの長さ」は、キーの生成に関する問題を示している可能性があります。 getBytes()
を使用します。これはおそらくエラーです。取得するバイトの種類(ANSI、UTF-8、EBCDICなど)を指定する必要があります。文字列からバイトへの変換のデフォルトの仮定が、この問題の原因である可能性があります。両端で明示的に使用される変換を指定します。そうすれば、それらが一致することを確認できます。
暗号化と復号化のパラメーターが完全に一致しない場合、暗号化は失敗するように設計されています。たとえば、キーに1ビットの違いがあっても、キーは失敗します。