59

The Security services API doesn't appear to allow me to compute a hash directly. There are plenty of public domain and liberally licensed versions available, but I'd rather use a system library implementation if possible.

The data is accessible via NSData, or plain pointers.

The cryptographic strength of the hash is important to me. SHA-256 is the minimum acceptable hash size.

James
  • 24,676
  • 13
  • 84
  • 130

6 Answers6

81

This is what I'm using for SHA1:

#import <CommonCrypto/CommonDigest.h>

+ (NSData *)sha1:(NSData *)data {
    unsigned char hash[CC_SHA1_DIGEST_LENGTH];
    if ( CC_SHA1([data bytes], [data length], hash) ) {
        NSData *sha1 = [NSData dataWithBytes:hash length:CC_SHA1_DIGEST_LENGTH];        
        return sha1;
    }
return nil;
}

Replace CC_SHA1 with CC_SHA256 (or whichever you need), as well as CC_SHA1_DIGEST_LENGTH with CC_SHA256_DIGEST_LENGTH.

Albert Renshaw
  • 17,282
  • 18
  • 107
  • 195
alex-i
  • 5,406
  • 2
  • 36
  • 56
  • This didn't work.. converting the returned data to an NSString returned nil for me. The post below "hashed_string" worked if I passed in the data. – TheJeff Nov 02 '16 at 22:02
  • @TheJeff - The question doesn't say anything about returning the SHA value as a hexadecimal string. Converting `NSData` to `NSString` can be a separate question on its own. – alex-i Nov 03 '16 at 08:52
  • @alex-i, you are right, the NSData comes back, however the conversion to string I was mentioning does not work - you have to use the method that EgeAkpinar proposed below. I'm still curious what and how that works, however like you said that isn't the purpose of this post. – TheJeff Nov 03 '16 at 22:34
  • Swift version for this? – Jayprakash Dubey Jul 13 '17 at 09:30
35

Here's a pretty similar one based on NSString

+ (NSString *)hashed_string:(NSString *)input
{
    const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:input.length];
    uint8_t digest[CC_SHA256_DIGEST_LENGTH];

    // This is an iOS5-specific method.
    // It takes in the data, how much data, and then output format, which in this case is an int array.
    CC_SHA256(data.bytes, data.length, digest);

    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];

    // Parse through the CC_SHA256 results (stored inside of digest[]).
    for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
        [output appendFormat:@"%02x", digest[i]];
    }

    return output;
}

(Credits go to http://www.raywenderlich.com/6475/basic-security-in-ios-5-tutorial-part-1)

Ege Akpinar
  • 3,266
  • 1
  • 23
  • 29
  • 4
    for iOS 7+ you to cast the data.length: CC_SHA256(data.bytes, (int)data.length, digest); – RyanG Jul 17 '14 at 14:31
  • data should be `[NSData dataWithBytes:cstr length:strlen(cstr)];` It'd be better to use `[input dataUsingEncoding:NSUTF8StringEncoding];` – mikeytdan May 26 '16 at 19:53
3

This is what worked for me

func sha256(securityString : String) -> String {
    let data = securityString.dataUsingEncoding(NSUTF8StringEncoding)!
    var hash = [UInt8](count: Int(CC_SHA256_DIGEST_LENGTH), repeatedValue: 0)
    CC_SHA256(data.bytes, CC_LONG(data.length), &hash)
    let output = NSMutableString(capacity: Int(CC_SHA1_DIGEST_LENGTH))
    for byte in hash {
        output.appendFormat("%02x", byte)
    }
    return output as String
}
mdkr
  • 225
  • 2
  • 13
0

Below link i used for creating document hash value and Its very simple and easy to calculate hash value specially for large files.

Link : http://www.joel.lopes-da-silva.com/2010/09/07/compute-md5-or-sha-hash-of-large-file-efficiently-on-ios-and-mac-os-x/comment-page-1/#comment-18533

Sunil aruru
  • 497
  • 5
  • 18
  • External links may disappear over time. Please include a self-contained piece of code in your answer. – bdesham May 15 '19 at 21:36
0
+ (NSData *)sha256DataFromData:(NSData *)data {
    unsigned char result[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256([data bytes], (int)[data length], result);
    return [NSData dataWithBytes:result length:CC_SHA256_DIGEST_LENGTH];
}
Boris
  • 11,373
  • 2
  • 33
  • 35
0

I cleaned up https://stackoverflow.com/a/13199111/1254812 a bit and structured it as an NSString extension

@interface NSString (SHA2HEX)

/*
 Get the SHA2 (256 bit) digest as a hex string.
 */
@property (nonatomic, readonly) NSString* sha2hex;
@end

@implementation NSString (SHA2HEX)

- (NSString*)sha2hex
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];

    if (data.length > UINT32_MAX)
        return nil;

    uint8_t digest[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256(data.bytes, (CC_LONG)data.length, digest);

    const int hexlen = CC_SHA256_DIGEST_LENGTH * 2;
    NSMutableString *hexstr = [NSMutableString stringWithCapacity:hexlen];

    for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
        [hexstr appendFormat:@"%02x", digest[i]];
    }

    return hexstr;
}

@end
dcow
  • 7,765
  • 3
  • 45
  • 65