I am migrating some code from .NET Framework to .NET Core and came across an issue.
I have a lot of strings that were encrypted on the old system and saved on the database on their encrypted version.
I've moved the code to .NET core, created a new class for Encrypt and Decrypt the strings, but when I try to use it I get the following error.
PlatformNotSupportedException: BlockSize must be 128 in this implementation.
My function is as follow
public static string DecryptString(string cipherText)
{
string passPhrase = EncryptingKey(EncKey);
byte[] cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
byte[] saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
byte[] ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
byte[] cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (Rfc2898DeriveBytes password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
byte[] keyBytes = password.GetBytes(Keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
I understand RijndaelManaged doesn't seem to support a keysize other than 128 on .NET Core, do I have any workaround to use 256 instead and not have to decrypt thousands of records and re-encrypt them again?
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rijndaelmanaged?view=net-5.0
Related
I am trying to work out why a C# DLL I have is crashing since I added in AES encryption.
I initially put managed rijndael encryption in with a 256 bit key and 256 bit blocksize and the DLL worked, but I found out that the dotnet base receiving end only supports 128 bit blocksize.
However, when I changed the blocksize to 128 bits the DLL simply crashes when I encrypt. I also read the rijndael managed should not be used for new projects and so I tied other examples of AES for C#. All of THESE OTHER EXAMPLES once again crash the DLL as soon as the encrypt function is called.
I am generating both a 64 bit version of the DLL and a 32 bit version of the DLL, both crash as soon as I try to encrypt a string of around 1000 characters.
Is there some sort of initialisation I am missing, or do I need to increase memory / Stack size to use AES in the DLL? Would really value some suggestions as to why this doesn't work.
This worked for 256 bit blocksize, but crashes for 128 bit blocksize
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
Various other ways I have tried so far are below:
byte[] ivBytes = ComputeSHA256(iVphrase);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = ComputeSHA256(password);
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Key = keyBytes;
aes.IV = ivBytes;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
ICryptoTransform crypto1 = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] encrypteddata = crypto1.TransformFinalBlock(plainTextBytes, 0, plainTextBytes.Length);
crypto1.Dispose();
return Convert.ToBase64String(encrypteddata);
byte[] encryptedData;
byte[] ivBytes = ComputeSHA256(iVphrase);
byte[] keyBytes = ComputeSHA256(password);
using (Aes aesAlgorithm = new AesManaged())
{
ICryptoTransform encryptor = aesAlgorithm.CreateEncryptor(keyBytes, ivBytes);
//Encryption will be done in a memory stream through a CryptoStream object
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
encryptedData = ms.ToArray();
}
}
return Convert.ToBase64String(encryptedData);
}
byte[] ivBytes = ComputeSHA256(iVphrase);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = ComputeSHA256(password);
using (var symmetricKey = Aes.Create("AesManaged"))
{
symmetricKey.BlockSize = 128;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.Key = keyBytes;
symmetricKey.IV = ivBytes;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cs = new CryptoStream(memoryStream, symmetricKey.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(plainTextBytes, 0, plainTextBytes.Length);
cs.Close();
}
var cipherBytes = memoryStream.ToArray();
memoryStream.Close();
return Convert.ToBase64String(cipherBytes);
}
}
}
I finally managed to get an exception output which identified the issue as being a 32 byte IV being passed in to a 128 bit Block size which generated an exception. On windows server machines the exception didn't return any result code, it simply crashed the machine. Testing on another windows 10 device correctly logged the incorrect IV length as an exception.
I'm trying to encrypt a plain text using RijndaelManaged class and then decrypt the encrypted string to have the same plain text in the end.
Everything is okay while ecrypting the plain text as below,
protected static string AESEncrypt(string plainText, string key)
{
byte[] encryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.KeySize = 256;
aes.BlockSize = 128;
var keyHold = new Rfc2898DeriveBytes(key, saltBytes, 1000);
aes.Key = keyHold.GetBytes(aes.KeySize / 8);
aes.IV = keyHold.GetBytes(aes.BlockSize / 8);
aes.Mode = CipherMode.CBC;
var bytesToBeEncrypted = Encoding.UTF8.GetBytes(plainText);
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return Convert.ToBase64String(encryptedBytes);
}
For instance, i'm encrypting this plain text "encryptMe" via calling above mentioned function as var encryptedString = AESEncrypt(plainText, "lockMe");. The result is nKytZ86r0DDKSzD3ph+ntg==.
Then I send that encrypted string to below mentioned fucntion,
protected static string AESDecrypt(string cryptedText, string key)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.KeySize = 256;
aes.BlockSize = 128;
var keyHold = new Rfc2898DeriveBytes(key, saltBytes, 1000);
aes.Key = keyHold.GetBytes(aes.KeySize / 8);
aes.IV = keyHold.GetBytes(aes.BlockSize / 8);
aes.Mode = CipherMode.CBC;
var bytesToBeDDecrypted = Encoding.UTF8.GetBytes(cryptedText);
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDDecrypted, 0, bytesToBeDDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return Encoding.UTF8.GetString(decryptedBytes);
}
On this method, code throws an error The input data is not a complete block while leaving CryptoStream.
My KeySize and BlockSize are both divisible by 8 and I can't see what I have overlook.
In AESDecrypt you have:
var bytesToBeDDecrypted = Encoding.UTF8.GetBytes(cryptedText);
Since you are passing base-64 encoded cipher this should instead be
var bytesToBeDDecrypted = Convert.FromBase64String(cryptedText);
There are also some security improvements you should make. You should increase the iteration count from 1000 to something much larger, 65K at least. The salt should be at least 12 bytes and should be generated randomly for each encryption. It does not need to be kept secret, it's usually convenient to prepend it to the cipher. The decrypter then extracts the salt from the passed-in ciphertext. You should also use a Message Authentication Code (MAC) to prevent tampering. Note that AES-GCM mode as well as some other modes include this MAC as an integral part of their operation. However, if AES-GCM is unavailable then HMAC-SHA256 likely will be and is acceptable.
i need to port the following C# function to Node
public static string Decrypt(string CipherText, string Password, string Salt, string InitialVector, int PasswordIterations, string HashAlgorithm = "SHA1", int KeySize = 256)
{
var InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
var SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
var CipherTextBytes = Convert.FromBase64String(CipherText);
var DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
var KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
var SymmetricKey = new RijndaelManaged();
SymmetricKey.Mode = CipherMode.CBC;
var PlainTextBytes = new byte[CipherTextBytes.Length];
var ByteCount = 0;
using (var Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes))
{
using (var MemStream = new MemoryStream(CipherTextBytes))
{
using (var CryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read))
{
ByteCount = CryptoStream.Read(PlainTextBytes, 0, PlainTextBytes.Length);
MemStream.Close();
CryptoStream.Close();
}
}
}
SymmetricKey.Clear();
return Encoding.UTF8.GetString(PlainTextBytes, 0, ByteCount);
}
I have been trying so far with various Node modules like mcrypt, aes-js, js-rijndael, rinjndael-js, crypto, crypto-js, cryptojs etc, but i am unable to find a way or understand how i need to approach this.
What confuses me specially is how to do the password iterations step. Can anyone suggest a node module that supports it or a way to implement it?
In ms SQL server, I have a field text with data look like below:
"!"$$$$$$!#$$$$!!!!! !!!!!!!!!!!!!! "!! ! " !" ! !" !!!! ! !!"!".
I belive that from a plain text string, they using a Rijndael algorithm to encrypted this string. from encrypted string, it was transform to string above.
Can anyone recognize what the algorithm to decrypt from string above to the encrypted string of Rijndael algorithm?
thanks
Hi me drona please find the below code. It will useful from you.
public static class Encrypt
{
// This size of the IV (in bytes) must = (keysize / 8). Default keysize is 256, so the IV must be
// 32 bytes long. Using a 16 character string here gives us 32 bytes when converted to a byte array.
private const string initVector = "pemgail9uzpgzl88";
// This constant is used to determine the keysize of the encryption algorithm
private const int keysize = 256;
//Encrypt
public static string EncryptString(string plainText, string passPhrase)
{
byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
//Decrypt
public static string DecryptString(string cipherText, string passPhrase)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
enter code here
when i use this code to encrypt and decrypt i got an error said
Padding is invalid and cannot be removed.
any idea
public static class Crypto
{
private static readonly byte[] initVectorBytes = Encoding.ASCII.GetBytes("tu89geji340t89u2");
// This constant is used to determine the keysize of the encryption algorithm.
private const int keysize = 256;
public static string Encrypt(string plainText, string passPhrase)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
}
I tried the following using your methods and it worked fine:
var passPhrase = "123456";
var e = Encrypt("testtesttesttest", passPhrase);
Console.WriteLine(e); // YEtSJshcn686ZO+JlEQ48ap/odhuvIGalbAT1XhinqQ=
var d = Decrypt(e, passPhrase);
Console.WriteLine(d); // testtesttesttest
This suggests that you're either passing a different passPhrase to Decrypt() to the one you passed to Encrypt(), or that you are somehow corrupting the ciphertext prior to decryption. (Are you perhaps calling Decrypt with the ciphertext and passphrase parameters reversed?)
It's also worth noting that essentially everything in the comments at the top of your code is wrong:
You're not passing any salt to PasswordDeriveBytes.
The size of the IV must be equal to the block size (16 bytes), it is unrelated to the key size used.
Passing a 16 character string through Encoding.ASCII.GetBytes() results in a 16 byte output, not 32 bytes. (This rather coincidentally means that your initVectorBytes is in fact the correct length for the IV).
Furthermore, PasswordDeriveBytes is deprecated and should not be used. You should be using Rfc2898DeriveBytes instead, and you should be using a proper salt value. The IV should also not be a static value, and definitely not one derived from an ASCII string!