1

質問の説明

String最近、このような事前定義されたキーを使用して、iOS と Android の間で 256-AES クロス プラットフォームの暗号化/復号化を行う必要がある状況に遭遇しましたPreDefinedKey

AES の実装は、このコードを使用して iOS で行われます。「クロスプラットフォーム」の暗号化/復号化を実行できるように、Android でコードを変更するだけです。

注: iOS の AES コードには重大なセキュリティ/メモリの問題があることは承知していますが、現時点では問題ではありません :-)

Android と iOS のいずれかで個別に暗号化/復号化を行うことができました。ただし、ここでの 2 つの AES 実装には些細な違いがあるようで、「クロスプラットフォーム」の暗号化/復号化を実行できませんでした。たとえば、Android で暗号化された文字列を iOS に配置すると、期待される結果が返されません (この場合は null が返されます)。

質問:

iOS と Android の両方のプラットフォームで、アルゴリズムは AES 実装のアルゴリズムであると確信していAES/ECB/PKCS7Paddingます128-Rijndael

両方のプラットフォームで 256 ビット サイズのキーを使用する必要があります。そして、iOS AES コードの内部を詳しく調べたところzeroes、キーを 256 ビットにパディングするために実際に使用されていることがわかりました。

iOS のゼロ パディング関連のコード スニペットを次に示します。

// 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

そのコードの AES パラメータは次のとおりです (Rijndael-128 アルゴリズム、256 ビット キー サイズ、初期ベクトルに NULL を使用)。

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesEncrypted);

しかし、Androidでは同様のことを行う方法がわからないので、誰かが私に正しい方法を指摘できますか?


私が使用しているコード

Androidプラットフォームでは、以下のコードを使用して AES 実装を行います

private static final String AES_SECRET = "PreDefinedKey";

/**
 * Method for AES encryption
 * @param raw
 * @param plain
 * @return
 * @throws Exception
 */
private static byte[] encrypt(byte[] raw, byte[] plain) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES/ECB/PKCS7Padding");
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(plain);
    return encrypted;
}



/**
 * AES decryption
 * @param encryptMsg
 * @return
 * @throws Exception
 */
public static String AESDecrypt(String encryptMsg)
        throws Exception {          
    byte[] rawKey = getRawKey(AES_SECRET.getBytes());
    //byte[] enc = toByte(encryptMsg);
    byte[] enc = Base64.decode(encryptMsg, 0);
    byte[] result = decrypt(rawKey, enc);
    return new String(result);

}

/**
 * Method for AES decryption
 * @param raw
 * @param encrypted
 * @return
 * @throws Exception
 */
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
    SecretKeySpec keySpec = new SecretKeySpec(raw, "AES/ECB/PKCS7Padding");
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.DECRYPT_MODE, keySpec);
    byte[] decrypted = cipher.doFinal(encrypted);
    return decrypted;

}

public static byte[] getRawKey(byte[] seed) throws Exception {

    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    sr.setSeed(seed);
    //Init for 256bit AES key
    kgen.init(256);
    SecretKey secret = kgen.generateKey();
    //Get secret raw key
    byte[] raw = secret.getEncoded();

    return seed;

}

の方法ではgetRawKey()SHA1PRNGランダムなパディングを生成して AES キーを 256 ビット サイズにするために使用しますが、これは iOS 実装とは異なります (キーを 256 ビットにパディングするためにゼロを使用します)。

では、このメソッドを変更して、事前に定義された文字列キーを使用できるようにするにはどうすればよいでしょうか。

さらに情報が必要な場合はお知らせください。どうも!

4

1 に答える 1

1

このゼロパディングスキームを思いついた人を見つけて、彼らを解雇してください. 次に、アプリをレビューします。

あなたの質問に関しては、長さ32のバイト配列を作成し、キーバイトを最初にコピーして、それを使用して初期化しますSecretKeySpec。はKeyGeneratorランダムなキーを生成し、「固定シード」のアイデア全体に欠陥があり、最新の Android バージョンでは機能しません。ここにいくつかのコードがあります:

// zeros by default
byte[] rawKey = new byte[32];
// if you don't specify the encoding you might get weird results
byte[] keyBytes = AES_SECRET.getBytes("ASCII");
System.arraycopy(keyBytes, 0, rawKey, 0, keyBytes.length);
SecretKey key = new SecretKeySpec(rawKey, "AES");
Cipher cipher = ...
// rest of your decryption code
于 2013-03-28T02:00:11.687 に答える