Different results in Python and C++ when computing SHA-1 digest - python

I get different results when trying to compute SHA-1 digest in Python and C++.
Python code:
import hashlib
salt = 0xF0C020D239062F875C7BD8FB218D8102C9B37656F653E8DF0C655EF2D4A0CB61
password = 'pass1'
m = hashlib.sha1()
m.update( bytearray.fromhex(hex(salt)[2:-1]) )
m.update( password )
print m.hexdigest()
# output: e92f9504b2d46db0af7732c6e89e0260e63ae9b8
I extracted from the C++ code a snippet:
BigNumber salt, x;
Sha1Hash xhash;
uint8 password[] = "pass1";
// salt is received from a network packet (32 bytes)
// 2014-08-16 16:06:37 --> salt=F0C020D239062F875C7BD8FB218D8102C9B37656F653E8DF0C655EF2D4A0CB61
salt.SetBinary(lc.salt, 32);
xhash.UpdateData(salt.AsByteArray(), salt.GetNumBytes());
xhash.UpdateData(password, sizeof(password) - 1);
xhash.Finalize();
x.SetBinary(xhash.GetDigest(), xhash.GetLength());
logdebug("--> x=%s", x.AsHexStr());
// output: E5B463090B335BBC734BD3F4683F310E87ED6E4A
How must I modify my Python code to have the same results as in C++?

You use different endiness in C++ and python. So you have to reverse the bytes of your salt in python.
import hashlib
salt = 'F0C020D239062F875C7BD8FB218D8102C9B37656F653E8DF0C655EF2D4A0CB61'.decode('hex')
password = 'pass1'
m = hashlib.sha1()
m.update( salt[::-1] )
m.update( password )
print m.hexdigest()
# output: 4a6eed870e313f68f4d34b73bc5b330b0963b4e5 <- the reversed of the C++ result

SHAs are specifications, hence some initial state can be implementation dependent.
I suggest to use the very same implementation if you need to compare Python and C++ codes.

Related

Generate a Java compatible Diffie-Hellman using Python

I am trying to rewrite the following code in Python. The original code is written in Javascript using the sjcl library.
// Inputs
var serverPubX = "WIUBDotrk02Rk/apL11jQPbmX0quyaYz2EIkGUlVf7s=";
var serverPubY = "diZ2CbfSUy5Kr82OIfd4Ajusq2K+/kjGZ7ymcqVwn2k=";
// The code
var serverPubXBits = sjcl.codec.base64.toBits(serverPubX);
var serverPubYBits = sjcl.codec.base64.toBits(serverPubY);
var serverPubKeyPointBits = serverPubXBits.concat(serverPubYBits);
var serverPubKey = new sjcl.ecc.elGamal.publicKey(
sjcl.ecc.curves.c256, serverPubKeyPointBits);
var clientKeys = sjcl.ecc.elGamal.generateKeys(256, 1);
// What I need:
var sharedKey = clientKeys.sec.dhJavaEc(serverPubKey);
My main problem is the dhJavaEc function. According to the sjcl documentation, it's a Java compatible Diffie-Hellman function. But I couldn't find anything equivalent in the pycryptodome library.
I checked the dhJavaEc code this is what it does:
// Looks like it converts the server key to Jacobian and then multiply it by client key
serverPubKey.J.toJac().mult(clientKeys.sec.I, serverPubKey.J).toAffine().x.toBits()
// serverPubKey.J is the X and Y keys concatenated:
sjcl.codec.base64.fromBits(serverPubKey.J.toBits())
"WIUBDotrk02Rk/apL11jQPbmX0quyaYz2EIkGUlVf7t2JnYJt9JTLkqvzY4h93gCO6yrYr7+SMZnvKZypXCfaQ=="
// In my example, clientKeys.sec.I is this:
sjcl.codec.base64.fromBits(clientKeys.sec.I.toBits())
"zIhDVlFUpWQiRP+bjyEIhSLq8rcB8+XInXGhm6JGcVI="
// And the calculated key is:
sjcl.codec.base64.fromBits(sharedKey)
"ZBin/RV1qnfKoIuel+5fzv1y8rn3UZkMPO3pXva3VzQ="
How can I generate a "sharedKey" equivalent using Python?
PyCryptodome does not seem to support ECDH at the moment, see Future plans. An alternative is the Cryptography library, see Elliptic Curve Key Exchange algorithm.
The library expects the private key as int and the public key in uncompressed format as bytes object. The uncompressed format consists of the concatenated x and y coordinates preceded by a 0x04 byte.
sjcl.ecc.curves.c256 defines secp256r1 (aka prime256v1 aka NIST P-256).
Then a possible implementation in Python with Cryptography is:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
import base64
curve = ec.SECP256R1()
clientKey = 'zIhDVlFUpWQiRP+bjyEIhSLq8rcB8+XInXGhm6JGcVI='
privateKeyInt = int.from_bytes(base64.b64decode(clientKey), byteorder='big', signed=False)
privateKey = ec.derive_private_key(privateKeyInt, curve, default_backend())
serverPubKey = 'WIUBDotrk02Rk/apL11jQPbmX0quyaYz2EIkGUlVf7t2JnYJt9JTLkqvzY4h93gCO6yrYr7+SMZnvKZypXCfaQ=='
publicKeyUncomp = b'\x04' + base64.b64decode(serverPubKey)
publicKey = ec.EllipticCurvePublicKey.from_encoded_point(curve, publicKeyUncomp)
sharedSecret = privateKey.exchange(ec.ECDH(), publicKey)
print(base64.b64encode(sharedSecret).decode('utf8')) # ZBin/RV1qnfKoIuel+5fzv1y8rn3UZkMPO3pXva3VzQ=
which produces the same shared secret as the JavaScript code.

