.Net and PHP Rijndael encryption not matching - php

At first i thought it was the padding since mcrypt uses zero padding but i changed the php to use PKCS7 and get the same exact results
Can anyone help? I think it has something to do with the padding in the php
Test output from .Net:
Key: d88f92e4fa27f6d45b49446c7fc76976
Text: Testing123
Encrypted: /DMkj7BL9Eu2LMxKhdGT+A==
Encrypted after base64 decode: ?3$??K?K?,?J???
Decrypted: Testing123
Test output from PHP:
Key: d88f92e4fa27f6d45b49446c7fc76976
Text: Testing123
Encrypted: K+ke5FNI5T6F6B/XvDF494+S8538Ze83cFz6v1FE89U=
Encrypted after base64 decode: +éäSHå>…è×¼1x÷’óüeï7p\ú¿QDóÕ
Decrypted: Testing123����������������������
PHP:
class rijndael{
var $mcrypt_cipher = MCRYPT_RIJNDAEL_256;
var $mcrypt_mode = MCRYPT_MODE_CBC;
function decrypt($pass, $encrypted)
{
$encrypted = base64_decode($encrypted);
$key = $this->getkey($pass);
$iv = $this->getiv($pass);
$decrypted = mcrypt_decrypt($this->mcrypt_cipher, $key, $encrypted, $this->mcrypt_mode, $iv);
$block = mcrypt_get_block_size($this->mcrypt_cipher, $this->mcrypt_mode);
$pad = ord($decrypted[($len = strlen($decrypted)) - 1]);
return substr($decrypted, 0, strlen($decrypted) - $pad);
}
function encrypt($pass, $decrypted)
{
$key = $this->getkey($pass);
$iv = $this->getiv($pass);
$block = mcrypt_get_block_size($this->mcrypt_cipher, $this->mcrypt_mode);
$pad = $block - (strlen($str) % $block);
$str .= str_repeat(chr($pad), $pad);
$encrypted = mcrypt_encrypt($this->mcrypt_cipher, $key, $decrypted, $this->mcrypt_mode, $iv);
return base64_encode($encrypted);
}
function getkey($passphrase)
{
$L1 = base64_encode(hash("sha256", $passphrase, true));
$L2 = $passphrase.$L1;
return hash("sha256", $L2, true);
}
function getiv($passphrase)
{
$L1 = base64_encode(md5($passphrase));
$L2 = $passphrase.$L1;
return md5($L2);
}
}
VB .Net:
Public Class RijnDael
Public Shared Function Decrypt(ByVal sData As String, ByVal sKey As String)
Dim bytData() As Byte = Encoding.UTF8.GetBytes(sData)
Return Decrypt(bytData, sKey)
End Function
Public Shared Function Decrypt(ByVal bytData As Byte(), ByVal strPass As String) As Byte()
Dim bytResult As Byte()
Using oRM As New System.Security.Cryptography.RijndaelManaged
oRM.KeySize = 256
oRM.Key = GeKey(strPass)
oRM.IV = GetIV(strPass)
oRM.Mode = CipherMode.CBC
oRM.Padding = PaddingMode.PKCS7
Using oMS As New MemoryStream(bytData)
Using oCS As New Cryptography.CryptoStream(oMS, oRM.CreateDecryptor, Security.Cryptography.CryptoStreamMode.Read)
Dim TempDecryptArr As Byte()
ReDim TempDecryptArr(bytData.Length)
Dim decryptedByteCount As Integer
decryptedByteCount = oCS.Read(TempDecryptArr, 0, bytData.Length)
'
ReDim bytResult(decryptedByteCount)
Array.Copy(TempDecryptArr, bytResult, decryptedByteCount)
'
oCS.Close()
End Using
oMS.Close()
End Using
End Using
Return bytResult
End Function
Public Shared Function Encrypt(ByVal sData As String, ByVal sKey As String)
Dim bytData() As Byte = Encoding.UTF8.GetBytes(sData)
Return Encrypt(bytData, sKey)
End Function
Public Shared Function Encrypt(ByVal bytData As Byte(), ByVal strPass As String) As Byte()
Dim bytResult As Byte()
Using oRM As New Cryptography.RijndaelManaged
oRM.KeySize = 256
oRM.Key = GeKey(strPass)
oRM.IV = GetIV(strPass)
oRM.Mode = CipherMode.CBC
oRM.Padding = PaddingMode.PKCS7
Using oMS As New MemoryStream
Using oCS As New Cryptography.CryptoStream(oMS, oRM.CreateEncryptor, Cryptography.CryptoStreamMode.Write)
oCS.Write(bytData, 0, bytData.Length)
oCS.FlushFinalBlock()
bytResult = oMS.ToArray()
oCS.Close()
End Using
oMS.Close()
End Using
End Using
Return bytResult
End Function
Private Shared Function GeKey(ByVal strPass As String) As Byte()
Dim bytResult As Byte()
'Generate a byte array of required length as the encryption key.
'A SHA256 hash of the passphrase has just the required length. It is used twice in a manner of self-salting.
Using oSHA256 As New Cryptography.SHA256Managed
Dim L1 As String = System.Convert.ToBase64String(oSHA256.ComputeHash(Encoding.UTF8.GetBytes(strPass)))
Dim L2 As String = strPass & L1
bytResult = oSHA256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(L2))
oSHA256.Clear()
End Using
Return bytResult
End Function
Private Shared Function GetIV(ByVal strPass As String) As Byte()
Dim bytResult As Byte()
'Generate a byte array of required length as the iv.
'A MD5 hash of the passphrase has just the required length. It is used twice in a manner of self-salting.
Using oMD5 As New Cryptography.MD5CryptoServiceProvider
Dim L1 As String = System.Convert.ToBase64String(oMD5.ComputeHash(Encoding.UTF8.GetBytes(strPass)))
Dim L2 As String = strPass & L1
bytResult = oMD5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(L2))
oMD5.Clear()
End Using
Return bytResult
End Function
End Class

