matching encryption from C++ (crypto++) to c# - c#

I'm trying to match encryption schemes on c++ using crypto++ and c# and can't seem to get the same results on both. They both work on them selves, but not from one to the other. Any help would be great!
C++ code using Crypto++:
std::string key = "01286567891233460123456789123456";
std::string iv = "0123456789123456";
std::string encrypt(const std::string& str_in)
{
std::string str_out;
CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());
StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);
stfEncryptor.MessageEnd();
return str_out;
}
std::string decrypt(const std::string& cipher_text)
{
std::string str_out;
CryptoPP::AES::Decryption aesDecryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, (byte*)iv.c_str());
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(str_out));
stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipher_text.c_str()), cipher_text.size());
stfDecryptor.MessageEnd();
return str_out;
}
The Code Ran:
std::string str = encrypt("123456789012345");
str = decrypt(str);
This output is:
Encrypted: Ö&qcƒ“¹yLY»Lïv¹w“¼LLŠÀ¶ó¢,óð9·
Length: 32
Decrypted: 123456789012345
Length: 16
Now in C#, I have the following code:
public string Encrypt(string clearText)
{
byte[] clearBytes = Encoding.Default.GetBytes(clearText);
using (Aes encryptor = Aes.Create("AES"))
{
// encryptor.BlockSize = 128;
encryptor.Padding = PaddingMode.Zeros;
encryptor.KeySize = 128;
encryptor.Mode = CipherMode.CBC;
encryptor.Key = Encoding.Default.GetBytes("01234567891234560123456789123456");
encryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
clearText = Encoding.Default.GetString(bt);// Convert.ToBase64String(bt);
}
}
return clearText; //Return the encrypted command
}
public string Decrypt(string cipherText)
{
byte[] clearBytes = Encoding.Default.GetBytes(cipherText);
using (Aes decryptor = Aes.Create("AES"))
{
// decryptor.BlockSize = 128;
decryptor.Padding = PaddingMode.Zeros;
decryptor.KeySize = 128;
decryptor.Mode = CipherMode.CBC;
decryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789123456");
decryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
cipherText = Encoding.Default.GetString(bt);// Convert.ToBase64String(bt);
}
}
return cipherText; //Return the decrypted text
}
}
The code ran:
string orig = "123456789012345";
string cipher = Encrypt(orig);
string dedata = Decrypt(cipher);
The results are:
Orig: 123456789012345
Encrypted: êßyoº0¦ëì›X˜Ü
Length: 16
Decrypted: 123456789012345
Length: 16
As you can see, the encrypted strings end up being different. So when I take an encrypted string in c++, it can't decrypt it in c#, as shown here:
bytes[] encryptedText = ENCRYPTED TEXT FROM C++
text = System.Text.Encoding.Default.GetString(encryptedText);
text = Decrypt(text);
The c++ returns 32 bytes for it's encrypted string which I believe is the padding being added. Not sure how to replicate this in the c# code or vise versa to match things up. Not sure if there is something else I'm missing here... Thanks for any help!
EDIT:
I've matched the keys and now the string matches on both ends except for the padding difference. When I try to decrypt the string in C# it tells me the input data is not the correct block size? Any help with this now?
EDIT AGAIN:
It seems to be generating the same byte string for each c# and c++ encryption function, so that problem is resolved. The problem I now seem to have is on the c# side, I receive the encrypted string and convert the bytes using: text = System.Text.Encoding.Default.GetString(recvBuf); recvBuf being the encrypted string from c++ and it's missing the last character of the string. It matches up with the c++ string minus the last char?? Not sure why this is happening.
For example, my c++ sends over this encrypted string: Ö&qcƒ“¹yLY»Lïv and my c# program will only receive this: Ö&qcƒ“¹yLY»Lï which in turn will make it fail at decryptng. The encrypted string is being sent over a TCP SOCKET if that makes any difference.
EDIT
Still missing bytes after changing encoding and decoding to base64 on both ends.
C++ 1iZxY4OTHrl5TFm7Gkzvdrl3k7xMTIrAtvOiLPPwObc=
C# 1iZxY4OTHrl5TFm7Gkzvdg==
C# RECEIVED 1iZxY4OTHrl5TFm
New Code C#:
public string Encrypt(string clearText)
{
byte[] clearBytes = Encoding.Default.GetBytes(clearText);
using (Aes encryptor = Aes.Create("AES"))
{
// encryptor.BlockSize = 128;
encryptor.Padding = PaddingMode.Zeros;
encryptor.KeySize = 128;
encryptor.Mode = CipherMode.CBC;
encryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789123456");
encryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
clearText = Convert.ToBase64String(bt);
}
}
return clearText; //Return the encrypted command
}
And C++ Code:
std::string encrypt(const std::string& str_in)
{
std::string str_out;
std::string str_out2;
CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());
StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);
stfEncryptor.MessageEnd();
str_out2 = base64_encode(reinterpret_cast<const unsigned char*>(str_out.c_str()), strlen(str_out.c_str()));
return str_out2;
}
EDIT
IT WORKS!!! It was simply an overlook on my part, my socket was checking the size of the data before encrypted and sending that size instead of the encrypted string size. Fix that and all it working perfect. Thanks Brandon for the help!

