Почему мой код Python и objective-c дает разные результаты hmac-sha1?

Я пишу клиент-серверный проект, которому нужна подпись. Я использую 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 для 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;
}

РЕШЕНИЕ: Спасибо всем ниже. Но я не должен говорить вам, что настоящая причина в том, что я набрал «TE S T» в своей среде разработки Python, а в этом сообщении набрал «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 (благодаря Бурхану Халиду) или закодирован в строку utf-8.

person clark    schedule 14.03.2013    source источник
comment
Согласно этому сайту, ваш друг - правильный   -  person dmg    schedule 14.03.2013
comment
Что ж, это было странно, ваш код также производит 7FH0NG0Ou4nb5luKUyjfrdWunos= на Python 2. Вы используете Python 3?   -  person dmg    schedule 14.03.2013
comment
Хорошо, последнее продолжение. Если вы используете Python 3, вы должны называть его как get_signature(b'KEY', b'TEXT'), поскольку strings - это unicode   -  person dmg    schedule 14.03.2013


Ответы (1)


Ваш друг совершенно прав, но вы тоже (вроде как). Ваша функция полностью верна как в Python 2, так и в Python 3. Однако ваш вызов немного ошибочен в Python 3. Как видите, в Python 3 строки являются Unicode, поэтому для передачи строки ASCII (как это делает ваш друг Objective C и как вы бы сделали в Python 2) , вам нужно вызвать свою функцию с помощью:

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

чтобы указать, что эти строки являются байтами или строками ASCII.

РЕДАКТИРОВАТЬ: Как отметил Бурхан Халид, гибкий способ сделать это в 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())
person dmg    schedule 14.03.2013
comment
Это правильный ответ, но чтобы применить его в своем методе, вы должны использовать bytearray(key) и bytearray(msg) - person Burhan Khalid; 14.03.2013