The problems in your two pieces of code are:
Use Rijndael-128 with a key and block size of 16 bytes / 128 bit in both the .NET and the PHP code. For Rijndael-256, your code generates an IV with the wrong length. And I don't know how to use AES-256 in PHP (key length of 32 bytes / 256 bits, block size of 16 bytes / 128 bit).
Use of MD5: In the PHP code, add a second parameter true to the md5() function (in two places) so the result is binary data and not a hexadecimal string.
In the encrypt() function in your PHP code, replace the variable $str with $decrypted (in two places). $str is never assigned a value and never used, so the padding has no effect.
If you fix these problems, then both programs will return the result:
Encrypted: /DMkj7BL9Eu2LMxKhdGT+A==
I haven't tried to decrypt it.

For starters the 2 bits of code will create different initialization vectors (PHP is using sha256, and .net md5). And you're not truncating the PHP output by then first null char. There are several potential char set issues in the code too.

Related

How do i transform a string into an openssl_encrypt string?

i have to translate a string into openssl encrypt AES-256.
The agency gave me a code snippet how they translate the code in VB.net
Dim iv As Byte() = {&HDB, &H84, &H95, &HBD, &HDA, &HD5, &HD3, &HF8, &HCE, &H81, &H9C, &HA5, &HB3, &H8B, &H24, &H54} (16 Character)
the password is already a hex-code "4093f94891...."
i want to use the following function
openssl_encrypt($string, $encrypt_method, $key, $option, $iv);
$string = "my string"
$encrypt_method = "AES-256-CBC"
$key = "4093f94891...."
$option = 0
$iv = ???
How do i translate the iv as byte() ?
Dim iv As Byte() = {&HDB, &H84, &H95, &HBD, &HDA, &HD5, &HD3, &HF8,
&HCE, &H81, &H9C, &HA5, &HB3, &H8B, &H24, &H54} (16 Character) in
PHP ?

AES 256 with PKCS7 padding