how to decrypt in php an encrypted text by python using AES-256-CCM

im trying to decrypt a chiphertext in PHP that was encrypted with AES-256-CCM using cryptography.hazmat in python
what i did in my python code is :
from cryptography.hazmat.primitives.ciphers.aead import AESCCM
from os import urandom
import base64
#Text To Encrypt
plaintext = bytes("message from python", encoding='utf-8')
#AES 256 Key Genrator
key = AESCCM.generate_key(256)
#Genrate Nonce
nonce= urandom(12)
#chipher
cipher = AESCCM(key, tag_length=8)
#Encryption
ciphertext = cipher.encrypt(nonce, plaintext, None)
then i convert the key , nonce and ciphertext to base64
key_b64 = base64.standard_b64encode(key)
ciphertext_b64 = base64.standard_b64encode(ciphertext)
nonce_b64 = base64.standard_b64encode(nonce)
in my example i got this results
key = b'\xcb\x14\x96{,0(\x15\x86 \xda\xf8\x1b"i|M\xbd\xc5d\xe7\xa6I\xdf\x7f\xe11\xae\xe8\x8a\xb3j'
key_b64 = b'yxSWeywwKBWGINr4GyJpfE29xWTnpknff+ExruiKs2o='
nonce = b'\xc7f\xdc\xe3\xe4\x03>M\x9by\x92\x9d
nonce_b64 = b'x2bc4+QDPk2beZKd'
ciphertext = b'R\x9f\xe6D\\_\xdexC\x82\xf8\x8e\x9b;\x91\xc7OLo\xc2\t/\x8fV>G='
ciphertext_b64 = b'Up/mRFxf3nhDgviOmzuRx09Mb8IJL49WPkc9'
i use the base64 results in my PHP code
<?php
$key_from_python = base64_decode('yxSWeywwKBWGINr4GyJpfE29xWTnpknff+ExruiKs2o=');
$ciphertext_from_python = base64_decode('ooGUzo0YiwKPs9+2wXySYEpdBNfSpyLUHm1M');
$nonce_from_python = base64_decode('Up/x2bc4+QDPk2beZKd');
$cipher = "aes-256-ccm";
if (in_array($cipher, openssl_get_cipher_methods())){
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$decrypted_mesage_from_pythom =
openssl_decrypt($encrypted_from_python_,$cipher,$key_from_python,$options=0 , $iv, $tag);
echo $decrypted_mesage_from_pythom;
}
its based on an example that i find here http://php.babo.ist/#/en/function.openssl-encrypt.html and i cant find another example
the decryption processes dose not return anything
and what really confusing me is :
we didn't use IV to encrypt in python code but the PHP need
non-NULL IV ,how to solve that ?
what $tag represent in PHP code and $tag_lenght both in PHP and
python(cipher = AESCCM(key, tag_length=8)) ?
if the decryption need nonce how to use it in my PHP code ?
How to get this work? encrypt from python and decrypt the same chiphertext in PHP
Note : i have to use python for encryption and php for decryption and i have to use AES-CCM, the python code is fixed , thank you for your understanding
thank you
There seems to be a bug in the PHP implementation for AES-CCM for a nonce length of 12 bytes (used by the OP) which results in a wrong ciphertext/tag. However, this bug is hidden by a number of flaws in the OP's PHP code. Therefore, these defects have to be fixed first:
The Python and PHP implementations differ in that in the Python code the ciphertext and tag are concatenated in that order, whereas in the PHP code the ciphertext and tag are processed separately.
The nonce in the Python code corresponds to the IV in the PHP code.
In the PHP code the OPENSSL_RAW_DATA flag must be set if the ciphertext is passed as raw data and not Base64 encoded.
The values for nonce and ciphertext (+ tag) differ in both codes. However, a correction is pointless because of the chosen 12 bytes nonce in combination with the PHP bug for a 12 bytes nonce, see below. I.e. a prerequisite for a successful test is a nonce size unequal to 12 bytes.
A PHP implementation that takes these points into account is e.g.
<?php
// Data from Python code
$key_from_python = base64_decode('<Base64 encoded key from Python>');
$ciphertext_from_python = base64_decode('<Base64 encoded (ciphertext + tag) from Python>');
$nonce_from_python = base64_decode('<Base64 encoded nonce from Python>');
$cipher = 'aes-256-ccm';
// Separate ciphertext and tag
$tagLength = 8;
$ciphertext = substr($ciphertext_from_python, 0, -$tagLength);
$tag = substr($ciphertext_from_python, -$tagLength);
// Decrypt
if (in_array($cipher, openssl_get_cipher_methods())){
$decrypted_mesage_from_pythom = openssl_decrypt($ciphertext, $cipher, $key_from_python, OPENSSL_RAW_DATA, $nonce_from_python, $tag);
echo $decrypted_mesage_from_pythom;
}
?>
With this PHP code it's possible to decrypt the data from the Python code as long as the length of the nonce is not equal to 12 bytes.
Python and PHP implementations allow a nonce with a length of 7 to 13 bytes (both inclusive), s. here for Python. Concerning the issue for a 12 bytes nonce, the following turns out: If in the PHP code the 12 bytes nonce is truncated to 7 bytes by removing the last 5 bytes, the same ciphertext/tag is created. The following PHP code illustrates this for the tag lengths of 8 and 16 bytes (PHP version 7.4.4):
<?php
function printCiphertextTag($plaintext, $key, $iv, $taglength){
$encrypted = openssl_encrypt($plaintext, "aes-256-ccm", $key, OPENSSL_RAW_DATA, $iv, $tag, NULL, $taglength);
echo sprintf("tag size: %2s, IV size: %2s, IV (hex): %-' 24s, ciphertext (hex): %s, tag (hex): %s\n", $taglength, strlen($iv), bin2hex($iv), bin2hex($encrypted), bin2hex($tag));
}
$plaintext = 'message from python';
$key = '01234567890123456789012345678901';
$nonce12 = openssl_random_pseudo_bytes(12);
$nonce7 = substr($nonce12, 0, 7);
printCiphertextTag($plaintext, $key, $iv = $nonce12, $taglength = 8);
printCiphertextTag($plaintext, $key, $iv = $nonce7, $taglength = 8);
printCiphertextTag($plaintext, $key, $iv = $nonce12, $taglength = 16);
printCiphertextTag($plaintext, $key, $iv = $nonce7, $taglength = 16);
?>
This result indicates a bug in the PHP implementation.
The Python code in contrast generates different ciphertexts/tags for a 12 bytes nonce compared to the PHP code (which is why the (corrected) OP's PHP code that uses a 12 bytes nonce fails). A check with Java/BC with identical parameters produces the same ciphertexts/tags for a 12 bytes nonce as the Python code, which verifies the values of the Python code and again indicates a bug in the PHP implementation.
EDIT: I've filed an issue here: https://bugs.php.net/bug.php?id=79601. Note: The issue was set to private by the admins, so that it cannot be opened (at least for now) without the appropriate permissions, s. here.

Encrypting and Decrypting with python and nodejs

I am trying to pass data between Python and Node.js application. For that i am using AES encryption. The problem is that Node.js produces encrypted data which is twice longer than the one produced using Python.
Below are code snippets.
Python 3.6
import binascii
from Crypto.Cipher import AES
key = 'key-xxxxxxxxxxxxxxxxxxZZ'
iv = '1234567812345678'
data = 'some_secret_data'
def _encrypt(data):
aes = AES.new(key, AES.MODE_CBC, iv[:16])
encrypted = aes.encrypt(data)
# encrypted = b'\xd54\xbb\x96\xd3\xbet#\x10\x01 [\reg\xaa'
encrypted_base64 = binascii.b2a_base64(encrypted)
# encrypted_base64 = b'1TS7ltO+dEAQASBbDWVnqg==\n'
encrypted_hex = binascii.hexlify(encrypted)
# encrypted_hex = b'd534bb96d3be74401001205b0d6567aa'
return encrypted_base64
output = _encrypt(data)
Node v6.10.0
let crypto = require("crypto");
let enc = require("./encryption");
var key = 'key-xxxxxxxxxxxxxxxxxxZZ';
var iv = '1234567812345678';
var data = 'some_secret_data';
var encrypted_hex = encrypt(data, 'hex');
var encrypted_base64 = encrypt(data, 'base64');
console.log(encrypted_hex);
// encrypted_hex = 'd534bb96d3be74401001205b0d6567aab4c31f7a76936598e5a1cc05385f3a91'
console.log(encrypted_base64);
// encrypted_base64 = '1TS7ltO+dEAQASBbDWVnqrTDH3p2k2WY5aHMBThfOpE='
function encrypt(msg, encoding){
var aes = crypto.createCipheriv('aes-192-cbc', key, iv);
var crypted = aes.update(msg,'utf8', encoding)
crypted += aes.final(encoding);
return crypted;
}
As you can see above, Python produces encrypted_hex which equals to d534bb96d3be74401001205b0d6567aa. In Node, encrypted_hex contains the value mentioned above + b4c31f7a76936598e5a1cc05385f3a91.
Could anyone help me understand what is going on here:
Why does Node.js produces result which is twice longer ?
I figured it out.
This happens because of different behavior of Pythons' PyCrypto package and Nodes' Crypto module. I am using AES, and since it is a block cypher, it requires data to come in chunks of specified length.
PyCrypto fails if it encounters data which doesn't come in 16 bit chunks. Nodes' Crypto, by default will pad data, so data will always come in chunks of good size.
For the sake of simplicity i've tested data having length of 16 bytes in the examples above. So why were the results different?
Python module did not pad data by default, and because data contained correct length, we've got expected result.
Node Crypto module, however, does pad the data, and apparently adds the whole 16 bit chunk of padding to original message (which really sounds like a bug). That is why the first part of encrypted Nodes' message corresponds to the one created in Python, the other one is just Node Crypto trying to encrypt its own excessive padding.
Anyway, to get rid of the error, i've simply added
aes.setAutoPadding(false);
in my encrypt() function.
Wooh.

Perl Crypt-Eksblowfish Cypher encrypted string and must be decrypted in python

A Perl script use this module to encrypt string
http://search.cpan.org/~zefram/Crypt-Eksblowfish-0.009/lib/Crypt/Eksblowfish.pm
I need to code the decrypt fonction in python . I know the key and the salt .
I tried to use py-bcrypt but it seems that the two equiv function
$ciphertext = $cipher->encrypt($plaintext);
$plaintext = $cipher->decrypt($ciphertext);
are not implemented .
How can i do ? Is there a python module anywhere that can help me to decrypt my strings ?
Update: The complete answer is the Perl code:
my $cipher = Crypt::EksBlowFish->new($cost, $salt, $key);
is equivalent to this Python code:
bf = Eksblowfish()
bf.expandkey(salt, key)
for i in xrange(cost << 1):
bf.expandkey(0, key)
bf.expandkey(0, salt)
See this repo for example code: https://github.com/erantapaa/python-bcrypt-tests
Original answer:
A partial answer...
I'm assuming you are calling this Perl code like this:
use Crypt::EksBlowfish;
my $cipher = Crypt::EksBlowFish->new($cost, $salt, $key);
$encoded = $cipher->encrypt("some plaintext");
The new method is implemented by the C function setup_eksblowfish_ks() in lib/Crypt/EksBlowfish.xs. This looks like it is the same as the expandKey method in the Python code (link)
The main difference is the $cost parameter which is not present in the Python method. In the Perl code the $cost parameter controls how many times this loop is executed after the key schedule has been set up:
for(count = 1U << cost; count--; ) {
for(j = 0; j != 2; j++) {
merge_key(j == 0 ? expanded_key : expanded_salt, ks);
munge_subkeys(ks);
}
}
The Perl ->encrypt() method enciphers a 64-bit word. The equivalent Python code is:
bf.cipher(xl, xr, bf.ENCRYPT)
where xl and xr are integers representing the left 32-bits and right 32-bits respectively.
So the recipe should go something like this:
Create the Python object: bf = EksBlowfish()
Initialize the key schedule: bf.expandkey(salt, key)
Further munge the key schedule using the cost parameter (TBD)
Encrypt with bf.cipher(xl, xr, bf.ENCRYPT)

Python 2 - Decrypt Java's PBEWithMD5AndDES

This question is related to this one: Replicate Java's PBEWithMD5AndDES in Python 2.7
This was the answer of the question (Python code):
from Crypto.Hash import MD5
from Crypto.Cipher import DES
_password = 'q1w2e3r4t5y6'
_salt = '\x80\x40\xe0\x10\xf8\x04\xfe\x01'
_iterations = 50
if "__main__" == __name__:
"""Mimic Java's PBEWithMD5AndDES algorithm to produce a DES key"""
print "Enter the password to encrypt:",
plaintext_to_encrypt = raw_input()
hasher = MD5.new()
hasher.update(_password)
hasher.update(_salt)
result = hasher.digest()
for i in range(1, _iterations):
hasher = MD5.new()
hasher.update(result)
result = hasher.digest()
# Pad plaintext per RFC 2898 Section 6.1
padding = 8 - len(plaintext_to_encrypt) % 8
plaintext_to_encrypt += chr(padding) * padding
encoder = DES.new(result[:8], DES.MODE_CBC, result[8:16])
encrypted = encoder.encrypt(plaintext_to_encrypt)
print encrypted.encode('base64')
I'm now trying to do the reverse operation (decrypt) with knowing the _password, _salt and _iterations variables, of course.
print encoder.decrypt(encrypted) doesn't match the initial password.
I don't know what to do next. I read the §6.1.2 of the rfc2898 but it didn't help me. Can anyone guide me to the right answer?
EDIT :
Seems like the following is needed:
encoder2 = DES.new(result[:8], DES.MODE_CBC, result[8:16])
print encoder2.decrypt(encrypted)
Why do I have to use DES.new() again? How can I get rid of the padding?
Actual decrypted output for "123456" is 123456☻☻
Do like this
decrypted = encoder2.decrypt(encrypted)
print decrypted.rstrip('\2,\1,\3,\4,\5,\6,\7')
Length of "123456" is 6 and the decrypter outputs 8 bytes. The remaining position is filled with a default byte, so the rstrip strips the bytes and gives the string.
EDIT: I have created a gist refer this
Link
Just take the last byte and remove as many characters as it encodes (including the last byte).
Beware that you should add an authentication tag if you are vulnerable to error oracles such as padding oracles.

Categories

Resources