AES ECB iOS加密

Bog*_*rda 4 encryption aes ios

我尝试使用带有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];
}
Run Code Online (Sandbox Code Playgroud)

但是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);
Run Code Online (Sandbox Code Playgroud)

输入字符串

"test_string,test2"
Run Code Online (Sandbox Code Playgroud)

结果是

jxtFOhYpgBVieM90zx9oDanqBkcsVAvRRJsM4GL3cio=
Run Code Online (Sandbox Code Playgroud)

在Android上的结果是

jxtFOhYpgBVieM90zx9oDUfV7v43WFv7F5bzErfxrL8=
Run Code Online (Sandbox Code Playgroud)

我错了什么?

zap*_*aph 6

简单地说,AES是一个块密码,这意味着它要求它的输入数据是块大小的倍数(AES为16字节).您的输入数据是17个字节,因此对齐错误.(它不是在谈论内存中的对齐).

处理此问题的方法是在选项中指定PKCS#7填充:

kCCOptionPKCS7Padding | kCCOptionECBMode
Run Code Online (Sandbox Code Playgroud)

输入数据将被填充到块多个,并且在解密时将删除填充.要在加密时允许此操作,必须将输出缓冲区增加一个块大小.

考虑不使用[ECB模式](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29 (向下滚动到企鹅),它不安全.

如果你在Android上使用mcrypt:不要,它是放弃软件,不支持标准填充,只支持空填充.相反,可以考虑使用defuseRNCryptor作为完全安全的实现,适用于iOS和Java.

如果您使用mcrypt,则需要添加自己的PKCS#7填充.

这是示例代码:

+ (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;
}
Run Code Online (Sandbox Code Playgroud)

示例PHP PKCS#7填充:
添加PKCS#7填充

$padLength = $blockSize - (strlen($clearText) % $blockSize);
$clearText = $clearText . str_repeat(chr($padLength), $padLength);
Run Code Online (Sandbox Code Playgroud)

剥离PKCS#7填充

$padLength = ord($cryptText[strlen($cryptText)-1]);
$cryptText = substr($cryptText, 0, strlen($cryptText) - $padLength);
Run Code Online (Sandbox Code Playgroud)