проблема длины ключа шифрования iPhone 3DES

Я ударял по голове на стене с этим. Я должен кодировать свое приложение для iPhone для шифрования 4 использований "контакта" цифры 3DES в режиме ЕЦБ для передачи к веб-сервису, которому я верю, записан в.NET.

+ (NSData *)TripleDESEncryptWithKey:(NSString *)key dataToEncrypt:(NSData*)encryptData {
NSLog(@"kCCKeySize3DES=%d", kCCKeySize3DES);
char keyBuffer[kCCKeySize3DES+1]; // room for terminator (unused)
bzero( keyBuffer, sizeof(keyBuffer) ); // fill with zeroes (for padding)

[key getCString: keyBuffer maxLength: sizeof(keyBuffer) encoding: NSUTF8StringEncoding];

// encrypts in-place, since this is a mutable data object
size_t numBytesEncrypted = 0;

size_t returnLength = ([encryptData length] + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);

// NSMutableData* returnBuffer = [NSMutableData dataWithLength:returnLength];
char* returnBuffer = malloc(returnLength * sizeof(uint8_t) );

CCCryptorStatus ccStatus = CCCrypt(kCCEncrypt, kCCAlgorithm3DES , kCCOptionECBMode,
                                 keyBuffer, kCCKeySize3DES, nil,
                                 [encryptData bytes], [encryptData length], 
                                 returnBuffer, returnLength,
                                 &numBytesEncrypted);

if (ccStatus == kCCParamError) NSLog(@"PARAM ERROR");
else if (ccStatus == kCCBufferTooSmall) NSLog(@"BUFFER TOO SMALL");
else if (ccStatus == kCCMemoryFailure) NSLog(@"MEMORY FAILURE");
else if (ccStatus == kCCAlignmentError) NSLog(@"ALIGNMENT");
else if (ccStatus == kCCDecodeError) NSLog(@"DECODE ERROR");
else if (ccStatus == kCCUnimplemented) NSLog(@"UNIMPLEMENTED");

if(ccStatus == kCCSuccess) {
    NSLog(@"TripleDESEncryptWithKey encrypted: %@", [NSData dataWithBytes:returnBuffer length:numBytesEncrypted]);
    return [NSData dataWithBytes:returnBuffer length:numBytesEncrypted];
}
else 
    return nil;
} }

Я действительно добираюсь, значение зашифровало использование вышеупомянутого кода, однако это не соответствует значению от веб-сервиса.NET.

Я полагаю, что проблема - то, что ключ шифрования, я был предоставлен разработчиками веб-сервиса, является 48 символами долго.

Я вижу, что iPhone SDK постоянный "kCCKeySize3DES" равняется 24. Таким образом, я ПОДОЗРЕВАЮ, но не знаю, что commoncrypto вызов API только использует первые 24 символа предоставленного ключа.

Это корректно?

Есть ли КАКОЙ-ЛИБО способ, которым я могу заставить это генерировать корректный зашифрованный контакт? Я произвел байты данных от шифрования ДО base64, кодирующего его, и попытался соответствовать этому против сгенерированных из кода.NET (с помощью разработчика.NET, который отправил вывод массива байтов мне). Ни non-base64 не закодировал массив байтов, ни финал base64 закодированное строковое соответствие.

6
задан Russell Hill 16 March 2010 в 13:37
поделиться

3 ответа

3DES - это симметричный блочный шифр. Используя 24-байтовый ключ, 3DES шифрует 8-байтовый блок в другой 8-байтовый блок. С тем же 24-байтовым ключом шифрование обратимо (т.е. можно расшифровать).

Ключ - это произвольная последовательность байтов. Это не то же самое, что «персонажи». В частности, совершенно законно иметь один из этих байтов со значением ноль. Точно так же ввод и вывод могут быть произвольными байтами.

Если предоставленный вам ключ состоит из «символов», то он должен быть каким-то образом преобразован в соответствующую последовательность байтов. Поскольку у вас есть 48-символьная «строка ключей», а 48 - это ровно 24 * 2, можно предположить, что ключ задан в шестнадцатеричной системе счисления: посмотрите, содержит ли он только цифры и буквы от «a» до «f».

Что касается заполнения: 3DES шифрует только 8-байтовые блоки. Когда «сообщение» должно быть зашифровано и имеет длину, отличную от 8 байтов, обычно форматируют, разбивают и обрабатывают сообщение так, чтобы его можно было зашифровать в нескольких вызовах 3DES. Два ключевых слова - это padding и chaining . Заполнение - это добавление некоторых дополнительных байтов в конце (таким образом, чтобы эти байты можно было однозначно удалить), чтобы длина была подходящей (например,кратно 8). Цепочка - это решение, что именно входит в каждый вызов 3DES (простое разделение дополненного сообщения на независимо зашифрованные блоки известно как «ECB» и имеет слабые места).

