вопрос длины ключа шифрования iPhone 3DES - PullRequest
6 голосов
/ 16 марта 2010

Я бился головой об стену с этим. Мне нужно закодировать приложение iPhone для шифрования 4-значного «пин-кода» с помощью 3DES в режиме ECB для передачи на веб-сервис, который, по моему мнению, написан на .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. Поэтому я ПОДТВЕРЖДАЮ, но не знаю, что вызов API commoncrypto использует только первые 24 символа предоставленного ключа.

Это правильно?

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

Ответы [ 3 ]

4 голосов
/ 16 марта 2010

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

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

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

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

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

2 голосов
/ 16 марта 2010

хорошо, мне удалось решить эту проблему с большим количеством чтения и комментариями здесь на 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 выглядит следующим образом:

* +1007 *

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

1 голос
/ 16 марта 2010

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

(kCCOptionPKCS7Padding | kCCOptionECBMode)
...