Postgresql decrypting data encrypted on C# - c#

So, I'm trying to decrypt a data on Postgres that was encrypted on C#.
On both sides I'm trying to have the same specification:
Algorithm: DES
Mode: ECB
Padding: PKCS
Key: md5 hashed bytes from string
Well, I couldn't find on Postgres docs anything about DES algorithm and "Postgres PKCS" and "C# PKCS7", while reading pgcrypto
So, for my tests I wrote an small sample code in C#, here:
using System;
public class Program
{
public static void Main()
{
System.Text.StringBuilder sbHash = new System.Text.StringBuilder();
System.Security.Cryptography.MD5CryptoServiceProvider md5provider = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] keyBytes = md5provider.ComputeHash(new System.Text.UTF8Encoding().GetBytes("myCriptoKey"));
string myText = "testing texts";
for (int i = 0; i < keyBytes.Length; i++)
{
sbHash.Append(keyBytes[i].ToString("x2")); //X2 for uppercase
}
Console.WriteLine("MD5 1: " + sbHash.ToString());
Console.WriteLine("MD5 2: " + BitConverter.ToString(keyBytes).Replace("-","").ToLower());
var criptoProvider = new System.Security.Cryptography.TripleDESCryptoServiceProvider
{
Mode = System.Security.Cryptography.CipherMode.ECB,
Key = keyBytes,
Padding = System.Security.Cryptography.PaddingMode.PKCS7
};
byte[] bytesFroMyText = System.Text.Encoding.UTF8.GetBytes(myText);
byte[] bytesEncrypted = criptoProvider.CreateEncryptor().TransformFinalBlock(bytesFroMyText, 0, bytesFroMyText.Length);
string result = Convert.ToBase64String(bytesEncrypted);
Console.WriteLine("To B64: " + result);
bytesFroMyText = Convert.FromBase64String(result);
byte[] bytesDecrypted = criptoProvider.CreateDecryptor().TransformFinalBlock(bytesFroMyText, 0, bytesFroMyText.Length);
result = System.Text.Encoding.UTF8.GetString(bytesDecrypted);
Console.WriteLine("From B64: " + result);
}
}
Generating the following output:
MD5 1: 0a76defbd66108b4d01405901f752604
MD5 2: 0a76defbd66108b4d01405901f752604
To B64: +hib+YR+/a0JuUhVm0TiJQ==
From B64: testing texts
So, as you can notice, my encrypted result after convert to base 64 is "+hib+YR+/a0JuUhVm0TiJQ==".
But I couldn't generate the same result on Postgres, trying the following:
SELECT ENCODE(ENCRYPT('testing texts', 'myCriptoKey', 'des-ecb/pad:pkcs')::bytea, 'base64');
SELECT ENCODE(ENCRYPT('testing texts', 'myCriptoKey'::bytea, 'des-ecb/pad:pkcs')::bytea, 'base64');
SELECT ENCODE(ENCRYPT('testing texts', MD5('myCriptoKey')::bytea, 'des-ecb/pad:pkcs')::bytea, 'base64');
SELECT ENCODE(ENCRYPT('testing texts', DIGEST('myCriptoKey', 'md5')::bytea, 'des-ecb/pad:pkcs')::bytea, 'base64');
Results are:
B5/rqJsOUBdMFQDgqYT9YA==
B5/rqJsOUBdMFQDgqYT9YA==
XQMiNJStZx/+xLvrLH8U7A==
0F/aYK60eaiYkI2T+IPaMA==
So if I use C# generated base64 string on any sql DECODE matching all tried encryption above, like:
SELECT CONVERT_FROM(DECRYPT(DECODE('+hib+YR+/a0JuUhVm0TiJQ==','base64')::bytea, DIGEST('myCriptoKey', 'md5')::bytea, 'des-ecb/pad:pkcs'), 'UTF-8')
Result is:
ERROR: invalid byte sequence for encoding "UTF8": 0xff
SQL state: 22021
So, my question is. How to decrypt on Postgres the generated data on C# script above.

Related

Compatibility between AesJS and C# System.Security.Cryptography

