AES ECB iOS加密

时间:2016-03-10 15:53:20

标签: ios encryption aes

我尝试使用带有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返回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=

我错了什么?

2 个答案:

答案 0 :(得分:6)

简单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:,则它是放弃软件并且不支持标准填充,只支持空填充。相反,考虑defuseRNCryptor这是一个完全安全的实现,可用于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);

答案 1 :(得分:0)

虽然不建议使用AES / ECB。这篇文章解释了为什么会出现对齐错误以及如何处理它。

对齐错误几乎意味着尺寸有问题。

为什么会出错?

分组密码适用于固定大小的单元(称为块大小),但消息有多种长度。因此,某些模式(即ECB和CBC)要求在加密前填充最终块。 (来源:https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_(ECB)

由于AES ECB不为您执行填充,因此您必须在加密原始数据之前对其进行处理。

当然,您可以在允许的情况下使用kCCOptionPKCS7Padding,但由于此主题正在讨论ECB模式和对齐错误,因此我们只关注如何填充数据。

我应填写多少字节?

普通数据字节的数量必须是当前算法块大小的整数倍

也就是说,如果您的区块大小为kCCBlockSizeAES128(16),则必须将数据填入&#34; 最接近的区块大小&#34; (16 * N)。

例如,

如果您的数据是&#34; abc&#34; ( 3 字节), 然后你必须将你的数据填充到 16 字节;

如果您的数据是&#34; 1234567890123456&#34; ( 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解密之前剥去额外的字节。