How to replicate ASP Classic SHA512 Hash function in PHP - php

I'm currently rewriting an asp classic site in PHP, everything so far has been simple until I reached the password hashing function. In PHP I've used hash_hmac and hash, but I seem unable to replicate this functions results using a static salt in PHP. Please could someone help guide me as to how to produce the same result in PHP?
<% Function Hash(strPassword, strIndividualSalt)
Const strSiteWideSalt = "Bacon and HASH is best served with a good Salt!"
Hash = HashSHA512Managed(strSiteWideSalt & strPassword & strIndividualSalt)
End Function
Function HashSHA512Managed(saltedPassword)
Dim objMD5, objUTF8
Dim arrByte
Dim strHash
Set objUnicode = CreateObject("System.Text.UnicodeEncoding")
Set objSHA512 = Server.CreateObject("System.Security.Cryptography.SHA512Managed")
arrByte = objUnicode.GetBytes_4(saltedPassword)
strHash = objSHA512.ComputeHash_2((arrByte))
HashSHA512Managed = ToBase64(strHash)
End Function
Function ToBase64(rabyt)
Dim xml: Set xml = CreateObject("MSXML2.DOMDocument.3.0")
xml.LoadXml "<root />"
xml.documentElement.dataType = "bin.base64"
xml.documentElement.nodeTypedValue = rabyt
ToBase64 = xml.documentElement.Text
End Function
response.write Hash("mypassword", "mysalt")%>
This outputs...
1Asf3PuLZetBni4laI7jDKG3fbhlzKzB41G2694oZdH6nELLXklqtvY8Tniqjf3/2/gGg01fzs4w67l1Tfs20A==
Should I be using hash_hmac? Or do I need to replicate the function in PHP using hash()? Any help would be appreciated.

Related

AES Encryption producing different results between PHP and Javascript

