2

我正在与一个合作伙伴合作,我们无法让 C# 和 Objective-C 使用我们认为在各自语言中相同的工具来生成相同的哈希值。在 C# 中,我这样做:

byte[] noncebytes=new byte[32];
//We seed the hash generator with a new 32 position array.  Each position is 0.
//In prod code this would be random, but for now it's all 0s.
HMACSHA256 hmac256 = new HMACSHA256(noncebytes);          
string plaintext = "hello";
string UTFString = Convert.ToBase64String(
    System.Text.Encoding.UTF8.GetBytes(plaintext));  
string HashString = Convert.ToBase64String(
    hmac256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(plaintext)));  //Convert that hash to a string.

这会产生以下 base64string 哈希:

Q1KybjP+DXaaiSKmuikAQQnwFojiasyebLNH5aWvxNo=

执行此操作的等效 Objective-C 代码是什么?我们需要客户端和服务器能够为匹配的数据生成匹配的哈希。

这是我们目前使用的 Objective-C 代码:

   ...

    NSData *zeroNumber = [self zeroDataWithBytes:32]; //empty byte array
    NSString *nonceTest = [zeroNumber base64String];  // using MF_Base64Additions.h here
    NSData *hashTest = [self hmacForKeyAndData:nonceTest withData:@"hello"]; //creating hash
    NSString *hashTestText = [hashTest base64String]; 
    NSLog(@"hello hash is %@",  hashTestText);

...

    //functions for zeroing out the byte.  I'm sure there's a better way

    - (NSData *)zeroDataWithBytes: (NSUInteger)length {
   NSMutableData *mutableData = [NSMutableData dataWithCapacity: length];
    for (unsigned int i = 0; i < length; i++) {
       NSInteger bits = 0;
      [mutableData appendBytes: (void *) &bits length: 1];
    } return mutableData;
}

//hash function

-(NSData *) hmacForKeyAndData:(NSString *)key withData:(NSString *) data {
    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}
4

2 回答 2

1

注意问题的objective-c部分的第二行代码。

NSString *nonceTest = [zeroNumber base64String]; 

但应该是这样的:

NSString *nonceTest = [[NSString alloc] initWithData:zeroNumber encoding:NSASCIIStringEncoding];

当我们不需要 hmac 播种时,将字符串转换为 base64 是一种情况。

我们现在得到: Q1KybjP+DXaaiSKmuikAQQnwFojiasyebLNH5aWvxNo= 作为两个平台上的哈希值。

于 2013-03-08T06:13:09.730 回答
1

更新

GitHub 上有一个相当不错的项目,它似乎可以完成您想要的一切,以及更多与加密相关的选项;包括单元测试。


NSData *hmacForKeyAndData(NSString *key, NSString *data)
{
    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}

来源

有了以上内容,我认为您将拥有 import <CommonCrypto/CommonHMAC.h>。编码为 Base64 的下一步:

+ (NSString *)Base64Encode:(NSData *)data
{
    //Point to start of the data and set buffer sizes
    int inLength = [data length];
    int outLength = ((((inLength * 4)/3)/4)*4) + (((inLength * 4)/3)%4 ? 4 : 0);
    const char *inputBuffer = [data bytes];
    char *outputBuffer = malloc(outLength);
    outputBuffer[outLength] = 0;

    //64 digit code
    static char Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    //start the count
    int cycle = 0;
    int inpos = 0;
    int outpos = 0;
    char temp;

    //Pad the last to bytes, the outbuffer must always be a multiple of 4
    outputBuffer[outLength-1] = '=';
    outputBuffer[outLength-2] = '=';

    /* http://en.wikipedia.org/wiki/Base64
     Text content   M           a           n
     ASCII          77          97          110
     8 Bit pattern  01001101    01100001    01101110

     6 Bit pattern  010011  010110  000101  101110
     Index          19      22      5       46
     Base64-encoded T       W       F       u
     */


    while (inpos < inLength){
        switch (cycle) {
            case 0:
                outputBuffer[outpos++] = Encode[(inputBuffer[inpos]&0xFC)>>2];
                cycle = 1;
                break;
            case 1:
                temp = (inputBuffer[inpos++]&0x03)<<4;
                outputBuffer[outpos] = Encode[temp];
                cycle = 2;
                break;
            case 2:
                outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xF0)>> 4];
                temp = (inputBuffer[inpos++]&0x0F)<<2;
                outputBuffer[outpos] = Encode[temp];
                cycle = 3;                  
                break;
            case 3:
                outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xC0)>>6];
                cycle = 4;
                break;
            case 4:
                outputBuffer[outpos++] = Encode[inputBuffer[inpos++]&0x3f];
                cycle = 0;
                break;                          
            default:
                cycle = 0;
                break;
        }
    }
    NSString *pictemp = [NSString stringWithUTF8String:outputBuffer];
    free(outputBuffer); 
    return pictemp;
}
于 2013-02-21T16:24:12.627 回答