简体   繁体   中英

Generating SHA256 in iOS

I tried to generate SHA256 in iOS using Arcane library with following data:

String: Amount=50&BillerID=59&ChannelID=2&Context=34|check|test&ReturnURL=https://uat.myfatoora.com/ReceiptPOC.aspx&TxnRefNum=000000000020003&UserName=DCS

Key: 71DD0F73AFFBB47825FF9864DDE95F3B

Result was 409dc622b3bef5c9fc46e45c3210111fcb4536d3a55833316fe0dc8154b3ea34

which I thought to be correct. However, the Windows counterpart is generating SHA256 using following code:

Windows Phone Source Code:

public static string HmacSha256(string secretKey, string value)
    {
        var msg = CryptographicBuffer.ConvertStringToBinary(value, BinaryStringEncoding.Utf8);
        byte[] convertedHash = new byte[secretKey.Length / 2];

        for (int i = 0; i < secretKey.Length / 2; i++)
        {
            convertedHash[i] = (byte)Int32.Parse(secretKey.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
        }

        // Create HMAC.
        var objMacProv = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256);
        CryptographicHash hash = objMacProv.CreateHash(convertedHash.AsBuffer());

        hash.Append(msg);
        return CryptographicBuffer.EncodeToHexString(hash.GetValueAndReset());

    }

and the result is: 94a20ca39c8487c7763823ec9c918d9e38ae83cb741439f6d129bcdef9edba73 which is different from what I got. Can somebody help me with this and let me know what the above code is doing and how can I replicate it in iOS.

Edit:

 iOS Source code

 let key = self.md5(string: "71DD0F73AFFBB47825FF9864DDE95F3B")

    let hash = HMAC.SHA256(str, key: key)

The key here is you need to convert your secret, which is a hex string, into NSData. In other words, NSData byte stream would "look" like the secret.

This should do what you want:

    // Hex string to NSData conversion from here http://stackoverflow.com/questions/7317860/converting-hex-nsstring-to-nsdata
    NSString *secret = @"71DD0F73AFFBB47825FF9864DDE95F3B";
    NSData *dataIn = [@"Amount=50&BillerID=59&ChannelID=2&Context=34|check|test&ReturnURL=https://uat.myfatoora.com/ReceiptPOC.aspx&TxnRefNum=000000000020003&UserName=DCS" dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];

    secret = [secret stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSMutableData *secretData = [[NSMutableData alloc] init];
    unsigned char whole_byte;
    char byte_chars[3] = {'\0','\0','\0'};
    int i;
    for (i=0; i < [secret length]/2; i++) {
        byte_chars[0] = [secret characterAtIndex:i*2];
        byte_chars[1] = [secret characterAtIndex:i*2+1];
        whole_byte = strtol(byte_chars, NULL, 16);
        [secretData appendBytes:&whole_byte length:1];
    }

    CCHmac(kCCHmacAlgSHA256, secretData.bytes, secretData.length, dataIn.bytes, dataIn.length, macOut.mutableBytes);

    NSMutableString *stringOut = [NSMutableString stringWithCapacity:macOut.length];
    const unsigned char *macOutBytes = macOut.bytes;

    for (NSInteger i=0; i<macOut.length; ++i) {
        [stringOut appendFormat:@"%02x", macOutBytes[i]];
    }

    NSLog(@"dataIn: %@", dataIn);
    NSLog(@"macOut: %@", macOut);
    NSLog(@"stringOut: %@", stringOut);

Output:

2016-09-27 20:18:54.181 JKS[27562:5321334] dataIn: <416d6f75 6e743d35 30264269 6c6c6572 49443d35 39264368 616e6e65 6c49443d 3226436f 6e746578 743d3334 7c636865 636b7c74 65737426 52657475 726e5552 4c3d6874 7470733a 2f2f7561 742e6d79 6661746f 6f72612e 636f6d2f 52656365 69707450 4f432e61 73707826 54786e52 65664e75 6d3d3030 30303030 30303030 32303030 33265573 65724e61 6d653d44 4353>

2016-09-27 20:18:54.181 JKS[27562:5321334] macOut: <94a20ca3 9c8487c7 763823ec 9c918d9e 38ae83cb 741439f6 d129bcde f9edba73>

2016-09-27 20:18:54.181 JKS[27562:5321334] stringOut: 94a20ca39c8487c7763823ec9c918d9e38ae83cb741439f6d129bcdef9edba73

Updated with Swift (code should be cleaned up)

// http://stackoverflow.com/questions/29799361/generate-a-hmac-swift-sdk8-3-using-cchmac
func generateHMAC(key: String, data: String) -> String {
    let keyData = key.dataFromHexadecimalString()! as NSData
    let dataIn = data.data(using: .utf8)! as NSData
    var result: [CUnsignedChar]
    result = Array(repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
    CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyData.bytes, keyData.length, dataIn.bytes, dataIn.length, &result)

    let hash = NSMutableString()
    for val in result {
        hash.appendFormat("%02hhx", val)
    }

    return hash as String
}

You can use this extension to convert the hex string to Data

// Modified slightly http://stackoverflow.com/questions/26501276/converting-hex-string-to-nsdata-in-swift
extension String {

    func dataFromHexadecimalString() -> Data? {
        var data = Data(capacity: characters.count / 2)

        let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
        regex.enumerateMatches(in: self, options: [], range: NSMakeRange(0, characters.count)) { match, flags, stop in
            let byteString = (self as NSString).substring(with: match!.range)
            var num = UInt8(byteString, radix: 16)
            data.append(&num!, count: 1)
        }

        return data
    }
}

And to use do something like:

    let secret = "71DD0F73AFFBB47825FF9864DDE95F3B"
    let value = "Amount=50&BillerID=59&ChannelID=2&Context=34|check|test&ReturnURL=https://uat.myfatoora.com/ReceiptPOC.aspx&TxnRefNum=000000000020003&UserName=DCS"

    print("\(generateHMAC(key: secret, data: value))")

Your output should be 94a20ca39c8487c7763823ec9c918d9e38ae83cb741439f6d129bcdef9edba73

You will need #import <CommonCrypto/CommonCrypto.h> in your bridging header.

The Windows code takes the string, interprets it as a hexadecimal number, and converts two characters a time into one byte.

Your Mac code most like takes the string as it is . Since the key starts with "71", your windows code takes that as a single byte with value 0x71 = 129, your Mac code takes it as two bytes with values '7' = 55 and '1' = 49.

All you need to do is convert the bytes on the Mac exactly as you do it on Windows. You might have to do the unthinkable and look at the source code of the Mac library to see how it does the actual hash calculation.

 #import <CommonCrypto/CommonHMAC.h> + (NSString *)hmacSHA256EncryptString{ NSString * parameterSecret = @"input secret key"; NSString *plainString = @"input encrypt content string"; const char *secretKey = [parameterSecret cStringUsingEncoding:NSUTF8StringEncoding]; const char *plainData = [plainString cStringUsingEncoding:NSUTF8StringEncoding]; unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA256, secretKey, strlen(secretKey), plainData, strlen(plainData), cHMAC); NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)]; const unsigned char *bufferChar = (const unsigned char *)[HMACData bytes]; NSMutableString *hmacString = [NSMutableString stringWithCapacity:HMACData.length * 2]; for (int i = 0; i < HMACData.length; ++i){ [hmacString appendFormat:@"%02x", bufferChar[i]]; } return hmacString; } 

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