在 IOS 中实施 AES256 加密
implementing AES256 encryption into IOS
这是我的 java 代码。现在我想在 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();
这是我的iOS实现
- (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;
}
这是我的哈希键生成函数。此函数 return android 和 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;
我得到了不同的输出。我做错了什么?请帮我找出答案。
那么,你的密钥有多大? kCCAlgorithmAES128
和 kCCKeySizeAES256
假定不同的密钥大小。我假设您使用的是 16 字节密钥,因为您的 Java 代码否则会抛出异常。如果您使用的是 128 位密钥,则应使用 kCCKeySizeAES128
.
此外,您没有传入任何 IV,因此假定 IV 填充了 0x00 字节,但在 Java 中,您将密钥用作 IV。
不要将密钥用作 IV。这首先减少了使用 IV 来随机化密文。您需要为每个加密生成一个随机 IV,并将其与密文一起发送,例如将其添加到密文中。
一个问题是Java代码使用了CBC模式,iOS代码使用了ECB模式。
接下来,来自引用的项目:
//result= yHbhApwTpQ2ZhE97AKF/g==
是无效的 Base64,它不包含 4 字节的倍数。
使用这些选项:CBC、PKCS#7 填充
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==
这是测试代码:
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);
这是加密方式(在classTestClass
):
+ (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;
}
注意:我将加密和数据转换分开。将它们混为一谈只会让测试变得更加复杂。
如果您使用在线加密实现,填充可能不是 PKCS#7,因为 mcrypt 不支持它,而是使用非标准空填充。由于填充字节只是填充字节的计数,因此可以在输入中模拟填充。这是一个使用 AES – Symmetric Ciphers Online
的例子
请注意,"hello" PKCS#7 填充到 16 字节的块大小添加 11 个字节的 uint8 值 11 或 0x0B
:68656c6c6f0B0B0B0B0B0B0B0B0B0B0B
。
最后的问题是为什么 Java 代码没有产生这个结果?
这是我的 java 代码。现在我想在 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();
这是我的iOS实现
- (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;
}
这是我的哈希键生成函数。此函数 return android 和 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;
我得到了不同的输出。我做错了什么?请帮我找出答案。
那么,你的密钥有多大? kCCAlgorithmAES128
和 kCCKeySizeAES256
假定不同的密钥大小。我假设您使用的是 16 字节密钥,因为您的 Java 代码否则会抛出异常。如果您使用的是 128 位密钥,则应使用 kCCKeySizeAES128
.
此外,您没有传入任何 IV,因此假定 IV 填充了 0x00 字节,但在 Java 中,您将密钥用作 IV。
不要将密钥用作 IV。这首先减少了使用 IV 来随机化密文。您需要为每个加密生成一个随机 IV,并将其与密文一起发送,例如将其添加到密文中。
一个问题是Java代码使用了CBC模式,iOS代码使用了ECB模式。
接下来,来自引用的项目:
//result= yHbhApwTpQ2ZhE97AKF/g==
是无效的 Base64,它不包含 4 字节的倍数。
使用这些选项:CBC、PKCS#7 填充
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==
这是测试代码:
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);
这是加密方式(在classTestClass
):
+ (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;
}
注意:我将加密和数据转换分开。将它们混为一谈只会让测试变得更加复杂。
如果您使用在线加密实现,填充可能不是 PKCS#7,因为 mcrypt 不支持它,而是使用非标准空填充。由于填充字节只是填充字节的计数,因此可以在输入中模拟填充。这是一个使用 AES – Symmetric Ciphers Online
的例子请注意,"hello" PKCS#7 填充到 16 字节的块大小添加 11 个字节的 uint8 值 11 或 0x0B
:68656c6c6f0B0B0B0B0B0B0B0B0B0B0B
。
最后的问题是为什么 Java 代码没有产生这个结果?