我有一个基于django的应用程序,它使用Redsys(早期的Sermepa)作为信用卡支付平台。最近,我们收到一条消息,敦促我们从旧的SHA1签名迁移到SHA256,以便继续安全地使用该平台。
平台提供了几个示例,说明如何使新请求生成新签名,但仅使用PHP和Java。现在,我正试图将提供的解决方案移植到Python,但没有成功。
这是一个PHP中的示例工作代码(带有伪密钥/数据):
<?php
// Init form with default data
$order = "ABCDEFGHI";
$merchant_parameters = array(
"DS_MERCHANT_AMOUNT" => "1000",
"DS_MERCHANT_ORDER" => strval($order) ,
"DS_MERCHANT_MERCHANTCODE" => "012345678",
"DS_MERCHANT_CURRENCY" => "978",
"DS_MERCHANT_TRANSACTIONTYPE" => "0",
"DS_MERCHANT_TERMINAL" => "1",
);
// Key definition, decoding, and encrypt using $order
$key = 'Bg8HYhVT79PDvOxbI/Newcm31QY/9999';
echo 'key --> ' , $key , '<br/><br/>';
$key_decoded = base64_decode($key);
echo 'key-decoded --> ' , $key_decoded , '<br/><br/>';
$ciphertext = mcrypt_encrypt(MCRYPT_3DES, $key_decoded, $order, MCRYPT_MODE_CBC, implode(array_map("chr", array(0,0,0,0,0,0,0,0))) );
echo 'ciphertext --> ' , $ciphertext , '<br/><br/>';
// Transform array in encoded json
$parameters = json_encode($merchant_parameters);
echo 'parameters --> ' , $parameters , '<br/><br/>';
$parameters_encoded = base64_encode($parameters);
echo 'parameters_encoded --> ' , $parameters_encoded , '<br/><br/>';
// Calculate MAC256 of encoded array
$mac_256 = hash_hmac('sha256', $parameters_encoded, $ciphertext, true);
echo 'mac_256 --> ' , $mac_256 , '<br/><br/>';
// Encode MAC256 in base64 to get the signature
$mac_256_encoded = base64_encode($mac_256);
echo 'mac_256_encoded --> ' , $mac_256_encoded , '<br/><br/>';
?>
这是我在Python中的等效代码,使用相同的伪数据:
# -*- encoding: utf-8 -*-
from pyDes import triple_des, CBC, PAD_PKCS5
import hashlib, json, base64, hmac
from json import JSONEncoder
# Init form with default data
order = "ABCDEFGHI"
merchant_parameters = {}
merchant_parameters['DS_MERCHANT_AMOUNT'] = "1000"
merchant_parameters['DS_MERCHANT_ORDER'] = order
merchant_parameters['DS_MERCHANT_MERCHANTCODE'] = "012345678"
merchant_parameters['DS_MERCHANT_CURRENCY'] = "978"
merchant_parameters['DS_MERCHANT_TRANSACTIONTYPE'] = "0"
merchant_parameters['DS_MERCHANT_TERMINAL'] = "1"
# Key definition, decoding, and encrypt using order
key = 'Bg8HYhVT79PDvOxbI/Newcm31QY/9999'
print 'nnkey --> %s' % key
key_decoded = base64.b64decode(key)
print 'nnkey_decoded --> %s' % key_decoded
k = triple_des(key_decoded, CBC, " ", pad=None, padmode=PAD_PKCS5)
ciphertext = k.encrypt(order)
print 'nnciphertext --> %s' % ciphertext
# Transform array in encoded json (with no lines
parameters = (json.dumps(merchant_parameters)).encode()
print 'nnparameters --> %s' % parameters
parameters_encoded = ''.join(unicode(base64.encodestring(parameters), 'utf-8').splitlines())
print 'nnparameters_encoded --> %s' % parameters_encoded
# Calculate MAC256 of encoded array
mac_256 = hmac.new(ciphertext, parameters_encoded, digestmod=hashlib.sha256).hexdigest()
print 'nnmac_256 --> %s' % mac_256
# Encode MAC256 in base64 to get the signature
mac_256_encoded = base64.b64encode(mac_256)
print 'nnmac_256_encoded --> %s' % mac_256_encoded
可以看出,如果运行代码,生成的签名是不等价的,因此支付平台拒绝了我的Python请求。
有人能注意到我在签名生成方面哪里错了吗?
提前感谢,阿尔瓦罗。
遇到了同样的问题。
实际上,在JSON编码之后,我不得不清理键/值对之间的空白。但我得到了不同的密文签名。这导致最终签名与示例不同。
注意,在示例代码中,他们在3DES加密中为订单号做了一个尾随填充。
iv = b' '
k = DES3.new(key, DES3.MODE_CBC, iv)
ceros = b' '*(len(DS_MERCHANT_ORDER)%8)
clave = k.encrypt(DS_MERCHANT_ORDER+ceros.encode('UTF-8'))
感谢
编辑:
最后我修复了它:
要获得特定的每个操作密钥:
iv = b' '
k = DES3.new(key, DES3.MODE_CBC, iv)
ceros = b' '*(len(DS_MERCHANT_ORDER)%8)
claveOp = k.encrypt(DS_MERCHANT_ORDER+ceros.encode('UTF-8'))
获取hmac.sha256:
from Crypto.Hash import HMAC, SHA256
# Realizo la codificacion SHA256
dig = HMAC.new(claveOp , msg=DS_MERCHANT_PARAMETERS, digestmod=SHA256).digest()
signatureEnc = base64.b64encode(dig)
希望它能帮助你
Hie,最后,我在pypi中发布了关于redsys客户端的新版本。https://pypi.python.org/pypi/redsys/
感谢阿尔瓦罗即将做sha256签名。