NSString из NSData всегда равен нулю

Я хотел бы подписать запрос с помощью HMAC SHA512, но я, кажется, испортил кодирование и декодирование из и в NSData и NSString. Я отчаянно пытался понять, что не так, но я просто не понимаю, что правильно.

ПСЕВДОКОД:

function hmac_512(msg, sec) {
    sec = Base64Decode(sec);
    result = hmac(msg, sec, sha512);
    return Base64Encode(result);
}


secret = "7pgj8Dm6";
message = "Test\0Message";

result = hmac_512(message, secret);
if (result == "69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==")
    print("Success!");
else
    printf("Error: %s", result);



Моя реализация:

+(void)doSomeMagic{

    NSString *message = @"Test\0Message";
    NSString *signedRequest = [self signRequestForParameterString:message];

    //checking against CORRECT (from JAVA equivalent) signed request 
    if ([signedRequest isEqualToString:@"69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==" ])
        NSLog(@"Success!");
    else
        NSLog(@"Error!");
}

Вот метод подписи:

+(NSString *)signRequestForParameterString:(NSString*)paramStr{

    NSString *secret = @"7pgj8Dm6";

    // secret is base64 encoded, so I decode it 
    NSData *decodedSecret = [secret base64DecodedData];
    NSString *decodedSecretString = [NSString stringWithUTF8String:[decodedSecret bytes]];

    NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
    NSString *dataString = [NSString stringWithUTF8String:[data bytes]];


    return [self generateHMACSHA512Hash:decodedSecretString data:dataString];

}

Вот функция хеширования:

+(NSString *)generateHMACSHA512Hash:(NSString *)key data:(NSString *)data{


    const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];

    unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];

    CCHmac(kCCHmacAlgSHA512, cKey, strlen(cKey), cData, strlen(cData), cHMAC);

    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC
                                          length:sizeof(cHMAC)];

    NSString *hash = [HMAC base64EncodedString];

    return hash;

} 

Я почти уверен, что это связано с кодировкой строк (decodedSecretString и dataString). decodedSecretString (декодированный base64) после декодирования кодируется в ASCII. Однако, когда я вызываю метод хеширования, я снова кодирую его в ascii, что приводит к нулевой ошибке. Меня все сейчас смущает.


person the_critic    schedule 29.11.2013    source источник
comment
Это много кода для проверки. Разве вы не можете немного отладить его и выяснить, что именно идет не так?   -  person Hot Licks    schedule 29.11.2013
comment
Если ваш секрет закодирован в Base64, вам следует просто декодировать его и передать декодированные NSData в вашу функцию HMAC. Не превращайте его обратно в строку.   -  person John Cromartie    schedule 29.11.2013
comment
Почему вы переходите от NSString к NSData обратно к NSString в +signRequestForParameterString:, когда он будет просто возвращен в массив байтов в методе HMAC? В чем смысл этого? Просто передайте строку методу HMAC. И вам, вероятно, следует придерживаться UTF8, а не ASCII, если только вы не знаете, что у вас есть текст ASCII, а сервер не может понять UTF-8.   -  person John Cromartie    schedule 29.11.2013


Ответы (2)


Ваш секрет не декодируется в допустимую строку UTF-8, а Java допускает байты NUL в строках, но когда вы конвертируете «Test\0Message» в строку C и используете strlen, ее длина равна 4.

Что-то вроде этого должно работать:

+(NSString *)signRequestForParameterString:(NSString*)paramStr{
    NSString *secret = @"7pgj8Dm6";
    NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
    return [self generateHMACSHA512Hash:[secret base64DecodedData] data:data];
}

+(NSString *)generateHMACSHA512Hash:(NSData *)key data:(NSData *)data{
    unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA512, key.bytes, key.length, data.bytes, data.length, cHMAC);
    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
    return [HMAC base64EncodedString];
}
person Jesús A. Álvarez    schedule 29.11.2013
comment
Невероятный! Большое спасибо! - person the_critic; 29.11.2013

При выполнении HMAC или других криптографических функций вы должны создать некоторые фундаментальные методы/функции, которые в первую очередь не работают со строками. Затем вы можете создавать методы-оболочки, которые декодируют/кодируют строковые данные или дайджесты удобным способом.

+ (NSData *)dataBySigningData:(NSData *)data withKey:(NSData *)key
{
  unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
  CCHmac(kCCHmacAlgSHA512, [key bytes], [key length], [data bytes], [data lenght], cHMAC);
  return [[NSData alloc] initWithBytes:cHMAC length:CC_SHA512_DIGEST_LENGTH];
}

+ (NSData *)dataBySigningMessage:(NSString *)message withKey:(NSData *)key
{
  return [self dataBySigningData:[message dataUsingEncoding:NSUTF8StringEncoding]
                         withKey:[key dataUsingEncoding:NSUTF8StringEncoding]];
}

(Примечание: этот код не тестировался, он просто собран в текстовом редакторе)

Не беспокойтесь о строковом представлении вашего ключа или данных. Затем вы можете пойти оттуда, например. получение кодировки base64 дайджеста.

Криптографические функции НЕ ЗАБОТИТСЯ о строках или текстовых кодировках. Они заботятся о байтах. Строки (в C, поскольку они заканчиваются нулем) — это просто подмножество того, что может быть представлено в данных. Таким образом, было бы строго ограничено иметь дело со строками.

person John Cromartie    schedule 29.11.2013