Hi there StackOverflow community,
After researching for countless of hours, I'm unable to find an explanation as to why my ouputs differ between javascript and my laravel application.
I could use input type hidden to make a post from my web browser, but that would defeat the purpose of having a secure client side processing and I fear that if I don't find the reason as to why this is happening, then decryption (which I plan to do through php) would not work either.
my php code is as follows:
$payload = "this is my plaintext";
$binary_signature = "";
$private_key = openssl_pkey_get_private(file_get_contents(storage_path('privatekey.pem')), 'enc123456789');
openssl_sign($payload, $binary_signature, $private_key, OPENSSL_ALGO_SHA256);
$signature = base64_encode($binary_signature);
$new_payload = $payload."&sign=".$signature; // where my actual plaintext is also used in my javascript code
$key = "thisismykey";
$iv = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0";
$encryption = openssl_encrypt($new_payload, 'AES-256-CBC', $key,OPENSSL_RAW_DATA, $iv);
dd(base64_encode($encyrption));
which outputs the following:
AEyHK+4DQWYjw8GeVV3mfzUJtk7ylxZINeryAdFptEbDyKOVbmNg8z32J2JgxGpFsQKpXxWaqDLf0IPNIq1jof0rKWhhDpaWzvTd0Tq/zgze7oGtZzEIqtdRDqax3ZvPkzNfuO/O14iW/YTwFkm9FLy9kGIirZDUTuAcOIjXGCgxhrhZHLn+V6SZpW5dYnH8u5rPDCeez2/HkUPI71YjD6hZ0DRjIkiXCyjPYH4fjNykz4yXo8hD+489Zxm8QPq1O1dyjR9JXSdrlYMWdixt6w0vz8EtPC8gZ+bDP/N/UEK07M52VB693zYb5uD1u7WuUUtsOjkr5ocF6QbEW7sjzI4q9yAxqvxRW/bkKqodcVqtglW6YsdJjrTR0EfA/Or/QF3e3QWVM5/2g4rT3ccE17OP6Rp/46yTpW9lOgS6Qiz2hY95GoaxbLfHB/Vb0Es+UppwDu8bd/u2Qax5erBi5ObZu3AjKNpTem45paspsKH3/vc2Jc810XrVQPjnDdZ8VrXvCgPiulywn5Mj28O7uUQ5bay3Zxy3bmHb7ESDEVMKiSEoru3LzDJ7wwPlidJzPcfWtuiMEMsPOv1Y6LaxtlizWM5/zYJFX/RA4d+KBl+Rn6BoPZDcX/6eh3oUoNhy
My JS Code (the plaintext is received through an ajax call which has the same sign method as you see from the php code, the encryption plaintext is of the same value from my php code)
function encrypt(plaintext, secretkey) {
var randomSeed = "";
randomSeed = secretkey;
var key = CryptoJS.enc.Utf8.parse(randomSeed.toUpperCase());
var iv = CryptoJS.enc.Utf8.parse("0000000000000000");
var encrypt = {};
encrypt = CryptoJS.AES.encrypt(plaintext, key, {
mode : CryptoJS.mode.CBC,
iv : iv
});
console.log("encryption is "+encrypt.toString());
return encrypt.toString(encrypt.toString());
}
Returns the correct value which is:
jLmAUr+JyCjbpctU4z6+dlF61jbHRphwTS0iAk3IRiy3jkfCtaCSWdiIO0awuX6G1jAlZroTiAuMl9OW0zj0q4HitndfGFtFUoMMCqZTzvMr6cy1TyG9EFz20T6ByrBnOvGuoVjv3Flufuk2Ghz5in2W2A3T+wF+SPXX/bIAnHtE3uW0bPl2q5tn6KyUI1uoQaYcMZKRPyzAQS7WSSwSOmAcVrRuDANgZQuO+3mh86QAdeFaYqFdZUnxD4c2kkbkGy17SUFfSK8Qjv+8tkTcYXV9QRRdWjGZiQQeyAr3PDKA4SDVzrcMNwJjTaLJiZv0Iau66HGpbf2yvRDLtIOoXQmnhs6NKTZpcSwZ07hHqVvBZmNRq+jqZOGw1s8GRH+Bz4yxSRycTS0DEddhyMoxhZcUc5wt42vDOYIEH2nuw/uu4gjrwpx0rVO1ssoZYRxvBaA6zSC4N04Wdn4JE2/LtXertDLEdLBtmk3c3n4QDU0tK5v31HMY7P7+fdQXU62niVxCNPSt9dpYa82IUrQuigNXgrbphQvZNmmcONi/4pnxJjKcKYpCn/1KhkBVUAhYm6UKJJvMNAo0M+cfsvReImrJx6IzPRdzTTFAQF5kW2NFkV4EIb0DtCF679RtdAhg5ShaP7QhqYL6EgFCs9WnJTACC26TmV20DAqUiuIYULLtjDW4qFOWi/y8D1JOWTar
I don't understand why my PHP encryption is giving the wrong output while my JavaScript encryption is giving the correct output
I'm hoping someone could give me an insight as to what I'm doing wrong from my PHP side. Wha I'm hoping to achieve is that my PHP encryption will output the same result as my JavaScript encryption.
Thank you in advance :)
I have solved my issue.
To those having a similar issue, here's a brief explanation. Crypto JS uses the following:
var key = CryptoJS.enc.Utf8.parse(randomSeed.toUpperCase());
var iv = CryptoJS.enc.Utf8.parse("0000000000000000");
Which translates to a word array if you console log the output. PHP needs to have the similar word array value that cryptoJS produces for it's AES encryption method. To solve this, you have to convert your $key and iv to be in hex format and format your code in php such as:
$key = pack("H*", "4a424d56595753555047553830334d42505a314f414256414c5a565239324659");
$iv = pack("H*", "30303030303030303030303030303030");
Then when you proceed to using openssl_encrypt
$encrypted_data = openssl_encrypt($plaintext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
you will get the same output as crpytoJS.
Hope this helps.

PHP and Android Keystore encryption / decryption

I've been trying to get this for hours now, and I can't find what's wrong. I'm using a php RESTful API that I made to encrypt data using asymmetric encryption.
First, I save my user's public key in the server by exporting it in android:
fun exportPublicKey() : String {
val publicKey = getPublicKey()
return android.util.Base64.encodeToString(
publicKey!!.encoded,
android.util.Base64.NO_WRAP
)
}
This allows me in the PHP server to do that:
$public_key_core = $_POST["public_key"];
$public_key = "-----BEGIN PUBLIC KEY-----\n" . $public_key_core . "\n-----END PUBLIC KEY-----";
I am unsure that's the right way but openssl seems to be "ok" with that key ?
I then tested my keystore in local using both keys, and it works just fine using this code:
Encrypt:
fun encryptAsymmetricData(data: String, usePrivateKey : Boolean = true): ByteArray {
val cipher : Cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
val encryptedBytes: ByteArray
if (usePrivateKey){
cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey())
encryptedBytes = cipher.doFinal(data.toByteArray(Charsets.UTF_8))
} else {
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey())
encryptedBytes= cipher.doFinal(data.toByteArray(Charsets.UTF_8))
}
return encryptedBytes
}
Decrypt:
fun decryptAsymmetricData(data: ByteArray): String{
val cipher : Cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey())
return cipher.doFinal(data).toString(Charsets.UTF_8)
}
Using this works because I do ".toByteArray(Charsets.UTF_8)" on the encryptData result.
Now here's the problem, I use base64 encoding and do the following to encrypt in PHP:
openssl_public_encrypt($token->token, $encrypted_token, $user->public_key);
openssl_public_encrypt($user->id, $encrypted_id, $user->public_key);
[...]
'encrypted_user_id' => base64_encode($encrypted_id),
'encrypted_token' => base64_encode($encrypted_token)
But when I try to decrypt this in Android I'm getting an exception "javax.crypto.IllegalBlockSizeException" caused by this code:
val tokenBA = String(getDecoder().decode(this.encryptedToken), Charsets.UTF_8).toByteArray(Charsets.UTF_8)
val userIDBA = String(getDecoder().decode(this.encryptedUserId), Charsets.UTF_8).toByteArray(Charsets.UTF_8)
val token = App.encryptionController.decryptAsymmetricData(tokenBA)
val userID = App.encryptionController.decryptAsymmetricData(userIDBA)
(The logic being, I use base64 to send back my data in PHP, so I convert it to UTF8 in Android, then get the associated ByteArray to decrypt it ?)
I know that the encryption works in "local" but it doesn't when using both PHP and KeyStore, so I guess the problem is coming either from the PHP encryption, or from the way I try to decrypt it in android, but I can't seem to find what wrong, could you guys help me there please ?
Thank you by advance!
Ok, after searching and making sure the issue wasn't the public key stored in the PHP server, I found the answer. It was caused by the way to convert the "base64" string in an actual ByteArray in the App. This worked:
val token = App.encryptionController.decryptAsymmetricData(getDecoder().decode(encryptedToken))
val userID = App.encryptionController.decryptAsymmetricData(getDecoder().decode(encryptedUserId))
This is only working because I do the "base64_encode" in the server, for some (bad) reason I thought it was needed to go back to UTF8 to get the ByteArray in the app.

