1

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?

Community
  • 1
  • 1
Fazle Khan
  • 55
  • 6
  • That is an untrue statement of iOS. SHA1 *must* have a 40 byte size. You should post your relevant code. – vcsjones Jan 19 '12 at 21:07
  • @vcsjones, SHA1 is *20bytes* in length, if you look at hexdump - 40. yet SHA or whatever hashing has nothing to do w/ hex. – bestsss Jan 19 '12 at 21:27
  • @bestsss Bha, lost my mind. Can't fix it now. Yes, **20** bytes is correct. – vcsjones Jan 19 '12 at 21:33

3 Answers3

2

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.

poupou
  • 43,413
  • 6
  • 77
  • 174
  • Our iphone developer found the bug in his code and the linked example from the initial post do in fact work. Thanks for the help! – Fazle Khan Jan 20 '12 at 16:40
  • Is is possible to take a fix in iOS/iPhone? If i convert my SHA1 output to byte array or any other way??? – DShah Jul 20 '12 at 14:38
0

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;

}
47tucanae
  • 133
  • 2
  • 8
  • When input is a unicode string containing curly quotes (for example), the objC sha1 method above returns the wrong sha1 value. To fix this, replace the first two lines of this method with NSData *data = [input dataUsingEncoding: NSUTF8StringEncoding]; – lifjoy Feb 08 '14 at 04:08
0

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

Moose
  • 2,607
  • 24
  • 23