What I am suggesting is your running afoul of text encoding both when converting the clear text to bytes for encrypting and also when converting from bytes to display string for "transmission".
Try this:
C# code
public string Encrypt(string clearText, Encoding encoding)
{
// use supplied encoding to convert clear text to bytes
byte[] clearBytes = encoding.GetBytes(clearText);
byte[] bt = // insert your encrypt code here...
// bt bytes are *not* ascii or utf8 or anything else. If you just
// use an encoding to convert to text, you won't have good results
// lets use base64 encoding to get a nice display string representation
// of the bytes
return Convert.ToBase64String(bt);
}
public string Decrypt(string base64EncryptedString, Encoding encoding)
{
// decode the base64
byte[] bt = Convert.FromBase64String(base64EncryptedString);
byte[] decrypted = // insert your decrypt code here
// now we have the original bytes. Convert back to string using the same
// encoding we used when encrypting
return encoding.GetString(decrypted);
}
// Usage:
var clearText = "Hello World";
var asciiEncrypted = Encrypt(clearText, Encoding.ASCII);
var decrypted = Decrypt(clearText, Encoding.ASCII); // MUST USE SAME ENCODING
var utf8Encrypted = Encrypt(clearText, Encoding.UTF8);
var utf8Decrypted = Decrypt(clearText, Encoding.UTF8);
You need to make the same base64 changes in your C++ code. I'm less familiar with the encoding of your C++ strings. I think that if you are using C++ string literals hard coded in the code, then they will be UTF8. This means that your C++ and C# code should agree once you make the C# changes, make the base64 changes in your C++ code, and pass UTF8 to your C# Encrypt/Decrypt methods.

Related

System.Text.Encoding.UTF8.GetString() is not converting complete byte array to string