Generate a hashed message with SHA256 hmac in php (key & msg are fake)

I'm using php 8.0.11, i have to generate a SHA256 encrypted messagesignature.When i test the API in postman with javascipt code in Pre-request script it give the right encrypted messagesignature, i converted the script to php when i test it in php it sends a different wrong encrypted messagesignature (key & msg are fake) :
javascript code (Pre-request script in postman):
let msg='mymessage'
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256,"myapipkey");
hmac.update(msg);
const messageSignature = hmac.finalize().toString();
pm.globals.set("messageSignature",messageSignature);
console.log('messageSi:',pm.globals.get('messageSignature'))
````
php code:
````php
$data_to_hash = "mymessage";
$data_hmac=hash('sha256', $data_to_hash);
$ctx = hash_init('sha256', HASH_HMAC, 'myapipkey');
hash_update($ctx, $data_hmac);
$result = hash_final($ctx);
echo $result;
````
A simple change to the PHP code should give the correct result.
It looks like you were hashing twice (or something like that!)
$data_to_hash = "mymessage";
$ctx = hash_init('sha256', HASH_HMAC, 'myapipkey');
hash_update($ctx, $data_to_hash);
$result = hash_final($ctx);
echo $result;
In any case, the output of the above code will be:
898786a1fa80da9b463c1c7c9045377451c40cf3684cbba73bdfee48cd3a5b8f
Which is the same as the JavaScript code, both match the output given here:
https://codebeautify.org/hmac-generator
With Algorithm = 'SHA256', Key = 'myapipkey' and Plaintext = 'mymessage'.

Having issues converting VBA.NET function to PHP

There's a following function written in VBA.NET which I'm trying convert to PHP. I'm primarly a PHP developer, and I have alsmost zero-knowledge in VB.
<%
Public Shared Function ComputeHash(ByVal Key As String) As String
Dim objSHA1 As New SHA1CryptoServiceProvider
objSHA1.ComputeHash(System.Text.Encoding.UTF8.GetBytes(Key.ToCharArray))
Dim buffer() As Byte = objSHA1.Hash
Dim HashValue As String = System.Convert.ToBase64String(buffer)
Return HashValue
End Function
%>
I have tried searching for manuals and found some guidelances.
This is so far what I have converted to PHP myself:
function compute_hash($string){
return base64_encode(sha1($string));
}
Hovewer it doesn't produce the same result as VB's function ComputeHash(). Coudn't someone tell what I'm doing wrong?
Example of execution on both languages:
VBA.NET
string = "orange45877687459999SENTRYORD01154321"
ComputeHash(string) // Returns = WbwSWEBzPqgo9C4nZmGwHhd/FBQ=
PHP
$string = "orange45877687459999SENTRYORD01154321";
compute_hash(string) // Returns = NTliYzEyNTg0MDczM2VhODI4ZjQyZTI3NjY2MWIwMWUxNzdmMTQxNA== (but I need "WbwSWEBzPqgo9C4nZmGwHhd/FBQ=")
You need to instruct PHP to return the SHA1-hash in bytes instead of in hex format, by passing the TRUE parameter to the hashing function:
function compute_hash($string){
return base64_encode(sha1($string, TRUE));
}
PHP manual for SHA1

PHP equivalent of .NET Code

I am converting .net project to PHP . But unable to convert the following code:
public static string HashString(string value)
{
SHA1 hasher = new SHA1CryptoServiceProvider();
UTF8Encoding enc = new UTF8Encoding();
byte[] hashInBytes = hasher.ComputeHash(enc.GetBytes(value));
return Convert.ToBase64String(hashInBytes);
}
So far I have done this but result is not same:
function HashString($str) {
return base64_encode(sha1($str));
}
Please help, thanks.
The reason behind the difference is, PHP uses ASCII encoding for hash calculations.
In C#, you can replace UTF8Encoding with ASCIIEncoding in order to have same results.
Finally I found the solution:
This is the final code which is equivalent to .net code:
function HashString($str) {
return base64_encode(sha1($str,true));
}
I have added "true" with sha1 function.

Categories