I'm developing an application in NodeJS that consums a C# API. And I want to implement securized calls with AES. I'm using AesJS in NodeJS and System.Security.Cryptography in C#.
The C# part is used in other parts of the application and works correctly, so I'm guessing my error is in the NodeJS part.
The error is:
Invalid length for a Base-64 char array or string.
My code:
NodeJS
encryptData = function(data) {
var key = pbkdf2.pbkdf2Sync(config.aes.pass, config.aes.salt, 1, 128 / 8, null);
var dataBytes = aesjs.utils.utf8.toBytes(data);
var ivBytes = aesjs.utils.utf8.toBytes(config.aes.iv);
var aesOfb = new aesjs.ModeOfOperation.ofb(key, ivBytes);
var encryptedBytes = aesOfb.encrypt(dataBytes);
var encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes);
return encryptedHex;
}
C#
public static string DecodeAndDecrypt(string encrypted)
{
using (var csp = Aes.Create())
{
var d = GetCryptoTransform(csp, false);
byte[] output = Convert.FromBase64String(encrypted);
byte[] decryptedOutput = d.TransformFinalBlock(output, 0, output.Length);
string decypted = Encoding.UTF8.GetString(decryptedOutput);
return decypted;
}
}
The error happens in this line:
byte[] output = Convert.FromBase64String(encrypted);
UPDATE
In order to test what's commented, I added parse to base64 in NodeJS:
return Buffer.from(encryptedHex).toString('base64');
Now I'm getting one step ahead into:
byte[] decryptedOutput = d.TransformFinalBlock(output, 0, output.Length);
And it returns error:
The input data is not a complete block.

c# Bouncy Castle Blowfish Decryption - Pad block corrupted

I am trying to decrypt a blowfish encrypted string with Bouncycastle in C#.
I am able to easily encrypt and decrypt my own string but, unfortunately, I have to decrypt a string that is generated by another system.
I AM able to recreate that same string with C# / Bouncycastle using the following but I have yet to decrypt it successfully.
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
...
static readonly Encoding Encoding = Encoding.UTF8;
public string BlowfishEncrypt(string strValue, string key)
{
try
{
BlowfishEngine engine = new BlowfishEngine();
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(engine);
KeyParameter keyBytes = new KeyParameter(Encoding.GetBytes(key));
cipher.Init(true, keyBytes);
byte[] inB = Encoding.GetBytes(strValue);
byte[] outB = new byte[cipher.GetOutputSize(inB.Length)];
int len1 = cipher.ProcessBytes(inB, 0, inB.Length, outB, 0);
cipher.DoFinal(outB, len1);
return BitConverter.ToString(outB).Replace("-", "");
}
catch (Exception)
{
return "";
}
}
Below is what I have for decryption at the moment. The line that fails with error "pad block corrupted" is cipher.DoFinal(out2, len2);
public string BlowfishDecrypt(string name, string keyString)
{
BlowfishEngine engine = new BlowfishEngine();
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(engine);
StringBuilder result = new StringBuilder();
cipher.Init(false, new KeyParameter(Encoding.GetBytes(keyString)));
byte[] out1 = Convert.FromBase64String(name);
byte[] out2 = new byte[cipher.GetOutputSize(out1.Length)];
int len2 = cipher.ProcessBytes(out1, 0, out1.Length, out2, 0);
cipher.DoFinal(out2, len2); //Pad block corrupted error happens here
String s2 = BitConverter.ToString(out2);
for (int i = 0; i < s2.Length; i++) {
char c = s2[i];
if (c != 0) {
result.Append(c.ToString());
}
}
return result.ToString();
}
Any idea what I might be doing wrong in BlowfishDecrypt()?
Note:
I converted the above (encrypt and decrypt) from a bouncycastle Java example I found somewhere; the encrypt works. The only difference I can see is that the Java example uses a StringBuffer where I use a StringBuilder.
Thank you, Artjom B!
byte[] out1 = Convert.FromBase64String(name);
Should have been
byte[] out1 = Hex.Decode(name);
From there, all I had to do was convert the Hex to a string.

Encrypt / Decrypt data with AES between c# and PHP - decrypted data starts with 255,254

