AES CBC Encryption With PKCS7Padding Has Different Results In Java And Objective-C

馋奶兔 提交于 2021-02-07 04:21:10

问题


I have created an application for Android in Java and used Cipher class to encrypt data with AES. Now I wanna take that algorithm into iOS with CommonCrypto class. The code works but has different results.

This is the code in Java:

public static String Decrypt(String text, String key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    byte[] keyBytes = new byte[16];
    byte[] b = key.getBytes("UTF-8");
    int len = b.length;
    if (len > keyBytes.length)
        len = keyBytes.length;
    System.arraycopy(b, 0, keyBytes, 0, len);
    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
    cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
    byte[] results = new byte[text.length()];
    BASE64Decoder decoder = new BASE64Decoder();
    try {
        results = cipher.doFinal(decoder.decodeBuffer(text));
    } catch (Exception e) {
        System.out.print("Erron in Decryption");
    }
    return new String(results, "UTF-8");
}

public static String Encrypt(String text, String key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    byte[] keyBytes = new byte[16];
    byte[] b = key.getBytes("UTF-8");
    int len = b.length;
    if (len > keyBytes.length)
        len = keyBytes.length;
    System.arraycopy(b, 0, keyBytes, 0, len);
    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
    System.out.println(keyBytes);
    System.out.println(keySpec);
    System.out.println(ivSpec);
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

    byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
    BASE64Encoder encoder = new BASE64Encoder();
    return encoder.encode(results);
}

This is the code in Objective-C:

+ (NSString*)AES256EncryptData:(NSString*)data WithKey:(NSString*)key {
    char keyPtr[kCCKeySizeAES128]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = data.length;

    size_t bufferSize           = dataLength + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);

    size_t numBytesEncrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          data.UTF8String, dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);

    if (cryptStatus == kCCSuccess) {
        return [[NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted] base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
    }

    free(buffer); //free the buffer;
    return nil;
}

+ (NSString*)AES256DecryptData:(NSString*)data WithKey:(NSString*)key {
    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = data.length;

    size_t bufferSize           = dataLength + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);

    size_t numBytesDecrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          data.UTF8String, dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        return [[NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted] base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
    }

    free(buffer); //free the buffer;
    return nil;
}

Update 1:

Data: text to encrypt

Key: testkey

Java (desired) Result: 7ptTEyImNz9KgC96+JPFXQ==

Objective-C Result: U7FAVHi01q0Hhf+m9NsKjw==


回答1:


Your problem is with the Objective-C code. You should use same method in both Java and Obj-C. You can use this code in order to make it return the same results:

AES.h

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>

@interface AES : NSObject 

+ (NSData *)Encrypt:(NSString *)data WithKey:(NSString *)key;
+ (NSString *)Decrypt:(NSData *)data WithKey:(NSString *)key;

+ (NSData *)AESOperation:(CCOperation)operation OnData:(NSData *)data key:(NSString *)key;

@end

AES.m

#import "AES.h"

@implementation AES

+ (NSData *)Encrypt:(NSString *)data WithKey:(NSString *)key {
    return [self AESOperation:kCCEncrypt OnData:[data dataUsingEncoding:NSUTF8StringEncoding] key:key];
}
+ (NSString *)Decrypt:(NSData *)data WithKey:(NSString *)key {
    return [[NSString alloc] initWithData:[self AESOperation:kCCDecrypt OnData:data key:key] encoding:NSUTF8StringEncoding];
}

+ (NSData *)AESOperation:(CCOperation)operation OnData:(NSData *)data key:(NSString *)key {
    char keyPtr[kCCKeySizeAES128];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [data length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(operation,
                                          kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCBlockSizeAES128,
                                          keyPtr,
                                          [data bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer);
    return nil;
}

@end



回答2:


In the java code, you are using an IV parameter:

IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);

In the Objective C, the IV parameter is set to NULL:

CCCrypt(..,   NULL /* initialization vector (optional) */,

That aside, the IV parameter should be some random values and not you secret key (or part of it). The idea is to outpout different cypher text and prevent block pattern matching




回答3:


You need to add an iv to the ObjC code, not NULL.

Do not use the key for the iv, instead create a iv of random bytes, prepend it to the encrypted data for use on decryption. In ObjC you can create an random iv with SecRandomCopyBytes:

uint8_t iv[kCCBlockSizeAES128];
SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, iv);

Output:

iv: 8617dcf92de01ac2c0b92763b206b3f5



来源:https://stackoverflow.com/questions/37477635/aes-cbc-encryption-with-pkcs7padding-has-different-results-in-java-and-objective

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!