问题
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