问题
This is my java code. Now I want to implement same functionality in Objective-C.
Cipher encryptCipher;
IvParameterSpec iv = new IvParameterSpec(key);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = encryptCipher.doFinal(dataToEncrypt.getBytes());
Log.d("TAG", "encrypted string:"
+ Base64.encodeToString(encrypted, Base64.DEFAULT));
return Base64.encodeToString(encrypted, Base64.DEFAULT).trim();
This is my iOS implementation
- (NSData *)AES256EncryptWithKey:(NSString*)key
{
char keyPtr[kCCKeySizeAES256 + 1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keyPtr,
kCCKeySizeAES256,
NULL,
[self bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess)
{
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}
This is my hash key generating function. this function return same key in android and ios
int dkLen = 16;
NSData *keyData = [hash_key dataUsingEncoding:NSUTF8StringEncoding];
NSData *salt = [saltKey dataUsingEncoding:NSUTF8StringEncoding];
uint rounds = 1000;
uint keySize = kCCKeySizeAES128;
NSMutableData *derivedKey = [NSMutableData dataWithLength:keySize];
CCKeyDerivationPBKDF(kCCPBKDF2, // algorithm
keyData.bytes, // password
keyData.length, // passwordLength
salt.bytes, // salt
salt.length, // saltLen
kCCPRFHmacAlgSHA1, // PRF
rounds, // rounds
derivedKey.mutableBytes, // derivedKey
dkLen*8);
return derivedKey;
I am getting a different output. I am doing anything wrong?.please help me to find out.
回答1:
One problem is that the Java code used CBC mode, the iOS code used ECB mode.
Next, from the referenced project://result= yHbhApwTpQ2ZhE97AKF/g==
is invalid Base64, it does not contain a multiple of 4 bytes.
With these options: CBC, PKCS#7 padding
inputs: data in: "hello" which will be null padded to the block length of 16-bytes key: base64: VQQhu+dUdqXGoE7RZL2JWg== hex: 550421bbe75476a5c6a04ed164bd895a iv: base64: VQQhu+dUdqXGoE7RZL2JWg== hex: 550421bbe75476a5c6a04ed164bd895a encrypted output: hex: ff21db840a704e943666113dec0285fe base64: /yHbhApwTpQ2ZhE97AKF/g==
This is the test code:
NSString *base64Key = @"VQQhu+dUdqXGoE7RZL2JWg==";
NSString *dataString = @"hello";
NSData *key = [[NSData alloc] initWithBase64EncodedString:base64Key options:0];
NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"key: %@", key);
NSLog(@"data: %@", data);
NSData *encryptedData = [TestClass crypt:data
iv:key
key:key
context:kCCEncrypt];
NSLog(@"encryptedData: %@", encryptedData);
NSString *encryptedBase64Data = [encryptedData base64EncodedStringWithOptions:0];
NSLog(@"encryptedBase64Data: %@", encryptedBase64Data);
This is the encryption method (in the class TestClass
):
+ (NSData *)crypt:(NSData *)dataIn
iv:(NSData *)iv
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0; // Number of bytes moved to buffer.
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
symmetricKey.bytes,
kCCKeySizeAES128,
iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus != kCCSuccess) {
NSLog(@"CCCrypt status: %d", ccStatus);
}
dataOut.length = cryptBytes;
return dataOut;
}
Note: I keep separate the encryption and data conversions. Conflating them just makes testing more complicated.
If you use an on-line encryption implementation the padding will probably not be PKCS#7 because mcrypt does not support it, instead it does non-standard null padding. Since the pad bytes are just the count of pad bytes the padding can be simulated in the input. Here is an example using AES – Symmetric Ciphers Online
Note that "hello" PKCS#7 padded to a block size of 16 bytes adds 11 bytes of the uint8 value 11 or 0x0B
: 68656c6c6f0B0B0B0B0B0B0B0B0B0B0B
.
Finally the question remains why the Java code does not produce this result?
回答2:
Well, how big is your key? kCCAlgorithmAES128
and kCCKeySizeAES256
assume different key sizes. I'm assuming that you're using a 16 byte key, because your Java code would throw an exception otherwise. If you're using a 128 bit key, then you should use kCCKeySizeAES128
.
Additionally, you're not passing in any IV, so it will be assumed that the IV is filled with 0x00 bytes, but in Java, you're using the key as IV.
Don't use the key as IV. That diminishes the use of the IV in the first place that is there to randomize the ciphertext. You need to generate a random IV for each encryption and send it along with the ciphertext, for example by prepending it to the ciphertext.
Yes, PKCS#5 padding and PKCS#7 padding are the same thing.
来源:https://stackoverflow.com/questions/33413723/implementing-aes256-encryption-into-ios