I have a decrypted XML string which was sent over the wire to the receiving box where my code resides. Now, I want to write this XML string to an XML file.
Here's the Decrypt method which my code calls to generate this XML string... maybe this needs to be changed?
[Update]: My problem is that I can't see a way to write/create an XML file from a string of XML... I can see samples using a stream, a URL, but that doesn't help me here.
protected string DecryptForm(byte[] encryptedString, byte[] key, byte[] vector)
{
rijndael = new RijndaelManaged();
rijndael.Mode = CipherMode.CBC;
// Create a decryptor to perform the stream transform
ICryptoTransform decryptor = rijndael.CreateDecryptor(key, vector);
string plainText = null;
try
{
//Create the streams used for decryption
using (MemoryStream msStream = new MemoryStream(encryptedString))
{
using (CryptoStream csStream = new CryptoStream(msStream,
decryptor, CryptoStreamMode.Read))
{
using (StreamReader readerStream = new StreamReader(csStream))
{
// Read the decrypted bytes from the decrypting stream
plainText = readerStream.ReadToEnd();
}
}
}
finally
{
// Clear the RijndaelManaged object
if(rijndael != null)
rijndael.Clear();
}
// Return the decrypted string
return plainText;
}
}
xmlDoc = new XmlDocument();
xmlDoc.LoadXML(MyXMLString);
xmlDoc.Save(MyFilePath)
Related
We are trying to encrypt huge table data (3 million ), When we use the below encryption method it constantly makes a memory issue. When use 'using' keyword memory stream object should be disposed some period of time, What could be the other reason? When I disable the line***(var encryptor = cryptoProvider.CreateEncryptor(key, initializationVector)***; // Does it make any problem ), memory becomes stable .
.NET 5
internal class EncryptionServiceBase
{
protected byte[] Encrypt(byte[] decryptedData, byte[] key, byte[] initializationVector, Action<AesCryptoServiceProvider> setupDelegate)
{
Guard.IsNotNullOrEmpty(decryptedData, nameof(decryptedData));
Guard.IsNotNullOrEmpty(key, nameof(key));
Guard.IsNotNullOrEmpty(initializationVector, nameof(initializationVector));
**using (var cryptoProvider = new AesCryptoServiceProvider())
{
setupDelegate(cryptoProvider);
var encryptor = cryptoProvider.CreateEncryptor(key, initializationVector);** // Does it make any problem
return GetCryptoTransformedData(decryptedData, encryptor);
}
}
protected byte[] Decrypt(byte[] encryptedData, byte[] key, byte[] initializationVector, Action<AesCryptoServiceProvider> setupDelegate)
{
Guard.IsNotNullOrEmpty(encryptedData, nameof(encryptedData));
Guard.IsNotNullOrEmpty(key, nameof(key));
Guard.IsNotNullOrEmpty(initializationVector, nameof(initializationVector));
using (var cryptoProvider = new AesCryptoServiceProvider())
{
setupDelegate(cryptoProvider);
var decryptor = cryptoProvider.CreateDecryptor(key, initializationVector);
return GetCryptoTransformedData(encryptedData, decryptor);
}
}
private byte[] GetCryptoTransformedData(byte[] data, ICryptoTransform cryptoTransform)
{
using (var memoryStream = new MemoryStream())
using (var cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
return memoryStream.ToArray();
}
}
}
I am trying to save encrypted data to a Text file and then open and decrypt it. When I try to Decrypt it I receive the error "Padding is Invalid and Cannot Be Removed." I am using example code directly from Microsoft for encryption and decryption.
Here is MY code to encrypt and save file:
string json = JsonConvert.SerializeObject(credentials);
using (AesManaged myAes = new AesManaged())
{
byte[] encrypted = ControlHelperscs.EncryptStringToBytes_Aes(json, myAes.Key, myAes.IV);
File.WriteAllBytes(subPath, encrypted);
}
Here is my code to Retrieve and Decrypt file:
using (AesManaged myAes = new AesManaged())
{
byte[] file = File.ReadAllBytes(subPath);
string decrypt = ControlHelperscs.DecryptStringFromBytes_Aes(file, myAes.Key, myAes.IV);
credentials = JsonConvert.DeserializeObject<LoginModel>(decrypt);
}
Here are Encrypt and Decrypt methods:
public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
public static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
I'm sorry I deleted my comment (it was wrong in that context), but I reworked your example to have a little less boilerplate and be able to encrypt and decrypt properly. The problem is that you're generating a new and different Key/IV pair to decrypt from the one you used to encrypt. Of course it won't be able to decrypt. So, here is the part to make it work:
byte[] key;
byte[] iv;
string json = JsonConvert.SerializeObject(credentials);
using (AesManaged myAes = new AesManaged())
{
key = myAes.Key;
iv = myAes.IV;
byte[] encrypted = ControlHelperscs.EncryptStringToBytes_Aes(json, key, iv);
File.WriteAllBytes(subPath, encrypted);
}
byte[] file = File.ReadAllBytes(subPath);
string decrypt = ControlHelperscs.DecryptStringFromBytes_Aes(file, key, iv);
credentials = JsonConvert.DeserializeObject<LoginModel>(decrypt);
and here are the slightly reworked heavy-lifting methods to be a bit more compact:
public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] key, byte[] iv)
{
// Check arguments.
if (plainText is null)
{
throw new ArgumentNullException(nameof(plainText));
}
if (plainText.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(plainText), plainText, "length cannot be zero");
}
if (key is null)
{
throw new ArgumentNullException(nameof(key));
}
if (key.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(key), key, "length cannot be zero");
}
if (iv is null)
{
throw new ArgumentNullException(nameof(iv));
}
if (iv.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(iv), iv, "length cannot be zero");
}
// Create an AesManaged object
// with the specified key and IV.
// Create an encryptor to perform the stream transform.
// Create the streams used for encryption.
using (SymmetricAlgorithm aesAlg = new AesManaged { Key = key, IV = iv })
using (ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
using (MemoryStream msEncrypt = new MemoryStream())
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (TextWriter swEncrypt = new StreamWriter(csEncrypt))
{
// Write all data to the stream.
swEncrypt.Write(plainText);
swEncrypt.Flush();
csEncrypt.FlushFinalBlock();
// Return the encrypted bytes from the memory stream.
return msEncrypt.ToArray();
}
}
public static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText is null)
{
throw new ArgumentNullException(nameof(cipherText));
}
if (cipherText.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(cipherText), cipherText, "length cannot be zero");
}
if (key is null)
{
throw new ArgumentNullException(nameof(key));
}
if (key.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(key), key, "length cannot be zero");
}
if (iv is null)
{
throw new ArgumentNullException(nameof(iv));
}
if (iv.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(iv), iv, "length cannot be zero");
}
// Create an AesManaged object
// with the specified key and IV.
// Create a decryptor to perform the stream transform.
// Create the streams used for decryption.
using (SymmetricAlgorithm aesAlg = new AesManaged { Key = key, IV = iv })
using (ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
using (Stream msDecrypt = new MemoryStream(cipherText))
using (Stream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (TextReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
return srDecrypt.ReadToEnd();
}
}
I create an asp.net 4.0 web application which has a web service for uploading images. I am uploading images by sending the image in form of Base64 string from my mobile app to the web service.
Following is my code:
public string Authenticate(string username, string password, string fileID, string imageData)
{
Dictionary<string, string> responseDictionary = new Dictionary<string, string>();
bool isAuthenticated = true; // Set this value based on the authentication logic
try
{
if (isAuthenticated)
{
UploadImage(imageData);
string result = "success";
var message = "Login successful";
responseDictionary["status"] = result;
responseDictionary["message"] = message;
}
}
catch (Exception ex)
{
responseDictionary["status"] = ex.Message;
responseDictionary["message"] = ex.StackTrace;
}
return new JavaScriptSerializer().Serialize(responseDictionary);
}
private void UploadImage(string uploadedImage)
{
// Convert Base64 String to byte[]
byte[] imageBytes = Convert.FromBase64String(uploadedImage);
MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)Image.FromStream(ms);
string uploadPath = Server.MapPath("..\\uploads\\") + DateTime.Now.Ticks.ToString() + ".jpeg";
ms.Close();
bitmap.Save(uploadPath, System.Drawing.Imaging.ImageFormat.Jpeg);
bitmap.Dispose();
}
This code was working fine on my local ASP.NET development server and I was able to see the uploaded image in my "uploads" directory. However, after transferring the code to the FTP directory, I am now getting the following error:
A generic error occurred in GDI+
I have checked that the upload directory has proper permission by creating a dummy .aspx page and creating a text file on page_load, and it works fine.
Even after doing google search, I was not able to solve this problem. Can anybody help me fixing this?
Thanks a lot in advance.
Instead of writing directly to files, save your bitmap to a MemoryStream and then save the contents of the stream to disk. This is an old, known issue and, frankly, I don't remember all the details why this is so.
MemoryStream mOutput = new MemoryStream();
bmp.Save( mOutput, ImageFormat.Png );
byte[] array = mOutput.ToArray();
// do whatever you want with the byte[]
In your case it could be either
private void UploadImage(string uploadedImage)
{
// Convert Base64 String to byte[]
byte[] imageBytes = Convert.FromBase64String(uploadedImage);
string uploadPath = Server.MapPath("..\\uploads\\") + DateTime.Now.Ticks.ToString() + ".jpeg";
// store the byte[] directly, without converting to Bitmap first
using ( FileStream fs = File.Create( uploadPath ) )
using ( BinaryWriter bw = new BinaryWriter( fs ) )
bw.Write( imageBytes );
}
or
private void UploadImage(string uploadedImage)
{
// Convert Base64 String to byte[]
byte[] imageBytes = Convert.FromBase64String(uploadedImage);
MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)Image.FromStream(ms);
string uploadPath = Server.MapPath("..\\uploads\\") + DateTime.Now.Ticks.ToString() + ".jpeg";
ms.Close();
// convert to image first and store it to disk
using ( MemoryStream mOutput = new MemoryStream() )
{
bitmap.Save( mOutput, System.Drawing.Imaging.ImageFormat.Jpeg);
using ( FileStream fs = File.Create( uploadPath ) )
using ( BinaryWriter bw = new BinaryWriter( fs ) )
bw.Write( mOutput.ToArray() );
}
}
Furthermore I think it's worth pointing out that when MemoryStream is used, stream must always be closed and save method MUST be called before the stream closure
byte[] byteBuffer = Convert.FromBase64String(Base64String);
MemoryStream memoryStream = new MemoryStream(byteBuffer);
memoryStream.Position = 0;
Bitmap bmpReturn = (Bitmap)Bitmap.FromStream(memoryStream);
bmpReturn.Save(PicPath, ImageFormat.Jpeg);
memoryStream.Close();
I am retrieving a text password as input from a file and applying AES encryption over that and later on, decrypting that.
When I did it for the first time, every 4 out of 5 times it was running correctly (encryption decryption successful) but 1 time, it was throwing BadPaddingException. Following is what I wrote :
//ABCD is class name
public static void enc(String fileName, String pwd) {
try {
Properties prop = new Properties();
InputStream input = ABCD.class.getClassLoader().getResourceAsStream(fileName);
prop.load(input);
input.close();
URL url = ABCD.class.getClassLoader().getResource(fileName);
FileOutputStream outputStream = new FileOutputStream(url.getPath());
KeyGenerator key = KeyGenerator.getInstance("AES");
key.init(128);
SecretKey aesKey = key.generateKey();
String newkey = new String(Base64.encode(aesKey.getEncoded()).getBytes("UTF-8"));
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] clear = pwd.getBytes("UTF-8");
byte[] cipher = aesCipher.doFinal(clear);
String encPwd = new String(cipher);
prop.setProperty("password", encPwd);
prop.setProperty("secKey", newkey);
prop.store(outputStream, null);
outputStream.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static String dec(Properties prop, String fileName) {
String decPwd = ABCD.map.get(fileName);
try {
String newkey = prop.getProperty("secKey");
StringBuilder pwd;
byte[] newkeybuff = Base64.decode(newkey.getBytes("UTF-8"));
SecretKey key = new SecretKeySpec(newkeyuff, "AES");
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.DECRYPT_MODE, key);
pwd = new StringBuilder(prop.getProperty("password"));
byte[] cipher = aesCipher.doFinal(pwd.toString().getBytes());
decPwd = new String(cipher);
} catch (Exception e) {
System.out.println(e);
}
ABCD.map.put(fileName, decPwd);
return decPwd;
}
I needed to fix this. Somewhere, I read that BadPaddingExcpetion occurs since of the operations done with String, in place of where actually byte should be used. Hence, I changed my code to the following :
public static void enc(String fileName, String pwd) {
try {
Properties prop = new Properties();
InputStream input = ABCD.class.getClassLoader().getResourceAsStream(fileName);
prop.load(input);
input.close();
URL url = ABCD.class.getClassLoader().getResource(fileName);
FileOutputStream outputStream = new FileOutputStream(url.getPath());
KeyGenerator key = KeyGenerator.getInstance("AES");
key.init(128);
SecretKey aesKey = key.generateKey();
byte[] newkey=(Base64.encode(aesKey.getEncoded())).getBytes("UTF-8");
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey,new IvParameterSpec(new byte[16]));
byte[] clear = pwd.getBytes("UTF-8");
byte[] cipher = aesCipher.doFinal(clear);
prop.setProperty("password", Arrays.toString(cipher));
prop.setProperty("secKey", Arrays.toString(newkey));
prop.store(outputStream, null);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static String dec(Properties prop, String fileName) {
String decPwd = ABCD.map.get(fileName);
try {
byte[] newkey=prop.getProperty("secKey").getBytes("UTF-8");
byte[] pwd;
byte[] newkeybuff = Base64.decode(newkey);
SecretKeySpec key = new SecretKeySpec(newkeybuff, "AES");
Cipher aesCipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(new byte[16]));
pwd = prop.getProperty("password").getBytes();
byte[] cipher = aesCipher.doFinal(pwd);
decPwd=new String(cipher);
System.out.println("Decrypted pwd " + decPwd);
}
catch (Exception e) {
System.out.println(e);
}
ABCD.map.put(fileName, decPwd);
return decPwd;
}
Now, I am getting InvalidKeyException. This time, I read that the size of the key should be 16 bytes. But I don't know how to apply this. Need a fix for this!
You should check your IV (Initialization Vector) which must be the same for encryption and decryption.
A padding error usually means the decryption failed.
Check that the key is a full length (16, 24 or 32 bytes), the IV is full length (16-bytes). If the key or IV is to short it will be padded with "something"and that man not be consistent, there is no standard for such padding.
getBytes("UTF-8") may return different length of bytes depending on the characters used.
Using new IvParameterSpec(new byte[16]) for the IV is incorrect, the IV should be a random bytes. A usual method of handling the IV is to create a random IV on encryption and prepend it to the encrypted data, it does not need to be secret and by prepending it will be available for decryption.
I am trying to sign an XML file in C# .NET 4.0 with a private RSA Key generated by OpenSSL.
My source code looks like :
public static void SignXml(String filePath, String certificatePath)
{
CspParameters cspParams1 = new CspParameters();
cspParams1.KeyContainerName = certificatePath;
RSACryptoServiceProvider rsakey = new RSACryptoServiceProvider(cspParams1);
XmlDocument xmlDoc = new XmlDocument();
// Load an XML file into the XmlDocument object.
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(filePath);
SignedXml signedXml = new SignedXml();
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = certificatePath;
// Create a new RSA signing key and save it in the container.
RSACryptoServiceProvider Key = new RSACryptoServiceProvider(cspParams);
// Add the key to the SignedXml document.
signedXml.SigningKey = Key;
// Create a reference to be signed.
Reference reference = new Reference();
reference.Uri = "";
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
KeyInfo keyInfo = new KeyInfo();
// Load the X509 certificate.
X509Certificate MSCert = X509Certificate.CreateFromCertFile(certificatePath);
// Load the certificate into a KeyInfoX509Data object
// and add it to the KeyInfo object.
keyInfo.AddClause(new KeyInfoX509Data(MSCert));
keyInfo.AddClause(new RSAKeyValue((RSA)Key));
// Add the KeyInfo object to the SignedXml object.
signedXml.KeyInfo = keyInfo;
// Compute the signature.
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
// Append the element to the XML document.
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
xmlDoc.Save(filePath);
}
I am calling the class (CPSMSXmlGenerator) in my application as a DLL(named DBTBeneficiariesCPSMS) and code for calling it is :
Dim genXml As String = DBTBeneficiariesCPSMS.CPSMSXmlGenerator.getXmlFile1(xml)
'Dim appPath As String = Request.PhysicalApplicationPath
Dim fullPath As String = Server.MapPath("/XML/") + dataSource + ".xml"
lblMessage.Text = fullPath
Dim SwFromFile As StreamWriter = New StreamWriter(fullPath)
SwFromFile.Write(genXml)
SwFromFile.Flush()
SwFromFile.Close()
CPSMSXmlGenerator.SignXml(fullPath, Server.MapPath("/XML/aua.cer"))
Now, the problem is whenever my application runs, it halts at ' Reference.Uri="" ' and an error as :-
Error: An XmlDocument context is required to resolve the Reference Uri .
is displayed, and XML file without digital signature certificate generates.
xmDoc is not passsed to SignedXml. Passing that as param should fix the problem
SignedXml signedXml = new SignedXml(xmlDoc);