Why does the decrypted string not match the input string? - c#

In this code snippet I have used the RSACryptoServiceProvider class to encrypt a key and IV generated by Rfc2898DerivedBytes class. The key and IV are then decrypted, inserted into an AesManaged encryptor, and then I use the AesManaged encryptor to encrypt a string(converted into a byte array). The process is reversed to decrypt the array which succeeds but then the string returned does not match the input string. Why is this?
I have already tried changing the Encoding format of the byte arrays but that did not work. I have inspected the original byte array and what it looks like after it has gone through the entire process of being encrypted and decrypted and they are identical.
class EncryptionBestPracticeDemo
{
public static byte[] keys;
public static AesManaged aesAlgorithm = new AesManaged();
public struct KeyIV
{
public byte[] Key { get; private set; }
public byte[] IV { get; private set; }
public KeyIV(byte[] key, byte[] iV)
{
this.Key = key;
this.IV = iV;
}
}
public static KeyIV GetEncryptedKeyAndIV()
{
KeyIV keySalt;
var password = "Pa$$w0rd";
var salt = "S#lt";
var rgb = new Rfc2898DeriveBytes(password, Encoding.Unicode.GetBytes(salt));
aesAlgorithm.Padding = PaddingMode.None;
var rgbKey = rgb.GetBytes(aesAlgorithm.KeySize / 8);
var rgbIV = rgb.GetBytes(aesAlgorithm.BlockSize / 8);
//Encrypt the key and IV
using (var rsaProvider = new RSACryptoServiceProvider())
{
var setOaemPadding = true;
keys = rsaProvider.ExportCspBlob(true);
keySalt = new KeyIV(rsaProvider.Encrypt(rgbKey, setOaemPadding), rsaProvider.Encrypt(rgbIV, setOaemPadding));
}
return keySalt;
}
public static void AesWithRSA()
{
//Use RSACryptoProvider to decrypt the secret key of the AesAlgorithm algorithm
var message = "NET Cryptography";
var messageByteArray = Encoding.UTF8.GetBytes(message);
byte[] encryptedData;
byte[] decryptedData;
//Get the encrypted Key and IV
var keySalt = GetEncryptedKeyAndIV();
using (var rsaProvider = new RSACryptoServiceProvider())
{
var setOaemPadding = true;
rsaProvider.ImportCspBlob(keys);
//Decrypt the key and IV
var key = rsaProvider.Decrypt(keySalt.Key, setOaemPadding);
var iV = rsaProvider.Decrypt(keySalt.IV, setOaemPadding);
//Use the decrypted key and IV in the AES encryptor
var encryptor = aesAlgorithm.CreateEncryptor(key, iV);
using (var bufferStream = new MemoryStream())
using (var cryptoStream = new CryptoStream(bufferStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(messageByteArray, 0, messageByteArray.Length);
encryptedData = bufferStream.ToArray();
}
}
using (var rsaProvider = new RSACryptoServiceProvider())
{
var setOaemPadding = true;
rsaProvider.ImportCspBlob(keys);
//Decrypt the key and IV
var key = rsaProvider.Decrypt(keySalt.Key, setOaemPadding);
var iV = rsaProvider.Decrypt(keySalt.IV, setOaemPadding);
//Use the decrypted key and IV in the AES decryptor
var decryptor = aesAlgorithm.CreateEncryptor(key, iV);
using (var bufferStream = new MemoryStream())
using (var cryptoStream = new CryptoStream(bufferStream, decryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(encryptedData, 0, encryptedData.Length);
decryptedData = bufferStream.ToArray();
Console.WriteLine(Encoding.UTF8.GetString(decryptedData));
}
}
}
}
Input string: "NET Cryptography".
Expected output string: "NET Cryptography".
Output string: "????b!?k?!? ?+X".

Related

Can't Verify Hash Password in C#

In C# language, my purpose is to hash password with hash_password(), then verify it with verify() methods. I hash and salt for password 's3cr3t', then check for two examples and return true if password is 's3cr3t' and return false for password 's3cr4t'.
using System;
using System.Text;
using System.Security.Cryptography;
public class Pbkdf2_test4
{
public const int salt_size = 24;
public const int hash_size = 24;
public const int iteration = 100000;
static byte[] salt1 = new byte[salt_size];
private static Rfc2898DeriveBytes hash_password(string password)
{
RandomNumberGenerator generator = RandomNumberGenerator.Create();
byte[] salt = new byte[salt_size];
generator.GetBytes(salt);
salt1 = salt;
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt1, iteration);
return pbkdf2;
}
private static bool verify(Rfc2898DeriveBytes pw_hash, string password)
{
//data1 can be a string or contents of a file.
string data1 = "Some test data";
try
{
Rfc2898DeriveBytes k1 = pw_hash;
Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(password, salt1, iteration);
// Encrypt the data.
Aes encAlg = Aes.Create();
encAlg.Key = k1.GetBytes(16);
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = new CryptoStream(encryptionStream, encAlg.CreateEncryptor(), CryptoStreamMode.Write);
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(data1);
encrypt.Write(utfD1, 0, utfD1.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] edata1 = encryptionStream.ToArray();
k1.Reset();
// Try to decrypt, thus showing it can be round-tripped.
Aes decAlg = Aes.Create();
decAlg.Key = k2.GetBytes(16);
decAlg.IV = encAlg.IV;
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(edata1, 0, edata1.Length);
decrypt.Flush();
decrypt.Close();
k2.Reset();
string data2 = new UTF8Encoding(false).GetString(decryptionStreamBacking.ToArray());
if (!data1.Equals(data2))
{
return false;
}
else
{
return true;
}
}
catch (Exception e)
{
return false;
}
}
public static void Run()
{
Rfc2898DeriveBytes pw_hash = hash_password("s3cr3t");
Console.WriteLine(System.Text.Encoding.UTF8.GetString(pw_hash.GetBytes(hash_size)));
var result1 = verify(pw_hash, "s3cr3t");
Console.WriteLine(result1);
var result2 = verify(pw_hash, "s3cr4t");
Console.WriteLine(result2);
}
}
My question, somehow there is a problem that for verify(pw_hash, "s3cr3t") that returns false however it should return true. In verify(), there is a problem but still could not understand because I give keys k1 and k2 true, but still does not receive hash/salt same, how can I fix this problem?
Apart from this, shuld I add anything to make password storage safest?
Here is program to encrypt and decrypt pass
internal class Program
{
static void Main(string[] args)
{
Pbkdf2_test4 test4 = new Pbkdf2_test4();
test4.Run();
Console.ReadLine();
}
}
public class Pbkdf2_test4
{
static string key = string.Empty;
static string iv = string.Empty;
public Pbkdf2_test4()
{
Aes encAlg = Aes.Create();
encAlg.GenerateKey();
key = Convert.ToBase64String(encAlg.Key);
encAlg.GenerateIV();
iv = Convert.ToBase64String(encAlg.IV);
}
public string Encrypt(string plainText, string Key, string IV)
{
// Check arguments.
if (string.IsNullOrWhiteSpace(plainText))
throw new ArgumentNullException(nameof(plainText));
if (string.IsNullOrWhiteSpace(Key))
throw new ArgumentNullException(nameof(Key));
if (string.IsNullOrWhiteSpace(IV))
throw new ArgumentNullException(nameof(IV));
byte[] encrypted;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(Key);
aes.IV = Convert.FromBase64String(IV);
// Create an encrypt-or to perform the stream transform.
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
}
encrypted = msEncrypt.ToArray();
}
}
// Return the encrypted bytes from the memory stream.
return Convert.ToBase64String(encrypted);
}
public string Decrypt(string cipherText, string Key, string IV)
{
// Check arguments.
if (string.IsNullOrWhiteSpace(cipherText))
throw new ArgumentNullException(nameof(cipherText));
if (string.IsNullOrWhiteSpace(Key))
throw new ArgumentNullException(nameof(Key));
if (string.IsNullOrWhiteSpace(IV))
throw new ArgumentNullException(nameof(IV));
// Declare the string used to hold
// the decrypted text.
string plaintext = string.Empty;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(Key);
aes.IV = Convert.FromBase64String(IV);
// Create a decrypt-or to perform the stream transform.
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
public void Run()
{
Console.WriteLine("Key is : " + key);
Console.WriteLine("IV is : " + iv);
string passord = "s3cr3t";
string encryptedPassowrd = Encrypt(passord, key, iv);
string decryptedPassowrd = Decrypt(encryptedPassowrd, key, iv);
Console.WriteLine($"Password = {passord} and Encrypted password = {encryptedPassowrd}");
Console.WriteLine($"Password = {passord} and Decrypted password = {decryptedPassowrd}");
string passord1 = "s3cr4t";
string encryptedPassowrd1 = Encrypt(passord1, key, iv);
string decryptedPassowrd1 = Decrypt(encryptedPassowrd1, key, iv);
Console.WriteLine($"Password = {passord1} and Encrypted password = {encryptedPassowrd1}");
Console.WriteLine($"Password = {passord1} and Decrypted password = {decryptedPassowrd1}");
}
}
I think you misunderstood the example in the documentation of Rfc2898DeriveBytes. This function can be used for password hashing (PBKDF2), but then you don't need the encryption parts. The original use case of a key derivation function like PBKDF2 was to take a (weak) user password and turn it into a (strong) key which can then be used to encrypt data (thus the name key-derivation). Later one saw that the same functions are suitable to generate password hashes.
In your case I would recommend to use an appropriate library for password hashing, like BCrypt.Net. The usage would look like:
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
string hashToStoreInDb = BCrypt.HashPassword(password);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from existingHashFromDb.
bool isPasswordCorrect = BCrypt.Verify(password, existingHashFromDb);

