AES 128 с CBC

#ios #objective-c #encryption #aes #cbc-mode

#iOS #objective-c #шифрование #aes #cbc-режим

Вопрос:

Я схожу с ума от простого AES 128 в Objective C, и нет способа получить ожидаемый зашифрованный текст в простом тесте. Кто-нибудь может сказать мне, что я делаю не так?

Тест:

 - (void)testAES128_1
{
    NSString *testVector    = @"6bc1bee22e409f96e93d7e117393172a";
    NSString *initVector    = @"000102030405060708090A0B0C0D0E0F";
    NSString *key           = @"2b7e151628aed2a6abf7158809cf4f3c";
    NSString *expected      = @"7649abac8119b246cee98e9b12e9197d";

    NSData *inputData = [self dataFromHexString:testVector];
    NSData *keyData = [self dataFromHexString:key];
    NSData *expectedData = [self dataFromHexString:expected];

    NSData *current = [inputData AES128EncryptWithIV:initVector andKey:key];
    // What I get in current = cf2ea38a123be20765eb8c5c56caf224 != expected

    BOOL res = [inputData isEqualToData:current];

    XCTAssertTrue(res);
}

// For Converting incoming HexString into NSData
- (NSData *)dataFromHexString:(NSString *)string
{
    NSMutableData *stringData = [[NSMutableData alloc] init];
    unsigned char whole_byte;
    char byte_chars[3] = {'','',''};
    int i;
    for (i=0; i < [string length] / 2; i  ) {
        byte_chars[0] = [string characterAtIndex:i*2];
        byte_chars[1] = [string characterAtIndex:i*2 1];
        whole_byte = strtol(byte_chars, NULL, 16);
        [stringData appendBytes:amp;whole_byte length:1];
    }
    return stringData;
}
  

Категория NSData (AES):

 - (NSData *)AES128EncryptWithIV:(NSString *)iv andKey:(NSString *)key {
    char ivPtr[kCCKeySizeAES128   1];
    bzero(ivPtr, sizeof(ivPtr));

    // fetch iv data
    [iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];

    char keyPtr[kCCKeySizeAES128 1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength   kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 0,
                                          keyPtr, kCCKeySizeAES128,
                                          ivPtr /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          amp;numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}
  

Я работаю с этим набором тестовых векторов AES:
http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors#aes-cbc-128

Спасибо

Ответ №1:

Просто вы не преобразуете iv в шестнадцатеричном ASCII в NSData . Пример тестового вектора имеет iv, поэтому для получения соответствующего зашифрованного текста вам необходимо использовать вектор инициализации.

Примечание: Строка: BOOL res = [Входные данные равны данным: текущий]; должно быть: BOOL res = [Ожидаемые данные равны данным: текущий];

Примечание: Количество выходных блоков не увеличивается, если нет заполнения.

Вот мой тестовый код:
Нет необходимости в категории, я просто создаю там методы класса methods.

   (void)testAES128_1 {
    NSString *testVector = @"6bc1bee22e409f96e93d7e117393172a";
    NSString *initVector = @"000102030405060708090A0B0C0D0E0F";
    NSString *key        = @"2b7e151628aed2a6abf7158809cf4f3c";
    NSString *expected   = @"7649abac8119b246cee98e9b12e9197d";

    NSData *inputData    = [self dataFromHexString:testVector];
    NSData *keyData      = [self dataFromHexString:key];
    NSData *ivData       = [self dataFromHexString:initVector];
    NSData *expectedData = [self dataFromHexString:expected];

    NSError *error;
    NSData *current = [Test doCipher:inputData
                                  iv:ivData
                                 key:keyData
                             context:kCCEncrypt
                               error:amp;error];

    BOOL res = [expectedData isEqualToData:current];
    NSLog(@"Match: %@", res ? @"Yes" : @"No"); // Match: Yes
}

  (NSData *)doCipher:(NSData *)dataIn
                  iv:(NSData *)iv
                 key:(NSData *)symmetricKey
             context:(CCOperation)encryptOrDecrypt // kCCEncrypt or kCCDecrypt
               error:(NSError **)error
{
    CCCryptorStatus ccStatus   = kCCSuccess;
    size_t          cryptBytes = 0;
    NSMutableData  *dataOut    = [NSMutableData dataWithLength:dataIn.length   kCCBlockSizeAES128];

    ccStatus = CCCrypt( encryptOrDecrypt,
                       kCCAlgorithmAES128,
                       0, //kCCOptionPKCS7Padding,
                       symmetricKey.bytes,
                       kCCKeySizeAES128,
                       iv.bytes,
                       dataIn.bytes,
                       dataIn.length,
                       dataOut.mutableBytes,
                       dataOut.length,
                       amp;cryptBytes);

    if (ccStatus == kCCSuccess) {
        dataOut.length = cryptBytes;
    }
    else {
        if (error) {
            *error = [NSError errorWithDomain:@"kEncryptionError"
                                         code:ccStatus
                                     userInfo:nil];
        }
        dataOut = nil;
    }

    return dataOut;
}
  

Комментарии:

1. Ваш код отлично работает. В моем, BOOL res = .. что ошибка опечатки, извините. Однако я все еще не понимаю, почему вы говорите, что я не использовал IV , когда указатель на него был передан CCCrypt как ivPtr . Что было не так?

2. Прояснил ответ в iv. IV является входом в режим CBC. Это данные той же формы, что и ключ. Вы не преобразовывали шестнадцатеричное значение в данные, как это было с ключом и входными данными.

3. Режим CBC является режимом по умолчанию для CCCrypt. От CommonCryptor.h , CCOptions : «По умолчанию используется CBC».