The GST Council has approved the implementation of ‘e-Invoicing’ or ‘electronic invoicing’ of Business to Business (B2B) invoices to GST System if company turnover is greater that 500 crore. Ref of gst portal API :einv-apisandbox.nic.in/index.html
I have to decrypt the encrypted SEK using APP key and encode json data using decrypted SEK to post for Einvoice Generation and i found sample code for java and C# and i have converted in PHP but unfortunately failed to get desired output
In my case encrypted SEK is: oRvKfBtmgNTSuk/oXUhiLOjXi45jiWA2oKNxhhQM3UH2o/32YWGLbUjK1/dohPe3
APP key: fao1PoKaLgd11xMrWTiL2cggAfx9QMwM
Symmetric decryption (AES) (in java)
public static String decrptyBySyymetricKey(String encryptedSek, byte[] appKey)
{
Key aesKey = new SecretKeySpec(appKey, "AES"); // converts bytes(32 byte random generated) to key
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // encryption type = AES with padding PKCS5
cipher.init(Cipher.DECRYPT_MODE, aesKey); // initiate decryption type with the key
byte[] encryptedSekBytes = Base64.decodeBase64(encryptedSek); // decode the base64 encryptedSek to bytes
byte[] decryptedSekBytes = cipher.doFinal(encryptedSekBytes); // decrypt the encryptedSek with the initialized cipher containing the key(Results in bytes)
String decryptedSek = Base64.encodeBase64String(decryptedSekBytes); // convert the decryptedSek(bytes) to Base64 StriNG
return decryptedSek; // return results in base64 string
}catch(Exception e) {
return "Exception; "+e;
}
}
Symmetric encryption (AES) (in java)
public static string EncryptBySymmetricKey(string text, string sek)
{
//Encrypting SEK
try
{
byte[] dataToEncrypt = Convert.FromBase64String(text);
var keyBytes = Convert.FromBase64String(sek);
AesManaged tdes = new AesManaged();
tdes.KeySize = 256;
tdes.BlockSize = 128;
tdes.Key = keyBytes;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
pICryptoTransform encrypt__1 = tdes.CreateEncryptor();
byte[] deCipher = encrypt__1.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);
tdes.Clear();
string EK_result = Convert.ToBase64String(deCipher);
return EK_result;
}
catch (Exception ex)
{
throw ex;
}
}
Symmetric encryption (AES) (in PHP)
function encrypt($data, $key)
{
$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, hash('SHA256', $key, true), $data, MCRYPT_MODE_ECB));
}
Symmetric decryption (AES) (in PHP)
function decrypt($key, $str)
{
$str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, hash('SHA256', $key, true), $str, MCRYPT_MODE_ECB);
$pad = ord($str[($len = strlen($str)) - 1]);
$len = strlen($str);
$pad = ord($str[$len-1]);
return base64_encode( substr($str, 0, strlen($str) - $pad));
}
The decryption of the session key (SEK) with the AppKey is possible in PHP as follows:
function decrptyBySymmetricKey($encSekB64, $appKey) {
$sek = openssl_decrypt($encSekB64, "aes-256-ecb", $appKey, 0); // the SEK
$sekB64 = base64_encode($sek); // the Base64 encoded SEK
return $sekB64;
}
The encryption of data with the SEK is possible in PHP as follows:
function encryptBySymmetricKey($dataB64, $sekB64){
$data = base64_decode($dataB64); // the data to encrypt
$sek = base64_decode($sekB64); // the SEK
$encDataB64 = openssl_encrypt($data, "aes-256-ecb", $sek, 0); // the Base64 encoded ciphertext
return $encDataB64;
}
Both functions can be tested with the following data:
$appKey = 'fao1PoKaLgd11xMrWTiL2cggAfx9QMwM'; // the 32 bytes AppKey
$encSekB64 = 'oRvKfBtmgNTSuk/oXUhiLOjXi45jiWA2oKNxhhQM3UH2o/32YWGLbUjK1/dohPe3'; // the Base64 encoded encrypted SEK
$dataB64 = 'VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=='; // the base64 encoded data
$sekB64 = decrptyBySymmetricKey($encSekB64, $appKey); // the Base64 encoded SEK
$encDataB64 = encryptBySymmetricKey($dataB64, $sekB64); // the Base64 encoded ciphertext
echo $sekB64 . "\n"; // zVoede7m2nnvMHcWYIfKhrvsilSFEZYiltJmxVQQnAQ=
echo $encDataB64; // JS+hxYf64FMHThrhoIejqk3VjGwFw+GTYzUyVKc6GEOLKERVuvaNY91zPdo829r0
The Java method decryptBySymmetricKey returns with
byte[] appKey = "fao1PoKaLgd11xMrWTiL2cggAfx9QMwM".getBytes(StandardCharsets.UTF_8);
String encSekB64 = "oRvKfBtmgNTSuk/oXUhiLOjXi45jiWA2oKNxhhQM3UH2o/32YWGLbUjK1/dohPe3";
String sekB64 = decryptBySymmetricKey(encSekB64, appKey);
the same value for the Base64 encoded SEK (zVoede7m2nnvMHcWYIfKhrvsilSFEZYiltJmxVQQnAQ=).
Likewise, the C# method EncryptBySymmetricKey (erroneously labeled in the question as Java function) returns with
string dataB64 = "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==";
string sekB64 = "zVoede7m2nnvMHcWYIfKhrvsilSFEZYiltJmxVQQnAQ=";
string encDataB64 = EncryptBySymmetricKey(dataB64, sekB64);
the same value for the Base64 encoded ciphertext (JS+hxYf64FMHThrhoIejqk3VjGwFw+GTYzUyVKc6GEOLKERVuvaNY91zPdo829r0).
Note:
The deprecated mcrypt is not used. Instead openssl is applied.
Besides the security aspect, openssl has the advantage over mcrypt, that PKCS7 padding is implicitly used, analogous to the C#/Java code. mcrypt applies Zero padding, so a user defined padding was necessary, which is obsolete with openssl.
The key is not derived from the passed key via SHA256, but applied directly, analogous to the C#/Java code.
You also might need to try with postman tool. I achieve the same and able to connect the NIC system but as per the document they have provided it's not possible to achieve the same encryption using OpenSSL or other encryption tool.
Now I moved on to GSP based API connectivity solution you might check this stuff from
https://github.com/sujianalytics/gst-e-invoicing-sap
It's open source but not relevant for your issue, might need to upgrade little bit as per your requirement.

