Encrypt string with Bouncy Castle AES/CBC/PKCS7 - c#

I have been looking everywhere for some sample code on how to encrypt a simple string with the encryption in the title using the Bouncy Castle Framework.
This code will run on a Windows Universal project.
My previous attempts to encrypt using the build in API's failed to decrypt on the server.
I tried this: which gives me a string like:
4pQUfomwVVsl68oQqWoWYNRmRM+Cp+vNFXBNdkN6dZPQ34VZ35vsKn9Q7QGTDVOj+w5mqVYHnGuAOFOgdgl8kA==
s = String.Format("{0}_{1}", s, DateTime.Now.ToString("ddMMyyyyHmmss"));
SymmetricKeyAlgorithmProvider algorithm = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
IBuffer keymaterial = CryptographicBuffer.ConvertStringToBinary("[Key]", BinaryStringEncoding.Utf8);
CryptographicKey KEY = algorithm.CreateSymmetricKey(keymaterial);
IBuffer IV = CryptographicBuffer.ConvertStringToBinary("[IV]", BinaryStringEncoding.Utf8);
IBuffer data = CryptographicBuffer.ConvertStringToBinary(s, BinaryStringEncoding.Utf8);
IBuffer output = CryptographicEngine.Encrypt(KEY, data, IV);
return CryptographicBuffer.EncodeToBase64String(output);
The server does encryption/decryption with
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);
}
}
public static string Decrypt(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 = Convert.FromBase64String(text);
using (ICryptoTransform decrypt = aes.CreateDecryptor(key, iv))
{
byte[] dest = decrypt.TransformFinalBlock(src, 0, src.Length);
decrypt.Dispose();
return Encoding.UTF8.GetString(dest); //Padding is invalid and cannot be removed.
}
}
But it fails becasue:
Padding is invalid and cannot be removed.
That's why I want to try Bouncy Castle, but I can't find any suitable example code.
EDIT
I tried using Bouncy Castle with the code provided in the answer.
Now I'm getting the error:
initialisation vector must be the same length as block size
byte[] inputBytes = Encoding.UTF8.GetBytes(s);
byte[] IV = Encoding.UTF8.GetBytes("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
byte[] key = Encoding.UTF8.GetBytes("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
//Set up
AesEngine engine = new AesEngine();
CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
Debug.WriteLine(IV.Length); //32
Debug.WriteLine(cipher.GetBlockSize()); //16
KeyParameter keyParam = new KeyParameter(key);
ParametersWithIV keyParamWithIv = new ParametersWithIV(keyParam, IV);
cipher.Init(true, keyParamWithIv); //Error Message thrown
byte[] outputBytes = new byte[cipher.GetOutputSize(inputBytes.Length)]; //cip
int length = cipher.ProcessBytes(inputBytes, outputBytes, 0);
cipher.DoFinal(outputBytes, length); //Do the final block
string encryptedInput = Convert.ToBase64String(outputBytes);
The length on the server is 128. How can I force it to be equal and same length?

Here are snippets I use. It uses the default built-in System.Security.Cryptography. It doesn't need to be BC
/// <summary>
/// Encrypt a byte array using AES 128
/// </summary>
/// <param name="key">128 bit key</param>
/// <param name="secret">byte array that need to be encrypted</param>
/// <returns>Encrypted array</returns>
public static byte[] EncryptByteArray(byte[] key, byte[] secret)
{
using (MemoryStream ms = new MemoryStream())
{
using (AesManaged cryptor = new AesManaged())
{
cryptor.Mode = CipherMode.CBC;
cryptor.Padding = PaddingMode.PKCS7;
cryptor.KeySize = 128;
cryptor.BlockSize = 128;
//We use the random generated iv created by AesManaged
byte[] iv = cryptor.IV;
using (CryptoStream cs = new CryptoStream(ms, cryptor.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
cs.Write(secret, 0, secret.Length);
}
byte[] encryptedContent = ms.ToArray();
//Create new byte array that should contain both unencrypted iv and encrypted data
byte[] result = new byte[iv.Length + encryptedContent.Length];
//copy our 2 array into one
System.Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
System.Buffer.BlockCopy(encryptedContent, 0, result, iv.Length, encryptedContent.Length);
return result;
}
}
}
/// <summary>
/// Decrypt a byte array using AES 128
/// </summary>
/// <param name="key">key in bytes</param>
/// <param name="secret">the encrypted bytes</param>
/// <returns>decrypted bytes</returns>
public static byte[] DecryptByteArray(byte[] key, byte[] secret)
{
byte[] iv = new byte[16]; //initial vector is 16 bytes
byte[] encryptedContent = new byte[secret.Length - 16]; //the rest should be encryptedcontent
//Copy data to byte array
System.Buffer.BlockCopy(secret, 0, iv, 0, iv.Length);
System.Buffer.BlockCopy(secret, iv.Length, encryptedContent, 0, encryptedContent.Length);
using (MemoryStream ms = new MemoryStream())
{
using (AesManaged cryptor = new AesManaged())
{
cryptor.Mode = CipherMode.CBC;
cryptor.Padding = PaddingMode.PKCS7;
cryptor.KeySize = 128;
cryptor.BlockSize = 128;
using (CryptoStream cs = new CryptoStream(ms, cryptor.CreateDecryptor(key, iv), CryptoStreamMode.Write))
{
cs.Write(encryptedContent, 0, encryptedContent.Length);
}
return ms.ToArray();
}
}
}
If you really need BC, here is a quick test I manage to write based on the test suit from https://github.com/bcgit/bc-csharp/blob/master/crypto/test/src/crypto/test/AESFastTest.cs
You can tailor it for your need
private static void TestBC()
{
//Demo params
string keyString = "jDxESdRrcYKmSZi7IOW4lw==";
string input = "abc";
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
byte[] iv = new byte[16]; //for the sake of demo
//Set up
AesEngine engine = new AesEngine();
CbcBlockCipher blockCipher = new CbcBlockCipher(engine); //CBC
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher); //Default scheme is PKCS5/PKCS7
KeyParameter keyParam = new KeyParameter(Convert.FromBase64String(keyString));
ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv, 0, 16);
// Encrypt
cipher.Init(true, keyParamWithIV);
byte[] outputBytes = new byte[cipher.GetOutputSize(inputBytes.Length)];
int length = cipher.ProcessBytes(inputBytes, outputBytes, 0);
cipher.DoFinal(outputBytes, length); //Do the final block
string encryptedInput = Convert.ToBase64String(outputBytes);
Console.WriteLine("Encrypted string: {0}", encryptedInput);
//Decrypt
cipher.Init(false, keyParamWithIV);
byte[] comparisonBytes = new byte[cipher.GetOutputSize(outputBytes.Length)];
length = cipher.ProcessBytes(outputBytes, comparisonBytes, 0);
cipher.DoFinal(comparisonBytes, length); //Do the final block
Console.WriteLine("Decrypted string: {0}",Encoding.UTF8.GetString(comparisonBytes)); //Should be abc
}

enter link description here
byte[] k; //32 byte
string para; // plaintext
string msgRefNo; // 16byte
byte[] inputBytes = Encoding.UTF8.GetBytes(para);
byte[] IV = Encoding.UTF8.GetBytes(msgRefNo);
byte[] key = k;
AesEngine engine = new AesEngine();
CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
PaddedBufferedBlockCipher cipher1 = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
KeyParameter keyParam = new KeyParameter(key);
ParametersWithIV keyParamWithIv = new ParametersWithIV(keyParam, IV);
cipher1.Init(true, keyParamWithIv); //Error Message thrown
byte[] outputBytes = new byte[cipher1.GetOutputSize(inputBytes.Length)]; //cip
int length = cipher1.ProcessBytes(inputBytes, outputBytes, 0);
cipher1.DoFinal(outputBytes, length); //Do the final block
string encryptedInput = Convert.ToBase64String(outputBytes);
return encryptedInput;

Related

Crypto Padding Invalid and cannot be removed

i'm call the StringCipher Class from a userform encrpyting the value and using it as a string parameter into a method in another class. this class then decrypts the value and uses it. (userform gets the username and passsword encrypts and sends to another object to handle the request. that other object decrypts the value and uses it).
here's the problem when i call the encrypt and decrypt in the same class i have no issues. but if i encrypt in one class and decrypt in another i get a "Padding Invalid and cannot be removed" error.
thoughts?
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
/// <summary>
/// Adding a namespace comment to change something
/// </summary>
namespace SYF.AMSDev.Security.Encryption
{
public static class StringCipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code to get the equivalent number of bytes.
private const int KeySize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is prepended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(KeySize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the salt bytes by extracting the first 32 bytes from the supplied cipherText btyes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(KeySize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(KeySize / 8).Take(KeySize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((KeySize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((KeySize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(KeySize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
// 32 bytes will give us 256 bits.
var randomBytes = new byte[32];
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
/// <summary>
/// Converts a plain text string into pre-formated hash string. This is currently intended for use with FD Connections.
/// </summary>
/// <param name="itemToHash">Plain text string that needs to be converted to a hash.</param>
/// <returns>The resulting hash string representation of the original plain text string provided.</returns>
public static string ConvertToHash(string itemToHash)
{
SHA1CryptoServiceProvider sha1Object = new SHA1CryptoServiceProvider();
byte[] bytesToHash = Encoding.ASCII.GetBytes(itemToHash);
bytesToHash = sha1Object.ComputeHash(bytesToHash);
string strResult = null;
foreach (byte byteToHash in bytesToHash)
{
strResult += byteToHash.ToString("x");
}
strResult = strResult.Substring(0, 15);
return string.Format("SHA10437{0}", strResult);
}
}
}

Wrong algorithm: AES or Rijndael required on c#

I had andriod code and I tried to convert it to c#. It's a simple Encryption class. But when I try to decrypt data with it I catch: Wrong algorithm: AES or Rijndael required.
Here is my converted code:
public static string decrypt(string data)
{
byte[] dataBytes = Convert.FromBase64String(data);
SecretKey secretKey = getSecretKey(hashTheKey("ABCD"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secretKey, new IvParameterSpec(new byte[16]),
SecureRandom.getInstance("SHA1PRNG"));
var x = cipher.doFinal(dataBytes);
return System.Text.Encoding.UTF8.GetString(x);
}
public static SecretKey getSecretKey(char[] key)
{
var secretKeyType = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
var secretkey = secretKeyType.generateSecret(new PBEKeySpec(key,
System.Text.Encoding.UTF8
.GetBytes("ABCD"),
100, 128)).getEncoded();
return new SecretKeySpec(secretkey, "AES/CBC/PKCS5Padding");
}
public static char[] hashTheKey(string key)
{
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(System.Text.Encoding.UTF8.GetBytes(key));
return Convert.ToBase64String(messageDigest.digest()).ToCharArray();
}
Here is my original android code:
private char[] hashTheKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(key.getBytes());
return Base64.encodeToString(messageDigest.digest(),
Base64.NO_PADDING).toCharArray();
}
private SecretKey getSecretKey(char[] key) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException {
return new SecretKeySpec(
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
.generateSecret(new PBEKeySpec(key,
"ABCD".getBytes("UTF8"),
100, 128)).getEncoded(), "AES");
}
public String decrypt(String data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeySpecException {
byte[] dataBytes = Base64.decode(data, Base64.DEFAULT);
SecretKey secretKey = getSecretKey(hashTheKey("ABCD"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secretKey, new IvParameterSpec(new byte[16]),
SecureRandom.getInstance("SHA1PRNG"));
return new String(cipher.doFinal(dataBytes));
}
c# and java are using the same well-estabilished cryptography algorithms, but differs in approach how to invoke them. It is still possible to convert the code though.
One key point is difference in base64 encoding - C# always use padding.
Converted code goes like:
const int KeySize = 128;
static string HashTheKey(string key) {
String hashKey;
using (var sha = new SHA1Managed()) {
hashKey = Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(key)));
}
// beware - you're on C# now so remove the padding and add the newline to match java
return hashKey.Replace("=", "") + "\n";
}
static byte[] GetSecretKey(string password) {
var salt = Encoding.UTF8.GetBytes("JVAaVhAiddKAaghraikhmaini");
using (var pass = new Rfc2898DeriveBytes(password, salt, 65536)) {
return pass.GetBytes(KeySize / 8);
}
}
static void Main(string[] args) {
string encrypted = "vtlkQHTz7/oz2weuAAkLz2Q5c2yj2LGukF7SHJjT+TA8oRLixTQSXQ7dG1O736hyT1HJxcz0P4DzzVaO5chWKKSJQ2uPEpDQJu/fZGguqDw=";
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
using (var aes = new AesManaged()) {
aes.KeySize = KeySize;
aes.Padding = PaddingMode.PKCS7;
aes.Key = GetSecretKey(HashTheKey("Android"));
// you're using the same init vector in your android code
aes.IV = new byte[16];
using (var decryptor = aes.CreateDecryptor()) {
// dumps {"barcode":"12345678","token":"cad603fc-1e53-4a95-9150-f1694baa07f9"}
Console.Out.WriteLine(Encoding.UTF8.GetString(decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length)));
}
}
}
C# does not handle the encryption algorithms as Android or java do you have to use either AES or Rijndael algorithm as you can see the error to covert to the simple text into Encrypted Base64 and vice versa you can use the following class in C#
public static class Stringcipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}

PHP and C# AES256 encryption -> decryption

I want to encrypt a text in PHP and to decrypt in in C#, but i can't.
This is my PHP code:
define('AES_256_ECB', 'aes-256-ecb');
$encryption_key = "SomeSimpleTest";
$data = "Test123";
$encryptedData = openssl_encrypt($data, AES_256_ECB, $encryption_key, 0);
..and this is my C# code:
(AESEncryption.cs class)
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;
namespace AESCrypto
{
class AESEncryption
{
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
// Set your salt here to meet your flavor:
byte[] saltBytes = passwordBytes;
// Example:
//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 = 256;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.ECB;
//AES.Padding = PaddingMode.PKCS7;
using (CryptoStream cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
public static string Decrypt(string decryptedText, byte[] passwordBytes)
{
byte[] bytesToBeDecrypted = Convert.FromBase64String(decryptedText);
// Hash the password with SHA256
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] decryptedBytes = AES_Decrypt(bytesToBeDecrypted, passwordBytes);
// Getting the size of salt
int saltSize = GetSaltSize(passwordBytes);
// Removing salt bytes, retrieving original bytes
byte[] originalBytes = new byte[decryptedBytes.Length - saltSize];
for (int i = saltSize; i < decryptedBytes.Length; i++)
{
originalBytes[i - saltSize] = decryptedBytes[i];
}
return Encoding.UTF8.GetString(originalBytes);
}
public static int GetSaltSize(byte[] passwordBytes)
{
var key = new Rfc2898DeriveBytes(passwordBytes, passwordBytes, 1000);
byte[] ba = key.GetBytes(2);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ba.Length; i++)
{
sb.Append(Convert.ToInt32(ba[i]).ToString());
}
int saltSize = 0;
string s = sb.ToString();
foreach (char c in s)
{
int intc = Convert.ToInt32(c.ToString());
saltSize = saltSize + intc;
}
return saltSize;
}
public static byte[] GetRandomBytes(int length)
{
byte[] ba = new byte[length];
RNGCryptoServiceProvider.Create().GetBytes(ba);
return ba;
}
}
}
Usage of it:
using AESCrypto;
...
public string DecryptText(string input, string password)
{
// Get the bytes of the string
byte[] bytesToBeDecrypted = Convert.FromBase64String(input);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] bytesDecrypted = AESEncryption.AES_Decrypt(bytesToBeDecrypted, passwordBytes);
string result = Encoding.UTF8.GetString(bytesDecrypted);
return result;
}
private void btn1_Click(object sender, EventArgs e)
{
textBox1.Text = DecryptText("KEY_ENCRYPTED_WITH_PHP", "SomeSimpleTest");
}
I even tried with CBC but does not work...The mode of encryption is not important. I only want to make it work as it should.
Thanks.
php code:
define('AES_128_ECB', 'aes-128-ecb');
$encryption_key = "MY_16_CHAR_KEY:)";
$data = "MyOwnEncryptedSecretText";
$encryptedData = openssl_encrypt($data, AES_128_ECB, $encryption_key, 0);
C# code:
public String Decrypt(String text, String key)
{
//decode cipher text from base64
byte[] cipher = Convert.FromBase64String(text);
//get key bytes
byte[] btkey = Encoding.ASCII.GetBytes(key);
//init AES 128
RijndaelManaged aes128 = new RijndaelManaged();
aes128.Mode = CipherMode.ECB;
aes128.Padding = PaddingMode.PKCS7;
//decrypt
ICryptoTransform decryptor = aes128.CreateDecryptor(btkey, null);
MemoryStream ms = new MemoryStream(cipher);
CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
byte[] plain = new byte[cipher.Length];
int decryptcount = cs.Read(plain, 0, plain.Length);
ms.Close();
cs.Close();
//return plaintext in String
return Encoding.UTF8.GetString(plain, 0, decryptcount);
}
and usage of it:
string DecryptedText = Decrypt("GENERATED_KEY", "MY_16_CHAR_KEY:)");
Now it works great :)
Thanks.

C# Encrypt data AES

Is there a way to encrypt data with AES? I'd love to use at least 128 Bits for the encryption Key.
I tried with AES default class provided by Microsoft but I can't do a lot... I can't set the Key Lenght.
Is there another Class that I can use?
Yes. You can use the code listed at http://www.codeproject.com/Articles/769741/Csharp-AES-bits-Encryption-Library-with-Salt
You Can Use RIJNDAEL:
First you need to include using System.Security.Cryptography;
public 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;
}
public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = 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.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
public void EncryptFile(string filename, string outfilename, string psw)
{
string file = filename;
string password = psw;
byte[] bytesToBeEncrypted = File.ReadAllBytes(file); //read bytes to encrypt them
byte[] passwordBytes = Encoding.UTF8.GetBytes(password); //read with UTF8 encoding the password.
passwordBytes = SHA256.Create().ComputeHash(passwordBytes); //hash the psw
byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);
string fileEncrypted = outfilename;
File.WriteAllBytes(fileEncrypted, bytesEncrypted);
}
public void DecryptFile(string filename, string outfilename, string psw)
{
string fileEncrypted = filename;
string password = psw;
byte[] bytesToBeDecrypted = File.ReadAllBytes(fileEncrypted);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes);
string file = outfilename;
File.WriteAllBytes(file, bytesDecrypted);
}

