I have to encrypt some data on reactjs side and decrypt data in c# app.
I am trying rijndael-js in reactjs. And on c# side i am using RijndaelManaged. Own each one codes like below.
reactjs codes;
import Rijndael from "rijndael-js"
class ServiceRequester{
getCrypto()
{
let original = "tolga";
let key = "00000000000000000000000000000000"; // 32 length
let iv = "0000000000000000"; // 16 length
let cipher = new Rijndael(key, "cbc");
let ciphertext = cipher.encrypt(original, 128, iv);
console.log(ciphertext.toString("base64"));
console.log(cipher.decrypt(ciphertext, 128, iv).toString());
return ciphertext.toString("base64");
}
}
c# code;
public static string Decrypt(string encryptedText)
{
if (encryptedText == null)
{
return null;
}
var bytesToBeDecrypted = Convert.FromBase64String(encryptedText);
var bytesDecrypted = Decrypt(bytesToBeDecrypted);
return Encoding.UTF8.GetString(bytesDecrypted);
}
private static byte[] Decrypt(byte[] bytesToBeDecrypted)
{
byte[] decryptedBytes = null;
using (var ms = new MemoryStream())
{
using (var AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Key = new byte[32];
AES.IV = new byte[16];
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;
}
c# app been throwing an error. Error is
System.Security.Cryptography.CryptographicException: 'Padding is invalid and cannot be removed.
Related
I'm trying to make encryption and decryption between php and c# using AES-128-ECB
I found a way to encrypt in php and decrypt in c#.
the problem now i'm trying to do the opposite I'm facing problem trying to understand how c# working with Cryptography
the code I used I found it on this question
PHP and C# AES256 encryption -> decryption
I'm using the same code it's easy to do it on php for decryption but my problem with c#
I found this docs cryptography using rijadealManaged I coudn't understand it
c# code :
public String Decryptions(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);
}
php code :
function encryption($json) {
$encrypted= '';
$plaintext = $json;
$cipher = 'AES-128-ECB';
$key = '1234567891123456';
$encrypted = openssl_encrypt($plaintext, $cipher, $key, 0);
return $encrypted;
echo $encrypted;
}
UPDATE :
tried this code from answers :
public string Encryption(string text,string key,string privatekey)
{
byte[] inputtextbyteArray = System.Text.Encoding.UTF8.GetBytes(text);
using RijndaelManaged aes128 = new RijndaelManaged { Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };
using var memstr = new MemoryStream();
using var crystr = new CryptoStream(memstr, aes128.CreateDecryptor(Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(privatekey)), CryptoStreamMode.Write);
crystr.Write(inputtextbyteArray, 0, inputtextbyteArray.Length);
return Convert.ToBase64String(memstr.ToArray());
}
public string Decryption(string base64, string key, string privatekey)
{
try
{
byte[] inputtextbyteArray = Convert.FromBase64String(base64.Replace(" ", "+"));
using RijndaelManaged aes128 = new RijndaelManaged { Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };
using var memstr = new MemoryStream();
using var crystr = new CryptoStream(memstr, aes128.CreateDecryptor(Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(privatekey)), CryptoStreamMode.Write);
crystr.Write(inputtextbyteArray, 0, inputtextbyteArray.Length);
return Encoding.UTF8.GetString(memstr.ToArray());
}
catch (Exception ex)
{
throw new Exception("LOL NO HACKING!");
}
}
I understand how code work but the Errors I'm getting confusing :
public string Encryption(string text,string key,string privatekey)
{
byte[] inputtextbyteArray = System.Text.Encoding.UTF8.GetBytes(text);
using RijndaelManaged aes128 = new RijndaelManaged { Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };
using var memstr = new MemoryStream();
using var crystr = new CryptoStream(memstr, aes128.CreateDecryptor(Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(privatekey)), CryptoStreamMode.Write);
crystr.Write(inputtextbyteArray, 0, inputtextbyteArray.Length);
return Convert.ToBase64String(memstr.ToArray());
}
public string Decryption(string base64, string key, string privatekey)
{
try
{
byte[] inputtextbyteArray = Convert.FromBase64String(base64.Replace(" ", "+"));
using RijndaelManaged aes128 = new RijndaelManaged { Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };
using var memstr = new MemoryStream();
using var crystr = new CryptoStream(memstr, aes128.CreateDecryptor(Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(privatekey)), CryptoStreamMode.Write);
crystr.Write(inputtextbyteArray, 0, inputtextbyteArray.Length);
return Encoding.UTF8.GetString(memstr.ToArray());
}
catch (Exception ex)
{
throw new Exception("LOL NO HACKING!");
}
}
I didn't test it
remeber by use "using" you dont need to use ms.Close();
And aes128.CreateDecryptor(btkey, null); why you use null
just make a private key
and btw i just choice "key" in my code but easy to call it chiper
I'm in the middle of porting an older application to .Net 6, and have hit a stumbling block of the encryption / decryption method is now failing. It still works perfectly fine under .Net 4.x.x.
The error being thrown is,
"Padding is invalid and cannot be removed."
Code: - Updated to actual original code. This code worked fine when targeting .Net 4.7.2, however after moving the code to .Net 6.0 RC2, it started to lose anything greater than 32 chars of the decrypted string, which lead to errors elsewhere as the strings weren't complete.
For context. This was running on a webhost & a desktop client, to encrypt messages in transit. The webhost has been updated and validated to be sending the correct encrypted value (decrypting the message using the .Net 4 client is successful). However, the .Net 6 desktop client isn't decrypting it correctly and is losing characters in the decrypted string.
#region Encrypt method(s)
private const int Keysize = 256;
private const int Blocksize = 128;
private const int DerivationIterations = 1000;
public async Task<string> EncryptStringWithValidatedPadding(string plainText, string passPhrase)
{
string encrypted = null;
bool valid = false;
while (!valid)
{
encrypted = await Encrypt(plainText, passPhrase);
if (!string.IsNullOrEmpty(await Decrypt(encrypted, passPhrase)))
{
valid = true;
}
}
return encrypted;
}
private async Task<string> Encrypt(string plainText, string passPhrase)
{
var saltStringBytes = GenerateRandomEntropy(32); // 256 bits
var ivStringBytes = GenerateRandomEntropy(16); // 128 bits
byte[] plainTextBytes = Convert.FromBase64String(plainText);
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new AesManaged())
{
symmetricKey.KeySize = Keysize;
symmetricKey.BlockSize = Blocksize;
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();
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
var encrypted64String = Convert.ToBase64String(cipherTextBytes);
return encrypted64String;
}
}
}
}
}
}
private static byte[] GenerateRandomEntropy(int byteSize)
{
var randomBytes = new byte[byteSize];
using (var rngCsp = new RNGCryptoServiceProvider())
{
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
#endregion
#region Decrypt method
public static async Task<string> Decrypt(string cipherText, string passPhrase)
{
try
{
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Blocksize / 8).ToArray();
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) + Blocksize / 8).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) + Blocksize / 8)).ToArray();
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new AesManaged())
{
symmetricKey.KeySize = 256;
symmetricKey.BlockSize = Blocksize;
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);
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return null;
}
#endregion
This is called with,
encryptedString = await new EncryptDecrypt().EncryptStringWithValidatedPadding(b64String, Convert.ToBase64String(Encoding.UTF8.GetBytes(passPhrase)));
I am assuming that saving the IV should solve this, but I'm wondering if there are any obvious flaws here that I'm just not seeing.
Can anyone explain it?
Update: As suggested I've refactored the code to the below. I've also stripped it right back for the minute to ensure the underlying algo's work.
Ref: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-6.0
namespace Encryption_Helper
{
public class EncryptDecrypt
{
#region Encrypt method(s)
private static byte[] bytes = new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 };
private const int Keysize = 256;
private const int Blocksize = 128;
private const int DerivationIterations = 1000;
public static async Task<string> EncryptStringWithValidatedPadding(string plainText, string passPhrase)
{
string encrypted = null;
bool valid = false;
while (!valid)
{
encrypted = await Encrypt(plainText, passPhrase);
if (!string.IsNullOrEmpty(await Decrypt(encrypted, passPhrase)))
{
valid = true;
}
}
return encrypted;
}
private static async Task<string> Encrypt(string plainText, string passPhrase)
{
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), bytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
var ivBytes = password.GetBytes(Blocksize / 8);
using (var aes = Aes.Create())
{
aes.Key = keyBytes;
aes.IV = ivBytes;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
plainText = Convert.ToBase64String(msEncrypt.ToArray());
}
}
}
return plainText;
}
}
#endregion
#region Decrypt method
public static async Task<string> Decrypt(string cipherText, string passPhrase)
{
try
{
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), bytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
var ivBytes = password.GetBytes(Blocksize / 8);
using (var aes = Aes.Create())
{
aes.Key = keyBytes;
aes.IV = ivBytes;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (var memoryStream = new MemoryStream(Convert.FromBase64String(cipherText)))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(cryptoStream))
{
cipherText = srDecrypt.ReadToEnd();
}
}
}
return cipherText;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
#endregion
}
}
It is still throwing a padding error!
Solved it!
public class EncryptDecrypt
{
#region Encrypt method(s)
private const int Keysize = 256;
private const int Blocksize = 128;
private const int DerivationIterations = 1000;
public static async Task<string> EncryptStringWithValidatedPadding(string plainText, string passPhrase)
{
string encrypted = null;
bool valid = false;
while (!valid)
{
encrypted = await Encrypt(plainText, passPhrase);
if (!string.IsNullOrEmpty(await Decrypt(encrypted, passPhrase)))
{
valid = true;
}
}
return encrypted;
}
private static async Task<string> Encrypt(string plainText, string passPhrase)
{
var saltStringBytes = GenerateRandomEntropy(Keysize / 8); // 256 bits
var ivStringBytes = GenerateRandomEntropy(Blocksize / 8); // 128 bits
byte[] plainTextBytes = Convert.FromBase64String(plainText);
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var aes = Aes.Create())
{
aes.KeySize = Keysize;
aes.BlockSize = Blocksize;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(keyBytes, ivStringBytes), CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
var encrypted64String = Convert.ToBase64String(cipherTextBytes);
return encrypted64String;
}
}
}
}
}
private static byte[] GenerateRandomEntropy(int byteSize)
{
var randomBytes = new byte[byteSize];
using (var rngCsp = new RNGCryptoServiceProvider())
{
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
#endregion
#region Decrypt method
public static async Task<string> Decrypt(string cipherText, string passPhrase)
{
try
{
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Blocksize / 8).ToArray();
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) + Blocksize / 8).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) + Blocksize / 8)).ToArray();
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var aes = Aes.Create())
{
aes.KeySize = Keysize;
aes.BlockSize = Blocksize;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
using (var ms = new MemoryStream(cipherTextBytes))
{
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(keyBytes, ivStringBytes), CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(cs))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
cipherText = srDecrypt.ReadToEnd();
}
}
}
return cipherText;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return null;
}
#endregion
After updating the decryption method, all's good in the world again.
It appears to me that .Net 6 broke the nested using loops, closing the stream before the return value was completely set.
I try to build simple AES encryption helper to encrypt/decrypt some strings
Fist, I have an issue with Padding mode wherein decryption it only accepts if Zero otherwise an error about padding occurs!
The second issue is when I try to encrypt simple string "Hello World," it got encrypted, and I have the base64 string, but when trying to decrypt, there's no error, but a weird unknown character is shown! like 㡲啁䎰廾ử靱㡲啁䎰廾ử靱
My code:
private static int keySizes = 256;
private static int blockSize = 128;
private static PaddingMode pMode = PaddingMode.Zeros;
private static CipherMode cMode = CipherMode.ECB;
private static byte[] key = GenEncryptionKey();
private const string passphrase = #"StartYourMorningWithASmile";
private static byte[] GenEncryptionKey()
{
HashAlgorithm hash = MD5.Create();
return hash.ComputeHash(Encoding.Unicode.GetBytes(passphrase));
}
private static AesManaged CreateCryptor()
{
AesManaged cryptor = new AesManaged();
cryptor.KeySize = keySizes;
cryptor.BlockSize = blockSize;
cryptor.Padding = pMode;
cryptor.Key = key;
cryptor.Mode = cMode;
cryptor.GenerateIV();
return cryptor;
}
public static string EncryptParams(string reqVal)
{
string cipherText = "";
if (string.IsNullOrEmpty(reqVal) || reqVal.Length < 1)
throw new ArgumentNullException();
byte[] plainBytes = Encoding.Unicode.GetBytes(reqVal);
using (var cryptor = CreateCryptor())
{
ICryptoTransform encryptor = cryptor.CreateEncryptor();
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(plainBytes, 0, plainBytes.Length);
}
byte[] cipherBytes = ms.ToArray();
cipherText = Convert.ToBase64String(cipherBytes);
}
cryptor.Clear();
}
return cipherText;
}
public static string DecryptParams(string resVal)
{
var data = Convert.FromBase64String(resVal);
byte[] cipherBytes = new byte[data.Length];
string plainText = "";
using (var crypto = CreateCryptor())
{
ICryptoTransform Dec = crypto.CreateDecryptor();
using (MemoryStream ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, Dec, CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
plainText = Encoding.Unicode.GetString(ms.ToArray());
}
}
crypto.Clear();
}
return plainText;
}
UPDATE 1:
Please set also the IV yourself to achieve successful decryption, as #maarten-bodewes pointed out. I missed that part and the decryption somehow worked (?) with your existing code, but you always should provide the same key and IV to a symmetric encryption algorithm to have it work both ways.
ORIGINAL ANSWER:
Your decryption fails (produces incorrect results) because you implemented the decryption part incorrectly (by using CryptoStreamMode.Write instead of CryptoStreamMode.Read) and besides feeding the decryption stream all zero bytes
At the point of execution of
cs.Write(cipherBytes, 0, cipherBytes.Length);
the variable cipherBytes is all zero. The real encrypted buffer is in the data variable which you only use to set the length of cipherBytes
So change your decryption method to this.
BONUS: After correcting the decryption part, you can specify the padding as you wish! I tested with PKCS7 and it is ok.
public static string DecryptParams(string resVal)
{
var cipherBytes = Convert.FromBase64String(resVal);
string plainText = "";
using (var crypto = CreateCryptor())
{
ICryptoTransform Dec = crypto.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(cipherBytes))
{
using (var cs = new CryptoStream(ms, Dec, CryptoStreamMode.Read))
{
byte[] decryptBlock = new byte[4096];
MemoryStream decryptStream = new MemoryStream();
int readBytes;
while ((readBytes = cs.Read(decryptBlock, 0, 4096)) > 0)
{
decryptStream.Write(decryptBlock, 0, readBytes);
}
plainText = Encoding.Unicode.GetString(decryptStream.ToArray());
}
}
crypto.Clear();
}
return plainText;
}
Hope this helps.
Thanks to Oguz
Below is my description method after edit
public static string DecryptParams(string resVal)
{
var data = Convert.FromBase64String(resVal);
byte[] cipherBytes = new byte[data.Length];
string plainText = "";
using (var crypto = CreateCryptor())
{
ICryptoTransform Dec = crypto.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(data))
{
using (var cs = new CryptoStream(ms, Dec, CryptoStreamMode.Read))
{
cs.Read(cipherBytes, 0, cipherBytes.Length);
plainText = Encoding.Unicode.GetString(cipherBytes.ToArray());
}
}
crypto.Clear();
}
return plainText;
}
one more thing about the return result after the decryption I got the original string plus \0\0\0\0 so I use myString.TrimEnd('\0') to solve that.
So I've made a desktop application (before the website) were i've made a login and a register system in it and an encryption ofcourse. And now I've had an idea to make a website with the register and login system because i thought it would be easier but the problem is i've made the website after the desktop application which means i've made a C# encryption/decryption before website and I want to convert the C# encryption to the PHP (if it is even possible) to match my database users information (password, username, mail etc.). This is my C# encryption and decryption code:
Encryption:
private static byte[] AesEncrypt(byte[] bytesToBeEncrypted, byte[]
passwordBytes)
{
byte[] encryptedBytes;
var saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; // min 8
using (var ms = new MemoryStream())
{
using (var 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;
}
Decryption:
private static byte[] AesDecrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes;
var saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; // min 8
using (var ms = new MemoryStream())
{
using (var 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;
}
Method which I use to encrypt data:
public static string Encrypt(string clearText, string password, byte[] salt = null)
{
var baPwd = Encoding.UTF8.GetBytes(password);
var baPwdHash = SHA256.Create().ComputeHash(baPwd);
var baText = Encoding.UTF8.GetBytes(clearText);
byte[] baSalt;
baSalt = salt;
var baEncrypted = new byte[baSalt.Length + baText.Length];
for (var i = 0; i < baSalt.Length; i++)
baEncrypted[i] = baSalt[i];
EncryptionSalt = baSalt.ToString();
for (var i = 0; i < baText.Length; i++)
baEncrypted[i + baSalt.Length] = baText[i];
baEncrypted = AesEncrypt(baEncrypted, baPwdHash);
var result = Convert.ToBase64String(baEncrypted);
EncryptionSalt = baSalt.ToString();
return result;
}
}
Method which I use to decrypt data:
public static string Decrypt(string cipherText, string password)
{
var baPwd = Encoding.UTF8.GetBytes(password);
var baPwdHash = SHA256.Create().ComputeHash(baPwd);
var baText = Convert.FromBase64String(cipherText);
var baDecrypted = AesDecrypt(baText, baPwdHash);
const int saltLength = 12;
var baResult = new byte[baDecrypted.Length - saltLength];
for (var i = 0; i < baResult.Length; i++)
baResult[i] = baDecrypted[i + saltLength];
var result = Encoding.UTF8.GetString(baResult);
return result;
}
An example of using C# encryption in my C# code:
Encryption.Encrypt(password, Encryption.RandomBytes().ToString(), salt));
And the RandomBytes method:
public static byte[] RandomBytes()
{
const int saltLength = 12;
var ba = new byte[saltLength];
RandomNumberGenerator.Create().GetBytes(ba);
return ba;
}
Firstly I need to know if it's possible, secondly if anyone wants to you could give me an example of this encryption in PHP or give me the code.
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.