2013-03-27 74 views
0

问题描述

我最近遇到一种情况,这种情况下,我需要做一个256-AES跨平台的加密/ iOS和之间解密Android使用预定义的String这样的密钥,如PreDefinedKey用零为AES/ECB 256位大小键自定义字符串填充/ PKCS7Padding

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密钥达到与iOS实现不同的256位大小(它使用零填充密钥到256位)。

那么,我该如何改变这个方法,以便我可以使用我的预定义的字符串键填充零到256位?

如果您需要更多信息,请让我知道。谢谢!

回答

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 
+0

很酷,我只是弹出并尝试你的方法,它工作!还有一个问题:我可能知道为什么(或如何)“固定大小”的东西不适用于最新的Android? – dumbfingers 2013-03-28 09:53:57

+1

我的意思是'固定种子'。这里:http://android-developers.blogspot.jp/2013/02/using-cryptography-to-store-credentials.html – 2013-03-28 11:09:48

+0

thx为链接:-) – dumbfingers 2013-03-28 11:23:10