自定义字符串填充,使用零到256位大小的密钥,用于AES / ECB / PKCS7Padding

时间:2013-03-27 16:23:43

标签: android ios encryption aes

问题描述

我最近遇到了一种情况,在这种情况下我需要在iOS和Android之间使用预定义的String密钥进行256-AES跨平台加密/解密,例如PreDefinedKey

AES实现在iOS上使用this code完成,我需要做的就是更改Android上的代码,以便我可以进行“跨平台”加密/解密。

注意:我知道iOS上的AES代码存在严重的安全/内存问题,但目前不是我关注的问题: - )

我能够分别在Android和iOS上进行加密/解密。然而,这里的两个AES实现似乎有一些微不足道的差异,这使我无法进行“跨平台”加密/解密。例如,我将Android加密的字符串放到iOS上,它无法返回预期的结果(在这种情况下,它返回null)。

问题:

在iOS平台和Android平台上,我确信算法为AES/ECB/PKCS7Padding,其中128-Rijndael算法用于AES实现。

两个平台都应该使用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位)。

那么,如何更改此方法以便我可以使用预先定义的字符串键,该键用零填充为256位?

如果您需要更多信息,请与我们联系。 THX!

1 个答案:

答案 0 :(得分:1)

找到那些想出这个零填充计划并让他们解雇的人。然后审核应用程序。

至于你的问题,只需创建一个长度为32的字节数组,并将键字节复制到开头,用它来初始化SecretKeySpecKeyGenerator将生成一个随机密钥,整个“固定种子”的想法存在缺陷,并且无法在最新的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