Best Practice For Exception Handling When Writing a Utility Class c# - c#

In my solution, I am making a Utility class for Encryption. It exposes methods for encryption, decryption and few other things. Any other project can use this utility wherever encryption is needed. All the methods are static.
I am not handling any Exception in the Utility. Instead I am leaving it to the caller to handle Exceptions.
What is the Best Practice for Exception Handling when designing small utilities like this.
CODE:
public class AESEncryptionUtility
{
public static byte[] Encrypt(byte[] plainBytes, byte[] key, byte[] IV, CipherMode cipherMode, PaddingMode padding)
{
byte[] encrypted = null;
using (AesCryptoServiceProvider aesAlgo = GetAesCryptoServiceProvider(key, IV, cipherMode, padding))
{
ICryptoTransform encryptor = aesAlgo.CreateEncryptor();
encrypted = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
return encrypted;
}
public static string EncryptUrlSafe(byte[] plainText, byte[] key, byte[] IV, CipherMode cipherMode, PaddingMode padding) // This will return safe Base64 Url Encoded string
{
byte[] encrypted = Encrypt(plainText, key, IV, cipherMode, padding);
return Convert.ToBase64String(encrypted).Replace('+', '-').Replace('/', '_').Replace('=', ',');
}
private static AesCryptoServiceProvider GetAesCryptoServiceProvider(byte[] key, byte[] IV, CipherMode cipherMode, PaddingMode padding)
{
AesCryptoServiceProvider aesAlgo = new AesCryptoServiceProvider();
aesAlgo.Key = key;
aesAlgo.IV = IV;
aesAlgo.Mode = cipherMode;
aesAlgo.Padding = padding;
return aesAlgo;
}
public static byte[] Decrypt(byte[] cipherBytes, byte[] key, byte[] IV, CipherMode cipherMode, PaddingMode padding)
{
byte[] decrypted = null;
using (AesCryptoServiceProvider aesAlgo = GetAesCryptoServiceProvider(key, IV, cipherMode, padding))
{
ICryptoTransform decryptor = aesAlgo.CreateDecryptor();
decrypted = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
}
return decrypted;
}
public static byte[] GenerateKey(string masterPassword, int size) //size in bytes
{
byte[] salt = GenerateSalt(size);
Rfc2898DeriveBytes pbfdk = new Rfc2898DeriveBytes(masterPassword, salt, 20000);
return pbfdk.GetBytes(size);
}
public static byte[] GenerateSalt(int size) //size in bytes
{
RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider();
byte[] salt = new byte[size];
generator.GetNonZeroBytes(salt);
return salt;
}
}

Related

Padding is invalid and cannot be removed while encryption decryption using AES

I'm working on AES encryption/decryption. I want to encrypt request from my angular app and send it to .net api and decrypt at api then encrypt the response from api side and send it to angular app and decrypt using AES.
But sometimes it gives me 'padding is invalid and cannot be removed' exception at api side.
Here is my angular typescript crypto service code:
aesEncrypt(keys: string, value: string) { // encrypt api request parameter with aes secretkey
var key = CryptoJS.enc.Utf8.parse(keys);
var iv = CryptoJS.enc.Utf8.parse(keys);
var encrypted = CryptoJS.AES.encrypt(JSON.stringify(value), key,
{
keySize: 128 / 8,
//keySize: 128,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.toString();
}
aesDecrypt(keys: string, value: any) { // decrypt api response parameter with aes secretkey
var key = CryptoJS.enc.Utf8.parse(keys);
var iv = CryptoJS.enc.Utf8.parse(keys);
var decrypted = CryptoJS.AES.decrypt(value, key, {
keySize: 128 / 8,
//keySize: 128,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8));
}
Here is my api crypto filter code:
Way 1:
public static string Encrypt(string key, string data)
{
byte[] encryptedBytes = new UTF8Encoding().GetBytes(data);
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
ICryptoTransform crypto = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();
return Convert.ToBase64String(secret);
}
public static string Decrypt(string key, string encrypted)
{
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();
return Encoding.UTF8.GetString(secret);
}
private static AesCryptoServiceProvider AesCryptoServiceProvider(string key)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
//aes.BlockSize = 128; //Not Required
//aes.KeySize = 256; //Not Required
//aes.KeySize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.UTF8.GetBytes(key); //PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0 =
aes.IV = Encoding.UTF8.GetBytes(key); //2314345645678765
return aes;
}
Way 2:
public static string Encrypt(string key, string data)
{
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
ICryptoTransform encryptor = aes.CreateEncryptor();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
StreamWriter streamWriter = new StreamWriter(cs);
streamWriter.Write(data);
streamWriter.Flush();
cs.FlushFinalBlock();
byte[] cypherTextBytes = ms.ToArray();
ms.Close();
return Convert.ToBase64String(cypherTextBytes);
}
public static string Decrypt(string key, string encrypted)
{
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
ICryptoTransform decryptor = aes.CreateDecryptor();
byte[] plainText = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(plainText);
}
private static AesCryptoServiceProvider AesCryptoServiceProvider(string key)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
//aes.BlockSize = 128; //Not Required
//aes.KeySize = 256; //Not Required
//aes.KeySize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.UTF8.GetBytes(key); //PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0 =
aes.IV = Encoding.UTF8.GetBytes(key); //2314345645678765
return aes;
}
I tried both the ways at api level but still it is giving me padding issue (sometimes, not always)

AES decrypted message not matching the original message

I am trying to Encrypt and Decrypt a string using AES256. But The decrypted string is not matching the original one. I am not sure, but maybe I am getting the Encoding part wrong.
I am using CSPRNG to generate the IV and PBDKF2 for generating a Key to be used for AES Encryption
Program.cs:
using System;
using System.Text;
namespace AESEncryptionUtility
{
class Program
{
private static string _pass = "MasterPass";
private static string _msg = "Mohit";
private static byte[] key = EncryptionUtility.GenerateKey(_pass, 32);
private static byte[] IV = EncryptionUtility.GenerateSalt(16);
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
byte[] encrypted = Encrypt(_msg);
byte[] decrypted = Decrypt(Encoding.ASCII.GetString(encrypted));
}
public static byte[] Encrypt(string msg)
{
byte[] asciiBytesOriginal = Encoding.ASCII.GetBytes(_msg);
byte[] encrypted = EncryptionUtility.Encrypt(asciiBytesOriginal, key, IV);
Console.WriteLine("encrypted started");
foreach(var b in encrypted)
{
Console.Write(b + " ");
}
Console.WriteLine("\nencrypted ended");
return encrypted;
}
public static byte[] Decrypt(string cipher)
{
byte[] asciiBytes = Encoding.ASCII.GetBytes(cipher);
byte[] originalBytes = EncryptionUtility.Decrypt(asciiBytes, key, IV);
Console.WriteLine("decrypted started");
foreach(var b in originalBytes)
{
Console.Write(b + " ");
}
Console.WriteLine("\ndecrypted ended");
string original = Encoding.ASCII.GetString(originalBytes);
Console.WriteLine("original string: " + original);
return originalBytes;
}
}
}
EncryptionUtility.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace AESEncryptionUtility
{
public static class EncryptionUtility
{
public static byte[] Encrypt(byte[] plainBytes, byte[] key, byte[] IV)
{
byte[] encrypted = null;
using (AesCryptoServiceProvider aesAlgo = new AesCryptoServiceProvider())
{
aesAlgo.Key = key;
aesAlgo.BlockSize = 128;
aesAlgo.Mode = CipherMode.CBC;
//aesAlgo.Padding = PaddingMode.PKCS7;
aesAlgo.Padding = PaddingMode.Zeros;
aesAlgo.IV = IV;
ICryptoTransform encryptor = aesAlgo.CreateEncryptor();
encrypted = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
return encrypted;
}
public static byte[] Decrypt(byte[] cipherBytes, byte[] key, byte[] IV)
{
byte[] decrypted = null;
using (AesCryptoServiceProvider aesAlgo = new AesCryptoServiceProvider())
{
aesAlgo.Key = key;
aesAlgo.BlockSize = 128;
aesAlgo.Mode = CipherMode.CBC;
//aesAlgo.Padding = PaddingMode.PKCS7;
aesAlgo.Padding = PaddingMode.Zeros;
aesAlgo.IV = IV;
ICryptoTransform decryptor = aesAlgo.CreateDecryptor();
decrypted = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
}
return decrypted;
}
public static byte[] GenerateKey(string masterPassword, int size) //size in bytes
{
byte[] salt = GenerateSalt(size);
Rfc2898DeriveBytes pbfdk = new Rfc2898DeriveBytes(masterPassword, salt, 20000);
return pbfdk.GetBytes(size);
}
public static byte[] GenerateSalt(int size) //size in bytes
{
RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider();
byte[] salt = new byte[size];
generator.GetNonZeroBytes(salt);
return salt;
}
}
}
You can't convert arbitrary binary data to a string:
byte[] decrypted = Decrypt(Encoding.ASCII.GetString(encrypted));
And expect it to, just by chance, make sense as the particular character encoding you have chosen. It doesn't work that way. Encryption algorithms operate on bytes, not strings. If you change the following, your code will work:
...
public static byte[] Decrypt(byte[] cipher)
{
byte[] asciiBytes = cipher;
...
Have you tried changing the second last line to:
byte [] decrypted = Decrypt ( encrypted);

Only Able to Decrypt Encrypted Data First Time

I have the following code to Encrypt/Decrypt PII data.
public static class Encryption
{
public static readonly int KeyLengthBits = 256; //AES Key Length in bits
public static readonly int SaltLength = 8; //Salt length in bytes
private static readonly RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
private const int PBKDF2IterCount = 1000; // default for Rfc2898DeriveBytes
private const int PBKDF2SubkeyLength = 256 / 8; // 256 bits
private const int SaltSize = 128 / 8; // 128 bits
public static string DecryptString(string ciphertext, string passphrase)
{
var inputs = ciphertext.Split(":".ToCharArray(), 3);
var iv = Convert.FromBase64String(inputs[0]); // Extract the IV
var salt = Convert.FromBase64String(inputs[1]); // Extract the salt
var ciphertextBytes = Convert.FromBase64String(inputs[2]); // Extract the ciphertext
// Derive the key from the supplied passphrase and extracted salt
byte[] key = DeriveKeyFromPassphrase(passphrase, salt);
// Decrypt
byte[] plaintext = DoCryptoOperation(ciphertextBytes, key, iv, false);
// Return the decrypted string
return Encoding.UTF8.GetString(plaintext);
}
public static string EncryptString(string plaintext, string passphrase)
{
var salt = GenerateRandomBytes(SaltLength); // Random salt
var iv = GenerateRandomBytes(16); // AES is always a 128-bit block size
var key = DeriveKeyFromPassphrase(passphrase, salt); // Derive the key from the passphrase
// Encrypt
var ciphertext = DoCryptoOperation(Encoding.UTF8.GetBytes(plaintext), key, iv, true);
// Return the formatted string
return String.Format("{0}:{1}:{2}", Convert.ToBase64String(iv), Convert.ToBase64String(salt), Convert.ToBase64String(ciphertext));
}
private static byte[] DeriveKeyFromPassphrase(string passphrase, byte[] salt, int iterationCount = 2000)
{
var keyDerivationFunction = new Rfc2898DeriveBytes(passphrase, salt, iterationCount); //PBKDF2
return keyDerivationFunction.GetBytes(KeyLengthBits / 8);
}
private static byte[] GenerateRandomBytes(int lengthBytes)
{
var bytes = new byte[lengthBytes];
rng.GetBytes(bytes);
return bytes;
}
// This function does both encryption and decryption, depending on the value of the "encrypt" parameter
private static byte[] DoCryptoOperation(byte[] inputData, byte[] key, byte[] iv, bool encrypt)
{
byte[] output;
using (var aes = new AesCryptoServiceProvider())
using (var ms = new MemoryStream())
{
var cryptoTransform = encrypt ? aes.CreateEncryptor(key, iv) : aes.CreateDecryptor(key, iv);
using (var cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))
cs.Write(inputData, 0, inputData.Length);
output = ms.ToArray();
}
return output;
}
}
If I publish this code and encrypt data and then decrypt it, there's no problem. I correctly receive the unencrypted data. If I rebuild my application without making any changes, then publish it again without re-encrypting the data, (it's already encrypted at this point), I'm unable to decrypt it. It just returns the encrypted strings.
Why would re-publishing to the same server to this? Should I be using a different approach? If so, please recommend that different approach.
Thanks

Encrypt String AES Windows Phone 8.1

I'm making an app which will need to encrypt a string.
I'm completely new to AES encryption.
I have to code that runs on the server to encrypt.
public static string Encrypt(string text, byte[] key, byte[] iv, int keysize = 128, int blocksize = 128, CipherMode cipher = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = blocksize;
aes.KeySize = keysize;
aes.Mode = cipher;
aes.Padding = padding;
byte[] src = Encoding.UTF8.GetBytes(text);
using (ICryptoTransform encrypt = aes.CreateEncryptor(key, iv))
{
byte[] dest = encrypt.TransformFinalBlock(src, 0, src.Length);
encrypt.Dispose();
return Convert.ToBase64String(dest);
}
}
I already have this, with a library Bouncy Castle, but I can't seem to find a simple example.
byte[] key = Encoding.UTF8.GetBytes("[SECRETKEY]");
byte[] iv = Encoding.UTF8.GetBytes("[IV]");
var cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7Padding");
cipher.Init(true, new KeyParameter(key));
If it can help I also have the code which runs an Android client.
Let me know then I can post it.
You can use the PCLCrypto library, there's a nuget package available (Install-Package PclCrypto)
From https://github.com/AArnott/PCLCrypto/wiki/Crypto-Recipes:
Perform AES encryption/decryption
byte[] keyMaterial;
byte[] data;
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var key = provider.CreateSymmetricKey(keyMaterial);
byte[] iv = null; // this is optional, but must be the same for both encrypting and decrypting
byte[] cipherText = WinRTCrypto.CryptographicEngine.Encrypt(key, data, iv);
byte[] plainText = WinRTCrypto.CryptographicEngine.Decrypt(key, cipherText, iv);
The cipherText variable is the encrypted data, plainText is the encrypted variable decrypted again

Length of the data to Encrypt is invalid

Getting Exception " length of the data to ENCRYPTION is invalid".
private static readonly byte[] salt = Encoding.ASCII.GetBytes("S#sh#kt# VMS");
public static string Encrypt(string textToEncrypt, string encryptionPassword)
{
byte[] encryptedBytes = null;
try
{
var algorithm = GetAlgorithm(encryptionPassword);
algorithm.Padding = PaddingMode.None;
using (ICryptoTransform encryptor = algorithm.CreateEncryptor(algorithm.Key, algorithm.IV))
{
byte[] bytesToEncrypt = Encoding.UTF8.GetBytes(textToEncrypt);
encryptedBytes = InMemoryCrypt(bytesToEncrypt, encryptor);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return Convert.ToBase64String(encryptedBytes);
}
// Performs an in-memory encrypt/decrypt transformation on a byte array.
private static byte[] InMemoryCrypt(byte[] data, ICryptoTransform transform)
{
MemoryStream memory = new MemoryStream();
using (Stream stream = new CryptoStream(memory, transform, CryptoStreamMode.Write))
{
stream.Flush();
stream.Write(data, 0, data.Length);
//stream.FlushFinalBlock();
}
return memory.ToArray();
}
private static RijndaelManaged GetAlgorithm(string encryptionPassword)
{
// Create an encryption key from the encryptionPassword and salt.
var key = new Rfc2898DeriveBytes(encryptionPassword, salt);
// Declare that we are going to use the Rijndael algorithm with the key that we've just got.
var algorithm = new RijndaelManaged();
int bytesForKey = algorithm.KeySize/8;
int bytesForIV = algorithm.BlockSize/8;
algorithm.Key = key.GetBytes(bytesForKey);
algorithm.IV = key.GetBytes(bytesForIV);
return algorithm;
}
And the decryption routine is:
public static string Decrypt(string encryptedText, string encryptionPassword)
{
var algorithm = GetAlgorithm(encryptionPassword);
algorithm.Padding = PaddingMode.PKCS7;
byte[] descryptedBytes;
using (ICryptoTransform decryptor = algorithm.CreateDecryptor(algorithm.Key, algorithm.IV))
{
byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
descryptedBytes = InMemoryCrypt(encryptedBytes, decryptor);
}
return Encoding.UTF8.GetString(descryptedBytes);
}
PaddingMode.None requires that the input is a multiple of the block size. Use somethink like PaddingMode.PKCS7 instread.
A few other issues with your code:
A constant doesn't make a good salt
The constant salt together with deterministic derivation of the IV from the password means that you're reusing (Key, IV) pairs, which should not be done
You don't add authentication/some kind of MAC. That often leads to padding oracles or similar attacks
You read more the native size from the PBKDF2 output. That halves your key derivation speed without slowing down an attacker.

Categories