Decrypting in PHP encrypted in VB

I have to decrypt data in PHP that was encrypted IN VB.
When I decrypt numbers I have no problem, but when I decrypt text I only get the first 8 characters and then random.
This is the key "a1R#f7D$"
This is what I am trying to decrypt:
LwEe+sQCn63m9kjtqiy67ul5R1Ng7SZPVO4YYxQvZtUZBwNTb+Ey0qCNsrczI4jN
And I get this:
{Preinsc]hn��m�ȕ�!��^߇� $! �E&;�e^#S�)6Ui�4�
I tried with MCRYPT_RIJNDAEL_256 and ecb but none worked to me.
function decrypt($data ){
$encryption_key = "a1R#f7D$";
$data = urldecode($data);
$key = md5(utf8_encode($encryption_key), true);
//Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8);
$data = base64_decode($data);
$data = mcrypt_decrypt('tripledes', $key, $data, 'ecb');
$block = mcrypt_get_block_size('tripledes', 'ecb');
$len = strlen($data);
$pad = ord($data[$len-1]);
return substr($data, 0, strlen($data) - $pad);
}
This is the function that encrypted this:
Public Shared Function tryingTripleDes (ByVal value As String, ByVal key As String) As String
Dim des As New Security.Cryptography.TripleDESCryptoServiceProvider
des.IV des.IV = New Byte(7) {}
Dim pdb As New Security.Cryptography.PasswordDeriveBytes(key, New Byte(-1) {})
des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, New Byte(7) {})
Dim ms As New IO.MemoryStream((value.Length * 2) - 1)
Dim encStream As New Security.Cryptography.CryptoStream(ms, des.CreateEncryptor(), Security.Cryptography.CryptoStreamMode.Write)
Dim plainBytes As Byte() = Text.Encoding.UTF8.GetBytes(value)
encStream.Write(plainBytes, 0, plainBytes.Length)
encStream.FlushFinalBlock()
Dim encryptedBytes(CInt(ms.Length - 1)) As Byte
ms.Position = 0
ms.Read(encryptedBytes, 0, CInt(ms.Length))
encStream.Close()
Return Convert.ToBase64String(encryptedBytes)
End Function
This would typically happen if the ciphertext is CBC encrypted with an all zero byte IV. Other modes may also work, but CBC is by far the most likely. Your key and cipher are correct, otherwise you will only get garbage in return - certainly not legible text.
Note that MCRYPT_RIJNDAEL_256 is not even AES, so trying that is kind of useless, you should use MCRYPT_RIJNDAEL_128 with a correctly sized key to get AES.
I won't go into the security of CBC with a zero byte IV and deprecated cipher like 3DES. It's not a good idea, especially not for transport security.

Convert VB.NET AES encoding to PHP using openssl_decrypt