I have to decrypt a string using AES algorithm. Basically I am converting a php code into C#. The implementation in PHP is working fine. Below is the php code for decryption:
function decrypt($data) //decrypt function
{
$authentication_key="NKu84HvQaPRr";
$iv="abcdef987654";
$payload=base64_decode($data);
$decrypt=openssl_decrypt($payload, 'AES-128-CBC', $authentication_key, 1, $iv);
return $decrypt;
}
I am able to get the $payload in my C# code but in a byte array. The byte array generated in C# matches with the byte array of $payload in PHP(Both are of same length and bytes. Screenshot is attached). Now as per the PHP code $payload is passed as a string in openssl_decrypt function, so I am also converting C# byte array to string using
string payLdBffrString = System.Text.Encoding.UTF8.GetString(payLoadBuffer,0,payLoadBuffer.Length).
Length of payLoadBuffer.Length is 1936 which is same as in PHP().
Length of payLdBffrString is 1843 which is not same as in PHP and should be same.().
Below is my C# code of decryption:
static string DecryptAes(string data, byte[] key, byte[] iv)
{
using (var aes = Aes.Create())
{
aes.Mode = CipherMode.CBC;
aes.KeySize = 128;
aes.BlockSize = 128;
aes.Padding = PaddingMode.Zeros;
aes.Key = key;
aes.IV = iv;
byte[] payLoadBuffer = Convert.FromBase64String(data);
string payLdBffrString =System.Text.Encoding.UTF8.GetString(payLoadBuffer,0,payLoadBuffer.Length);
//string payLdBffrString = BytesToString(payLoadBuffer);
//var s = new StringBuilder();
//foreach (byte b in payLoadBuffer)
//{
// s.Append(b.ToString());
//}
int strLen = payLdBffrString.Length;
//byte[] dataBuffer = Encoding.Unicode.GetBytes(data);
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
{
byte[] decryptedByteArr = PerformCryptography(payLoadBuffer, decryptor);
}
}
}
static byte[] PerformCryptography(byte[] data, ICryptoTransform cryptoTransform)
{
using (var ms = new MemoryStream())
using (var cryptoStream = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
return ms.ToArray();
}
}
Now I am stuck in generating the $payload string in C#. I have used StringBuilder and all the encodings available in .net with no success. It is also mentioned that only UTF8 encoding is giving me the desired string but problem here is that I am not getting complete string as I get in PHP code at $payload variable.
I need help regarding generation of complete payload string in C# as I get in PHP so that I can decrypt it in C#
EDIT: I have updated the DecryptAes() function and added PerformCryptography() function which is giving me again byte array. Then how can I convert this byte array to the string again?

C ++ (crypto ++) and C # encryption matching

