Я написал код, который использует Common Crypto для iOS для шифрования и дешифрования объекта NSData
. Ключами шифрования являются AES128 и хранятся в цепочке ключей iOS. Я могу зашифровать и дешифровать данные успешно, поэтому я знаю, что часть кода работает. Тем не менее, как проверка работоспособности, я также создал второй ключ AES128 и попытался расшифровать данные, которые были зашифрованы с помощью ключа шифрования сперва. Я ожидал, что значение CCCryptorStatus
будет чем-то иным, чем kCCSuccess
, однако это было не так. Я получил обратно объект NSData
и никаких ошибок. Мой зашифровать/расшифровать код выглядит примерно так ...Common Crypto - тестирование плохого ключа в расшифровке?
-(NSData *)dataDecryptedUsingAlgorithm:(CCAlgorithm)algorithm
data:(NSData *)data
key:(id)key
initializationVector:(id)iv
options:(CCOptions)options
error:(CCCryptorStatus *)error {
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;
NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]);
NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]);
NSMutableData * keyData, * ivData;
if ([key isKindOfClass: [NSData class]])
keyData = (NSMutableData *) [key mutableCopy];
else
keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
if ([iv isKindOfClass: [NSString class]])
ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
else
ivData = (NSMutableData *) [iv mutableCopy]; // data or nil
// [keyData autorelease];
// [ivData autorelease];
// ensure correct lengths for key and iv data, based on algorithms
FixKeyLengths(algorithm, keyData, ivData);
status = CCCryptorCreate(kCCDecrypt, algorithm, options,
[keyData bytes], [keyData length], [ivData bytes],
&cryptor);
if (status != kCCSuccess)
{
if (error != NULL)
*error = status;
return (nil);
}
NSData *result = [self runCryptor:cryptor onData:data result:&status];
if ((result == nil) && (error != NULL))
*error = status;
CCCryptorRelease(cryptor);
return (result);
}
-(NSData *)dataEncryptedUsingAlgorithm:(CCAlgorithm) algorithm
data:(NSData *)data
key:(id)key
initializationVector:(id)iv
options:(CCOptions)options
error:(CCCryptorStatus *)error {
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;
NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]);
NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]);
NSMutableData * keyData, * ivData;
if ([key isKindOfClass: [NSData class]])
keyData = (NSMutableData *) [key mutableCopy];
else
keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
if ([iv isKindOfClass: [NSString class]])
ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
else
ivData = (NSMutableData *) [iv mutableCopy]; // data or nil
// [keyData autorelease];
// [ivData autorelease];
// ensure correct lengths for key and iv data, based on algorithms
FixKeyLengths(algorithm, keyData, ivData);
status = CCCryptorCreate(kCCEncrypt, algorithm, options,
[keyData bytes], [keyData length], [ivData bytes],
&cryptor);
if (status != kCCSuccess)
{
if (error != NULL)
*error = status;
return (nil);
}
NSData *result = [self runCryptor:cryptor onData:data result:&status];
if ((result == nil) && (error != NULL))
*error = status;
CCCryptorRelease(cryptor);
return (result);
}
-(NSData *)runCryptor:(CCCryptorRef)cryptor onData:(NSData *)data result:(CCCryptorStatus *)status {
size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[data length], true);
void * buf = malloc(bufsize);
size_t bufused = 0;
size_t bytesTotal = 0;
*status = CCCryptorUpdate(cryptor, [data bytes], (size_t)[data length],
buf, bufsize, &bufused);
if (*status != kCCSuccess)
{
free(buf);
return (nil);
}
bytesTotal += bufused;
// From Brent Royal-Gordon (Twitter: architechies):
// Need to update buf ptr past used bytes when calling CCCryptorFinal()
*status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);
if (*status != kCCSuccess)
{
free(buf);
return (nil);
}
bytesTotal += bufused;
return ([NSData dataWithBytesNoCopy: buf length: bytesTotal]);
}
Когда я называю шифровать и расшифровывать методы, я передаю в kCCAlgorithmAES128
как мой алгоритм, и kCCOptionPKCS7Padding
как мои варианты. Есть ли способ поймать, когда для дешифрования используется плохая клавиша, поэтому я могу вернуть соответствующую ошибку?
Лично мне нравится KCV (значения проверки ключа), поскольку они дают вам некоторое представление о том, что может быть неправильным. Но KCV также может стать поврежденным, поэтому вы по-прежнему не можете отличить плохой ключ от поврежденных данных. См. Также мой вопрос [здесь] (http://crypto.stackexchange.com/q/1930/1172). Обратите внимание, что ваш протокол использует KCV и MAC - просто добавление KCV недостаточно, вы должны сделать это ясно в своем ответе. –
Поскольку я уже использовал HKDF-Expand для генерации других материалов для ввода ключей, казалось естественным продолжить процесс и использовать его для создания валидатора. Однако я был бы рад услышать любые предлагаемые улучшения в формате. Хотя верно, что валидатор (или KCV) сам по себе может быть поврежден, он по-прежнему представляет собой значительную выгоду для больших сообщений, которые могут потребовать значительного времени для проверки HMAC, и для которых коррупция вне валидатора гораздо более вероятна (но неправильный пароль даже если * больше * наверняка). Валидатор также недвусмыслен, если он проверяет, но HMAC терпит неудачу. –
Я доволен токеном проверки. И да, использование KDF для создания токена проверки является, очевидно, хорошей идеей, и тогда я бы, конечно, сам выбрал HKDF. Маркер проверки является лучшим именем, чем KCV, поскольку вычисление напрямую не связано с самим ключом. –