Зашифруйте и расшифруйте случайную строку NSString с помощью CES AES128 в iOS с заданным ключом
Я не уверен, насколько безопасно мое решение.
Rob Napier имеет необычную платформу ( RNCryptor) для шифрования и дешифрования в iOS и других системах.
Насколько я знаю, он использует AES-CBC, что на самом деле является стандартом CommonCryptor.h
Однако мои требования заставили меня использовать AES-CTR. Оба действительно похожи, поэтому в теории это должно было быть что-то легкое. Но не было.
Недостаточно информации вокруг CommonCryptor.h. Это одна из худших объясненных структур за всю историю.
Работая с CBC, вам просто нужно позвонить CCCrypt()
, Однако для работы с CTR вам необходимо позвонить: CCCrytorCreate()
, CCCryptorUpdate()
, CCCryptorFinal(
) а также CCCryptorRelease()
Пытаясь зашифровать свои данные, я каждый раз получал разные данные, разумеется, расшифровка приводила к неверным результатам.
У меня было две большие проблемы в первом подходе: длина ключа и количество байтов, записанных в dataOut.
Я разобрал проблемы с:
1.- NSString ключ из 32 символов
NSString *key = @"1234567890ABCDEFGHIJKLMNOPQRSTUV";
2.- Чтобы вырезать данные с необходимой длины
Наконец, это мой код для шифрования и дешифрования:
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonKeyDerivation.h>
#import <Security/Security.h>
+ (NSMutableData*) encryptString: (NSString*) stringToEncrypt withKey: (NSString*) keyString
{
//Key to Data
NSData *key = [keyString dataUsingEncoding:NSUTF8StringEncoding];
//String to encrypt to Data
NSData *data = [stringToEncrypt dataUsingEncoding:NSUTF8StringEncoding];
// Init cryptor
CCCryptorRef cryptor = NULL;
// Alloc Data Out
NSMutableData *cipherData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];
//Empty IV: initialization vector
NSMutableData *iv = [NSMutableData dataWithLength:kCCBlockSizeAES128];
//Create Cryptor
CCCryptorStatus create = CCCryptorCreateWithMode(kCCEncrypt,
kCCModeCTR,
kCCAlgorithmAES,
ccPKCS7Padding,
iv.bytes, // can be NULL, because null is full of zeros
key.bytes,
key.length,
NULL,
0,
0,
kCCModeOptionCTR_BE,
&cryptor);
if (create == kCCSuccess)
{
//alloc number of bytes written to data Out
size_t outLength;
//Update Cryptor
CCCryptorStatus update = CCCryptorUpdate(cryptor,
data.bytes,
data.length,
cipherData.mutableBytes,
cipherData.length,
&outLength);
if (update == kCCSuccess)
{
//Cut Data Out with nedded length
cipherData.length = outLength;
//Final Cryptor
CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
cipherData.mutableBytes, //void *dataOut,
cipherData.length, // size_t dataOutAvailable,
&outLength); // size_t *dataOutMoved)
if (final == kCCSuccess)
{
//Release Cryptor
//CCCryptorStatus release =
CCCryptorRelease(cryptor ); //CCCryptorRef cryptorRef
}
return cipherData;
}
}
else
{
//error
}
return nil;
}
+ (NSString*) decryptData: (NSData*) data withKey: (NSString*) keyString
{
//Key to Data
NSData *key = [keyString dataUsingEncoding:NSUTF8StringEncoding];
// Init cryptor
CCCryptorRef cryptor = NULL;
//Empty IV: initialization vector
NSMutableData *iv = [NSMutableData dataWithLength:kCCBlockSizeAES128];
// Create Cryptor
CCCryptorStatus createDecrypt = CCCryptorCreateWithMode(kCCDecrypt, // operation
kCCModeCTR, // mode CTR
kCCAlgorithmAES, // Algorithm
ccPKCS7Padding, // padding
iv.bytes, // can be NULL, because null is full of zeros
key.bytes, // key
key.length, // keylength
NULL, //const void *tweak
0, //size_t tweakLength,
0, //int numRounds,
kCCModeOptionCTR_BE, //CCModeOptions options,
&cryptor); //CCCryptorRef *cryptorRef
if (createDecrypt == kCCSuccess)
{
// Alloc Data Out
NSMutableData *cipherDataDecrypt = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];
//alloc number of bytes written to data Out
size_t outLengthDecrypt;
//Update Cryptor
CCCryptorStatus updateDecrypt = CCCryptorUpdate(cryptor,
data.bytes, //const void *dataIn,
data.length, //size_t dataInLength,
cipherDataDecrypt.mutableBytes, //void *dataOut,
cipherDataDecrypt.length, // size_t dataOutAvailable,
&outLengthDecrypt); // size_t *dataOutMoved)
if (updateDecrypt == kCCSuccess)
{
//Cut Data Out with nedded length
cipherDataDecrypt.length = outLengthDecrypt;
// Data to String
NSString* cipherFinalDecrypt = [[NSString alloc] initWithData:cipherDataDecrypt encoding:NSUTF8StringEncoding];
//Final Cryptor
CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
cipherDataDecrypt.mutableBytes, //void *dataOut,
cipherDataDecrypt.length, // size_t dataOutAvailable,
&outLengthDecrypt); // size_t *dataOutMoved)
if (final == kCCSuccess)
{
//Release Cryptor
//CCCryptorStatus release =
CCCryptorRelease(cryptor); //CCCryptorRef cryptorRef
}
return cipherFinalDecrypt;
}
}
else
{
//error
}
return nil;
}
Чтобы назвать это:
NSString *key = @"1234567890ABCDEFGHIJKLMNOPQRSTUV";
NSString *stringToEncrypt = @"Gabriel.Massana";
NSData* encrypted = [GM_AES128_CTR encryptString:stringToEncrypt withKey:key];
NSString *decrypted = [GM_AES128_CTR decryptData:encrypted withKey:key];
Я публикую свое решение, потому что для AES CTR не так много вопросов в Stackru. Кроме того, если кто-то хочет проверить это и сказать мне, если что-то не так, будет очень признателен.
Насколько безопасно это решение? Легко взломать систему? Каковы мои возможности для повышения безопасности AES-CTR?
1 ответ
Я перечисляю это как отдельный ответ, но я только усиливаю то, что уже сказал Заф:
Это полностью сломанное шифрование.
Не удивительно, что это случилось с вами. Это очень распространенная проблема, когда вы пытаетесь построить свою собственную схему. Есть только много мест, где вы можете испортить. Но я не хочу преуменьшать, насколько небезопасна эта схема. Это действительно, действительно сломано.
CTR никогда не может повторять один и тот же ключ nonce+, и вы каждый раз повторно используете nonce. Это очень отличается от CBC. В CBC, если вы повторно используете IV, то злоумышленнику будет несколько проще взломать ваше шифрование. В CTR, если вы повторно используете ключ nonce+, довольно легко расшифровать сообщение, если у вас есть несколько зашифрованных текстов. Некоторое хорошее обсуждение можно найти в RFC3686.
При правильном использовании AES-CTR обеспечивает высокий уровень конфиденциальности. К сожалению, AES-CTR легко использовать неправильно. Будучи потоковым шифром, любое повторное использование значения для пакета, называемого IV, с тем же одноразовым номером и ключом является катастрофическим. Столкновение IV немедленно пропускает информацию о незашифрованном тексте в обоих пакетах. По этой причине нецелесообразно использовать этот режим работы со статическими ключами. Необходимы чрезвычайные меры для предотвращения повторного использования значения IV со статическим ключом в циклах питания. Для безопасности реализации ДОЛЖНЫ использовать свежие ключи с AES-CTR. Протокол Internet Key Exchange (IKE) [IKE] может использоваться для установки свежих ключей. IKE также может предоставить значение nonce.
Обратите внимание, что RNCryptor изначально использовал CTR. Я вернулся в CBC по рекомендации Apple, после того, как поговорил с ними о том, как тяжело испортить CTR. Если вы можете избежать CTR, вы обязательно должны. Это чрезвычайно полезно для определенных проблем, но для общего шифрования файлов это редко подходит.
Тем не менее, я понимаю, у вас есть проблема в чипе. Как ваш чип получит свой ключ? Кажется странным использовать симметричное шифрование с чипом таким способом. В любом случае RNCryptor v1 может удовлетворить ваши потребности. Вы, вероятно, должны использовать encryptFromStream:toStream:encryptionKey:HMACKey:error:
так как я предполагаю, что чип не может обрабатывать PBKDF2.
Пытаясь зашифровать свои данные, я каждый раз получал разные данные, разумеется, расшифровка приводила к неверным результатам.
Любая хорошая система шифрования будет иметь это свойство. Вот почему вам нужно отправить ваш nonce/IV (и если вы используете пароли, соли) вместе с зашифрованным текстом.
NSString * key = @ "1234567890ABCDEFGHIJKLMNOPQRSTUV";
Это не ключ. Это пароль, который значительно сокращает доступное пространство ключей. Ключи, как правило, будут NSData
поскольку их нужно выбирать среди всех возможных значений, а не только в ASCII.