Padding is invalid and cannot be removed AES PKCS7 - c#

I am attempting to test a simple class to encrypt and decrypt data in C#.
`
{ [TestFixture]
public class CryptTest
{
[Test]
public void TestMethod()
{
String text = "Hello World!";
String crypt = EncryptionService.Encrypt(text, Config.KEY_STRING);
Console.WriteLine(crypt);
String clear = EncryptionService.Decrypt(crypt, Config.KEY_STRING);
Console.WriteLine(clear);
Assert.That(clear, Is.EqualTo(text));
}
`However, I am receiving the following exception:
Message: System.Security.Cryptography.CryptographicException : Padding is invalid and cannot be removed.
with the stack:
StackTrace " at System.Security.Cryptography.CapiSymmetricAlgorithm.DepadBlock(Byte[] block, Int32 offset, Int32 count)\r\n at System.Security.Cryptography.CapiSymmetricAlgorithm.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)\r\n at System.Security.Cryptography.CryptoStream.Read(Byte[] buffer, Int32 offset, Int32 count)\r\n at System.IO.StreamReader.ReadBuffer()\r\n at System.IO.StreamReader.ReadToEnd()\r\n at InsuranceMidAm.Services.EncryptionService.Decrypt(String cipher, String key) in C:\\Visual Studio Projects\\InsuranceMidAm\\InsuranceMidAm\\Services\\EncryptionService.cs:line 72\r\n at InsuranceMidAm.Tests.CryptTest.TestMethod() in C:\\Visual Studio Projects\\InsuranceMidAm\\InsuranceMidAm.Tests\\CryptTest.cs:line 20" string
This is the class under test:
namespace InsuranceMidAm.Services
{
public class EncryptionService
{
// Reference: https://stackoverflow.com/questions/273452/using-aes-encryption-in-c-sharp
public static String Encrypt(String text, String key)
{
byte[] value = UTF8Encoding.UTF8.GetBytes(text);
byte[] crypt;
byte[] iv;
using (Aes myAes = Aes.Create())
{
myAes.KeySize = 256;
myAes.Mode = CipherMode.CBC;
myAes.Key = HexToBin(key);
myAes.GenerateIV();
myAes.Padding = PaddingMode.PKCS7;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, myAes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(value, 0, value.Length);
cs.FlushFinalBlock();
crypt = ms.ToArray();
}
}
iv = myAes.IV;
myAes.Clear();
}
return ByteArrayToString(crypt) + ":" + ByteArrayToString(iv);
}
public static string Decrypt(String cipher, String key)
{
String outputString = "";
byte[] ivBytes = HexToBin(getIV(cipher));
byte[] valBytes = HexToBin(getSSN(cipher));
using (Aes myAes = Aes.Create())
{
int size = valBytes.Count();
myAes.KeySize = 256;
myAes.Mode = CipherMode.CBC;
myAes.Key = HexToBin(key);
myAes.IV = ivBytes;
myAes.Padding = PaddingMode.PKCS7;
char[] output = new char[256];
ICryptoTransform myDecrypter = myAes.CreateDecryptor(myAes.Key, myAes.IV);
using (MemoryStream memory = new MemoryStream(ivBytes))
{
using (CryptoStream cryptStream = new CryptoStream(memory, myDecrypter, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cryptStream))
{
outputString = reader.ReadToEnd();
}
return outputString;
}
}
}
}
private static byte[] HexToBin(String hexString)
{
int charCount = hexString.Length;
byte[] output = new byte[charCount / 2];
for (int i = 0; i < charCount; i += 2)
{
output[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
}
return output;
}
private static String getSSN(String cipher)
{
int delimiterIndex = cipher.IndexOf(":");
String SSN = cipher.Substring(0, delimiterIndex);
return SSN;
}
private static String getIV(String cipher)
{
int delimiterIndex = cipher.IndexOf(":");
String IV = cipher.Substring(delimiterIndex + 1);
return IV;
}
// Reference: https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa
private static string ByteArrayToString(byte[] ba)
{
string hex = BitConverter.ToString(ba);
return hex.Replace("-", "");
}
}
}
Line 73 (where the exception is encountered) is the end of the using block for the StreamReader in the decrypt method:
using (StreamReader reader = new StreamReader(cryptStream))
{
outputString = reader.ReadToEnd();
}
I referenced the following question, but could not resolve my issue.
Originally, the data was encrypted in a PHP application, and decrypted using a C# application (using nearly exactly the same decrypt method above). Now, I am wanting to both encrypt and decrypt the data using C#; however, I must still be able to properly decrypt the existing data (that was encrypted using PHP), so I would rather not modify the decrypt method too much.
Any advice would be appreciated.

