Android AES 128加密

时间:2013-03-13 16:06:30

标签: android iphone encryption aes

我正在尝试在Android上实施AES128加密。我有一个使用Objective C在iPhone上工作的解决方案,但无法将其移植到Android。我搜索了stackoverflow的解决方案,但我似乎做错了什么。我对Java很新,所以我觉得我错过了与数据,字符串转换有关的事情。

这是我的iPhone加密:

char keyPtr[kCCKeySizeAES128+1];
[keyString getCString:keyPtr
            maxLength:sizeof(keyPtr)
             encoding:NSASCIIStringEncoding];

// CString for the plain text
char plainBytes[[plainString length]+1];
[plainString getCString:plainBytes
              maxLength:sizeof(plainBytes)
               encoding:NSASCIIStringEncoding];

size_t bytesEncrypted = 0;

// Allocate the space for encrypted data
NSUInteger dataLength = [plainString length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);

// Encrypt
CCCryptorStatus ret = CCCrypt(kCCEncrypt,
                              kCCAlgorithmAES128,
                              kCCOptionPKCS7Padding | kCCOptionECBMode,
                              keyPtr,
                              kCCKeySizeAES128,
                              NULL,
                              plainBytes, sizeof(plainBytes),
                              buffer, bufferSize,
                              &bytesEncrypted);
if (ret != kCCSuccess) {
    free(buffer);
}

encryptedData = [NSData dataWithBytes:buffer length:bytesEncrypted];

这是我的Java:

    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));

在iPhone和Java中使用相同的密钥和明文会产生不同的结果。我的iPhone结果以我需要的方式工作,所以我试图让java给我iPhone的结果。我肯定在Java中遗漏了一些东西,只是不确定它是什么。

修改

根据以下建议,我将Java修改为

    byte[] keyBytes = plainTextKey.getBytes("US-ASCII");
    SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, "AES");
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(plainText.getBytes("US-ASCII"));

但我仍然在Android和iPhone之间得到不同的结果

3 个答案:

答案 0 :(得分:4)

除了使用明文编码困难(如注释中指出的vcsjones),请确保密钥字符串的编码相同(请注意,使用原始字符串,如密码,直接作为加密密钥是坏消息熊,在密码上使用密钥派生函数如PBKDF2来获取密钥)。

此外,Java for Java的编码字符串为US-ASCII,而不仅仅是ASCII,因此请务必在getBytes来电中使用该字符串。

编辑:发现您的问题:iOS字符串在末尾加密了一个额外的空字符(0x00),而java却没有。因此,在java中加密“hello world \ 0”将为您提供与iOS中“hello world”相同的输出

答案 1 :(得分:0)

互联网上的大多数例子都是AES的弱实现。为了实现强大,应始终使用随机IV,并且应对密钥进行散列。

对于更安全(随机IV +哈希键)跨平台(android,ios,c#)的AES实现,请参阅我的答案 - https://stackoverflow.com/a/24561148/2480840

答案 2 :(得分:0)

我已经编写了这个管理器文件,它的功能对我来说非常好。这是针对 AES 128 的,没有任何盐分。

public class CryptoManager {

private static CryptoManager shared;
private String privateKey = "your_private_key_here";
private String ivString = "your_iv_here";


private CryptoManager(){
}

public static CryptoManager getShared() {
    if (shared != null ){
        return shared;
    }else{
        shared = new CryptoManager();
        return shared;
    }
}

public String encrypt(String value) {
    try {
        IvParameterSpec iv = new IvParameterSpec(ivString.getBytes("UTF-8"));
        SecretKeySpec skeySpec = new SecretKeySpec(privateKey.getBytes("UTF-8"), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

        byte[] encrypted = cipher.doFinal(value.getBytes());
        return android.util.Base64.encodeToString(encrypted, android.util.Base64.DEFAULT);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}


public String decrypt(String encrypted) {
    try {
        IvParameterSpec iv = new IvParameterSpec(ivString.getBytes("UTF-8"));
        SecretKeySpec skeySpec = new SecretKeySpec(privateKey.getBytes("UTF-8"), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        byte[] original = new byte[0];
        original = cipher.doFinal(android.util.Base64.decode(encrypted, android.util.Base64.DEFAULT));

        return new String(original);
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return null;
}
}

你需要像这样调用函数。

String dataToEncrypt = "I need to encrypt myself";
String encryptedData = CryptoManager.getShared().encrypt(data);

您将使用以下行获得加密字符串

String decryptedString = CryptoManager.getShared().decrypt(encryptedData);