0

我想用 HMAC SHA512 签署一个请求,但我似乎弄乱了 NSData 和 NSString 之间的编码和解码。我拼命想弄清楚哪里出了问题,但我似乎没有做对。

伪代码:

function hmac_512(msg, sec) {
    sec = Base64Decode(sec);
    result = hmac(msg, sec, sha512);
    return Base64Encode(result);
}


secret = "7pgj8Dm6";
message = "Test\0Message";

result = hmac_512(message, secret);
if (result == "69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==")
    print("Success!");
else
    printf("Error: %s", result);



我的实现:

+(void)doSomeMagic{

    NSString *message = @"Test\0Message";
    NSString *signedRequest = [self signRequestForParameterString:message];

    //checking against CORRECT (from JAVA equivalent) signed request 
    if ([signedRequest isEqualToString:@"69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==" ])
        NSLog(@"Success!");
    else
        NSLog(@"Error!");
}

这是签名方法:

+(NSString *)signRequestForParameterString:(NSString*)paramStr{

    NSString *secret = @"7pgj8Dm6";

    // secret is base64 encoded, so I decode it 
    NSData *decodedSecret = [secret base64DecodedData];
    NSString *decodedSecretString = [NSString stringWithUTF8String:[decodedSecret bytes]];

    NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
    NSString *dataString = [NSString stringWithUTF8String:[data bytes]];


    return [self generateHMACSHA512Hash:decodedSecretString data:dataString];

}

这是哈希函数:

+(NSString *)generateHMACSHA512Hash:(NSString *)key data:(NSString *)data{


    const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];

    unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];

    CCHmac(kCCHmacAlgSHA512, cKey, strlen(cKey), cData, strlen(cData), cHMAC);

    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC
                                          length:sizeof(cHMAC)];

    NSString *hash = [HMAC base64EncodedString];

    return hash;

} 

我很确定这是由于字符串的编码(decodedSecretString 和 dataString)。decodedSecretString(解码base64)解码后用ASCII编码。但是,当我调用散列方法时,我再次将其编码为 ascii,这将导致 null 错误。现在一切都让我感到困惑。

4

2 回答 2

2

您的秘密不会解码为有效的 UTF-8 字符串,Java 允许字符串中包含 NUL 字节,但是当您将“Test\0Message”转换为 C 字符串并使用 strlen 时,其长度为 4。

像这样的东西应该工作:

+(NSString *)signRequestForParameterString:(NSString*)paramStr{
    NSString *secret = @"7pgj8Dm6";
    NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
    return [self generateHMACSHA512Hash:[secret base64DecodedData] data:data];
}

+(NSString *)generateHMACSHA512Hash:(NSData *)key data:(NSData *)data{
    unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA512, key.bytes, key.length, data.bytes, data.length, cHMAC);
    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
    return [HMAC base64EncodedString];
}
于 2013-11-29T16:42:56.390 回答
0

在执行 HMAC 或其他加密函数时,您应该首先构建一些不处理字符串的基本方法/函数。然后,您可以创建包装器方法,以方便的方式解码/编码字符串数据或摘要。

+ (NSData *)dataBySigningData:(NSData *)data withKey:(NSData *)key
{
  unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
  CCHmac(kCCHmacAlgSHA512, [key bytes], [key length], [data bytes], [data lenght], cHMAC);
  return [[NSData alloc] initWithBytes:cHMAC length:CC_SHA512_DIGEST_LENGTH];
}

+ (NSData *)dataBySigningMessage:(NSString *)message withKey:(NSData *)key
{
  return [self dataBySigningData:[message dataUsingEncoding:NSUTF8StringEncoding]
                         withKey:[key dataUsingEncoding:NSUTF8StringEncoding]];
}

(注意:此代码未经测试,只是在文本编辑器中一起破解)

不必担心密钥或数据的字符串表示形式。然后您可以从那里开始,例如获取摘要的base64 编码。

加密函数不关心字符串或文本编码。他们关心字节。字符串(在 C 中,因为它们是空终止的)只是可以在数据中表示的内容的一个子集。因此,处理字符串将受到严重限制。

于 2013-11-29T17:09:58.057 回答