为什么我的python和objective-c代码得到不同的hmac-sha1结果?

时间:2013-03-14 09:28:12

标签: python objective-c base64 sha1 hmac

我正在编写需要签名的客户端/服务器项目。我使用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代码(来自Objective-C sample code for HMAC-SHA1的副本):

(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字符串

1 个答案:

答案 0 :(得分:3)

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

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

为了指定这些字符串是bytes a.k.a. 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())