2013-03-14 1 views
3

Я пишу проект клиент/сервер, которому нужна подпись. Я использую base64(hmac-sha1(key, data)) для создания подписи. Но я получил разные подписи между питона кода и Objective-C код:Почему мой код python и object-c получает другой результат hmac-sha1?

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

не только значения base64 различны, HMAC-SHA1 дайджест значения отличаются слишком. Я пытаюсь разобраться с моим другом в течение нескольких часов, но не понимаю. Где проблема моего кода?

Мой питон код:

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; 
} 

РЕШИТЬ: Спасибо всем ниже. Но я не должен вам сказать, что реальная причина я напечатал «TE S T» в моем питона IDE, а напечатал «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.
+0

По [этот сайт] (http://hash.online-convert.com/sha1-generator), ваш друг правильный – dmg

+0

Ну, это было странно, ваш код создает '7FH0NG0Ou4nb5luKUyjfrdWunos =' также на Python 2. Вы используя Python 3? – dmg

+2

ОК, окончательный контроль. Если вы используете Python 3, вы должны называть его как 'get_signature (b'KEY ', b'TEXT')' as 'string' '' unicode' – dmg

ответ

3

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

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

для того, чтобы указать, что эти строки bytes ака ASCII строк.

EDIT: Как отметил 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()) 
+2

Этот ответ верный, но для его применения в вашем методе вы следует использовать 'bytearray (key)' и 'bytearray (msg)' –

+0

спасибо! см. мое обновление ~ – clark