Related
I'm getting the infamous "Padding is invalid and cannot be removed." error. However, despite ensuring the padding mode is set as well as verifying the key is the same on both encrypt and decrypt. I can't get past the issue.
What am I doing wrong o' great sages of the internet?
//Targeting .Net 4.5.2
//Key is hard coded, ONLY while working through this error in a minimum repo.
byte[] testKey = Convert.FromBase64String("KN1df3fOkLmSPyOP4r+grlVFDC/JVlWuew1u/hDGvUU=");
//Called to Encrypt ("D:\\Assets\\", "Test.txt")
public void DoWork(string filePath, string fileName){
CryptographyUtil crypto = new CryptographyUtil(testKey);
crypto.EncryptFile(filePath, fileName));
}
//Called to Decrypt ("D:\\Assets\\", "Test.txt.dat")
public void UnDoWork(string filePath, string fileName){
CryptographyUtil crypto = new CryptographyUtil(testKey);
crypto.DecryptFile(filePath, fileName));
}
public class CryptographyUtil(){
RijndaelManaged rjndl;
RNGCryptoServiceProvider cRng;
public CryptographyUtil(byte[] key, int keySize = 256, int blockSize = 256) {
cRng = new RNGCryptoServiceProvider();
rjndl = new RijndaelManaged();
rjndl.Key = key;
rjndl.KeySize = keySize;
rjndl.BlockSize = blockSize;
rjndl.Mode = CipherMode.CBC;
rjndl.Padding = PaddingMode.PKCS7;
}
public void EncryptFile(string filePath, string fileName) {
string inputFilePath = Path.Combine(filePath, fileName);
if(!File.Exists(inputFilePath)) {
throw new FileLoadException("Unable to locate or open file.", inputFilePath);
}
string outputDirectory = Path.Combine(filePath, "Encrypted");
if(!Directory.Exists(outputDirectory)){
Directory.CreateDirectory(outputDirectory);
}
string outputPath = Path.Combine(outputDirectory, fileName + ".dat");
//Create a unique IV each time
byte[] iv = new byte[rjndl.BlockSize / 8]
cRng.GetBytes(iv);
byte[] ivSize = BitConverter.GetBytes(iv.Length);
ICryptoTransform encryptor = rjndl.CreateEncryptor(rjndl.Key, iv);
using(FileStream readStream = File.OpenRead(inputFilePath)) {
using(FileStream writeStream = new FileStream(outputPath, FileMode.Create)) {
using(CryptoStream encryptStream = new CryptoStream(writeStream, encryptor, CryptoStreamMode.Write)) {
//Write the following to the file before the encrypted data:
// - length of the IV
// - the IV
writeStream.Write(ivSize, 0, ivSize.Length);
writeStream.Write(iv, 0, iv.Length);
readStream.CopyTo(encryptStream);
readStream.Flush();
encryptStream.FlushFinalBlock();
encryptStream.Close();
}
writeStream.Close();
}
readStream.Close();
}
}
public void DecryptFile(string filePath, string fileName) {
string outputDirectory = Path.Combine(filePath, "Decrypted");
if(!Directory.Exists(outputDirectory)){
Directory.CreateDirectory(outputDirectory);
}
//Remove the ".dat" from the end of the file
string outputFilePath = Path.Combine(outputDirectory, fileName.Substring(0, fileName.LastIndexOf('.')));
if(File.Exists(outputFilePath)){
File.Delete(outputFilePath);
}
using(FileStream readStream = File.OpenRead(Path.Combine(filePath, fileName))) {
//Size buffer for IV Length (int = 4 bytes)
byte[] buffer = new byte[4];
readStream.Read(buffer, 0, buffer.Length);
int ivLength = BitConverter.ToUInt16(buffer, 0);
//Re-size buffer for IV
buffer = new byte[ivLength];
//Read IV to buffer and use to create decryptor
readStream.Read(buffer, 0, ivLength);
//Use IV in buffer to create decryptor
ICryptoTransform decryptor = rjndl.CreateDecryptor(rjndl.Key, buffer);
buffer = new byte[1024];
using(FileStream writeStream = new FileStream(outputFilePath, FileMode.Create)) {
using(CryptoStream decryptStream = new CryptoStream(readStream, decryptor, CryptoStreamMode.Read)) {
//FIXME: Padding Error
int readIdx = decryptStream.Read(buffer, 0, buffer.Length);
while(readIdx > 0) {
writeStream.Write(buffer, 0, readIdx);
readIdx = decryptStream.Read(buffer, 0, buffer.Length);
}
decryptStream.Flush();
decryptStream.Close();
}
writeStream.Close();
}
readStream.Close();
}
}
}
Using RijndaelManaged as I have to create encrypted packages for legacy software that uses it to decrypt.
I have issues to get the data decrypted and not sure what I do wrong as tried almost everything.
private static byte[] AES_Encrypt(byte[] byteArray)
{
byte[] salt = GenerateRandomSalt();
MemoryStream fsCrypt = new MemoryStream();
byte[] ms = new byte[0];
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(keyName);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Padding = PaddingMode.None;
var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
fsCrypt.Write(salt, 0, salt.Length);
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write);
MemoryStream fsIn = new MemoryStream(byteArray);
byte[] buffer = new byte[1048576];
int read;
try
{
if (byteArray.Length <= buffer.Length)
cs.Write(buffer, 0, buffer.Length);
else
while ((read = fsIn.Read(buffer, 0, buffer.Length)) > 0)
{
cs.Write(buffer, 0, read);
}
ms = fsCrypt.ToArray();
fsIn.Close();
}
catch (Exception ex)
{
}
finally
{
try
{
cs.Close();
fsCrypt.Close();
}
catch (Exception err)
{
}
}
string response = Encoding.UTF8.GetString(ms.ToArray());
return ms.ToArray();
}
private static byte[] AES_Decrypt(byte[] byteArray)
{
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(keyName);
byte[] salt = new byte[32];
byte[] ms = new byte[0];
MemoryStream fsCrypt = new MemoryStream(byteArray);
fsCrypt.Read(salt, 0, salt.Length);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = PaddingMode.None;
AES.Mode = CipherMode.CFB;
MemoryStream fsOut = new MemoryStream();
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read);
int read;
byte[] buffer = new byte[1048576];
try
{
string response = Encoding.UTF8.GetString(byteArray);
if (byteArray.Length <= buffer.Length)
{
while ((read = cs.Read(byteArray, 0, byteArray.Length)) > 0)
{
fsOut.Read(byteArray, 0, read);
}
string vresponse = Encoding.UTF8.GetString(fsOut.ToArray());
}
else
while ((read = cs.Read(buffer, 0, buffer.Length)) > 0)
{
fsOut.Write(buffer, 0, read);
}
}
catch (System.Security.Cryptography.CryptographicException ex_CryptographicException)
{
}
catch (Exception ex)
{
}
try
{
cs.Close();
}
catch (Exception ex)
{
}
finally
{
fsOut.Close();
//fsCrypt.Close();
}
return ms.ToArray();
}
My data is sometimes shorter than the 1MB being used so I want to catch th shorter data to use less byte, however its for later concern.
The data I send to the decryptor is using the same static keys now and the inbound encrypted data is identical as the out type encrypted data.
If I put the PaddingMode.None; to PaddingMode.PKCS7 it gives me a mapping error, which comes as I assume in the shorter string than the buffer actually is, so as far my assumations this is correct, so I use for now 'none'.
I have looked to lots of links as:
https://stackoverflow.com/questions/31486028/decrypting-cryptostream-into-memorystream
https://stackoverflow.com/questions/31486028/decrypting-cryptostream-into-memorystream
https://stackoverflow.com/questions/8583112/padding-is-invalid-and-cannot-be-removed
[Encrypt to memory stream, pass it to file stream
[AES encryption on large files
The problem I cant figure out why the encrypted data wont decrypt as should.
100% sure I do something not correct but cant figure out what, any help would be appriciated.
I have changes some code and tried different options, now using this but on both option I get errors.
using (var msi = new MemoryStream())
{
try
{
using (var cs = new CryptoStream(msi, aesAlg.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytes, 0, bytes.Length); //Option 1, gives error, length is invalid of byte array
do //Option 2, give error, Padding is invalid and cannot be removed.
{
count = msi.Read(bytes, 0, blockSizeBytes);
offset += count;
cs.Write(data, 0, count);
}
while (count > 0);
}
var plainText = msi.ToArray();
var text = Encoding.Unicode.GetString(plainText);
}
catch (Exception e)
{
}
//return text;
}
I checked the data length and using Unicode encoding it is 4258 and the bytes are 8516, which should be from my point of view as using Unicode.
Not sure if using the right encoding as found this https://stackoverflow.com/a/10380166/3763117 and can do without but gives same lengthas unicode. little stucked on this any help with some samples would be appriciated.
I am developing an image encrypting program. I have got two applications. One of them, converting image to byte array and encrypting with Rijndael. After it is saving encrypted byte array to a file. Second application is for decrypting. I am reading byte array from file. After i am decrypt and show image in picturebox.
But i am geting "Padding is invalid and cannot be removed." error in decryption application.
Now i am saving encrypted byte array to a file this code (I am not sure is it true way for byte array to file ?);
protected bool SaveData(string FileName, byte[] Data)
{
BinaryWriter Writer = null;
try
{
// Create a new stream to write to the file
Writer = new BinaryWriter(File.Open(FileName,FileMode.OpenOrCreate));
// Writer raw data
Writer.Write(Data);
Writer.Flush();
Writer.Close();
}
catch
{
return false;
}
return true;
}
I am giving this method save file location and encrypted byte array. And It is worked. But i dont know, is it correct way ?
And my decryption application reading encrypted byte array from file method;
protected byte[] GetData(string FileName)
{
FileInfo f = new FileInfo(FileName);
BinaryReader br = new BinaryReader(File.Open(FileName, FileMode.Open));
byte[] a = br.ReadBytes(Convert.ToInt32(f.Length));
return a;
}
And Error location decryption method;
public static byte[] DecryptBytes(byte[] encryptedBytes, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream(encryptedBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] plainBytes = new byte[encryptedBytes.Length];
int DecryptedCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length); // I am getting error this line. Padding is invalid and cannot be removed.
memoryStream.Flush();
cryptoStream.Flush();
memoryStream.Close();
cryptoStream.Close();
return plainBytes;
}
Encryption Code
public static byte[] EncryptBytes(byte[] inputBytes, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(inputBytes, 0, inputBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] CipherBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
return CipherBytes;
}
Full Code Decryption Application
namespace ImageDecrypte
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private string EncPass;
private string line;
private string OkunanVeri;
private byte[] SifreliDosyaDizi;
private byte[] CozulmusDosyaDizi;
private const string SaltPass = "CodeWork";
private string Sfre;
private string dyol;
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog file = new OpenFileDialog();
file.Filter = "Şifrelenmiş Dosyalar (*.cw)|*.cw";
file.FilterIndex = 2;
file.RestoreDirectory = true;
file.CheckFileExists = false;
file.Title = "Şifrelenmiş Dosya Seçiniz..";
file.InitialDirectory =
Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (file.ShowDialog() == DialogResult.OK)
{
dyol = file.FileName;
string DosyaAdi = file.SafeFileName;
label1.Text = DosyaAdi;
Sfre = textBox1.Text;
}
}
private void button2_Click(object sender, EventArgs e)
{
Sfre = textBox1.Text;
SifreliDosyaDizi = GetData(dyol);
CozulmusDosyaDizi = DecryptBytes(SifreliDosyaDizi, Sfre, SaltPass);
pictureBox1.Image = byteArrayToImage(CozulmusDosyaDizi);
}
public static byte[] DecryptBytes(byte[] encryptedBytes, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream(encryptedBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] plainBytes = new byte[encryptedBytes.Length];
int DecryptedCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);
memoryStream.Flush();
cryptoStream.Flush();
memoryStream.Close();
cryptoStream.Close();
return plainBytes.Take(DecryptedCount).ToArray();
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
//File To Byte Array ###################################################################
protected byte[] GetData(string FileName)
{
FileInfo f = new FileInfo(FileName);
BinaryReader br = new BinaryReader(File.Open(FileName, FileMode.Open));
byte[] a = br.ReadBytes(Convert.ToInt32(f.Length));
return a;
}
//File To Byte Array ###################################################################
}
}
Full Code Encryption Application
namespace ImageEncrypte
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private string EncPass;
private byte[] byteArrayForImage;
private byte[] byteArrayCoded;
private const string SaltPass = "CodeWork";
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog file = new OpenFileDialog();
file.Filter = "Jpeg Dosyası |*.jpg| Png Dosyası|*.png";
file.FilterIndex = 2;
file.RestoreDirectory = true;
file.CheckFileExists = false;
file.Title = "Bir İmaj Dosyası Seçiniz..";
file.InitialDirectory =
Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
EncPass = textBox1.Text;
if (file.ShowDialog() == DialogResult.OK)
{
string DosyaYolu = file.FileName;
string DosyaAdi = file.SafeFileName;
label1.Text = DosyaAdi;
Image img = Image.FromFile(DosyaYolu);
pictureBox1.Image = img;
byteArrayForImage = imageToByteArray(img);
byteArrayCoded = EncryptBytes(byteArrayForImage, EncPass, SaltPass);
}
}
private void button2_Click(object sender, EventArgs e)
{
SaveFileDialog sf = new SaveFileDialog();
sf.Title = "Şifrelenmiş Dosyayı Kaydet";
sf.CheckFileExists = false;
sf.CheckPathExists = true;
sf.RestoreDirectory = true;
sf.DefaultExt = "cw";
sf.FileName = "EncodedFile";
sf.SupportMultiDottedExtensions = false;
sf.Filter = "Şifrelenmiş Dosyalar (*.cw)|*.cw";
sf.InitialDirectory =
Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (sf.ShowDialog() == DialogResult.OK)
{
string DosyaYolu = sf.FileName;
bool cevap = SaveData(DosyaYolu, byteArrayCoded);
if (cevap)
{
MessageBox.Show("OK");
}
else
{
MessageBox.Show("PROBLEM");
}
}
}
//Image To Byte Array ####################################################################
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
using (var ms = new MemoryStream())
{
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
}
//Image To Byte Array ####################################################################
//Byte Array To File ###################################################################
protected bool SaveData(string FileName, byte[] Data)
{
BinaryWriter Writer = null;
try
{
// Create a new stream to write to the file
Writer = new BinaryWriter(File.Open(FileName,FileMode.OpenOrCreate));
// Writer raw data
Writer.Write(Data);
Writer.Flush();
Writer.Close();
}
catch
{
return false;
}
return true;
}
//Bytte Array To File ###################################################################
//EncryptBytes ###################################################################
public static byte[] EncryptBytes(byte[] inputBytes, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(inputBytes, 0, inputBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] CipherBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
return CipherBytes;
}
//EncryptBytes ###################################################################
}
}
What can i do before going to be a crazy man ? Thank you and waiting your precious answers.
Thanks to Maximilian Gerhardt Solution is here;
public static byte[] EncryptBytes(byte[] inputBytes, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Mode = CipherMode.CBC;
RijndaelCipher.Padding = PaddingMode.PKCS7;
byte[] salt = Encoding.UTF32.GetBytes(saltValue);
//byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(inputBytes, 0, inputBytes.Length);
cryptoStream.FlushFinalBlock();
cryptoStream.Flush();
byte[] CipherBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
return CipherBytes;
}
public static byte[] DecryptBytes(byte[] encryptedBytes, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Mode = CipherMode.CBC;
RijndaelCipher.Padding = PaddingMode.PKCS7;
byte[] salt = Encoding.UTF32.GetBytes(saltValue);
//byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream(encryptedBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] plainBytes = new byte[encryptedBytes.Length];
int DecryptedCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);
memoryStream.Flush();
cryptoStream.Flush();
memoryStream.Close();
cryptoStream.Close();
return plainBytes.Take(DecryptedCount).ToArray();
}
public static byte[] GetData(string FileName)
{
return File.ReadAllBytes(FileName);
}
protected bool SaveData(string FileName, byte[] Data)
{
try
{
File.WriteAllBytes(FileName, Data);
return true;
}
catch
{
return false;
}
}
I have error from CryptoStream:
Padding is invalid and cannot be removed.
Code
public MemoryStream EncrypteBytes(Stream inputStream, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Padding = PaddingMode.PKCS7;
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
var buffer = new byte[1024];
var read = inputStream.Read(buffer, 0, buffer.Length);
while (read > 0)
{
cryptoStream.Write(buffer, 0, read);
read = inputStream.Read(buffer, 0, buffer.Length);
}
cryptoStream.FlushFinalBlock();
memoryStream.Position = 0;
return memoryStream;
}
// Example usage: DecryptBytes(encryptedBytes, "SensitivePhrase", "SodiumChloride");
public byte[] DecrypteBytes(MemoryStream memoryStream, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Padding = PaddingMode.PKCS7;
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(password.GetBytes(32), password.GetBytes(16));
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] plainBytes = new byte[memoryStream.Length];
int DecryptedCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);
return plainBytes;
}
Use PaddingMode.Zeros to fix problem , Following code:
public byte[] EncryptFile(Stream input, string password, string salt)
{
// Essentially, if you want to use RijndaelManaged as AES you need to make sure that:
// 1.The block size is set to 128 bits
// 2.You are not using CFB mode, or if you are the feedback size is also 128 bits
var algorithm = new RijndaelManaged { KeySize = 256, BlockSize = 128 };
var key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(salt));
algorithm.Key = key.GetBytes(algorithm.KeySize / 8);
algorithm.IV = key.GetBytes(algorithm.BlockSize / 8);
algorithm.Padding = PaddingMode.Zeros;
using (Stream cryptoStream = new MemoryStream())
using (var encryptedStream = new CryptoStream(cryptoStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write))
{
CopyStream(input, encryptedStream);
return ReadToEnd(cryptoStream);
}
}
public byte[] DecryptFile(Stream input, Stream output, string password, string salt)
{
// Essentially, if you want to use RijndaelManaged as AES you need to make sure that:
// 1.The block size is set to 128 bits
// 2.You are not using CFB mode, or if you are the feedback size is also 128 bits
var algorithm = new RijndaelManaged { KeySize = 256, BlockSize = 128 };
var key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(salt));
algorithm.Key = key.GetBytes(algorithm.KeySize / 8);
algorithm.IV = key.GetBytes(algorithm.BlockSize / 8);
algorithm.Padding = PaddingMode.Zeros;
try
{
using (var decryptedStream = new CryptoStream(output, algorithm.CreateDecryptor(), CryptoStreamMode.Write))
{
CopyStream(input, decryptedStream);
return ReadToEnd(output);
}
}
catch (CryptographicException ex)
{
throw new InvalidDataException("Please supply a correct password");
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
I hop help you.
Please check your pass phrase - it should be same in both methods EncrypteBytes and DecrypteBytes. If both are not same, then it will generate the error.
My problem was I was taking the encryped output in bytes and converting it to a string. The string back to byte array (for decrypting) was not the same. I was using UTF8Encoding, then I tried ASCIIEnconding. Neither worked.
Convert.FromBase64String/ToBase64String worked fine, got rid of the padding issues and actually decrypted the data.
It's work
using (FileStream fs = new FileStream( absolute, FileMode.Open )) {
// create a CryptoStream in read mode
using (CryptoStream cryptoStream = new CryptoStream( fs, decryptor, CryptoStreamMode.Read )) {
int readLength = ( int )fs.Length;
byte[] buffer = new byte[readLength];
cryptoStream.Read( buffer, 0, readLength );
using (MemoryStream ms = new MemoryStream( buffer )) {
BinaryFormatter bf = new BinaryFormatter( );
settings = ( SettingsJson )bf.Deserialize( ms );// Deserialize SettingsJson array
}
}
fs.Close( );
}
I have a DLL in C# that encrypts and decrypts string texts (something basic), but now I need to implement the same encryption method in Java, so that some applications can encrypt data and send it to the library.
I can't modify the C# code, because it's already in production, but the Java don't, so please, any suggestion must be done at the Java side.
Basically I'm trying to implement the same C# encryption method in Java. Here are my C# codes:
NOTE: the passphrase, salt, etc. values obviously are just referential.
const string PassPhrase = "IhDyHz6bgQyS0Ff1/1s=";
const string SaltValue = "0A0Qvv09OXd3GsYHVrA=";
const string HashAlgorithm = "SHA1";
const int PasswordIterations = 3;
const string InitVector = "GjrlRZ6INgNckBqv";
const int KeySize = 256;
public static string Encrypt(string plainText)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
PasswordDeriveBytes password = new PasswordDeriveBytes(
PassPhrase,
saltValueBytes,
HashAlgorithm,
PasswordIterations);
byte[] keyBytes = password.GetBytes(KeySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
keyBytes,
initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream,
encryptor,
CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
string cipherText = Convert.ToBase64String(cipherTextBytes);
return cipherText;
}
public static string Decrypt(string cipherText)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
PasswordDeriveBytes password = new PasswordDeriveBytes(
PassPhrase,
saltValueBytes,
HashAlgorithm,
PasswordIterations);
byte[] keyBytes = password.GetBytes(KeySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
keyBytes,
initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream,
decryptor,
CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes,
0,
plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
string plainText = Encoding.UTF8.GetString(plainTextBytes,
0,
decryptedByteCount);
return plainText;
}
Here is my java code, it encrypts the data, but not at the same way as the C# encryption code, so when I try to decrypt it using the C# library it throws the exception: "Length of the data to decrypt is invalid"
static final String PassPhrase = "IhDyHz6bgQyS0Ff1/1s=";
static final String SaltValue = "0A0Qvv09OXd3GsYHVrA=";
static final String HashAlgorithm = "SHA1";
static final int PasswordIterations = 3;
static final String InitVector = "GjrlRZ6INgNckBqv";
static final int KeySize = 256;
public static String encrypt(String plainText)
{
char[] password = PassPhrase.toCharArray();
byte[] salt = SaltValue.getBytes();
byte[] iv = InitVector.getBytes();
byte[] ciphertext = new byte[0];
SecretKeyFactory factory;
try {
factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, PasswordIterations, 256);
SecretKey tmp;
tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
//iv = params.getParameterSpec(IvParameterSpec.class).getIV();
ciphertext = cipher.doFinal(plainText.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//catch (InvalidParameterSpecException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
//}
catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Base64.encode(new String(ciphertext));
}
EDIT 1: I fixed the final byte array conversion to String in the Java code, as Jon Skeet suggested.
This is what's wrong, in the Java code:
return Base64.encode(ciphertext.toString());
You're calling toString() on the byte array, which will always give a string such as [B#3e25a5.
EDIT: Ooh, just noticed that you can change the Java side. Hooray.
Basically, you need to use a Base64 API which allows:
return Base64.encode(ciphertext);
I'm always disappointed in Base64 APIs which allow you to "encode" a string, to be honest... base64 fundamentally encodes binary data to text, and decodes text data to binary. Oh well...
Anyway, use this API (the encodeBytes method) if you need one which allows you to pass in a byte array.
I haven't checked over the actual encryption part in detail, but the C# code at least looks like it's doing the right thing in terms of encodings. It could do with using statements though :)
Here is a C# example, you need the IterationCount and PaddingMode.None
protected void Page_Load(object sender, EventArgs e)
{
string value = "";
string password = "";
string salt = "";
string iv = "";
byte[] vectorBytes = Convert.FromBase64String(Server.UrlDecode(iv));
byte[] cipherText = Convert.FromBase64String(Server.UrlDecode(value));
Rfc2898DeriveBytes key1 = new Rfc2898DeriveBytes(password, StringToByteArray(salt)); //same as PBKDF2WithHmacSHA1
key1.IterationCount = 32;
byte[] keyBytes = key1.GetBytes(16);
string Answer = DecryptDataAES(cipherText, keyBytes, vectorBytes); //vectorBytes is good
//litAnswer.Text = Answer;
}
public static string DecryptDataAES(byte[] cipherText, byte[] key, byte[] iv)
{
string plaintext = null;
using (Rijndael rijndael = Rijndael.Create())
{
rijndael.Key = key;
rijndael.IV = iv;
rijndael.Padding = PaddingMode.None;
ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.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))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length / 2;
byte[] bytes = new byte[NumberChars];
using (var sr = new StringReader(hex))
{
for (int i = 0; i < NumberChars; i++)
bytes[i] =
Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
}
return bytes;
}