For secure communication between client and server, I want to encrypt and decrypt data from both the client and the server, but I cannot get the same results, the data that comes from the client to the server is not decrypted, also when encrypting the same the same data from the server, I get a distinctive result from encryption on the client.
The client is written in C ++ using Crypto ++. The code:
string data = "teststring,teststring,teststring";
string encryptedData = client.encrypt(userData, "01234567891234560123456789123456", "0123456789123456");
string Client::encrypt(const string& str_in, const string& key, const string& iv)
{
try {
string str_out;
AES::Encryption aesEncryption((byte*)key.c_str(), key.length());
CBC_Mode_ExternalCipher::Encryption encryption(aesEncryption, (byte*)iv.c_str());
StringSource encryptor(str_in, true,
new StreamTransformationFilter(encryption,
new Base64Encoder(
new StringSink(str_out),
false
)
)
);
return str_out;
}
catch (exception e) {
return "null";
}
}
string Client::decrypt(const string& str_in, const string& key, const string& iv)
{
try {
string str_out;
CBC_Mode<AES>::Decryption decryption((byte*)key.c_str(), key.length(), (byte*)iv.c_str());
StringSource decryptor(str_in, true,
new Base64Decoder(
new StreamTransformationFilter(decryption,
new StringSink(str_out)
)
)
);
return str_out;
}
catch (exception e) {
return "null";
}
}
Gives the following output:
data: "teststring,teststring,teststring"
encryptedData: "STpuD/dRgYard+Yqpdd5KOYET7607i7ZRUoKm5eshHzR3ErafaxgZ2+T1tSp0lWJ"
The server side of the code is written in C # (ASP.NET Core 3.1):
public static string Encrypt(string input)
{
byte[] clearBytes = Encoding.Default.GetBytes(input);
using (Aes encryptor = Aes.Create("AES"))
{
// encryptor.BlockSize = 32;
encryptor.Padding = PaddingMode.Zeros;
encryptor.KeySize = 128;
encryptor.Mode = CipherMode.CBC;
encryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789123456");
encryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
input = Convert.ToBase64String(bt);
}
}
return input;
}
public static string Decrypt(string input)
{
byte[] clearBytes = Encoding.ASCII.GetBytes(input);
using (Aes decryptor = Aes.Create("AES"))
{
//decryptor.BlockSize = 32;
decryptor.Padding = PaddingMode.Zeros;
decryptor.KeySize = 128;
decryptor.Mode = CipherMode.CBC;
decryptor.Key = Encoding.ASCII.GetBytes("01234567891234560123456789123456");
decryptor.IV = Encoding.ASCII.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
input = Encoding.ASCII.GetString(bt);
}
}
return input;
}
Output:
data: "teststring,teststring,teststring"
encryptedData: "tIDlWnnzOQWh5HIvRDJya6z7jOglkIlYrICeYW9RoEM="
I cannot decrypt data from both the client and the server. Help me please.
The posted C++ code is fine. It returns the posted ciphertext STpu...0lWJ on my machine and the ciphertext can be decrypted with the decrypt() method.
In contrast, although the posted C# code returns the posted ciphertext tIDl...RoEM=, the ciphertext cannot be decrypted using the Decrypt() method. This has two reasons:
In the Encrypt() and in the Decrypt() method different keys are used. The key of the Decrypt() method matches the key applied in the C++ code. With regard to a comparison of the ciphertexts of both codes, the key in the Encrypt() method should be replaced.
The ciphertext is Base64 encoded in the Encrypt() method, but not Base64 decoded in the Decrypt() method (but ASCII encoded instead). Here a Base64 decoding must be done in the Decrypt() method (note that an ASCII decoding in the Encrypt() method is not an alternative, since this would corrupt the ciphertext).
If these two bugs are fixed, the ciphertexts of C++ and C# code match except for the end. This last mismatch is caused by different paddings. In the C++ code PKCS7 padding is used, in the C# code Zero padding. If the padding in the C# code (in the Encrypt() and Decrypt() methods) is changed to PaddingMode.PKCS7, the ciphertexts match.
Other problems in the C# code are:
In the Encrypt() method Encoding.Default is used, in the Decrypt() method Encoding.ASCII. Here a consistent encoding, e.g. Encoding.UTF8 should be applied.
The specified 128-bit key size is not consistent with the 256-bit key used. This has no effect because the explicit key specification automatically corrects the key size (nevertheless, the key size should be specified correctly or completely omitted).
Also, it should be noted that a static IV is insecure (for testing purposes, of course, that's OK).

Junk bytes before payload in C# UTF8 to AES to Base64 conversion

I have been trying to implement proper IV practice in methods to encrypt and decrypt a UTF-8 string with AES which is then returned as a Base64 string. Using this question as a reference, I have prepended the generated IV to the byte array before the Base64 conversion. I'm having an issue where the decrypt method returns the UTF-8 string with exactly fifty characters of random junk (encryption artifacts?). I don't believe the issue is with the encryption because the decrypt method does consistently return the encrypted string. I think the problem is with one of the other conversion steps but I'm having trouble seeing where this might be coming from. Any help would be wildly appreciated.
Encrypt method
public static string EncryptString(string input, string key)
{
using (var aes = new AesCryptoServiceProvider())
{
aes.Key = System.Convert.FromBase64String(key);
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
byte[] rawData = Encoding.UTF8.GetBytes(input);
// IV is the 16 byte AES Initialization Vector
aes.GenerateIV();
using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
{
using (var ms = new MemoryStream())
{
ms.Write(aes.IV, 0, aes.IV.Length); // aes.IV.Length should be 16
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(rawData, 0, rawData.Length);
cs.FlushFinalBlock();
}
byte[] encryptedData = ms.ToArray();
// this will hold the IV prepended to the encrypted data
byte[] output = new byte[aes.IV.Length + encryptedData.Length];
Array.Copy(aes.IV, output, aes.IV.Length); // save the iv
Array.Copy(encryptedData, 0, output, aes.IV.Length, encryptedData.Length); // save the data
// now encode the whole thing as base 64
return System.Convert.ToBase64String(output);
}
}
}
}
Decrypt method
public static string DecryptString(string input, string key)
{
using (var aes = new AesCryptoServiceProvider())
{
aes.Key = Convert.FromBase64String(key);
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
byte[] rawData = Convert.FromBase64String(input);
byte[] IV = new byte[16]; // aes.IV.Length should be 16
Array.Copy(rawData, IV, IV.Length);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(aes.Key, IV), CryptoStreamMode.Write))
{
using (var binaryWriter = new BinaryWriter(cs))
{
binaryWriter.Write(rawData,IV.Length ,rawData.Length - IV.Length);
}
}
return Encoding.UTF8.GetString(ms.ToArray());
}
}
}
My test
static void Main(string[] args)
{
string payload = "My super secret string";
string key = "tR4mPn7mBQ8G6HWusyFnGk/gqdd/enWiUTr7YbhNrJg=";
Console.WriteLine(payload);
Console.WriteLine(key);
Console.WriteLine("");
string encrypted = EncryptString(payload, key);
Console.WriteLine(encrypted);
Console.WriteLine("");
string decrypted = DecryptString(encrypted, key);
Console.WriteLine(decrypted);
Console.WriteLine(decrypted.Length.ToString() + " " + encrypted.Length.ToString());
Console.ReadKey();
}
Edit to add - this is an example of the output:
�XQ��=F�]�D�?�My super secret string
You are writing the IV to the output twice in EncryptString. First you have:
ms.Write(aes.IV, 0, aes.IV.Length); // aes.IV.Length should be 16
which is the start of encryptedData. You then copy the IV and encryptedData (which already includes the IV) into a new byte array:
// this will hold the IV prepended to the encrypted data
byte[] output = new byte[aes.IV.Length + encryptedData.Length];
Array.Copy(aes.IV, output, aes.IV.Length); // save the iv
Array.Copy(encryptedData, 0, output, aes.IV.Length, encryptedData.Length); // save the data
This doubling of the IV is what is causing the extra bytes.
You don’t need to do the second copying. Just convert encryptedData to base 64 directly and return that:
return System.Convert.ToBase64String(encryptedData);

