AES ECB iOS 加密
AES ECB iOS Encrypt
我尝试使用带有 ECB 选项的 AES 算法来加密一些字符串。
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode,
encryptionKey, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
但是 func returns kCCAlignmentError (-4303)
然后我尝试对齐数据:
unsigned long diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
unsigned long newSize = 0;
if (diff > 0) {
newSize = dataLength + diff;
}
char dataPtr[newSize];
memcpy(dataPtr, [self bytes], [self length]);
for(int i = 0; i < diff; i++) {
dataPtr[i + dataLength] = 0x20;
}
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode,
encryptionKey, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
dataPtr, sizeof(dataPtr), /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
输入字符串
"test_string,test2"
结果是
jxtFOhYpgBVieM90zx9oDanqBkcsVAvRRJsM4GL3cio=
在 Android 结果是
jxtFOhYpgBVieM90zx9oDUfV7v43WFv7F5bzErfxrL8=
我做错了什么?
简单地说,AES 是一种块密码,这意味着它要求输入数据是块大小的倍数(AES 为 16 字节)。您的输入数据是 17 个字节,因此存在对齐错误。 (不是说内存中的对齐)
处理这个问题的方法是在选项中指定 PKCS#7 填充:
kCCOptionPKCS7Padding | kCCOptionECBMode
输入数据将被填充到一个块的倍数,并且在解密时填充将被删除。要在加密时允许这样做,必须将输出缓冲区增加一个块大小。
考虑不使用 [ECB 模式](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29(向下滚动到企鹅),它不安全。
如果您在 Android 上使用 mcrypt:不要,它是废弃软件,不支持标准填充,仅支持空填充。相反,请考虑 defuse or RNCryptor,这是一个完全安全的实现,可用于 iOS 和 Java。
如果您确实使用 mcrypt,则需要添加您自己的 PKCS#7 padding。
示例代码如下:
+ (NSData *)doCipher:(NSData *)dataIn
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt // kCCEncrypt or kCCDecrypt
{
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 | kCCOptionECBMode,
symmetricKey.bytes,
kCCKeySizeAES128,
0,
dataIn.bytes, dataIn.length,
dataOut.mutableBytes, dataOut.length,
&cryptBytes);
if (ccStatus != kCCSuccess) {
NSLog(@"CCCrypt status: %d", ccStatus);
}
dataOut.length = cryptBytes;
return dataOut;
}
示例PHP PKCS#7 填充:
添加 PKCS#7 填充
$padLength = $blockSize - (strlen($clearText) % $blockSize);
$clearText = $clearText . str_repeat(chr($padLength), $padLength);
去除 PKCS#7 填充
$padLength = ord($cryptText[strlen($cryptText)-1]);
$cryptText = substr($cryptText, 0, strlen($cryptText) - $padLength);
虽然AES/ECB不是很推荐。 post 解释了为什么会出现对齐错误以及如何处理它。
对齐错误几乎意味着尺寸有问题。
为什么会出现错误?
块密码以固定大小(称为块大小)为单位工作,但消息有多种长度。因此某些模式(即 ECB 和 CBC)要求在加密之前填充 final block。 (来源:https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_(ECB))
由于 AES ECB 不为您填充,因此您必须在加密前处理原始数据。
当然可以在允许的情况下使用kCCOptionPKCS7Padding
,但是由于本帖讨论的是ECB模式和对齐错误,所以我们只关注如何填充数据。
我应该填充多少字节?
明文数据字节数必须当前算法块大小的整数倍。
也就是说,如果您的块大小是 kCCBlockSizeAES128
(16),则必须将数据填充到“最接近块大小的倍数”(16 *n).
例如,
如果您的数据是 "abc"(3 字节),
那么你必须将数据填充到 16 字节;
如果您的数据是“1234567890123456”(16 字节),
然后你必须把它填充成 32 字节。
0 ~ 15 bytes => pad to 16 bytes
16 ~ 31 bytes => pad to 32 bytes
32 ~ 47 bytes => pad to 48 bytes
... and so on
要填充的字节的值是多少?
If you have to pad 1 byte, then the 1 byte you pad would be '01';
If you have to pad 2 bytes, then the 2 bytes you pad would be '02';
...
If you have to pad 16 bytes, then the 16 bytes you pad would be '10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10'
加密前原始数据和填充数据示例
Example 1. (under block size 16)
Original data string: "abc" (3 bytes)
Data Bytes: "61 62 63"
Padded Data Bytes: "61 62 63 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d"
Explanation:
Data are 3 bytes, so the nearest multiple of the block size is 16 bytes.
So there are 13 bytes to be padded.
And 13 in hex would be 0xd, so '0d' is padded for 13 times.
让我们再举一个恰好是块大小倍数的数据示例。
Example 2. (under block size 16)
Original data string: "1234567890123456" (16 bytes)
Data Bytes: "31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36"
Padded Data Bytes: "31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10"
Explanation:
Data are 16 bytes, so the nearest multiple of the block size is 32 bytes.
So there are 16 bytes to be padded.
And 16 in hex would be 0x10, so '10' is padded for 16 times.
填充Objective-C
中的数据
以下是使用 AES/ECB 加密模式时如何填充数据的示例:
+ (NSData *)addPaddingBeforeEncryptWithAESECB:(NSData *) data{
//Length has to be the nearest multiple of the block size
int cipherLen = (int)(data.length/kAlgorithmBlockSize + 1)*kAlgorithmBlockSize;
NSMutableData *newData = [NSMutableData dataWithLength:cipherLen];
newData = [data mutableCopy];
//How many bytes to be padded
int bytesToAddOn = kAlgorithmBlockSize - data.length%kAlgorithmBlockSize;
//Each byte in hex
char byteToAdd = bytesToAddOn & 0xff;
char *buffer = malloc(bytesToAddOn * sizeof byteToAdd);
memset (buffer, byteToAdd, sizeof (char) * bytesToAddOn);
[newData appendBytes:buffer length:bytesToAddOn];
return newData;
}
AES ECB 加密的完整示例:
+ (NSData *)encryptDataWithAESECB:(NSData *)data
key:(NSData *) key
error:(NSError **)error {
size_t outLength;
int cipherLen = (int)(data.length/kAlgorithmBlockSize + 1)*kAlgorithmBlockSize;
NSMutableData *cipherData = [NSMutableData dataWithLength:cipherLen];
NSData *newData = [self addPaddingBeforeEncryptWithAESECB:data];
CCCryptorStatus result = CCCrypt(kCCEncrypt, // operation
kAlgorithm, // Algorithm
kCCOptionECBMode, // Mode
key.bytes, // key
key.length, // keylength
0,// iv
newData.bytes, // dataIn
newData.length, // dataInLength,
cipherData.mutableBytes, // dataOut
cipherData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result == kCCSuccess) {
cipherData.length = outLength;
}else {
if (error) {
*error = [NSError errorWithDomain:kRNCryptManagerErrorDomain code:result userInfo:nil];
}
return nil;
}
return cipherData;
}
下一步是什么?
您必须在 AES ECB 解密之前去除多余的字节。
我尝试使用带有 ECB 选项的 AES 算法来加密一些字符串。
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode,
encryptionKey, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
但是 func returns kCCAlignmentError (-4303)
然后我尝试对齐数据:
unsigned long diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
unsigned long newSize = 0;
if (diff > 0) {
newSize = dataLength + diff;
}
char dataPtr[newSize];
memcpy(dataPtr, [self bytes], [self length]);
for(int i = 0; i < diff; i++) {
dataPtr[i + dataLength] = 0x20;
}
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode,
encryptionKey, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
dataPtr, sizeof(dataPtr), /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
输入字符串
"test_string,test2"
结果是
jxtFOhYpgBVieM90zx9oDanqBkcsVAvRRJsM4GL3cio=
在 Android 结果是
jxtFOhYpgBVieM90zx9oDUfV7v43WFv7F5bzErfxrL8=
我做错了什么?
简单地说,AES 是一种块密码,这意味着它要求输入数据是块大小的倍数(AES 为 16 字节)。您的输入数据是 17 个字节,因此存在对齐错误。 (不是说内存中的对齐)
处理这个问题的方法是在选项中指定 PKCS#7 填充:
kCCOptionPKCS7Padding | kCCOptionECBMode
输入数据将被填充到一个块的倍数,并且在解密时填充将被删除。要在加密时允许这样做,必须将输出缓冲区增加一个块大小。
考虑不使用 [ECB 模式](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29(向下滚动到企鹅),它不安全。
如果您在 Android 上使用 mcrypt:不要,它是废弃软件,不支持标准填充,仅支持空填充。相反,请考虑 defuse or RNCryptor,这是一个完全安全的实现,可用于 iOS 和 Java。
如果您确实使用 mcrypt,则需要添加您自己的 PKCS#7 padding。
示例代码如下:
+ (NSData *)doCipher:(NSData *)dataIn
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt // kCCEncrypt or kCCDecrypt
{
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 | kCCOptionECBMode,
symmetricKey.bytes,
kCCKeySizeAES128,
0,
dataIn.bytes, dataIn.length,
dataOut.mutableBytes, dataOut.length,
&cryptBytes);
if (ccStatus != kCCSuccess) {
NSLog(@"CCCrypt status: %d", ccStatus);
}
dataOut.length = cryptBytes;
return dataOut;
}
示例PHP PKCS#7 填充:
添加 PKCS#7 填充
$padLength = $blockSize - (strlen($clearText) % $blockSize);
$clearText = $clearText . str_repeat(chr($padLength), $padLength);
去除 PKCS#7 填充
$padLength = ord($cryptText[strlen($cryptText)-1]);
$cryptText = substr($cryptText, 0, strlen($cryptText) - $padLength);
虽然AES/ECB不是很推荐。 post 解释了为什么会出现对齐错误以及如何处理它。
对齐错误几乎意味着尺寸有问题。
为什么会出现错误?
块密码以固定大小(称为块大小)为单位工作,但消息有多种长度。因此某些模式(即 ECB 和 CBC)要求在加密之前填充 final block。 (来源:https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_(ECB))
由于 AES ECB 不为您填充,因此您必须在加密前处理原始数据。
当然可以在允许的情况下使用kCCOptionPKCS7Padding
,但是由于本帖讨论的是ECB模式和对齐错误,所以我们只关注如何填充数据。
我应该填充多少字节?
明文数据字节数必须当前算法块大小的整数倍。
也就是说,如果您的块大小是 kCCBlockSizeAES128
(16),则必须将数据填充到“最接近块大小的倍数”(16 *n).
例如,
如果您的数据是 "abc"(3 字节), 那么你必须将数据填充到 16 字节;
如果您的数据是“1234567890123456”(16 字节), 然后你必须把它填充成 32 字节。
0 ~ 15 bytes => pad to 16 bytes
16 ~ 31 bytes => pad to 32 bytes
32 ~ 47 bytes => pad to 48 bytes
... and so on
要填充的字节的值是多少?
If you have to pad 1 byte, then the 1 byte you pad would be '01';
If you have to pad 2 bytes, then the 2 bytes you pad would be '02';
...
If you have to pad 16 bytes, then the 16 bytes you pad would be '10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10'
加密前原始数据和填充数据示例
Example 1. (under block size 16)
Original data string: "abc" (3 bytes)
Data Bytes: "61 62 63"
Padded Data Bytes: "61 62 63 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d"
Explanation:
Data are 3 bytes, so the nearest multiple of the block size is 16 bytes.
So there are 13 bytes to be padded.
And 13 in hex would be 0xd, so '0d' is padded for 13 times.
让我们再举一个恰好是块大小倍数的数据示例。
Example 2. (under block size 16)
Original data string: "1234567890123456" (16 bytes)
Data Bytes: "31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36"
Padded Data Bytes: "31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10"
Explanation:
Data are 16 bytes, so the nearest multiple of the block size is 32 bytes.
So there are 16 bytes to be padded.
And 16 in hex would be 0x10, so '10' is padded for 16 times.
填充Objective-C
中的数据以下是使用 AES/ECB 加密模式时如何填充数据的示例:
+ (NSData *)addPaddingBeforeEncryptWithAESECB:(NSData *) data{
//Length has to be the nearest multiple of the block size
int cipherLen = (int)(data.length/kAlgorithmBlockSize + 1)*kAlgorithmBlockSize;
NSMutableData *newData = [NSMutableData dataWithLength:cipherLen];
newData = [data mutableCopy];
//How many bytes to be padded
int bytesToAddOn = kAlgorithmBlockSize - data.length%kAlgorithmBlockSize;
//Each byte in hex
char byteToAdd = bytesToAddOn & 0xff;
char *buffer = malloc(bytesToAddOn * sizeof byteToAdd);
memset (buffer, byteToAdd, sizeof (char) * bytesToAddOn);
[newData appendBytes:buffer length:bytesToAddOn];
return newData;
}
AES ECB 加密的完整示例:
+ (NSData *)encryptDataWithAESECB:(NSData *)data
key:(NSData *) key
error:(NSError **)error {
size_t outLength;
int cipherLen = (int)(data.length/kAlgorithmBlockSize + 1)*kAlgorithmBlockSize;
NSMutableData *cipherData = [NSMutableData dataWithLength:cipherLen];
NSData *newData = [self addPaddingBeforeEncryptWithAESECB:data];
CCCryptorStatus result = CCCrypt(kCCEncrypt, // operation
kAlgorithm, // Algorithm
kCCOptionECBMode, // Mode
key.bytes, // key
key.length, // keylength
0,// iv
newData.bytes, // dataIn
newData.length, // dataInLength,
cipherData.mutableBytes, // dataOut
cipherData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result == kCCSuccess) {
cipherData.length = outLength;
}else {
if (error) {
*error = [NSError errorWithDomain:kRNCryptManagerErrorDomain code:result userInfo:nil];
}
return nil;
}
return cipherData;
}
下一步是什么?
您必须在 AES ECB 解密之前去除多余的字节。