3

我正在编写一个需要签名的客户端/服务器项目。我base64(hmac-sha1(key, data))用来生成签名。但是我在python代码和objective-c代码之间得到了不同的签名:

get_signature('KEY', 'TEXT')   //python get 'dAOnR2oXWP9xa4vUBdDvVXTpzQo='
[self hmacsha1:@"KEY" @"TEXT"] //obj-c  get '7FH0NG0Ou4nb5luKUyjfrdWunos='

不仅 base64 值不同,hmac-sha1 摘要值也不同。我试着和我的朋友一起解决了几个小时,仍然不明白。我的代码问题出在哪里?

我的python代码:

import hmac
import hashlib
import base64
def get_signature(key, msg):
    return base64.b64encode(hmac.new(key, msg, hashlib.sha1).digest())

我朋友的 Objective-C 代码(复制自HMAC-SHA1 的 Objective-C 示例代码):

(NSString *)hmac_sha1:(NSString *)key text:(NSString *)text{

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

    unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);

    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
    NSString *hash = [GTMBase64 stringByEncodingData:HMAC];
    return hash;
}

已解决:感谢以下所有人。但我不必告诉你真正的原因是我在我的 python IDE 中输入了“TE S T”,而在这篇文章中输入了“TE X T”:P

为了不浪费您的时间,我根据您的回答做了一些测试并得到了更好的解决方案:

print get_signature('KEY', 'TEXT')                        
# 7FH0NG0Ou4nb5luKUyjfrdWunos=

print get_signature(bytearray('KEY'), bytearray('TEXT'))  
# 7FH0NG0Ou4nb5luKUyjfrdWunos=

print get_signature('KEY', u'你好'.encode('utf-8'))  # best solution, i think!
# PxEm7Oibj7ijZ55ko7V3isSkD1Q=

print get_signature('KEY', bytearray(u'你好'))           
# TypeError: unicode argument without an encoding

print get_signature('KEY', u'你好')                      
# UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

print get_signature(u'KEY', 'TEXT')                      
# TypeError: character mapping must return integer, None or unicode

print get_signature(b'KEY', b'TEXT')                       
# 7FH0NG0Ou4nb5luKUyjfrdWunos=

结论:

  1. 要签名的消息应编码为双方的 utf-8 字符串。
  2. (感谢DJV)在 python 3 中,字符串都是 unicode,所以它们应该与 'b' 或 bytearray 一起使用(感谢Burhan Khalid),或者编码为 utf-8 字符串。
4

1 回答 1

3

你的朋友是完全正确的,但你也是(有点)。你的函数在 Python 2 和 Python 3 中都是完全正确的。但是,你的调用在 Python 3 中有点错误。你看,在 Python 3 中,字符串是 unicode,所以为了传递一个 ASCII 字符串(作为你的 Objective C 朋友和你在 Python 2 中所做的一样),你需要调用你的函数:

get_signature(b'KEY', b'TEXT')

为了指定这些字符串是字节,也就是 ASCII 字符串。

编辑:正如Burhan Khalid所指出的,在 Python 3 中执行此操作的灵活方法是像这样调用您的函数:

get_signature(key.encode('ascii'), test.encode('ascii'))

或将其定义为:

def get_signature(key, msg):
    if(isinstance(key, str)):
        key = key.encode('ascii')
    if(isinstance(msg, str)):
        msg = msg.encode('ascii')
    return base64.b64encode(hmac.new(key, msg, hashlib.sha1).digest())
于 2013-03-14T09:48:34.543 回答