AES 128 Cross-Platform Swift / C#

I've been trying to encrypt and decrypt on both iOS and .NET but I haven't been very successful. I've used this question but I get the error:
Specified initialisation vector (IV) does not match the block size for this algorithm.
Here's my encryption code for Swift using CryptoSwift:
let encrypt = try! "oauth_token".AES_encrypt("my key here (is 32 characters long)", iv: "1234567890123456")
func AES_encrypt(key: String, iv: String) throws -> String {
let data = self.dataUsingEncoding(NSUTF8StringEncoding)
let enc = try AES(key: key, iv: iv, blockMode:.CBC).encrypt(data!.arrayOfBytes(), padding: PKCS7())
let encData = NSData(bytes: enc, length: Int(enc.count))
let base64String: String = encData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0));
let result = String(base64String)
return result
}
And my decryption code for .NET:
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] key, byte[] iv)
{
byte[] decryptedBytes = null;
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Key = key;
AES.IV = iv;
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
byte[] encrypted_text = Convert.FromBase64String("secret token");
byte[] key = Convert.FromBase64String("32 character key");
byte[] iv = Convert.FromBase64String("0123456789012345");
string plaintext = Convert.ToBase64String(AES_Decrypt(encrypted_text, key, iv));
The block size is 16 bytes (AES.blockSize). Either you're using old version or your AES_encrypt() have some problem (AES_encrypt is not part of CryptoSwift).
Simple example from README:
let input: NSData // data to encrypt
let encrypted = try? input.encrypt(AES(key: "secret0key000000", iv:"0123456789012345"))
or this
// Encrypt string and get Base64 representation of result
let base64: String = try? "my secret string".encrypt(AES(key: "secret0key000000", iv: "0123456789012345"))

How to fix invalid key size when decrypting data in C# that was encrypted in php

I am trying to solve an encryption issue I am having between php and c#.
I have encrypted data using the following php and openssl operation.
$encrypt_method = "AES-256-CBC";
$secret_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$secret_iv = 'XXXXXXXXXXXXXXXX';
$key = hash ('sha256', $secret_key);
$iv = substr (hash ('sha256', $secret_iv), 0, 16);
$output = openssl_encrypt ($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode ($output);
I have tried a couple of methods in C# to decrypt but this is what I am trying now.
public string Encrypt_Decrypt(string action, string value) {
string secretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string secretIV = "XXXXXXXXXXXXXXXX";
string key = Hash(secretKey);
string iv = Hash(secretIV).Substring(0,16);
string retValue = "";
if (action == "encrypt") {
retValue = EncryptString(value, key, iv);
}
else if (action == "decrypt") {
retValue = DecryptString(value, key, iv);
}
}
// Hash to match php hash function
public static string Hash(string unhashedString) {
return BitConverter.ToString(new SHA256CryptoServiceProvider().ComputeHash(Encoding.Default.GetBytes(unhashedString))).Replace("-", String.Empty).ToLower();
}
public static string DecryptString(string cipherData, string keyString, string ivString) {
byte[] key = Encoding.UTF8.GetBytes(keyString);
Console.WriteLine(key.Length);
byte[] iv = Encoding.UTF8.GetBytes(ivString);
Console.WriteLine(iv.Length);
byte[] cipherCrypt = Convert.FromBase64String(cipherData);
for (int i = 0; i < cipherCrypt.Length; i++) {
Console.Write(cipherCrypt[i] + " ");
}
try {
RijndaelManaged crypto = new RijndaelManaged();
crypto.Key = key;
crypto.IV = iv;
crypto.Mode = CipherMode.CBC;
crypto.KeySize = 256;
crypto.BlockSize = 128;
crypto.Padding = PaddingMode.None;
ICryptoTransform decryptor = crypto.CreateDecryptor(crypto.Key, crypto.IV);
using (MemoryStream memStream = new MemoryStream(cipherCrypt)) {
using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read)) {
using (StreamReader streamReader = new StreamReader(cryptoStream)) {
return streamReader.ReadToEnd();
}
}
}
}
catch (CryptographicException e) {
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
}
I have tried a couple different encoding types when getting the byte[] for the operation.
I keep getting the following error:
Specified key is not a valid size for this algorithm.
Not sure what I am missing. Any help is appreciated.
Also, I already read through this and tried what the solution suggestion recommended. I got the same resulting error.
UPDATE - 01
I have updated the code here to reflect the code I have changed.
The key length is 32,
The iv length is 16,
The data coming in at "cipherData" is length 32,
When "cipherData" goes through "FromBase64String(cipherData)" it comes out as a 24 byte array. This is causing an issue for the decryptor which wants a 32 byte array.
There are obviously problems with the key size. The code between PHP and C# seem to match. The problem seems to be that the code is wrong in both cases.
Let's see how long the key actually is:
Start with a 32 byte key (non-encoded).
Hash the key with SHA-256: 32 bytes (non-encoded).
Encode to hex (integrated into PHP's hash() function by default): 64 bytes.
AES only supports the following key sizes: 16, 24 and 32 bytes. openssl_encrypt() will only use the first 32 bytes of the hex key silently. So, you need to use the first 32 bytes in C#.
Note that openssl_encrypt() takes an options argument which denotes that the output is Base64 when OPENSSL_RAW_DATA is not set. It means that the PHP output was encoded twice with Base64. So you need to decode it twice in C#.

Categories

Resources