How can I encrypt text with aesKey and private cert in C#?

I created public and private keys (pem) with openSsl tool. I used commands:
openssl genrsa -out privatekey.pem 2048
openssl req -new -key privatekey.pem -x509 -days 3650 -out publiccert.pem
Then I generate aesKey:
byte[] GenerateAesKey()
{
var rnd = new RNGCryptoServiceProvider();
var b = new byte[16];
rnd.GetNonZeroBytes(b);
return b;
}
My method for encrypt data:
string CreateSecurePayload(byte[] aesKey)
{
object obj = new
{
contact = new
{
email = "myName#email.com",
firstName = "John",
lastName = "Doe"
}
};
var json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
var res = "";
using (Aes myRijndael = Aes.Create())
{
byte[] encrypted = EncryptStringToBytes(json, aesKey, myRijndael.IV);
res = Convert.ToBase64String(encrypted);
}
return res;
}
byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
byte[] encrypted;
using (Aes rijAlg = Aes.Create())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.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();
}
}
}
return encrypted;
}
And then I encrypt my aesKey with private key:
string SecureKey(byte[] aesKey)
{
byte[] plainTextBytes = aesKey;
AsymmetricCipherKeyPair keys;
FileStream fileStream = new FileStream("path/to/privatekey.pem", FileMode.Open);
using (var reader = new StreamReader(fileStream))
{
var pr = new PemReader(reader);
keys = (AsymmetricCipherKeyPair)pr.ReadObject();
}
var eng = new OaepEncoding(new RsaEngine());
eng.Init(true, keys.Private);
int length = plainTextBytes.Length;
int blockSize = eng.GetInputBlockSize();
var cipherTextBytes = new List<byte>();
for (int chunkPosition = 0;
chunkPosition < length;
chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, length - chunkPosition);
cipherTextBytes.AddRange(eng.ProcessBlock(
plainTextBytes, chunkPosition, chunkSize
));
}
return Convert.ToBase64String(cipherTextBytes.ToArray());
}
Call methods:
void Main()
{
var aesKey = GenerateAesKey();
var encryptData = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
securePayload = CreateSecurePayload(aesKey),
secureKey = SecureKey(aesKey)
});
}
I have a problem. Service does not decrypt my data with public key. I upload public key earlier in service.
Could you help me? Thanks
And I have examples of how I can encrypt data but in other languages:
I got the example, but on JS. I think I have a problem with IV, because I don`t send it
Here is the class that help you to perform Encryption/Decryption:
public static class DecryptionHelper
{
private static string EncryptionDecryptionKey = "your_key";
public static string Encrypt(string Text)
{
//var key = GenerateKey();
var key = Encoding.UTF8.GetBytes(EncryptionDecryptionKey);
var plainText = Text;
var encryptedData = EncryptStringToBytes(key, plainText);
return Convert.ToBase64String(encryptedData);
}
public static string Decrypt(string Text)
{
//var key = GenerateKey();
var key = Encoding.UTF8.GetBytes(EncryptionDecryptionKey);
byte[] encryptedData = Convert.FromBase64String(Text);
var decryptedData = DecryptBytesToString(key, encryptedData);
return decryptedData;
}
private static string DecryptBytesToString(byte[] key, byte[] data)
{
// IV was prepended to the encrypted bytes so peel that off
Tuple<byte[], byte[]> splitResult = SplitByteArray(data);
byte[] iv = splitResult.Item1;
byte[] cipherText = splitResult.Item2;
// Declare the string used to hold the decrypted text.
string plaintext;
// Create an RijndaelManaged object
// with the specified key and IV.
using (var aes = CreateAes256Algorithm())
{
aes.Key = key;
aes.IV = iv;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
// Create the streams used for decryption.
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
private static Tuple<byte[], byte[]> SplitByteArray(byte[] data)
{
byte[] first = new byte[16];
Buffer.BlockCopy(data, 0, first, 0, first.Length);
byte[] second = new byte[data.Length - first.Length];
Buffer.BlockCopy(data, first.Length, second, 0, second.Length);
return Tuple.Create(first, second);
}
private static byte[] GenerateKey()
{
using (var aes = CreateAes256Algorithm())
{
aes.GenerateKey();
return aes.Key;
}
}
private static RijndaelManaged CreateAes256Algorithm()
{
return new RijndaelManaged { KeySize = 256, BlockSize = 128 };
}
private static byte[] EncryptStringToBytes(byte[] key, string plainText)
{
byte[] encrypted;
byte[] iv;
// Create an RijndaelManaged object with the specified key and IV.
using (var aes = CreateAes256Algorithm())
{
aes.Key = key;
aes.GenerateIV();
iv = aes.IV;
// Create a encrytor to perform the stream transform.
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
// Create the streams used for encryption.
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
// convert stream to bytes
encrypted = msEncrypt.ToArray();
}
}
}
// Prepend the iV to the encrypted bytes
return CombineByteArrays(iv, encrypted);
}
private static byte[] CombineByteArrays(byte[] first, byte[] second)
{
byte[] ret = new byte[first.Length + second.Length];
Buffer.BlockCopy(first, 0, ret, 0, first.Length);
Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
return ret;
}
}
Then to use it like:
Keys.FacebookClientId = DecryptionHelper.Decrypt(FacebookClientId);
using System;
using System.Text;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Encodings;
using System.Security.Cryptography;
using System.IO;
public static string CreateSecureLoad(string unencryptedPayload, ref byte[] generatedAesKey)
{
// This method generates and returns a secure payload ​
RijndaelManaged cryptoAlgo = new RijndaelManaged
{
Padding = PaddingMode.PKCS7,
Mode = CipherMode.ECB,
KeySize = 128,
BlockSize = 128
};​
generatedAesKey = cryptoAlgo.Key;
var clearTextArray = Encoding.UTF8.GetBytes(unencryptedPayload);
var encryptor = cryptoAlgo.CreateEncryptor();​
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(
msEncrypt,
encryptor,
CryptoStreamMode.Write))
{
csEncrypt.Write(clearTextArray);
csEncrypt.FlushFinalBlock();
var cipher = msEncrypt.ToArray();
return Convert.ToBase64String(cipher);
}
}
}
public static string CreateSecureKey(byte[] aesKey, string privateKeyPEM)
{
// This method generates and returns a secure key
// Accepts the string contents of the private key PEM file as input
​
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
​
using (var textReader = new StringReader(privateKeyPEM))
{
var pemReader = new PemReader(textReader);
var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
encryptEngine.Init(true, keyPair.Private);
}
​
var encrypted = Convert.ToBase64String(
encryptEngine.ProcessBlock(
aesKey,
0,
aesKey.Length));
return encrypted;
}
static void Main(string[] args)
{
String payload = "some json";
​
byte[] generatedAesKey = new byte[16];
var privateKeyPEM = File.ReadAllText("privatekey.pem");
​
var securePayload = CreateSecureLoad(payload, ref generatedAesKey);
var secureKey = CreateSecureKey(generatedAesKey, privateKeyPEM);
​
// Return encrypted key
Console.WriteLine("secureKey: " + secureKey);
​
// Return encrypted payload
Console.WriteLine("securePayload: " + securePayload);​
Console.ReadLine();​
}
}

'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;
}
}
}

AES decryption does not return original value

I have written a SecurityExtensions static class to deal with encryption using AES CBC 128 Bit
public static class SecurityExtensions
{
private static Aes GetAes(string keyText, byte[] iv)
{
var key = keyText.ToByteArray();
using var result = Aes.Create();
result.Mode = CipherMode.CBC;
result.Padding = PaddingMode.Zeros;
result.KeySize = 128;
if (iv.Length > 0)
{
result.IV = iv;
}
result.Key = key;
return result;
}
public static AesEncryptionInfo EncryptWithAes(this string plainText, string keyText)
{
var aesAlg = GetAes(keyText, new byte[0]);
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
byte[] encrypted;
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();
}
}
var result = new AesEncryptionInfo(encrypted, aesAlg.IV);
return result;
}
public static string DecryptFromAes(this byte[] cipherText, string keyText, byte[] iv)
{
var aesAlg = GetAes(keyText, iv);
var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
var result = srDecrypt.ReadToEnd();
return result;
}
}
}
}
}
This crashes unless I have the result.Padding = PaddingMode.Zeros line (which is not in the MS example I used as a basis)
When I use the extension as below, the original value is not returned
const string key = "test1234test1234";
var textToEncrypt = "TESTING ENCRYPTION";
var actualEncryptionInfo = textToEncrypt.EncryptWithAes(key);
var decryptedText = actualEncryptionInfo.Encrypted.DecryptFromAes(key, actualEncryptionInfo.InversionVector);
What am I doing wrong?
The AesEncryptionInfo is a simple class that holds the encrypted value and the IV
public class AesEncryptionInfo
{
public AesEncryptionInfo(byte[] encrypted, byte[] inversionVector)
{
InversionVector = inversionVector;
Encrypted = encrypted;
}
public byte[] InversionVector { get; set; }
public byte[] Encrypted { get; set; }
}
Paul
You are disposing the Aes instance with using statement in GetAes method.
Change:
using var result = Aes.Create();
to:
var result = Aes.Create();
And dispose the Aes in DecryptFromAes and EncryptWithAes.
using var aesAlg = GetAes(keyText, new byte[0]);
using var aesAlg = GetAes(keyText, iv);

AES encryption works only with small, 0 bytes size on the disk, files

I am interested, why encryption/decryption only works with small, 0 bytes size on the disk files, but stop working with larger files, where I get errors The input data is not a complete block and Index was outside the bounds of the array.
I use ECDiffieHellmanCng for generating the same symmetric key on both sides.
Exchange of keys on encryption side:
using (ECDiffieHellmanCng sendingMode = new ECDiffieHellmanCng())
{
sendingMode.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
sendingMode.HashAlgorithm = CngAlgorithm.Sha256;
sendersPublicKey = sendingMode.PublicKey.ToByteArray();
CngKey secretKey = CngKey.Import(receiversPublicKey, CngKeyBlobFormat.EccPublicBlob);
sendersKey = sendingMode.DeriveKeyMaterial(CngKey.Import(receiversPublicKey, CngKeyBlobFormat.EccPublicBlob));
byte[] encryptedFile = null;
byte[] ivFile = null;
byte[] fileBytes = File.ReadAllBytes(fileToSendPath);
Encryption(sendersKey, fileBytes, out encryptedFile, out ivFile);
}
Exchange on receiving side:
using (ECDiffieHellmanCng receivingMode = new ECDiffieHellmanCng())
{
receivingMode.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
receivingMode.HashAlgorithm = CngAlgorithm.Sha256;
receiversPublicKey = receivingMode.PublicKey.ToByteArray();
CngKey secretKey = CngKey.Import(sendersPublicKey, CngKeyBlobFormat.EccPublicBlob);
receiversKey = receivingMode.DeriveKeyMaterial(CngKey.Import(sendersPublicKey, CngKeyBlobFormat.EccPublicBlob));
byte[] decryptedFile = new byte[50000000];
Decryption(encryptedFile, ivFile, out decryptedFile);
}
Encrypt/decrypt methods:
private void Encryption(byte[] key, byte[] unencryptedMessage,out byte[] encryptedMessage, out byte[] iv)
{
using (Aes aes = new AesCryptoServiceProvider())
{
aes.Key = key;
iv = aes.IV;
// Encrypt the message
using (MemoryStream ciphertext = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ciphertext, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(unencryptedMessage, 0, unencryptedMessage.Length);
cs.Close();
encryptedMessage = ciphertext.ToArray();
}
}
}
private void Decryption(byte[] encryptedMessage, byte[] iv, out byte[] decryptedMessage)
{
using (Aes aes = new AesCryptoServiceProvider())
{
aes.Key = receiversKey;
aes.IV = iv;
// Decrypt the message
using (MemoryStream decryptedBytes = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(decryptedBytes, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(encryptedMessage, 0, encryptedMessage.Length);
cs.Close();
decryptedMessage = decryptedBytes.ToArray();
}
}
}
}
AES is a block cipher requiring input to be in block size multiples, 16-bytes for AES. The simple solution is to use PKCS#7 (née PKCS#5) padding option and the padding will be transparently added on encryption and removed on decryption.

Categories

Resources