You have minor mistake here:
ICryptoTransform myDecrypter = myAes.CreateDecryptor(myAes.Key, myAes.IV);
using (MemoryStream memory = new MemoryStream(ivBytes))
You pass your IV value to decrypt, instead of actually encrypted bytes. Fix:
ICryptoTransform myDecrypter = myAes.CreateDecryptor(myAes.Key, myAes.IV);
using (MemoryStream memory = new MemoryStream(valBytes))

Related

Class with broken AES encryption service after upgrading from .Net 5 to .Net 6

I have the following class with service for AES encryption and decryption. Everything works fine until .Net 5. After migrating to .Net 6, the decryption method returns incomplete text.
Cryptography class:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace framework.mstiCSharp.Services
{
public class CriptografiaService
{
#region Settings
private static int _iterations = 2;
private static int _keySize = 256;
private static string _hash = "SHA1";
private static string _salt = "aselrias38490a32"; // Random
private static string _vector = "8947az34awl34kjq"; // Random
#endregion
public static string Encrypt(string value, string AesKey)
{
return Encrypt<AesManaged>(value, AesKey);
}
private static string Encrypt<RijndaelManaged>(string value, string password)
where RijndaelManaged : SymmetricAlgorithm, new()
{
byte[] vectorBytes = Encoding.UTF8.GetBytes(_vector);
byte[] saltBytes = Encoding.UTF8.GetBytes(_salt);
byte[] valueBytes = Encoding.UTF8.GetBytes(value);
byte[] encrypted;
using (RijndaelManaged cipher = new RijndaelManaged())
{
PasswordDeriveBytes _passwordBytes =
new PasswordDeriveBytes(password, saltBytes, _hash, _iterations);
byte[] keyBytes = _passwordBytes.GetBytes(_keySize / 8);
cipher.Mode = CipherMode.CBC;
using (ICryptoTransform encryptor = cipher.CreateEncryptor(keyBytes, vectorBytes))
{
using (MemoryStream to = new MemoryStream())
{
using (CryptoStream writer = new CryptoStream(to, encryptor, CryptoStreamMode.Write))
{
writer.Write(valueBytes, 0, valueBytes.Length);
writer.FlushFinalBlock();
encrypted = to.ToArray();
}
}
}
cipher.Clear();
}
return Convert.ToBase64String(encrypted);
}
public static string Decrypt(string value, string AesKey)
{
return Decrypt<AesManaged>(value, AesKey);
}
private static string Decrypt<T>(string value, string password) where T : SymmetricAlgorithm, new()
{
byte[] vectorBytes = Encoding.UTF8.GetBytes(_vector);
byte[] saltBytes = Encoding.UTF8.GetBytes(_salt);
byte[] valueBytes = Convert.FromBase64String(value);
byte[] decrypted;
int decryptedByteCount = 0;
using (T cipher = new T())
{
PasswordDeriveBytes _passwordBytes = new PasswordDeriveBytes(password, saltBytes, _hash, _iterations);
byte[] keyBytes = _passwordBytes.GetBytes(_keySize / 8);
cipher.Mode = CipherMode.CBC;
try
{
using (ICryptoTransform decryptor = cipher.CreateDecryptor(keyBytes, vectorBytes))
{
using (MemoryStream from = new MemoryStream(valueBytes))
{
using (CryptoStream reader = new CryptoStream(from, decryptor, CryptoStreamMode.Read))
{
decrypted = new byte[valueBytes.Length];
decryptedByteCount = reader.Read(decrypted, 0, decrypted.Length);
}
}
}
}
catch (Exception)
{
return String.Empty;
}
cipher.Clear();
}
return Encoding.UTF8.GetString(decrypted, 0, decryptedByteCount);
}
}
}
Test class:
using framework.mstiCSharp.Services;
using Xunit;
namespace framework.mstiCSharpTest
{
public class CriptografiaServiceTest
{
[Theory]
[InlineData("abc123")]
[InlineData("Silvair Leite Soares")]
[InlineData("abcdefghij 1234567890")]
public void encriptTest(string originalText)
{
string key = "1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm";
string encriptText = CriptografiaService.Encrypt(originalText, key);
string decriptText = CriptografiaService.Decrypt(encriptText, key);
Assert.Equal(originalText, decriptText);
}
}
}
I found this other question Problem Updating to .Net 6 - Encrypting String, and this issue AES Encryption broken on Dot Net 6, on this same subject. But I couldn't adapt the answers and suggestions to my situation.
Test cases:
Test
1
Original text
Silvair Leite Soares
After encryption
u2LcEdwpyTT4j+YJSYenJzFz0o+t0027DbvOn/i8bjU=
After decrypting
Silvair Leite So
Test
2
Original text
abc123
After encryption
k3tyVen0ulvrsLJ/MuVevA==
After decrypting
abc123
Test
3
Original text
abcdefghij 1234567890
After encryption
BUCUPbc1PhLOBvV9R2XP2NE7bWYQi5O4BjciiZd70pI=
After decrypting
abcdefghij 12345
As can be seen, in some situations, with smaller text, it still works. But in larger texts, it fails every time.
Any help will be most welcome.

