porting aes encryption function from php to python - python

we used the following function in PHP to encrypt some data:
function aes_encrypt_turnover($reg_id,$receipt_nr,$data,$key_base64) {
$method = 'AES-256-CTR';
$library = 'OpenSSL';
$tc_bin = pack("J",$data);
$key_bin = base64_decode($key_base64);
$iv_bin = substr(hash('sha256', $reg_id . $receipt_nr, true), 0, 16);
$tc_encrypted_base64 = openssl_encrypt($tc_bin, $method, $key_bin, false, $iv_bin);
return $tc_encrypted_base64;
}
now we try to translate this to python but without success. with same testdata the python Version returns not the same encryption values.
Our python version is als follows:
import base64
import struct
import hashlib
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto.Util.number import bytes_to_long
data = 12345
reg_id = "DEMO_DATA"
receipt_nr = 843234
key_base64 = 'RCsRmHn5tkLQrRpiZq2ucwPpwvHJLiMgLvwrwEImddI='
tc_bin = struct.pack('>I', data)
key_bin = base64.b64decode(key_base64)
hash_string = str(reg_id) + str(receipt_nr)
iv_bin = hashlib.sha256(hash_string.encode()).digest()[:16]
counter = Counter.new(128, initial_value = bytes_to_long(iv_bin))
cipher = AES.new(key_bin, AES.MODE_CTR, counter=counter)
encrypted = cipher.encrypt(tc_bin)
encrypted_b64 = base64.b64encode(encrypted)
maybe anybody can tell whats wrong in our python version

Related

ValueError: IV must be 16 bytes long

I am trying to make a program to decrypt via python. The cipher used is AES-CBC.
But I get this error and I don't know how to fix it. Do you have any ideas?
Thanks in advance
#!/usr/bin/env python3
import base64
import binascii
from Crypto.Cipher import AES
key = "YELLOW SUBMARINE"
iv_dec = "a5f6ba42255643907a5bb3709840ca5b"
block_size = 16
pad_char = u"\00"
pad = lambda s: s + (block_size - len(s) % block_size) * pad_char
ciphertext = "412053617563657266756c206f662053656372657473"
# Decrypt
aes_dec = AES.new(str(key), AES.MODE_CBC, str(iv_dec))
decrypted = aes_dec.decrypt(ciphertext)
print ("Decrypted text: {} ".format(decrypted.rstrip(pad_char)))

PHP to Python port of password encryption

I want to convert the following code from PHP to Python.
public static function encryptPassword($password, $publicKeyId, $publicKey)
{
$key = openssl_random_pseudo_bytes(32);
$iv = openssl_random_pseudo_bytes(12);
$time = time();
openssl_public_encrypt($key ,$encryptedAesKey, base64_decode($publicKey));
$encrypted = openssl_encrypt($password, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, strval($time));
$payload = base64_encode("\x01" | pack('n', intval($publicKeyId)) . $iv . pack('s', strlen($encryptedAesKey)) . $encryptedAesKey . $tag . $encrypted);
return sprintf('#PWD:1:%s:%s', $time, $payload);
}
I have tried the following :
import base64
import datetime
import struct
import time
from Cryptodome.Random import get_random_bytes
from Cryptodome.Cipher import AES, PKCS1_v1_5
from Cryptodome.PublicKey import RSA
def main():
print(encpass())
def encpass():
password = ""
publickeyid =
publickey = ""
session_key = get_random_bytes(32)
iv = get_random_bytes(12)
time = str(int(datetime.datetime.now().timestamp()))
decoded_publickey = base64.b64decode(publickey.encode())
recipient_key = RSA.import_key(decoded_publickey)
cipher_rsa = PKCS1_v1_5.new(recipient_key)
enc_session_key = cipher_rsa.encrypt(session_key)
cipher_aes = AES.new(session_key, AES.MODE_GCM, nonce=iv)
cipher_aes.update(time.encode())
ciphertext, tag = cipher_aes.encrypt_and_digest(password.encode("utf8"))
payload = base64.b64encode((b"\x01\x00"
+ struct.pack('H', publickeyid))
+ iv
+ struct.pack('h', len(enc_session_key))
+ enc_session_key
+ tag
+ ciphertext)
return f"#PWD:1:{time}:{payload.decode()}"
Would like to know what is wrong in comparison to the PHP code ?
As I am sure it is working but the output is not exactly like the php function..
Thanks
I have updated the code now , i think somewhere in encoding I am wrong , can you detect ?

