Я новичок в криптографии, и я создаю некоторые тестовые приложения, чтобы попытаться понять основы этого. Я не пытаюсь строить алгоритмы с нуля, но я пытаюсь сделать два разных варианта реализации AES-256 друг с другом.
У меня есть база данных, которая была заполнена эта реализация Javascript, хранящаяся в Base64. Теперь я пытаюсь получить метод Objective-C для расшифровки его содержимого, но я немного потерял, где различия в реализациях. Я могу зашифровать/дешифровать в Javascript, и я могу зашифровать/расшифровать в Cocoa, но не могу сделать строку, зашифрованную в Javascript, расшифрованной в Cocoa или наоборот.
Я предполагаю, что это связано с вектором инициализации, nonce, встречным режимом работы или всем этим, что, откровенно говоря, не говорит мне в данный момент.
Здесь то, что я использую в Objective-C, адаптировано в основном из this и this:
@implementation NSString (Crypto)
- (NSString *)encryptAES256:(NSString *)key {
NSData *input = [self dataUsingEncoding: NSUTF8StringEncoding];
NSData *output = [NSString cryptoAES256:input key:key doEncrypt:TRUE];
return [Base64 encode:output];
}
- (NSString *)decryptAES256:(NSString *)key {
NSData *input = [Base64 decode:self];
NSData *output = [NSString cryptoAES256:input key:key doEncrypt:FALSE];
return [[[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding] autorelease];
}
+ (NSData *)cryptoAES256:(NSData *)input key:(NSString *)key doEncrypt:(BOOL)doEncrypt {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256 + 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 = [input 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 why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);
size_t numBytesCrypted = 0;
CCCryptorStatus cryptStatus =
CCCrypt(doEncrypt ? kCCEncrypt : kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionECBMode | kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
nil, // initialization vector (optional)
[input bytes], dataLength, // input
buffer, bufferSize, // output
&numBytesCrypted
);
if (cryptStatus == kCCSuccess) {
// the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
}
free(buffer); // free the buffer;
return nil;
}
@end
Конечно, вход Base64 декодирован заранее.
Я вижу, что каждое шифрование с одним и тем же содержимым в Javascript дает другую зашифрованную строку, что не соответствует реализации Objective-C, которая всегда дает ту же зашифрованную строку. Я прочитал ответы этого сообщения, и это заставляет меня думать, что я прав насчет чего-то в соответствии с инициализацией вектора, но мне нужна ваша помощь, чтобы определить, что точно.
Спасибо!
Yup, существует ряд различий между двумя реализациями.
Реализация Javascript использует режим CTR, в то время как реализация Objective-C использует режим ECB (ECB слаб и не должен использоваться.)
В реализации Javascript используется расширение ключа. То есть он преобразует ключ перед передачей его в код AES. Не уверен в реализации Objective-C. В любом случае, вы можете почти быть уверены, что две реализации не используют один и тот же ключ для шифрования.
Реализация Javascript использует текущее время для генерации 8-байтового IV, который добавляется к зашифрованному тексту. Этот IV используется для инициализации счетчика для режима CTR. Из-за изменений IV, шифрование одного и того же открытого текста приведет к разным зашифрованным текстам. Также использование текущего времени для генерации режима IV для CTR в порядке, если вы не зашифровываете два зашифрованных текста в течение одного такта tick(). Реализация Objective-C не использует IV (поскольку использует режим ECB).
В коде Objective-C используется дополнение PKCS # 7, код Javascript не использует его. Это является следствием использования различных режимов шифрования.
Кроме того, вам также нужно проверить, как кодируется шифрованный текст. Код Javascript использует кодировку Base64. Код Objective-C слишком много распределен по нескольким сообщениям, что я не нашел соответствующий код.
kCCAlgorithmAES128
, но в вашем тексте говорится, что вы пытаетесь реализовать AES-256. Вы случайно используете блок меньшего размера?
Для тестирования вам следует использовать тестовые значения из сайта NIST для AES и FIPS 197.