I create an HMAC in Node like below:
const check = crypto.createHmac("sha1", "mysecret");
check.update(JSON.stringify("mybody"));
const digest = check.digest("hex");
Then I create the HMAC in PHP:
hash_hmac("sha1","mybody","mysecret")
Then I create the HMAC in Python 3
key = bytes("mysecret", 'utf-8')
message = bytes("mybody", 'utf-8')
digester = hmac.new(key, message, hashlib.sha1).hexdigest():
Then HMAC from Node and PHP match, no issues. But the HMAC from Python is always different and I cant figure out why.
Any help will be appreciated.
Related
I have this issue where something is encrypted in python using aes 256 cbc encryption as shown in the python codes encrypt method .
I am trying to create a Decrypt method in php to actually decrypt whats encrypted using the python class .
Here is my attempt to convert the python decryption method to php does it look right or am I missing something in my conversion as every time i use the php version to decrypt it says hmac failed ?
anyhelp in converting the python class to php i will appreciate.
public function decrypt(){
$encrypt_method ="AES-256-CBC";
$secret_key =base64_decode('samekeyusedintheencryption');
$encrypted=(string)'some encrypted text to be decrypted';
$data=json_decode(base64_decode($encrypted),true);
$secret_iv =base64_decode($data['iv']);
$output = \openssl_decrypt($data['value'],
$encrypt_method,$secret_key,0,$secret_iv);
return json_encode($output);
}
def decrypt(self, payload):
data = json_c.decode(base64.b64decode(payload))
value = base64.b64decode(data['value'])
iv = base64.b64decode(data['iv'])
crypt_object=AES.new(self.key,AES.MODE_CBC,iv)
plaintext = crypt_object.decrypt(value)
return loads(plaintext)
OK, I got it to work!
function decrypt($encryptedText, $secret_key){
$secret_key = base64_decode($secret_key);
$encrypt_method ="AES-256-CBC";
$data = json_decode(base64_decode($encryptedText),true);
$data['iv'] = base64_decode($data['iv']);
$data['value'] = base64_decode($data['value']);
return openssl_decrypt($data['value'], $encrypt_method, $secret_key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $data['iv']);
}
Some things I learned:
If the options in the openssl function are set to '0' it expects a base64_encoded input for the cipher text. Also, if the default options is set to '0' the padding default is set to PKCS#7. This, I think, is why we were getting the bad block size error.
So, the cipher text needs to be base64_decoded and we need to set both options for the padding.
I was able to decrypt your provided cipher text and see the email addresses.
You are provided the MAC in the Data array so this would allow you to check the MAC in the PHP script. This allows you to make sure the data has not been tampered with.
I recently did an encryption project and started with the open ssl, but ended up changing to the libSodium library. I highly recommend you check it out for any further projects.
Cheers!
I'm trying to implement authentication in API request but I am having weird issue with while signing data. The output from crypto.createHmac in NodeJS is different from that of hash_hmac in PHP. I am trying to implement this on PHP and response from NodeJs is what I expected.
Code for NodeJS
var crypto = require('crypto');
var hmac = crypto.createHmac('sha512', new Buffer(key, 'base64'));
var digest = hmac.update(salt + '\n' + returnUrl).digest();
var signature = digest.toString('base64');
console.log(signature);
Code for PHP
$signature = base64_encode(hash_hmac("sha512",$salt.'\n'.$returnUrl, $key));
echo $signature;
For NodeJS Application I got
VZ+gH+BVdZl6GIILfN5TFAxEIUqstiD5YwuQYTdk3R4LSxVzsAXPpPpn5MwHDoRllz5ll5iBpAOuO2DQ9nvtGA==
which is expected response but PHP gave me different result
NzNlNmFhNWUwOTg2OGQ3NzdhNjU0MWZmOTZhZDZjYmFiYjE4ZjMxZTc5OTk3MDI5ZGI1M2M3YmU3MjRiYTdiNjJmODM4NDA1NmMzNWZlOWE2NTVkZjhmZTg4MDg0MjA3ZmYzMjg1MGQxYzFiZDNkODA2M2MzZGVhOTRiZWMzNTA=
which is entirely different than expected. Is there a way I can recreate NodeJS crypto functionality in PHP getting same response.
In the following example, I use node.js and PHP to get signing data, and both of them get the same output. You can take that as a reference.
Code for Node.js
var crypto = require('crypto');
var hmac = crypto.createHmac('sha512', 'sharedpassword');
var digest = hmac.update('12345\nhttps://google.com').digest('hex');
var signature = new Buffer(digest).toString('base64');
console.log(signature);
Then I get:
OTllY2U2NTU4ZWVkYzczZmNlMTQ2YzdlMmI4NjI5MTdhODRhYWNmOGEyNmYzM2M5ZjQ5ZjE1NTM5MjQ1ZDAzYWU1MzlkYTViODY4MjcwM2UyMTA5MjVhMzcyNWJhOWU3OTU3MjY5NWI4ZjkzZGY1Zjg1NTNmYzI3MWU0ZTIyZWE=
Code for PHP
$signature = base64_encode(hash_hmac('sha512', "12345\nhttps://google.com", 'sharedpassword'));
echo $signature;
Got:
OTllY2U2NTU4ZWVkYzczZmNlMTQ2YzdlMmI4NjI5MTdhODRhYWNmOGEyNmYzM2M5ZjQ5ZjE1NTM5MjQ1ZDAzYWU1MzlkYTViODY4MjcwM2UyMTA5MjVhMzcyNWJhOWU3OTU3MjY5NWI4ZjkzZGY1Zjg1NTNmYzI3MWU0ZTIyZWE=
Also note that PHP only interprets escaped characters when in double quotes ("). So \n must be in double quotes!
So I am working on a PHP script that queries an API which uses HMAC authentication headers. However, I have been banging my head trying to encode the HMAC signature correctly. I have a preexisting nodejs script to work from as a template.
In the nodejs script, the HMAC signature is calculated using the following:
var crypto = require('crypto');
var hmac = [];
hmac.secret = 'ODc0YTM3YzUxODFlMWQ1YTdhMGQwY2NiZmE1N2Y1ODdjYzM5NTgyMDJhZjVkYTE4MmQxYzQ5ODk0M2QzNWQxYw==';
hmac.timestamp = 1457326475000;
hmac.path = '/account/';
hmac.message = hmac.path +'\n' + hmac.timestamp;
var sig = crypto.createHmac('sha512', new Buffer(hmac.secret, 'base64'));
hmac.signature = sig.update(hmac.message).digest('base64');
console.log(hmac);
This correctly calculates the HMAC signature as:
bWjIFFtFmWnj0+xHLW2uWVa6M6DpbIV81uyUWwRFCJUg+0Xyt40QWZWQjGvfPUB/JbjGZHUoso0Qv5JHMYEv3A==.
Meanwhile, in PHP, I am using:
<?php
$hmac['secret'] = 'ODc0YTM3YzUxODFlMWQ1YTdhMGQwY2NiZmE1N2Y1ODdjYzM5NTgyMDJhZjVkYTE4MmQxYzQ5ODk0M2QzNWQxYw==';
$hmac['nonce'] = '1457326475000';
$hmac['path'] = '/account/';
$hmac['message'] = $hmac['path']."\n".$hmac['nonce'] ;
$hmac['signature'] = base64_encode(hash_hmac('sha512',$hmac['message'],
$hmac['secret'], true));
print_r($hmac);
The above code, will calculate the HMAC signature as:
vqP49m/bk9nA4S3nMqW2r+kc2+yBfwhY/jWGUfz6dlKJUMkC2ktiPnuCcymdSWl4XezZT5VKCATYfus86Hz/Gg==
Working from the principle that "one million monkeys hacking away at a million keyboards" might one day be able to encode a valid HMAC signature, I have even tested a loop that iterates through all the permutations of the above PHP code (with/without base64 encoding the message, secret; with/without binary encoding of the HMAC, etc.)... to no avail.
Any suggestions for this here, one exhausted simian?
The problem is that you're not decoding your $hmac['secret'] first before passing it to hash_hmac().
Try:
$hmac['secret'] = base64_decode($hmac['secret']);
$hmac['signature'] = base64_encode(
hash_hmac('sha512', $hmac['message'], $hmac['secret'], true)
);
In our application we are getting encrypted text from external server. This text have been encrypted using openssl in php.
When I am trying to decrypt the text in my Ruby code, I am getting following error message:
OpenSSL::Cipher::CipherError: wrong final block length
I read couple of solutions on Stackoverflow and was suggest to add following line to the code cipher.padding = 0. But after adding padding = 0, I am getting different error:
OpenSSL::Cipher::CipherError: data not multiple of block length
Below is my rough script I have written to decrypt the code.
require 'openssl'
require 'digest/sha1'
require 'base64'
encrypted = "VaZYJzn9QVEQIH4fmtA1Cg=="
key = "my_secret_key"
cipher = OpenSSL::Cipher::Cipher.new("aes-128-ecb")
cipher.decrypt
cipher.padding = 0
cipher.key = key
decrypted = cipher.update(encrypted)
decrypted << cipher.final
puts Base64.decode64(decrypted)
If I encrypt the text using Ruby then I can easily decrypt it. I am having problem to decrypt the code which are encrypted in php. Is there any way I can make encryption and decryption compatible between php and Ruby.
Simply change the way you call it.
From decrypted << cipher.final to decrypted = cipher.update(encrypted) + cipher.final
could get the string like
<GF\x8F\xDC\x91\xE1ew\xB1\x1C\xE8\xF8V\xA0\x99g\x01C\xCDF\xD6\v\x841l\x13\xA6\x9496{
Last, quote from Ruby Doc You should never use ECB mode unless you are absolutely sure that you absolutely need it
phpseclib:
php code :
include('Crypt/RSA_XML.php');
$rsa = new Crypt_RSA_XML();
$rsa->loadKeyfromXML($public_key_xml);
$data = "invoice_number=1,100.00&customer_tin=674858994885&serial=ONLYPEMPSERIAL&tin=ONLYPUMPTIN&vat_1_net=2,0000&vat_1_value=3600&vat_2_net=0&vat_2_value=0&vat_3_net=0&vat_3_value=0&vat_4_net=0&vat_4_value=0&vat_5_net=0&vat_5_value=0&vat_6_net=0&vat_6_value=0&vat_7_net=0&vat_7_value=0&vat_8_net=0&vat_8_value=0&payment_mode=3&discount=200&total_gross=9562";
$plaintext = $data;
//define('CRYPT_RSA_PKCS15_COMPAT', true);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$ciphertext = base64_encode(strrev($rsa->encrypt($plaintext)));
echo "data";
echo $ciphertext; // there is encoded value getting
and
then how to decrypt encrypted data using private key:
echo $rsa->decrypt($ciphertext); // this is giving error , decryption error
actually , i want to encrypt in php and decrypt in c# ,
data encrypted successfully and when c# rsa crypto service decrypt this encrypted data then giving error message : invalid base-64 string length
$public_key_xml and $private_key_xml is defined below...
public key :
<RSAKeyValue>
<Modulus>uidt3bPfWozkIkC6nHnRDbXrvjqplfCslV2zP4hKJ6sVjVnPfjMM0ueCuEDFZ9NK+kCWaPNAVhOKKwL8HmoX/7KcFLWkwSoatnrncHTH5STey+bqR1xTFY+Rubj8BZt7D9JJYyLQC46wn4ySVnLWkCZZ9+aaTriEBzGTpUzeRiUTWVprp3oXsA7ZKyn+lhZfMx1ILhcD8dnX7xFHB57jIKvPBxAdT4K7GxdgENeS76I/zmVmlF//JnmtZ/RM1WmRkx8mFmcK/Ky8gLsmIpPPltoyBWIKIf2NQH9kHqHa2gwoPg34LTutV9AACTWuiVOjqU7Gq2BHQcjovXMF8t3Wiw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
private key :
<RSAKeyValue>
<Modulus>uidt3bPfWozkIkC6nHnRDbXrvjqplfCslV2zP4hKJ6sVjVnPfjMM0ueCuEDFZ9NK+kCWaPNAVhOKKwL8HmoX/7KcFLWkwSoatnrncHTH5STey+bqR1xTFY+Rubj8BZt7D9JJYyLQC46wn4ySVnLWkCZZ9+aaTriEBzGTpUzeRiUTWVprp3oXsA7ZKyn+lhZfMx1ILhcD8dnX7xFHB57jIKvPBxAdT4K7GxdgENeS76I/zmVmlF//JnmtZ/RM1WmRkx8mFmcK/Ky8gLsmIpPPltoyBWIKIf2NQH9kHqHa2gwoPg34LTutV9AACTWuiVOjqU7Gq2BHQcjovXMF8t3Wiw==</Modulus><Exponent>AQAB</Exponent><P>9NiLuI9TjNvpAPQqD9ySdMX37OmEDCF02isoovt8hwPpiXcZYH4FeasNZoydRrBUOHTTRrW3xdUYGsCZI0H9tSg+gIjo/k/JhmECT7RuSgjEL7mLpusAhi1RFv81TNERGvWP8V9HtB4oZONgOpdTuNqJwhyZ3+aA3zyy7k1mKJc=</P><Q>wqJndWnlZ2i8sW8zhX9SPUddyf8E+wHek3SYynUNQ3T7zJbk+woqyjMuSImXXuZO47uBJlwskYwR+mJr/AuCR7Y0+jtByJF8RoqkY7ttdhS8CpJ9J2o5YMGcGw0JoJ16L0W6QvhY5Zxb5IAG5nuiPLDlgZYNo7+oKRcDyF+fbC0=</Q><DP>hwimhjMFsTnXV19Rk03it+Q2x8JBwS7ycyA6WSi5lPzjX5z/sefOvTtJOLV0R/gXestzehveLo1Hrflqe7d5ZN+9GMZpOVhnnGUEEVFBQjNzf56lFnmk4Fs9zaESlDr5ZBTqPgR+VygKvxlniOjMk7ZzI0sC0ikeCgA/7o1hOiE=</DP><DQ>Fpj2fBpcaSIu7kbj63b53GWBzScPs/jml6Ys6yyl6pQVfA507XSjvTAuCnv3GCyTMjud5g9DmW5y0+hDc1L+wEa2ZeslWx0RGbuVFIM5VUFZB700TLQ3jzVLY5Si7oP6IKzu0EG3SIlb3e7DXlUyY+uB6ga69K0W4BZs+QGpJ80=</DQ><InverseQ>nob08brDfoswDV8JAkGJIg5T9ktMBRzn5djbAfSorOCCVwW+iRz/hkzSs4LaeMuoC3V5AnLeTg1T7J3op67KGerRwwjXSgCKO4crs2pODcZuIMkaE8e/5Ti1O40yKl05mQaxLk/SgSAhy97HhHoiteg/ttLcrvsCcSfyyxzHT3M=</InverseQ><D>bwqYEbh7EjOa3gfIiRBtMIWFExtBD6zZ9dtH0i0FNvZpy8B38iqXirMImcohNxal0fN3BTGc/ft33sJQDABzQlaTnhLgLU1lU9aqeb1fhANjVzPuKhUbhm/2mFeNFfcyCDUDC7y3Zz19hB7BKAomjSQjZKnNAAo2z2e2T9Mzf5kV8uuYsnoum6LEvEfluQ3q3+9Ua64P0E4D2j2iaOnvpBzTCpeaBMDfWZEe19MaS40d/OrZOwlyAVPCW9RkT3948fC5KDvE0KetYDsrVApRSKzvBUQCVNmcO2o+rhMO1qKvS+zkw2VW5OxGDk/QuHuXIkCyipUEMa/DmK74hoxCaQ==</D></RSAKeyValue>
You must be using a really old version of phpseclib since phpseclib has had built in support for the XML format for quite a few years. So my first recommendation would be to upgrade to the latest version. After that you should be able to do something like this:
<?php
include('Crypt/RSA.php');
$plaintext = 'zzz';
$rsa = new Crypt_RSA();
$rsa->loadKey('<RSAKeyValue>
<Modulus>uidt3bPfWozkIkC6nHnRDbXrvjqplfCslV2zP4hKJ6sVjVnPfjMM0ueCuEDFZ9NK+kCWaPNAVhOKKwL8HmoX/7KcFLWkwSoatnrncHTH5STey+bqR1xTFY+Rubj8BZt7D9JJYyLQC46wn4ySVnLWkCZZ9+aaTriEBzGTpUzeRiUTWVprp3oXsA7ZKyn+lhZfMx1ILhcD8dnX7xFHB57jIKvPBxAdT4K7GxdgENeS76I/zmVmlF//JnmtZ/RM1WmRkx8mFmcK/Ky8gLsmIpPPltoyBWIKIf2NQH9kHqHa2gwoPg34LTutV9AACTWuiVOjqU7Gq2BHQcjovXMF8t3Wiw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>');
define('CRYPT_RSA_PKCS15_COMPAT', true);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
echo base64_encode($rsa->encrypt($plaintext));
If that doesn't work it'd help to see the .NET code you're using to decrypt. Also, if you could encrypt a string in .NET and post the public key you used to do the encryption and the ciphertext itself that'd be useful. From that I could play around with the phpseclib options until I found some combination of options that let me decrypt the string, which would, presumably, in turn, give us insight in how to encrypt the string.