tonistair
tonistair

Reputation: 53

iOS/Objective C: SHA-1 and Base64

I have to convert the phrase '1234' into the Base64-encoding of its SHA-1 hash.

I want to have: '1234' = cRDtpNCeBiql5KOQsKVyrA0sAiA= (This example work in connection with the server communication)...

But when I checked it manualley on these sites or use my Methods in my XCode Project the result is always different:

1234

After SHA-1 (http://www.sha1.cz/) 7110eda4d09e062aa5e4a390b0a572ac0d2c0220

After Base64 (http://base64-encoder-online.waraxe.us/) NzExMGVkYTRkMDllMDYyYWE1ZTRhMzkwYjBhNTcyYWMwZDJjMDIyMA==

This is my SHA-1 function:

- (NSString *)sha1:(NSString *)str {
    const char *cStr = [str UTF8String];
    unsigned char result[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(cStr, strlen(cStr), result);
    NSString *s = [NSString  stringWithFormat:
                   @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                   result[0], result[1], result[2], result[3], result[4],
                   result[5], result[6], result[7],
                   result[8], result[9], result[10], result[11], result[12],
                   result[13], result[14], result[15],
                   result[16], result[17], result[18], result[19]
                   ];

    return [s lowercaseString];
}

For Base64 I use a this class: http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html

This is the call of SHA-1 and Base64:

 NSString *pwHash =[self sha1:self._txtFieldPW.text]; //In my case '1234'
 NSLog(@"Hash: %@",pwHash); //7110eda4d09e062aa5e4a390b0a572ac0d2c0220
 //7110eda4d09e062aa5e4a390b0a572ac0d2c0220
 NSData *pwHashData = [[NSData alloc]initWithData:[pwHash dataUsingEncoding:1]];
 NSString *base64 = [pwHashData base64Encoding];
 NSLog(@"Base64: %@",base64); 
 //NzExMGVkYTRkMDllMDYyYWE1ZTRhMzkwYjBhNTcyYWMwZDJjMDIyMA==

What is going wrong?

Upvotes: 2

Views: 4136

Answers (1)

Seva Alekseyev
Seva Alekseyev

Reputation: 61396

Hash is a binary value. The "cRDtpNCeBiql5KOQsKVyrA0sAiA=" string is a result of the binary value of the hash, encoded. Meanwhile, the "NzExMGVkYTRkMDllMDYyYWE1ZTRhMzkwYjBhNTcyYWMwZDJjMDIyMA==" string is the result of the Base64 transform on the hexadecimal presentation of the hash.

Did that make sense? So you have a SHA1 hash, an array of 20 bytes: {0x71, 0x10, ...}. You can Base64-encode that chunk of memory as it is. Or you can convert each byte into two lowercase hex digits, then you'll get the ASCII string "7110eda4d09e062aa5e4a390b0a572ac0d2c0220". If you apply Base64 encoding to that string, as opposed to the original hash bytes, you'll get the Base64 value "NzExMGV...".

EDIT, with extra binary goodness: reformulate the second snippet thus:

unsigned char result[CC_SHA1_DIGEST_LENGTH]; 
const char *cStr = [self._txtFieldPW.text UTF8String];
CC_SHA1(cStr, strlen(cStr), result); //Now result contains the hash

//Wrap the result in a NSData object
NSData *pwHashData = [[NSData alloc] initWithBytes:result length: sizeof result];  
//And take Base64 of that
NSString *base64 = [pwHashData base64Encoding];  
NSLog(@"Base64: %@",base64); 

And get rid of the sha1 method. Once you remove the monstrous stringWithFormat call, it's a two-liner. If you really want the hex hash in the log, be my guest; but don't treat the hex string as the true value of the hash, 'cause it's not.

Unless you're using ARC, don't forget to free the NSData object afterwards.

Upvotes: 9

Related Questions