PHP to Python port of password encryption - python

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 ?

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)))

How to write the equivalent Python encryption/decryption functions as the C# ones so that Python/C# could decrypt each other encrypted string?

Have two programs, one is developed in C#.NET, having the below C# encryption/decryption functions:
public static string Encrypt(string plainText, string keyString)
{
byte[] cipherData;
Aes aes = Aes.Create();
aes.Key = Encoding.UTF8.GetBytes(keyString);
aes.GenerateIV();
aes.Mode = CipherMode.CBC;
ICryptoTransform cipher = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, cipher, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
}
cipherData = ms.ToArray();
}
byte[] combinedData = new byte[aes.IV.Length + cipherData.Length];
Array.Copy(aes.IV, 0, combinedData, 0, aes.IV.Length);
Array.Copy(cipherData, 0, combinedData, aes.IV.Length, cipherData.Length);
return Convert.ToBase64String(combinedData);
}
public static string Decrypt(string combinedString, string keyString)
{
string plainText;
byte[] combinedData = Convert.FromBase64String(combinedString);
Aes aes = Aes.Create();
aes.Key = Encoding.UTF8.GetBytes(keyString);
byte[] iv = new byte[aes.BlockSize / 8];
byte[] cipherText = new byte[combinedData.Length - iv.Length];
Array.Copy(combinedData, iv, iv.Length);
Array.Copy(combinedData, iv.Length, cipherText, 0, cipherText.Length);
aes.IV = iv;
aes.Mode = CipherMode.CBC;
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream(cipherText))
{
using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
plainText = sr.ReadToEnd();
}
}
return plainText;
}
}
Another program is using Python, need to decrypt the encrypted string from the C# program.
What are the Python encryption/decryption functions so that Python's decryption function could decrypt the encrypted string by the above C# encryption function, also C#'s decryption function could decrypt the encrypted string by Python's encryption function?
The below are the Python functions worked for me:
import Crypto.Random
from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import unpad, pad
def encrypt(plain_text, key_string):
raw = pad(plain_text.encode(), AES.block_size)
iv = Crypto.Random.get_random_bytes(AES.block_size)
cipher = AES.new(key_string, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw))
def decrypt(combined_string, key_string):
enc = base64.b64decode(combined_string)
iv = enc[:AES.block_size]
cipher = AES.new(key_string, AES.MODE_CBC, iv)
msg = unpad(cipher.decrypt(enc[AES.block_size:]), AES.block_size)
return msg.decode()

porting aes encryption function from php to 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

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.

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