简体   繁体   中英

NSString from NSData always null

I would like to sign a request with HMAC SHA512, but I seem to mess up encoding and decoding from and to NSData and NSString. I desperately tried to figure out what is wrong, but I just don't seem to get it right.

PSEUDOCODE:

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);



My implementation:

+(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!");
}

Here is the signing method:

+(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];

}

Here is the hashing function:

+(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;

} 

I am pretty sure it is due to the encoding of the strings (decodedSecretString and dataString). decodedSecretString (decoded base64) after decoding is encoded in ASCII. However, when I call the hashing method, I encode it in ascii again, which will result in a null error. Everything is confusing me right now.

Your secret doesn't decode to a valid UTF-8 string, and Java allows NUL bytes in strings, but when you're converting "Test\\0Message" to a C string and using strlen, its length is 4.

Something like this should work:

+(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];
}

When doing HMAC or other cryptographic functions, you should build up some fundamental methods/functions that don't deal with strings first. Then you can create wrapper methods that decode/encode string data or digests in a convenient way.

+ (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]];
}

(Note: this code is not tested, just hacked together in a text editor)

Don't worry about the string representation of your key or data. Then you can go from there, eg getting the base64 encoding of the digest.

Cryptographic functions DO NOT CARE about strings or text encodings. They care about bytes. Strings (in C, since they are null-terminated) are a mere subset of what can be represented in data. So it would be severely limiting to deal with strings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM