Im bulding a checkout that need creditcard 3DES Crypto, but I getting differente result on Python and NodeJs.
Python code: (im using pycryptodome package)
import binascii
import base64
from Crypto.Cipher import DES3
import json
iv = '04njBuE3/dc='
iv = base64.b64decode(iv)
key = 'DpzDLcvVCHdVoRqE/NuIHs0QJ0xFdH2p'
key = base64.b64decode(key)
data = {'CartaoNumero': '0000000000000000',
'CartaoMesAno':'00/0000',
'CartaoSeg': '000',
'CartaoNome':'Teste Teste',
'IdentFatura':'Teste',
'Valor':'1000',
'NomeCliente':'Teste Teste',
'EmailCliente':'teste@teste.com',
'CpfCliente':'11122233344'}
data = json.dumps(data)
data = base64.b64encode(data.encode('utf-8'))
#print (data)
def card_encrypt(iv,key, data):
desT = DES3.new(key, DES3.MODE_CBC, IV=iv)
desT_key = desT.encrypt(data)
desT_key = base64.b64encode(desT_key)
return (desT_key)
Result: b'+TSfdiGmLAir8RVEze4yr72d3Sm5RBkDBwLYhpv1NKIIfVM+AnIhoSArFzV5am7qOdaFO0Ob4KSS8vXRYnBAO1xyk9MEoNc93uf/53cCMVHbZ8FUx14Vilx3Mg8+kbSMsASki5Dn+hlKE0ElFC/nyiWoOJvkWmtndoL+EEb4rkFil0zg637YXFE7f0yTOWhz97G6CEb4mvegCPpizuVdh2sBQQFDsJMEQE1kGeY2gDiDADwRQiMTrznhWFn3H6SylMxjQaNJTxu820BNitefMgcwAUTUJSrZt6DyuJ59e7772DK2jLubpK8/8xNolKalcjYMx106T7jOxDoPWZEoIe7YSGn9+Z3IGe5R7YFQJVLJUJ3SzlwWLptr3ZbMRnDCh2rB4FbTsM4igic4ZUQjS3DUzUVpT5URQyGjJK9+434ivMehknko4x+1owaEgcLGsPT9zBADlKFQ+OE8JqOhwJ5IztyoWeOmBVPZsOQdYvo='
Nodejs code:
var secretKey = 'DpzDLcvVCHdVoRqE/NuIHs0QJ0xFdH2p'
var secretIV = '04njBuE3/dc='
var dataOfCard = {'CartaoNumero': '0000000000000000',
'CartaoMesAno':'00/0000',
'CartaoSeg': '000',
'CartaoNome':'Teste Teste',
'IdentFatura':'Teste',
'Valor':'1000',
'NomeCliente':'Teste Teste',
'EmailCliente':'teste@teste.com',
'CpfCliente':'11122233344'}
const crypto = require('crypto');
async function encryptCardData(dataOfCard, secretKey, secretIV) {
try {
const des3_key = new Buffer.from(secretKey, "base64");
console.log(des3_key)
const des3_iv = new Buffer.from(secretIV, "base64");
console.log(des3_iv)
const cardString = JSON.stringify(dataOfCard);
console.log(cardString)
const cipher = crypto.createCipheriv('des-ede3-cbc', des3_key, des3_iv);
const encrypted = cipher.update(cardString, 'utf8', 'base64');
return encrypted + cipher.final('base64');
} catch (error) {
console.error("Error:", error.message);
throw error;
}
}
encryptCardData(dataOfCard, secretKey, secretIV)
Result: '7pkXCZCKIDY1ueGwkfLk5W5AnDw2iP4jiZ5YHUBRMd56eDhVyZvnJ6EG+mh/wmHl3ljrJ+sfDMgAbpOgljRRQb4pOc1LQKHdkgcl3ZWmlvmqv8mGKdGaZYTgXnQ9pZGwoUQJAcuQgOCYWD5wMvIA6g4zd8O1iy/IsXWkBEzCkQA3x6NIkwrCNdftogu3JZlbmOIj90flo8t+J2X89rXzQmWKw6uCWrzzfGQvmvqqNf7ecDduTtCXee3WCdvcC3Ar7TbVpSv+NenoK+Oh+Tkj6Y8h4t6YAexyE8HxQ1GqCqFlMAzdCa2TtA=='
The NodeJS is generating the correct result. What I need to correct on Python model?
The Python code differs from the NodeJS code for the following reasons:
The conversion to a JSON string with json.dumps()
is slightly different from that with JSON.stringify()
. json.dumps()
, unlike JSON.stringify()
, inserts spaces after the separators (for better readability), see here. To avoid this, use the following modification:
dataJSON = json.dumps(data, separators=(',', ':'))
In the NodeJS code, padding is done implicitly with PKCS7, but not in Python. Here the padding must be performed explicitly, for which PyCryptodome provides a padding module:
from Crypto.Util.Padding import pad
...
dataPadded = pad(dataJSON.encode('utf-8'), 8)
8 is the 3DES block size in bytes.
The Base64 encoding of the data must be removed:
#data = base64.b64encode(data.encode('utf-8'))
With that:
ciphertext = card_encrypt(iv,key, dataPadded)
print (ciphertext)
returns the ciphertext:
b'7pkXCZCKIDY1ueGwkfLk5W5AnDw2iP4jiZ5YHUBRMd56eDhVyZvnJ6EG+mh/wmHl3ljrJ+sfDMgAbpOgljRRQb4pOc1LQKHdkgcl3ZWmlvmqv8mGKdGaZYTgXnQ9pZGwoUQJAcuQgOCYWD5wMvIA6g4zd8O1iy/IsXWkBEzCkQA3x6NIkwrCNdftogu3JZlbmOIj90flo8t+J2X89rXzQmWKw6uCWrzzfGQvmvqqNf7ecDduTtCXee3WCdvcC3Ar7TbVpSv+NenoK+Oh+Tkj6Y8h4t6YAexyE8HxQ1GqCqFlMAzdCa2TtA=='
which matches the ciphertext of the NodeJS code.
Please note that 3DES is deprecated and should be replaced by e.g. the more modern and performant AES, s. here. Apart from that, the use of a static IV is generally insecure, s here.