C# AES Encryption Need

I have an Encrypted string and function to decrypt it. Now I need to edit this string and encrypt it. When I use this function to encrypt and decrypt in result strings are not the same.
Orginal encrypted string:
APpuC6G3f3cUKaAuOFXOGIo9rwz/+fQ0tBCi6Fk40THVnIT+au7JXkOQHdgPcpQ3VUrXw69rIL+QRsHea5+Q6TxOeuAnzkU8c3UClx6Toe+jOIVi3DlkLIGzE8DmyBArtZYpKTOt4rrOSDyLKifdgcM+MgwuJbDXyXVuQyp2C42zZ1ETPUOF2TSIZKhnMSR43FFy8WEbpKBAjkPmgVpqqhrjabu+JHbj7kPIxGGjDHGaCCyCtFwsk3264Lv4GTp049SCjNNYV0NVcN4wV0MaWMEO0iLuNGkseHuu5Snvp3YzZfXxDBWSLOUXc2zeXL2tA6So9WA5P3lZ/ga5i366EQ==
Orginal encrypted string after decrypt:
{"status":"PASS","data":{"map_path":"VOtKu0.yGT","file_extension":"KAmXWV","username":"damianek","timestamp":9999999999},"message":"Logged in successfully. Your license will run out at 2021-12-03 18:41:39"}
Orginal decrypt function:
public static string Decypher(string var1)
{
var1 = var1.Trim();
byte[] array = Convert.FromBase64String(var1);
byte[] array2 = new byte[16];
byte[] array3 = new byte[32];
byte[] array4 = new byte[array.Length - 48];
for (int i = 0; i < 16; i++)
{
array2[i] = array[i];
}
for (int j = 16; j < 48; j++)
{
array3[j - 16] = array[j];
}
for (int k = 48; k < array.Length; k++)
{
array4[k - 48] = array[k];
}
ivv = array2;
Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Key = GetToken();
aes.IV = array2;
MemoryStream memoryStream = new MemoryStream();
ICryptoTransform transform = aes.CreateDecryptor();
CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write);
string result = string.Empty;
try
{
cryptoStream.Write(array4, 0, array4.Length);
cryptoStream.FlushFinalBlock();
byte[] array5 = memoryStream.ToArray();
result = Encoding.ASCII.GetString(array5, 0, array5.Length);
memoryStream.Close();
cryptoStream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace);
}
return result;
}
My encrypt function:
public void EncryptStringToBytes()
{
string plainText = textBox2.Text;
byte[] array = Encoding.UTF8.GetBytes(plainText);
byte[] encrypted;
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = GetToken();
aesAlg.IV = new byte[16];
aesAlg.Mode = CipherMode.CBC;
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
textBox3.Text = Convert.ToBase64String(encrypted);
}
String after my encrypt & decrypt with orginal function:
?%j>]???r?????":"KAmXWV","username":"damianek","timestamp":1637955589},"message":"Logged in successfully. Your license will run out at 2021-12-03 18:41:39"}
EDIT:
Now encrypt function look:
public void EncryptStringToBytes()
{
string plainText = textBox2.Text.Trim();
byte[] array = Encoding.ASCII.GetBytes(plainText);
byte[] encrypted;
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = GetToken();
aesAlg.IV = GetIV();
aesAlg.Mode = CipherMode.CBC;
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (var msEncrypt = new MemoryStream())
{
msEncrypt.Write(aesAlg.Key, 0, aesAlg.Key.Length);
msEncrypt.Flush();
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(aesAlg.Key, 0, aesAlg.Key.Length);
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
textBox3.Text = Convert.ToBase64String(encrypted);
}
But string after encrypt & decrypt look:
;???En Dp??g???{"status":"PASS","data":{"map_path":"VOtKu0.yGT","file_extension":"KAmXWV","username":"damianek","timestamp":1637955589},"message":"Logged in successfully. Your license will run out at 2021-12-03 18:41:39"}
My C# AES implementation
from my answer AES Crypto C# compatible Java
The IV is randomized in every Encrypt process to get different output with same text and avoid to intruders/attackers get original text easily.
The default mode is CBC.
The encoding used is UTF-8. UTF-8 is the most widely used encoding on the web.
You can test/run this code on https://replit.com/#JomaCorpFX/AesCbcEncrypt#main.cs
The code
using System;
using System.Security.Cryptography;
using System.Text;
public enum HashAlgorithm
{
MD5,
SHA1,
SHA256,
SHA384,
SHA512
}
public class HashManager
{
public static byte[] ToRawHash(byte[] data, HashAlgorithm algorithm)
{
byte[] hash;
switch (algorithm)
{
case HashAlgorithm.MD5:
MD5 md5 = MD5.Create();
hash = md5.ComputeHash(data, 0, data.Length);
return hash;
case HashAlgorithm.SHA1:
SHA1Managed sha1 = new SHA1Managed();
hash = sha1.ComputeHash(data);
return hash;
case HashAlgorithm.SHA256:
SHA256Managed sha256 = new SHA256Managed();
hash = sha256.ComputeHash(data);
return hash;
case HashAlgorithm.SHA384:
SHA384Managed sha384 = new SHA384Managed();
hash = sha384.ComputeHash(data);
return hash;
case HashAlgorithm.SHA512:
SHA512Managed sha512 = new SHA512Managed();
hash = sha512.ComputeHash(data, 0, data.Length);
return hash;
default:
throw new ArgumentException("Invalid Algorithm");
}
}
}
public class AesManager
{
private const int MAX_IV_LENGTH = 16;
private const int MAX_KEY_LENGTH = 32;
private static byte[] GenerateValidKey(byte[] keyBytes)
{
byte[] ret = new byte[MAX_KEY_LENGTH];
byte[] hash = HashManager.ToRawHash(keyBytes, HashAlgorithm.SHA256);
Array.Copy(hash, ret, MAX_KEY_LENGTH);
return ret;
}
public static byte[] EncryptRaw(byte[] PlainBytes, byte[] Key)
{
AesManaged AesAlgorithm = new AesManaged()
{
Key = GenerateValidKey(Key)
};
AesAlgorithm.GenerateIV();
var Encrypted = AesAlgorithm.CreateEncryptor().TransformFinalBlock(PlainBytes, 0, PlainBytes.Length);
byte[] ret = new byte[Encrypted.Length + MAX_IV_LENGTH];
Array.Copy(Encrypted, ret, Encrypted.Length);
Array.Copy(AesAlgorithm.IV, 0, ret, ret.Length - MAX_IV_LENGTH, MAX_IV_LENGTH);
return ret;
}
public static byte[] DecryptRaw(byte[] CipherBytes, byte[] Key)
{
AesManaged AesAlgorithm = new AesManaged()
{
Key = GenerateValidKey(Key)
};
byte[] IV = new byte[MAX_IV_LENGTH];
Array.Copy(CipherBytes, CipherBytes.Length - MAX_IV_LENGTH, IV, 0, MAX_IV_LENGTH);
AesAlgorithm.IV = IV;
byte[] RealBytes = new byte[CipherBytes.Length - MAX_IV_LENGTH];
Array.Copy(CipherBytes, RealBytes, CipherBytes.Length - MAX_IV_LENGTH);
return AesAlgorithm.CreateDecryptor().TransformFinalBlock(RealBytes, 0, RealBytes.Length); ;
}
public static String EncryptToBase64(String Plaintext, String Key)
{
byte[] PlainBytes = Encoding.UTF8.GetBytes(Plaintext);
return Base64Manager.ToBase64(EncryptRaw(PlainBytes, Encoding.UTF8.GetBytes(Key)), false);
}
public static String DecryptFromBase64(String CipherText, String Key)
{
byte[] CiPherBytes = Base64Manager.Base64ToByteArray(CipherText);
byte[] Encrypted = DecryptRaw(CiPherBytes, Encoding.UTF8.GetBytes(Key));
return Encoding.UTF8.GetString(Encrypted, 0, Encrypted.Length);
}
}
public class Base64Manager
{
public static byte[] Base64ToByteArray(String base64)
{
return Convert.FromBase64String(base64);
}
public static String ToBase64(byte[] data, Boolean insertLineBreaks = default(Boolean))
{
return insertLineBreaks ? Convert.ToBase64String(data, Base64FormattingOptions.InsertLineBreaks) : Convert.ToBase64String(data);
}
}
public class Program
{
public static void Main()
{
Console.Write("Plain text: ");
string plainText = Console.ReadLine();
Console.Write("Password: ");
string password = Console.ReadLine();
string encrypted = AesManager.EncryptToBase64(plainText, password);
Console.WriteLine();
Console.WriteLine($"Password: {password}" );
Console.WriteLine();
Console.WriteLine($"Encrypted: {encrypted}");
Console.WriteLine();
Console.WriteLine($"Decrypted: {AesManager.DecryptFromBase64(encrypted, password)}");
Console.ReadLine();
}
}
Output

'Padding is invalid and cannot be removed.'

encryption in this way works fine but when i try to use Decrypt it gives me padding Error i don't know why ?? Here is main Method and used Key & IV Value.
& BaseEncryptor Class Where i Use Encryption & Decryption Method
I tried uesing every type in padding but it also doesn't work.I tried to change block size and key size it also doesn't work.
static void Main(string[] args)
{
string key = "ldm_encrypt_code1234567891234567";
string IV = "9876897123651785";
string encstr = BaseEncryptor.EncryptUsingAes(Encoding.UTF8.GetBytes(#"Hello Code"), Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(IV)); //Encryption
string xc=BaseEncryptor.Decrypt(Encoding.UTF8.GetBytes(encstr), Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(IV)); //Decryption way
}
public class BaseEncryptor
{
public static string EncryptUsingAes(byte[] inputTextByte, byte[] privateKeyByte, byte[] sharedIVKeyByte)
{
using (var aesEncryption = AesEncryptionType(privateKeyByte, sharedIVKeyByte))
{
// Convert string to byte array
byte[] dest = new byte[inputTextByte.Length];
// encryption
using (ICryptoTransform encrypt = aesEncryption.CreateEncryptor(aesEncryption.Key, aesEncryption.IV))
{
dest = encrypt.TransformFinalBlock(inputTextByte, 0, inputTextByte.Length);
encrypt.Dispose();
}
return BitConverter.ToString(dest).Replace("-", "");
}
}
public static AesCryptoServiceProvider AesEncryptionType(byte[] privateKeyByte, byte[] sharedIVKeyByte)
{
//used in both encryption & Decryption
var aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.IV = sharedIVKeyByte;
aes.Key = privateKeyByte;
aes.Mode = CipherMode.CBC; //Mode
aes.Padding = PaddingMode.PKCS7; //Padding not working in case of none or Zeros
return aes;
}
public static string DecryptUsingAes(byte[] inputTextByte, byte[] privateKeyByte, byte[] sharedIVKeyByte)
{
using (var aesDecryption = AesEncryptionType(privateKeyByte, sharedIVKeyByte))
{
// Convert string to byte array
byte[] dest = new byte[inputTextByte.Length];
// encryption
using (ICryptoTransform decrypt = aesDecryption.CreateDecryptor(aesDecryption.Key, aesDecryption.IV))
{
dest = decrypt.TransformFinalBlock(inputTextByte, 0, inputTextByte.Length);
decrypt.Dispose();
}
// Convert byte array to UTF8 string
return Encoding.UTF8.GetString(dest); ;
}
}
public static string Decrypt(byte[] cipherText, byte[] Key, byte[] IV)
{
string plaintext = null;
// Create AesManaged
using (var aesDecryption = AesEncryptionType(Key, IV))
{
// Create a decryptor
// Create the streams used for decryption.
using (ICryptoTransform decryptor = aesDecryption.CreateDecryptor(Key, IV))
{
string result;
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
result = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
}
}

Is it possible to run a PHP function in .NET?

I'm trying to decrypt AES-128 CBC strings in C# but with no success (tried every decrypt method I found on internet for this type of encryption).
The only way I got a result was decrypting those strings in PHP using this code:
<?php
$crypto_data = hex2bin($crypto_data_hex);
$real_data = openssl_decrypt($crypto_data,
'AES-128-CBC',
'23d854ce7364b4f7',
OPENSSL_RAW_DATA,
'23d854ce7364b4f7');
?>
So, is there a way to run this PHP code in .NET (using a PHP.dll library or something similar) ? Or is there a real equivalent method for this operation in .NET C# ?
Thank you
The question seems to boil down to writing C# function that is equivalent to PHP function.
Try this code:
public class Program
{
public static byte[] HexToBytes(string hex)
{
int numberChars = hex.Length;
byte[] bytes = new byte[numberChars / 2];
for (int i = 0; i < numberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
static string Decrypt(byte[] cipherText, byte[] key, byte[] iv)
{
string plaintext;
AesManaged aes = new AesManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
BlockSize = 128,
Key = key,
IV = iv
};
using (aes)
{
ICryptoTransform decryptor = aes.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(cipherText))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cs))
{
plaintext = reader.ReadToEnd();
}
}
}
}
return plaintext;
}
public static void Main()
{
string crypto_data_hex = "00965fa56e761b11d37b887f98e6bcc2"; // paste $crypto_data_hex value here
string sKey = "23d854ce7364b4f7";
string sIv = "23d854ce7364b4f7";
byte[] encrypted = HexToBytes(crypto_data_hex);
byte[] key = Encoding.ASCII.GetBytes(sKey);
byte[] iv = Encoding.ASCII.GetBytes(sIv);
string decrypted = Decrypt(encrypted, key, iv);
Console.WriteLine(decrypted);
}
}

C# - Problem with AES Decryption - always get null

I am trying to implement image steganography with LSB and everything works except decrypting.
There is my class responsible for encryption and decryption of strings below. Encrypting works fine but Decrypt method always returns null:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace WindowsFormsApp1
{
class Encryptor {
//text to encrypt or already decrypted
private String decryptedText = "";
//text to decrypt or already encrypted
private String encryptedText = "";
private String key = "";
public Encryptor setDecryptedText(String text)
{
decryptedText = text;
return this;
}
public Encryptor setEncryptedText(String text)
{
encryptedText = text;
return this;
}
public Encryptor setKey(String text)
{
key = text;
return this;
}
Byte[] getHash(Byte[] hash)
{
Byte[] newHash = new Byte[32];
for (int i = 0; i < 32; i++)
{
newHash[i] = hash[i];
}
return newHash;
}
Byte[] getIV(Byte[] hash)
{
Byte[] newHash = new Byte[16];
int j = 0;
for (int i = 32; i < 48; i++)
{
newHash[j++] = hash[i];
}
return newHash;
}
String EncryptAesManaged()
{
SHA512 shaM = new SHA512Managed();
Byte[] data = Encoding.UTF8.GetBytes(key);
Byte[] hash = shaM.ComputeHash(data);
try
{
return Encrypt(decryptedText, getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return null;
}
String DecryptAesManaged()
{
SHA512 shaM = new SHA512Managed();
var data = Encoding.UTF8.GetBytes(key);
Byte[] hash = shaM.ComputeHash(data);
try
{
return Decrypt(Convert.FromBase64String(encryptedText), getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return "";
}
String Encrypt(string plainText, byte[] Key, byte[] IV)
{
Byte[] encrypted;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs)) {
sw.Write(Encoding.UTF8.GetBytes(plainText));
cs.FlushFinalBlock();
encrypted = ms.ToArray();
}
}
}
aes.Clear();
}
return Convert.ToBase64String(encrypted);
}
string Decrypt(byte[] cipherText, byte[] Key, byte[] IV)
{
string plaintext = null;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform decryptor = aes.CreateDecryptor(Key, IV);
try
{
using (MemoryStream ms = new MemoryStream(cipherText))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
using (StreamReader reader = new StreamReader(cs))
{
plaintext = reader.ReadToEnd(); //Here get null
}
aes.Clear();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return plaintext;
}
public String getEncrypted()
{
return EncryptAesManaged();
}
public String getDecrypted()
{
return DecryptAesManaged();
}
}
}
Why is Decrypt() returning null rather than the originally encrypted string?
You don't show how you use your Encryptor class, so your question doesn't quite include a Minimal, Complete, and Verifiable example. I was able to reproduce the problem with the following test harness:
public static void Test()
{
var key = "my key";
var plainText = "hello";
var encryptor = new Encryptor();
encryptor.setDecryptedText(plainText);
encryptor.setKey(key);
var encrypted = encryptor.getEncrypted();
Console.WriteLine(encrypted);
var deecryptor = new Encryptor();
deecryptor.setEncryptedText(encrypted);
deecryptor.setKey(key);
var decrypted = deecryptor.getDecrypted();
Console.WriteLine(decrypted);
Assert.IsTrue(plainText == decrypted);
}
Demo fiddle #1 here.
Given that, your code has 2 problems, both of which are actually in encryption rather than decryption.
Firstly, in Encrypt(string plainText, byte[] Key, byte[] IV), you are writing to the StreamWriter sw, then flushing the CryptoStream and returning the MemoryStream contents -- but you never flush or dispose sw, so its buffered contents are never forwarded to the underlying stream(s).
To fix this, your code should looks something like:
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(Encoding.UTF8.GetBytes(plainText));
}
}
encrypted = ms.ToArray();
}
Now getDecrypted() no longer returns a null result -- but instead returns a wrong result of "System.Byte[]", as shown in demo fiddle #2 here.
Secondly, again in Encrypt(...), you are effectively encoding your plainText twice at this line:
sw.Write(Encoding.UTF8.GetBytes(plainText));
Encoding.UTF8.GetBytes(plainText) converts the plain text to a byte array, but the StreamWriter is also intended to do this job, converting strings to bytes and passing them to the underlying stream. So, since you are not passing a string to Write(), the overload that gets called is StreamWriter.Write(Object):
Writes the text representation of an object to the text string or stream by calling the ToString() method on that object.
Thus what actually gets encrypted is the ToString() value of a byte array, which is "System.Byte[]".
To fix this, simply remove the call to Encoding.UTF8.GetBytes(plainText) and write the string directly. Thus your Encrypt() method should now look like:
static String Encrypt(string plainText, byte[] Key, byte[] IV)
{
string encrypted;
using (var aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write, true))
{
using (var sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
}
// Calling GetBuffer() avoids the extra allocation of ToArray().
encrypted = Convert.ToBase64String(ms.GetBuffer(), 0, checked((int)ms.Length));
}
aes.Clear();
}
return encrypted;
}
Demo fiddle #3 here that now passes successfully.
Disclaimer: this answer does not attempt to to review your code for security best practices such as secure setup of salt and IV.

Categories

Resources