getting different results when encoding with python and when encoding with nodejs

i am trying to encode a particular string with python with pycrypto and encode the same string with nodejs with crypto.
i am getting different results in both the cases for the same input string
python code:
from Crypto.Cipher import AES
from hashlib import md5
import base64
password = 'aquickbrownfoxjumpsoverthelazydog'
input = 'hello+world'
BLOCK_SIZE = 16
def pad (data):
pad = BLOCK_SIZE - len(data) % BLOCK_SIZE
return data + pad * chr(pad)
def unpad (padded):
pad = ord(padded[-1])
return padded[:-pad]
def text_encrypt(data, nonce, password):
m = md5()
m.update(password)
key = m.hexdigest()
m = md5()
m.update(password + key)
iv = m.hexdigest()
data = pad(data)
aes = AES.new(key, AES.MODE_CBC, iv[:16])
encrypted = aes.encrypt(data)
return base64.urlsafe_b64encode(encrypted)
output = text_encrypt(input, "", password)
print output
and the nodejs code is as follows:
var crypto = require('crypto');
var password = 'aquickbrownfoxjumpsoverthelazydog';
var input = 'hello+world';
var encrypt = function (input, password, callback) {
var m = crypto.createHash('md5');
m.update(password)
var key = m.digest('hex');
m = crypto.createHash('md5');
m.update(password + key)
var iv = m.digest('hex');
var data = new Buffer(input, 'utf8').toString('binary');
var cipher = crypto.createCipheriv('aes-256-cbc', key, iv.slice(0,16));
var nodev = process.version.match(/^v(\d+)\.(\d+)/);
var encrypted;
if( nodev[1] === '0' && parseInt(nodev[2]) < 10) {
encrypted = cipher.update(data, 'binary') + cipher.final('binary');
} else {
encrypted = cipher.update(data, 'utf8', 'binary') + cipher.final('binary');
}
var encoded = new Buffer(encrypted, 'binary').toString('base64');
callback(encoded);
};
encrypt(input, password, function (encoded) {
console.log(encoded);
});
the results for both the cases is different but after decryption they both tend to give the same correct result.
what might be the issue here?
You didn't specify what different results are you getting but those two should produce same-ish result. The only difference I see is in the base64 alphabet you're using.
In Python you're calling base64.urlsafe_b64encode() which differs from the standard Base64 in what characters it uses for values for 62 and 63 (- and _ instead of + and /). To get the same result, either in Python return:
return base64.b64encode(encrypted)
Or post-process the base64 encoded string in Node.js:
encoded = encoded.replace(/_/g, '/').replace(/-/g, '+');
All this being said, as I've mentioned in my comment, never derive an IV from your password/key (or anything else deterministic and unchanging). Use a cryptographically secure PRNG for it.

why the AES result is different between Crypto and M2Crypto with Python?

