简体   繁体   English

Android AES 128 加密

[英]Android AES 128 encryption

I'm trying to implement AES128 encryption on an Android.我正在尝试在 Android 上实现 AES128 加密。 I've got a solution working on an iPhone with Objective C but having trouble porting it to Android.我有一个在 iPhone 上使用 Objective C 的解决方案,但无法将其移植到 Android。 I've searched stackoverflow for a solution, but I seem to be doing something wrong.我已经在 stackoverflow 上搜索了解决方案,但我似乎做错了什么。 I'm fairly new to Java so I think I'm missing something to do with data, string conversion.我对 Java 还很陌生,所以我想我错过了一些与数据、字符串转换有关的东西。

Here is my iPhone encrypt:这是我的 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];

Here is my Java:这是我的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"));

Using the same key and plaintext in iPhone and Java give different results.在 iPhone 和 Java 中使用相同的密钥和明文会产生不同的结果。 My iPhone result works the way I need it so I'm trying to get java to give me the iPhone result.我的 iPhone 结果按我需要的方式工作,所以我试图让 java 给我 iPhone 结果。 I'm missing something in the Java for sure, just not sure what it is.我肯定在 Java 中遗漏了一些东西,只是不确定它是什么。

edit编辑

based on suggestions below I modified my Java to this根据下面的建议,我将我的 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"));

but I'm still getting different results between android and iPhone但我仍然在 android 和 iPhone 之间得到不同的结果

in addition to encoding difficulties with your plaintext (as vcsjones pointed out in the comments), make sure that the encoding is the same for the key string (note that using a raw string, like a password, directly as an crypto key is bad news bears, use a key derivation function like PBKDF2 on the password to get derive a key).除了纯文本编码困难(正如 vcsjones 在评论中指出的那样),确保密钥字符串的编码相同(请注意,使用原始字符串,如密码,直接作为加密密钥是个坏消息熊,在密码上使用像 PBKDF2 这样的密钥派生函数来派生密钥)。

Also, the encoding string for Java for ASCII is US-ASCII , not just ASCII , so make sure to use that in your getBytes calls.此外,用于 ASCII 的 Java 编码字符串是US-ASCII ,而不仅仅是ASCII ,因此请确保在您的getBytes调用中使用它。

EDIT : found your problem: the iOS string is being encrypted with an extra null charcter (0x00) at the end, while the java was not.编辑:发现您的问题:iOS 字符串在末尾使用额外的空字符 (0x00) 进行加密,而 java 则没有。 So encrypting "hello world\\0" in java will give you the same output as "hello world" does in iOS所以在java中加密“hello world\\0”会给你与iOS中“hello world”相同的输出

Most of the examples on internet are weak implementation of AES.互联网上的大多数示例都是 AES 的弱实现。 For an implementation to be strong, random IV should be used all the time and key should be hashed.为了实现强大的功能,应该一直使用随机 IV,并且应该对密钥进行散列。

For more secure(random IV + hashed key) cross platform (android, ios, c#) implementation of AES see my answer here - https://stackoverflow.com/a/24561148/2480840有关 AES 的更安全(随机 IV + 散列密钥)跨平台(android、ios、c#)实现,请在此处查看我的答案 - https://stackoverflow.com/a/24561148/2480840

I have written this manager file and its functions are working perfectly fine for me.我已经编写了这个管理器文件,它的功能对我来说非常好。 This is for AES 128 and without any salt.这是针对 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;
}
}

You need to call the functions like this.您需要像这样调用函数。

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

And you will get your encrypted string with the following line您将使用以下行获得加密字符串

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM