#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».