i have two script in python , one is encrypt data using Crypto
from Crypto.Cipher import AES
from Crypto import Random
IV = 'c782dc4c098c66cb'
secrect_key = 'c286696d887c9aa0'
cipher = AES.new(secrect_key, AES.MODE_CFB, IV)
data = 'This is a 48-byte message (exactly 3 AES blocks)'
print repr(cipher.encrypt(data))
and the other using M2Crypto
import M2Crypto.EVP as EVP
import cStringIO
ENCRYPT_OP = 1
DECRYPT_OP = 0
def aes_encrypt(iv, secret_key, plain_text):
cipher = EVP.Cipher(alg='aes_128_cfb',
key=secret_key,
iv=iv,
op=ENCRYPT_OP)
input_buffer = cStringIO.StringIO(plain_text)
cipher_data1 = cipher.update(input_buffer.read())
cipher_data2 = cipher.final()
input_buffer.close()
output_buffer = cStringIO.StringIO()
output_buffer.write(cipher_data1)
output_buffer.write(cipher_data2)
cipher_text = output_buffer.getvalue()
output_buffer.close()
return cipher_text
IV = 'c782dc4c098c66cb' # 16 bytes
secrect_key = 'c286696d887c9aa0' # 16 bytes
data = 'This is a 48-byte message (exactly 3 AES blocks)'
cipher_text = aes_encrypt(IV, secrect_key, data)
print(repr(cipher_text))
i have pass the same argument to module, but i cannot get the same result, i don't know why.
and, is one of the result is vulnerability?

How to achieve C# RSACryptoServiceProvider-like encryption in Python?

So, in C# I have the following code:
public static void Main (string[] args)
{
publicKeyXml = "<Modulus>mFCubVhPGG+euHuVQbNObqod/Ji0kRe+oh2OCFR7aV09xYiOklqFQ8jgIgAHvyCcM1JowqfFeJ5jV9up0Lh0eIiv3FPRu14aQS35kMdBLMebSW2DNBkfVsOF3l498WWQS9/THIqIaxbqwRDUxba5btBLTN0/A2y6WWiXl05Xu1c=</Modulus><Exponent>AQAB</Exponent>";
RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider ();
rSACryptoServiceProvider.FromXmlString (publicKeyXml);
Console.WriteLine(Convert.ToBase64String (rSACryptoServiceProvider.Encrypt (Encoding.ASCII.GetBytes(args[0]), false)));
}
Which when I use to encrypt a message, it works just fine on a remote server (to which I have no source code for). However, when trying to do a similar thing in Python with PyCrypto, the remote server cannot decrypt.
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
KEY = RSA.importKey(open('login.key').read()) # Converted to standard format
KEY_CIPHER = PKCS1_v1_5.new(KEY)
testmsg = KEY_CIPHER.encrypt("test msg").encode('base64').replace('\n', '')
# send testmsg down a socket
# Response: {"info":"java.lang.IllegalArgumentException: Could not decrypt.","msg":"Fail"}
Any thoughts as to why this would be the case?
OK, in my case it was rather odd. The server side was expecting my stuff backwards. To solve, I simply did this:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
KEY = RSA.importKey(open('login.key').read()) # Converted to standard format
KEY_CIPHER = PKCS1_v1_5.new(KEY)
testmsg = KEY_CIPHER.encrypt("test msg").encode('base64').replace('\n', '')
testmsg = "".join(reversed([testmsg[i:i+2] for i in range(0, len(testmsg), 2)]))
Modulus = "mFCubVhPGG+euHuVQbNObqod/Ji0kRe+oh2OCFR7aV09xYiOklqFQ8jgIgAHvyCcM1JowqfFeJ5jV9up0Lh0eIiv3FPRu14aQS35kMdBLMebSW2DNBkfVsOF3l498WWQS9/THIqIaxbqwRDUxba5btBLTN0/A2y6WWiXl05Xu1c="
Exponent = "AQAB"
mod_raw = b64decode(Modulus)
exp_raw = b64decode(Exponent)
mod = int(mod_raw.encode('hex'), 16)
exp = int(exp_raw.encode('hex'), 16)
seq = asn1.DerSequence()
seq.append(mod)
seq.append(exp)
der = seq.encode()
keyPub = RSA.importKey(der)
print base64.b64encode(keyPub.encrypt('test msg', 0)[0])

Categories

Resources