Если ваш PIN-код состоит из 4 цифр, тогда должно быть какое-то соглашение о том, как эти четыре цифры становятся как минимум 8 байтами для подачи в 3DES. Если iPhone ведет себя аналогично тому, что описано на этой странице руководства для MacOS X , то ваш код не должен работать успешно, если длина encryptData не кратна восьми. Это означает, что код, который вы не показываете, который преобразует 4-значный PIN-код в 8-байтовый буфер, уже выполняет некоторые нетривиальные преобразования. Например, этот код может поместить четыре цифры в четыре байта (с использованием кодировки ASCII) и установить четыре других байта в ноль. Или, может быть, этого не происходит. В любом случае важен каждый из 64 входных битов для 3DES, и вы должны получать его точно так же, как и сервер. Вам также следует изучить этот код.

4
ответ дан 17 December 2019 в 00:07
поделиться

Что ж, мне удалось решить эту проблему с помощью большого количества чтения и комментариев по stackoverflow. Там где несколько вопросов. Ключ, который мне дали разработчики .NET, состоял из 48 символов. Это, конечно, нужно было читать как шестнадцатеричную строку и вместо этого преобразовывать до 24 символов.

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

+ (NSString *)doCipher3DES:(NSString *)sTextIn key:(NSString *)sKey {
NSMutableData * dTextIn;
CCCryptorStatus ccStatus = kCCSuccess;

// need to add 4 zeros as sTextIn will be a 4 digit PIN
sTextIn = [sTextIn stringByAppendingString:@"0000"];

// convert to data
dTextIn = [[sTextIn dataUsingEncoding: NSASCIIStringEncoding] mutableCopy];           

// key will be a 48 char hex stream, so process it down to 24 chars
const char * bytes = [sKey cStringUsingEncoding: NSUTF8StringEncoding];
NSUInteger length = strlen(bytes);
unsigned char * r = (unsigned char *) malloc(length / 2 + 1);
unsigned char * index = r;

while ((*bytes) && (*(bytes +1))) {
    *index = strToChar(*bytes, *(bytes +1));
    index++;
    bytes+=2;
}
*index = '\0';

NSData *dKey = [NSData dataWithBytes: r length: length / 2];
free(r);

NSLog(@"doCipher3DES - key: %@", dKey);

uint8_t *bufferPtr1 = NULL;    
size_t bufferPtrSize1 = 0;    
size_t movedBytes1 = 0;    
uint8_t iv[kCCBlockSize3DES];    
memset((void *) iv, 0x0, (size_t) sizeof(iv));    
bufferPtrSize1 = ([sTextIn length] + kCCBlockSize3DES) & ~(kCCBlockSize3DES -1);    
bufferPtr1 = malloc(bufferPtrSize1 * sizeof(uint8_t));    
memset((void *)bufferPtr1, 0x00, bufferPtrSize1);    

ccStatus = CCCrypt(kCCEncrypt, // CCOperation op    
                   kCCAlgorithm3DES, // CCAlgorithm alg    
                   kCCOptionECBMode, // CCOptions options    
                   (const void *)[dKey bytes], // const void *key    
                   kCCKeySize3DES, // size_t keyLength    
                   nil, // const void *iv    
                   (const void *)[dTextIn bytes], // const void *dataIn
                   [dTextIn length],  // size_t dataInLength    
                   (void *)bufferPtr1, // void *dataOut    
                   bufferPtrSize1,     // size_t dataOutAvailable 
                   &movedBytes1);      // size_t *dataOutMoved     

if (ccStatus == kCCParamError) NSLog(@"PARAM ERROR");
else if (ccStatus == kCCBufferTooSmall) NSLog(@"BUFFER TOO SMALL");
else if (ccStatus == kCCMemoryFailure) NSLog(@"MEMORY FAILURE");
else if (ccStatus == kCCAlignmentError) NSLog(@"ALIGNMENT");
else if (ccStatus == kCCDecodeError) NSLog(@"DECODE ERROR");
else if (ccStatus == kCCUnimplemented) NSLog(@"UNIMPLEMENTED");

NSString * sResult;    
NSData *dResult = [NSData dataWithBytes:bufferPtr1 length:movedBytes1];    

NSLog(@"doCipher3DES encrypted: %@", dResult);

sResult = [Base64 encode:dResult];    

return sResult; }

Код для strToChar следующий:

unsigned char strToChar (char a, char b) {
char encoder[3] = {'\0','\0','\0'};
encoder[0] = a;
encoder[1] = b;
return (char) strtol(encoder,NULL,16); }

Надеюсь, это кому-то поможет ...

2
ответ дан 17 December 2019 в 00:07
поделиться

Может нужно использовать отступы? Попробуйте установить следующие параметры:

(kCCOptionPKCS7Padding | kCCOptionECBMode)
1
ответ дан 17 December 2019 в 00:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: