首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AES欧洲央行iOS加密

AES欧洲央行iOS加密
EN

Stack Overflow用户
提问于 2016-03-10 15:53:20
回答 2查看 4.5K关注 0票数 4

我尝试使用带有ECB选项的AES算法加密一些字符串。

代码语言:javascript
复制
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)

然后我试着对齐数据:

代码语言:javascript
复制
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);

输入串

代码语言:javascript
复制
"test_string,test2"

结果是

代码语言:javascript
复制
jxtFOhYpgBVieM90zx9oDanqBkcsVAvRRJsM4GL3cio=

关于Android的结果是

代码语言:javascript
复制
jxtFOhYpgBVieM90zx9oDUfV7v43WFv7F5bzErfxrL8=

我做错什么了?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-10 16:21:01

简单地说,AES是一个分组密码,这意味着它需要它的输入数据是块大小的倍数(对于AES来说是16字节)。您的输入数据为17个字节,从而导致对齐错误。(它不是在谈论内存中的对齐)。

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

代码语言:javascript
复制
kCCOptionPKCS7Padding | kCCOptionECBMode

输入数据将被填充到块倍数,并且在解密时填充将被移除。为了在加密时允许这样做,必须将输出缓冲区增加一个块大小。

考虑不使用欧洲央行模式(.28ECB.29(卷轴向下到企鹅)),它是不安全的。

如果您在Android上使用mcrypt:不支持,那么它是放弃软件,不支持标准填充,只支持空填充。相反,考虑一下解消RNCryptor,这是一个完全安全的实现,可用于iOS和Java。

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

下面是示例代码:

代码语言:javascript
复制
+ (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;
}

示例:

添加PKCS#7填充

代码语言:javascript
复制
$padLength = $blockSize - (strlen($clearText) % $blockSize);
$clearText = $clearText . str_repeat(chr($padLength), $padLength);

条形PKCS#7填充

代码语言:javascript
复制
$padLength = ord($cryptText[strlen($cryptText)-1]);
$cryptText = substr($cryptText, 0, strlen($cryptText) - $padLength);
票数 7
EN

Stack Overflow用户

发布于 2018-02-01 09:28:26

尽管AES/ECB并不是真正推荐的。这篇文章解释了为什么会出现对齐错误,以及如何处理。

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

为什么会有错误?

块密码工作在一个固定大小的单位(称为块大小),,但消息有不同的长度。因此,有些模式(即ECB和CBC)要求在加密之前先填充最后块。(资料来源:https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_(ECB%29)

由于AES欧洲央行不为您做填充,您必须先处理原始数据,然后再加密它。

当然,您可以在允许的情况下使用kCCOptionPKCS7Padding,但是由于这个线程讨论的是欧洲央行模式和对齐错误,让我们只关注如何填充数据。

我应该放多少字节?

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

也就是说,如果您的块大小为kCCBlockSizeAES128 (16),则必须将数据放入“最接近块大小的倍数”(16*n)。

例如,

如果您的数据是"abc“(3字节),那么您必须将数据放入16字节;

如果您的数据是"1234567890123456“(16字节),则必须将其放入32字节。

代码语言:javascript
复制
0  ~ 15 bytes => pad to 16 bytes
16 ~ 31 bytes => pad to 32 bytes
32 ~ 47 bytes => pad to 48 bytes
... and so on

要填充的字节的值是多少?

代码语言:javascript
复制
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'

加密前原始数据和填充数据示例

代码语言:javascript
复制
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.

让我们再举一个数据的例子,它正好是块大小的倍数。

代码语言:javascript
复制
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.

将数据放入目标C中

下面是使用AES/ECB加密模式时如何填充数据的示例:

代码语言:javascript
复制
+ (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欧洲央行加密的完整示例:

代码语言:javascript
复制
+ (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欧洲央行解密之前,你必须去掉额外的字节。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35921254

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档