Currently I'm working on integration of external service wrote in VB.NET.
This service send me a string with some information encrypted with below function (this is a cut and past from the external service developer that send me the code)
Public Function Decode(ByVal S As String, ByVal chiave As String, ByVal iv As String) As String
Dim rjm As RijndaelManaged = New RijndaelManaged
rjm.KeySize = 128
rjm.BlockSize = 128
rjm.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(chiave)
rjm.IV = System.Text.ASCIIEncoding.ASCII.GetBytes(iv)
Try
Dim input() As Byte = System.Convert.FromBase64String(S)
Dim output() As Byte = rjm.CreateDecryptor.TransformFinalBlock(input, 0, input.Length)
Return System.Text.Encoding.UTF8.GetString(output)
Catch ex As System.Exception
Return S
End Try
End Function
if I decode the string with below mcrypt function everything work as expected:
$mcrypt_cipher = MCRYPT_RIJNDAEL_128;
$mcrypt_mode = MCRYPT_MODE_CBC;
$iv= '1234567891011121';
$key = '1234567891011121';
$message= base64_decode($message);
$message = rtrim(mcrypt_decrypt($mcrypt_cipher, $key, $message, $mcrypt_mode, $iv), "\0");;
But i'm unable to obtain same result with openssl_decrypt. the function always fail with false as result, below the code:
$result = openssl_decrypt(
base64_decode($message),
'AES-128-CBC',
$key,
OPENSSL_RAW_DATA,
$iv
);
I'm pretty sure that the problem is related to some padding that i missing.. but I don't understand where the problem is exactly.
UPDATE1 -
I correct the code, both $iv and $key are strings i forgot the ' both are of 16Bytes = 128Bits

Rijndael in PHP

I am trying to encrypt a string with a key and iv with Rijndael in PHP.
I have wrote this in VB .Net and the result is the expected one:
'This is the byte Array of "1234567890ABCDEF1234567890ABCDEF". I am using this for IV
Private _key1 As Byte() = New Byte(15) {CByte(18), CByte(52), CByte(86), CByte(120), CByte(144), CByte(171), _
CByte(205), CByte(239), CByte(18), CByte(52), CByte(86), CByte(120), _
CByte(144), CByte(171), CByte(205), CByte(239)}
Public Sub Init()
Dim sKey As String = "D6850B89370BD603BD48CEAD43488639DE3ABE73D2CF7C54B0CF72D2FB06E162"
Dim resBytes As Byte() = Me.EncryData("a", sKey)
File.WriteAllBytes("C:/myFile.txt", resBytes)
End Sub
Public Function EncryData(sPath As String, sKey As String) As Byte()
Return Me.AESEncrypt(plainText, Me.Data_Hex_Asc(sKey))
End Function
Public Function Data_Hex_Asc(ByRef Data As String) As Byte()
Dim str1 As String = ""
Dim list As New List(Of Byte)()
While Data.Length > 0
Dim num As Integer = CInt(Convert.ToChar(Convert.ToUInt32(Data.Substring(0, 2), 16)))
Dim str2 As String = Convert.ToChar(Convert.ToUInt32(Data.Substring(0, 2), 16)).ToString()
list.Add(CByte(Convert.ToUInt32(Data.Substring(0, 2), 16)))
str1 += str2
Data = Data.Substring(2, Data.Length - 2)
End While
Return list.ToArray()
End Function
Public Function AESEncrypt(plainText As String, aByte As Byte()) As Byte()
Dim symmetricAlgorithm As SymmetricAlgorithm = DirectCast(Rijndael.Create(), SymmetricAlgorithm)
Dim bytes As Byte() = Encoding.UTF8.GetBytes(plainText)
symmetricAlgorithm.Key = aByte
symmetricAlgorithm.IV = Me._key1
Dim memoryStream As New MemoryStream()
Dim cryptoStream As New CryptoStream(DirectCast(memoryStream, Stream), symmetricAlgorithm.CreateEncryptor(), CryptoStreamMode.Write)
cryptoStream.Write(bytes, 0, bytes.Length)
cryptoStream.FlushFinalBlock()
Dim numArray As Byte() = memoryStream.ToArray()
cryptoStream.Close()
memoryStream.Close()
Return numArray
End Function
Now the PHP version of that:
$AES_KEY = "D6850B89370BD603BD48CEAD43488639DE3ABE73D2CF7C54B0CF72D2FB06E162";
$key = pack('H*', $AES_KEY);
$plaintext = "a"; ;
$iv = pack('H*', "1234567890ABCDEF1234567890ABCDEF");
$enc_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
The result from PHP code is different from the VB's.
Any suggestions for different php approach?
VB .net implementation of Rijndael uses as default padding: PKCS7 and mode: CBC
Results: vb .net: PFΑ&\O?„\LϋAμCt php:_yJ_½%sAj«SUhA
16 chars length, both of them.

Categories