Fazle Khan
Fazle Khan

Reputation: 55

SHA-1 encoding difference between Java and iOS/iPhone

We are trying to duplicate the sha1 crypto encoding done in our java 1.6 server with the iOS/iPhone CommonCrypto libraries.

A basic question I have is why does Java have a fix output of 40 bytes while iOS has a fix output of 20 bytes from the SHA1 algorithms

I have found this link which shows how to generate the encoding in both environments but the output would be of different lengths, correct?

How to SHA1 hash a string in Android?

Upvotes: 1

Views: 1996

Answers (3)

Moose
Moose

Reputation: 2737

Android or iOS, the SHA-1 has an expected length of 20 bytes.

But there is a difference in the sha-1 algorithm return.

iOS simply does not terminate the result with a null character.

So I guess the point is to not use the sha output length to generate the output data, but the CC_SHA1_DIGEST_LENGTH constant - which is 20.

uint8_t digest[CC_SHA1_DIGEST_LENGTH];
NSData* data = [stringToHash dataUsingEncoding:NSUTF8StringEncoding];
char* sha = CC_SHA1(data.bytes, data.length, digest);
NSData *hashedData = [NSData dataWithBytes:sha length:CC_SHA1_DIGEST_LENGTH];

If you terminate the digest yourself, then the sha output is correct:

uint8_t digest[CC_SHA1_DIGEST_LENGTH+1];
memset(digest,0,CC_SHA1_DIGEST_LENGTH+1);
NSData* data = [stringToHash dataUsingEncoding:NSUTF8StringEncoding];
char* sha = CC_SHA1(data.bytes, data.length, digest);
NSData *hashedData = [NSData dataWithBytes:sha length:strlen(sha)];

Hope it helps, cheers :)

Upvotes: 0

47tucanae
47tucanae

Reputation: 143

Yesterday i was facing exactly this problem, the sha1 algorithm implementation i was using, was not compatible with the android one, after more or less one hour searching on android and ios implementations, i realize it was only a problem of String Formating. (change X to x).

Im sharing the snippet of what we are using for sha1 algorithm implementation ios/android compatible ... Hope this helps as a version of @poupou theory answer :-).

public static String sha1(String s) {
    MessageDigest digest = null;
    try {
        digest = MessageDigest.getInstance("SHA-1");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    digest.reset();
    byte[] data = digest.digest(s.getBytes());
    return String.format("%0" + (data.length * 2) + "X", new BigInteger(1, data));
}


-(NSString*) sha1:(NSString*)input
{
    const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:input.length];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(data.bytes, data.length, digest);
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02X", digest[i]];
    return output;

}

Upvotes: 0

poupou
poupou

Reputation: 43553

The SHA1 algorithm always return 160 bits (or 20 bytes).

I suspect your Java code is turning the byte array into a hexadecimal string, i.e. where each byte would show as two characters.

To compare this with CommonCrypto you can either:

  • convert the Java output to a byte array; or

  • convert the CommonCrypto byte array to an hexadecimal string (this is what the link in your question is doing)

before comparing the values.

Upvotes: 2

Related Questions