I have to request data from an external existing webservice written in C#.
This webservice requires some of the data to be encrypted (The connection uses an SSL connection, some of the data is aes encrypted)
On the php site openssl is used for decrypting.
The following settings are used on the c# site
(This are the default values for the AesCryptoServiceProvider):
Algorithm: AES
Padding: PKCS7
Mode: CBC
Keysize: 256
The padding for PKCS7 works as following:
01 If 1 byte is missing
02 02 If 2 bytes are missing
and so on
so this values are not added by the padding.
What am I doing wrong?
I've checked this with c#, php and ruby - the decrypted data starts with 255, 254
To reproduce use the following parameters:
data:1234567890123456
key: First1
salt(iv):Data
using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
namespace crypto_test
{
class MainClass
{
public static void Main(string[] args)
{
bool running = true;
while (running)
{
Console.WriteLine("Enter data:");
var data = Console.ReadLine();
Console.WriteLine("Enter key:");
var key = Console.ReadLine();
Console.WriteLine("Enter iv:");
var iv = Console.ReadLine();
Console.WriteLine("Enter d for decode");
var decode = (Console.ReadLine() == "d");
string encoded=Crypt(data, key, iv, decode);
Console.WriteLine(encoded);
if (!decode)
{
encoded= Crypt(encoded, key, iv, true);
Console.WriteLine(encoded);
}
Console.WriteLine("quit to exit");
running = !(Console.ReadLine() == "quit");
}
}
public static string Crypt(string value, string password, string salt, bool decrypt)
{
DeriveBytes rgb = new Rfc2898DeriveBytes(password, Encoding.Unicode.GetBytes(salt));
SymmetricAlgorithm algorithm = new AesCryptoServiceProvider();
byte[] rgbKey = rgb.GetBytes(algorithm.KeySize >> 3);
byte[] rgbIV = rgb.GetBytes(algorithm.BlockSize >> 3);
Console.WriteLine("rbKey: size:{0} key:{1}", (algorithm.KeySize >> 3), GetHex(rgbKey));
Console.WriteLine("rgbIV: size:{0} key:{1}", (algorithm.BlockSize >> 3), GetHex(rgbIV));
ICryptoTransform transform = decrypt ? algorithm.CreateDecryptor(rgbKey, rgbIV) : algorithm.CreateEncryptor(rgbKey, rgbIV);
Console.WriteLine("Mode {0}", algorithm.Mode);
Console.WriteLine("PAdding {0}", algorithm.Padding);
using (MemoryStream buffer = new MemoryStream())
{
using (CryptoStream stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write))
{
try
{
if (decrypt)
{
byte[] data = Convert.FromBase64String(value);
stream.Write(data,0,data.Length);
}
else
{
using (StreamWriter writer = new StreamWriter(stream, Encoding.Unicode))
{
writer.Write(value);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
byte[] buff = buffer.ToArray();
if (decrypt)
{
return Encoding.Unicode.GetString(buff) + "\r\n" + GetHex(buff);
}
else
return Convert.ToBase64String(buff);
}
}
public static string GetHex(byte[] data)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.Length; ++i)
sb.Append(data[i].ToString("X2"));
return sb.ToString();
}
}
}
I have not found an equivalent to Rfc2898DeriveBytes until now,
so I copied the key and iv
php
<?php
$salt='Data';
$pass='First1';
$data='1234567890123456';
$encrypted_base64='VKNd9Pi+cttaM6ne8pzAuFbH1U0gJiJ2Wlbbr1rU5z8vbIfAS6nb0/5py4p54aK7';
$encrypted=base64_decode($encrypted_base64);
$key = pack('H*', "30EE7F95F0EF4835F048A481424F2F52EE21B7CEB97F8CC437E5949DB53797D9");
$iv = pack('H*', "B29F5ECF7057065758102385509F0637");
$cipher='AES-256-CBC';
$decrypted = openssl_decrypt($encrypted,$cipher, $key,true,$iv);
for($i =0; $i<strlen($decrypted);++$i)
{
echo "char:" . ord($decrypted[$i])."<br/>";
}
echo $decrypted
?>
ruby:
require ('openssl')
require ('base64')
while true
enc_data='VKNd9Pi+cttaM6ne8pzAuFbH1U0gJiJ2Wlbbr1rU5z8vbIfAS6nb0/5py4p54aK7'
data = Base64.decode64(enc_data)
key_hex='30EE7F95F0EF4835F048A481424F2F52EE21B7CEB97F8CC437E5949DB53797D9'
iv_hex='B29F5ECF7057065758102385509F0637'
key = [key_hex].pack('H*')
iv = [iv_hex].pack('H*')
decipher = OpenSSL::Cipher::AES.new(256, :CBC)
decipher.decrypt
decipher.key = key
decipher.iv = iv
plain = decipher.update(data) + decipher.final
puts plain
puts plain.bytes
end
Good news, your decryption seems to work OK.
What you are seeing in the decrypted ciphertext is the byte order mark for UTF-16 LE, which is (incorrectly) indicated by Microsoft as Encoding.Unicode. You need to do either one off two things:
decode the text with a decoder that groks UTF-16 LE including byte order mark;
encode using much more reasonable UTF-8 encoding (in the C# code).
Personally I would put a strong preference on (2).

PHP & C# compatible Rijndael managed CBC mode, 256 bit encryption/decryption

This is my very first attempt at cryptography and I am having trouble with porting the encryption from PHP to C#.
I had searched the internet for a working solution to my problem but everything I have tried does not work. I am getting different results between the two languages.
In PHP I have the following code:
function encrypt($Key, $strToEncrypt){
$md5Key = md5(pack("H*", $Key));
$md5Iv = md5($Key);
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$padding = $block - (strlen($strToEncrypt) % $block);
$strToEncrypt .= str_repeat(chr($padding), $padding);
$enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $md5Key, $strToEncrypt, MCRYPT_MODE_CBC, $md5Iv);
$enc2 = base64_encode($enc);
return $enc2;
}
and in C# the following code:
public string Encrypt(string strToEncrypt)
{
string ret;
var pKey = PackH(_appkey);
var md5Key = CalcMd5(pKey);
var iv = CalcMd5(_appkey);
var enc =Encoding.UTF8;
var eIv = enc.GetBytes(iv);
var eKey = enc.GetBytes(md5Key);
using (var rij = new RijndaelManaged { BlockSize = 256, KeySize = 256, IV = eIv, Key = eKey, Mode = CipherMode.CBC, Padding = PaddingMode.Zeros})
using (var memoryStream = new MemoryStream())
using (var cryptoStream = new CryptoStream(memoryStream, rij.CreateEncryptor(eKey, eIv), CryptoStreamMode.Write))
{
using (var sw = new StreamWriter(cryptoStream))
{
sw.Write(strToEncrypt);
}
ret = Convert.ToBase64String(memoryStream.ToArray());
}
return ret;
}
The C# Pack function:
protected byte[] PackH(string hex)
{
if ((hex.Length % 2) == 1) hex += '0';
var bytes = new byte[hex.Length / 2];
for (var i = 0; i < hex.Length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
And the C# CalcMd5 function:
protected string CalcMd5(string textToEnc)
{
var sB = new StringBuilder();
using (var mdHash = MD5.Create())
{
var cHash = mdHash.ComputeHash(Encoding.UTF8.GetBytes(textToEnc));
foreach (byte t in cHash)
{
sB.Append(t.ToString("x2"));
}
}
return sB.ToString();
}
I have another CalcMd5 function that takes in a byte[] (it is like the one above but does not have the GetBytes part).
The keys and the string that needs encrypting are the same both in PHP and C#:
The Key: "24acd2fcc7b20b8bd33ff45176f03061a09b729487e10d2dd38ab917" and
The string that I want to encode: "110114135AB96637711100"
In C# the result of the function is:"LHTqpxCJrONmbDdUFHyUZZUVf94z1RmSXWo85/wyEew=" while in PHP is: "5MkCjfs0vp2HSKdY5XPUAuV68YsrP31Q+ddZsd5p7Sc=".
I have tried modifying the padding mode in C#, also tried different methods found on the stackoverflow site but none of them works.
I have checked and the final key and Iv that are passed to the mcrypt function and RijndaelManaged function are the same and both have 32 byte size.
The oddly part is that the decryption functions are working very well (it is working to decrypt the PHP encrypted string with C# function and the other war around C# encrypted string is decrypted with the PHP function).
Could it be a problem with the encoding? Or maybe the padding? Or is there something else that I have overlooked?
The problem seems to be your padding, on PHP-side you are manually doing PKCS7-Padding:
$padding = $block - (strlen($strToEncrypt) % $block);
$strToEncrypt .= str_repeat(chr($padding), $padding);
And on C#-side you are using:
Padding = PaddingMode.Zeros
To fix this you could either modify the PHP-code by removing the above mentioned two lines since mcrypt() does automatically do ZeroBytePadding for you.
Or you could change the padding in C# to:
Padding = PaddingMode.PKCS7

Ruby sha and hash to c#

Im trying to translate this to c#
f1 = Digest::SHA1.hexdigest(#password)
f2 = nonce + ":" + f1
Digest::MD5.hexdigest(f2)
My Code
private static string GetSHA1HashData(string data)
{
//create new instance of md5
SHA1 sha1 = SHA1.Create();
//convert the input text to array of bytes
byte[] hashData = sha1.ComputeHash(Encoding.Default.GetBytes(data));
//create new instance of StringBuilder to save hashed data
StringBuilder returnValue = new StringBuilder();
//loop for each byte and add it to StringBuilder
for (int i = 0; i < hashData.Length; i++)
{
returnValue.Append(hashData[i].ToString());
}
// return hexadecimal string
return returnValue.ToString();
}
public static string CreateMD5Hash(string input)
{
// Use input string to calculate MD5 hash
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
// To force the hex string to lower-case letters instead of
// upper-case, use he following line instead:
// sb.Append(hashBytes[i].ToString("x2"));
}
return sb.ToString();
}
Call
var nonce = "1386755695841";
var password = "edc123";
var sha = GetSHA1HashData(password);
var md5 = CreateMD5Hash(nonce + ":" + sha);
But i cant get it right, any ideas
The problem is that .NET uses UTF-16 by default whilst Ruby will use something else (normally UTF-8, but it may also respect encoding that has been set by database or web source).
I think you just need to alter one line:
//convert the input text to array of bytes
byte[] hashData = sha1.ComputeHash(Encoding.ASCII.GetBytes(data));
You may need UTF-8 or even some other encoding instead, depending on the range of passwords accepted by the Ruby version. However, the ASCII coding should at least prove correctness of this answer in general from your sample data.

Categories