Decryption using Rijndael in C#

I have the following encryption method. I am not able to decrypt it. I have inherited the encryption algorithm so it cannot be changed.
public static string Encrypt(string plaintext)
{
byte[] rgbIV;
byte[] key;
RijndaelManaged rijndael = BuildRigndaelCommon(out rgbIV, out key);
//convert plaintext into a byte array
byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
int BlockSize;
BlockSize = 16 * (1 + (plaintext.Length / 16));
Array.Resize(ref plaintextBytes, BlockSize);
// fill the remaining space with 0
for (int i = plaintext.Length; i < BlockSize; i++)
{
plaintextBytes[i] = 0;
}
byte[] cipherTextBytes = null;
//create uninitialized Rijndael encryption obj
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
var transform = rijndael.CreateEncryptor();
//Chaining mode
symmetricKey.Mode = CipherMode.CFB;
//create encryptor from the key and the IV value
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream())
{
//define cryptographic stream - contains the transformation key to be used and the mode
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
//encrypt contents of cryptostream
cs.Write(plaintextBytes, 0, BlockSize);
cs.FlushFinalBlock();
//convert encrypted data from a memory stream into a byte array
cipherTextBytes = ms.ToArray();
}
}
}
//store result as a hex value
string hexOutput = BitConverter.ToString(cipherTextBytes).Replace("-", "");
hexOutput = hexOutput.Substring(0, plaintext.Length * 2);
//finially return encrypted string
return hexOutput;
}
As you can see it's pretty standard except at the end it's converted to hex and substring is performed. I'm having great difficulty doing the opposite.
My decrypt method is like:
public static string Decrypt(string disguisedtext)
{
byte[] rgbIV;
byte[] key;
BuildRigndaelCommon(out rgbIV, out key);
byte[] disguishedtextBytes = FromHexString(disguisedtext);
string visiabletext = "";
//create uninitialized Rijndael encryption obj
using (var symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
symmetricKey.Mode = CipherMode.CFB;
//create encryptor from the key and the IV value
// ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream(disguishedtextBytes))
{
//define cryptographic stream - contains the transformation to be used and the mode
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
{
byte[] plaintextBytes = new Byte[disguishedtextBytes.Length];
cs.Write(disguishedtextBytes, 0, disguishedtextBytes.Length);
cs.FlushFinalBlock();
//convert decrypted data from a memory stream into a byte array
byte[] visiabletextBytes = ms.ToArray();
visiabletext = Encoding.UTF8.GetString(visiabletextBytes);
}
}
}
return visiabletext;
}
Helper Methods:
private static RijndaelManaged BuildRigndaelCommon(out byte[] rgbIV, out byte[] key)
{
rgbIV = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 };
key = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 };
//Specify the algorithms key & IV
RijndaelManaged rijndael = new RijndaelManaged{BlockSize = 128, IV = rgbIV, KeySize = 128, Key = key, Padding = PaddingMode.None};
return rijndael;
}
public static byte[] FromHexString(string hexString)
{
if (hexString == null)
{
return new byte[0];
}
var numberChars = hexString.Length;
var bytes = new byte[numberChars / 2];
for (var i = 0; i < numberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
}
return bytes;
}
I'm getting various errors regarding the length of the string and that the padding is invalid. Has anybody any ideas to get the decryption working. I've tried padding out the input string back to 32 bytes but no avail.
Your problem is a subtle error in your Encrypt method. You are losing data from your returned ciphertext by messing with the the hexOutput string. Instead of:
//store result as a hex value
string hexOutput = BitConverter.ToString(cipherTextBytes).Replace("-", "");
hexOutput = hexOutput.Substring(0, plaintext.Length * 2);
//finially return encrypted string
return hexOutput;
You should just return the output:
return BitConverter.ToString(cipherTextBytes).Replace("-", "");
You will also need to change the padding mode in your Decrypt method to None. Though this will now correctly decrypt it will also include the manual padding characters that you add in your encrypt method. As you don't know your plain text you have no GOOD way of removing them. You could always add a method to remove all bytes in your array that dont match your padding value of zero:
int endMarker = decryptedData.Length;
do { endMarker--; } while (decryptedData[endMarker] == 0);
Array.Resize(ref decryptedData, endMarker + 1);
However this isn't really a good idea as you're possibly discarding otherwise valid data. A better solution would be to update your encrypt and decrypt methods to let the cipher handle the padding. Putting it all together we get (showing only what i've changed):
private static RijndaelManaged BuildRigndaelCommon(out byte[] rgbIV, out byte[] key)
{
rgbIV = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 };
key = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 };
//Specify the algorithms key & IV
RijndaelManaged rijndael = new RijndaelManaged{BlockSize = 128, IV = rgbIV, KeySize = 128, Key = key, Padding = PaddingMode.PKCS7 };
return rijndael;
}
public static string Encrypt(string plaintext)
{
byte[] rgbIV;
byte[] key;
RijndaelManaged rijndael = BuildRigndaelCommon(out rgbIV, out key);
//convert plaintext into a byte array
byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
byte[] cipherTextBytes = null;
//create uninitialized Rijndael encryption obj
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
var transform = rijndael.CreateEncryptor();
//Chaining mode
symmetricKey.Mode = CipherMode.CFB;
//create encryptor from the key and the IV value
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
//encrypt contents of cryptostream
cs.Write(plaintextBytes, 0, plaintextBytes.Length);
cs.Flush();
cs.FlushFinalBlock();
//convert encrypted data from a memory stream into a byte array
ms.Position = 0;
cipherTextBytes = ms.ToArray();
ms.Close();
cs.Close();
}
}
//store result as a hex value
return BitConverter.ToString(cipherTextBytes).Replace("-", "");
}
public static string Decrypt(string disguisedtext)
{
byte[] disguishedtextBytes = FromHexString(disguisedtext);
byte[] rgbIV;
byte[] key;
BuildRigndaelCommon(out rgbIV, out key);
string visiabletext = "";
//create uninitialized Rijndael encryption obj
using (var symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
symmetricKey.Mode = CipherMode.CFB;
symmetricKey.BlockSize = 128;
//create encryptor from the key and the IV value
// ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream(disguishedtextBytes))
{
//define cryptographic stream - contains the transformation to be used and the mode
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
byte[] decryptedData = new byte[disguishedtextBytes.Length];
int stringSize = cs.Read(decryptedData, 0, disguishedtextBytes.Length);
cs.Close();
//Trim the excess empty elements from the array and convert back to a string
byte[] trimmedData = new byte[stringSize];
Array.Copy(decryptedData, trimmedData, stringSize);
visiabletext = Encoding.UTF8.GetString(trimmedData);
}
}
}
return visiabletext;
}
Hope this helps point you on your way. As an aside I maintain a set of encryption utilities on Snipt that may be of use to you, particularly the SymmetricEncrypt and SymmetricDecrypt methods.
------ EDIT ------
As noted in the comment below, we are not allowed to alter the Encrypt method. I do like a good challenge! With appropriate byte mangling applied, here's a decrypt that honours the return coming form the Encrypt method:
public static string Decrypt(string disguisedtext)
{
byte[] disguishedtextBytes = FromHexString(disguisedtext);
var originalLength = disguishedtextBytes.Length;
int BlockSize;
BlockSize = 16 * (1 + (originalLength / 16));
Array.Resize(ref disguishedtextBytes, BlockSize);
// fill the remaining space with 0
for (int i = originalLength; i < BlockSize; i++)
{
disguishedtextBytes[i] = 0;
}
byte[] rgbIV;
byte[] key;
BuildRigndaelCommon(out rgbIV, out key);
string visiabletext = "";
//create uninitialized Rijndael encryption obj
using (var symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
symmetricKey.Mode = CipherMode.CFB;
symmetricKey.BlockSize = 128;
symmetricKey.Padding = PaddingMode.None;
// ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream(disguishedtextBytes))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
byte[] decryptedData = new byte[disguishedtextBytes.Length];
int stringSize = cs.Read(decryptedData, 0, disguishedtextBytes.Length);
cs.Close();
//Trim the excess empty elements from the array and convert back to a string
byte[] trimmedData = new byte[stringSize];
Array.Copy(decryptedData, trimmedData, originalLength);
Array.Resize(ref trimmedData, originalLength);
visiabletext = Encoding.UTF8.GetString(trimmedData);
}
}
return visiabletext;
}
It looks like your encryption method outputs a space separated hex string, representing a byte array: "OA FE 82 3B ...". It also makes assumptions about the plaintext and chops off any padding.
Your first step it to convert the hex string back into a byte array, which is pretty easy.
To deal with the lost padding just set decryption to NoPadding, as #Wolfwyrd suggests. You may have to check that your data is correctly terminated if the padding length was off.
If the assumptions about plaintext characters were wrong, then it is likely you will have to recover things by hand. If the plaintext is strict ASCII (7 bit characters only) then this should not be a problem. Anything outside that, such as accented letters: á, é etc. will break the assumption.

Categories