cant open the image after decryption of DES encryption C# - c#

I'm having trouble in encrypting and decrypting image with DES encryption
I'm using the code from http://support.microsoft.com/kb/307010
I modified it a bit(I add the "cryptostream.FlushFinalBlock();" and change the encoding to "Encoding.Default")
I tried to encrypt an image and decrypt it but the decrypted image cant be opened(it says
"file appears to be damaged or corrupted")
the original image size is 18,7 KB(19,159 bytes), the encrypted image is 18,7 KB(19,160 bytes), but the decrypted image is 33,4 KB(34,248 bytes).
here is my code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
namespace microsoft_example
{
public partial class Form1:Form
{
//
// Call this function to remove the key from memory after use for security
[System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint="RtlZeroMemory")]
public static extern bool ZeroMemory(IntPtr Destination, int Length);
// Function to Generate a 64 bits Key.
static string GenerateKey()
{
// Create an instance of Symetric Algorithm. Key and IV is generated automatically.
DESCryptoServiceProvider desCrypto =(DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
// Use the Automatically generated key for Encryption.
return Encoding.Default.GetString(desCrypto.Key);
}
static void EncryptFile(string sInputFilename, string sOutputFilename, string sKey)
{
FileStream fsInput = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = Encoding.Default.GetBytes(sKey);
DES.IV = Encoding.Default.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted, desencrypt, CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.FlushFinalBlock();
cryptostream.Close();
fsInput.Close();
fsEncrypted.Close();
}
static void DecryptFile(string sInputFilename, string sOutputFilename, string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
//A 64 bit key and IV is required for this provider.
//Set secret key For DES algorithm.
DES.Key = Encoding.Default.GetBytes(sKey);
//Set initialization vector.
DES.IV = Encoding.Default.GetBytes(sKey);
//Create a file stream to read the encrypted file back.
FileStream fsread = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
//Create a DES decryptor from the DES instance.
ICryptoTransform desdecrypt = DES.CreateDecryptor();
//Create crypto stream set to read and do a
//DES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsread, desdecrypt, CryptoStreamMode.Read);
//Print the contents of the decrypted file.
StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
}
//
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender,EventArgs e)
{
// Must be 64 bits, 8 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;
// Get the Key for the file to Encrypt.
sSecretKey = GenerateKey();
// For additional security Pin the key.
GCHandle gch = GCHandle.Alloc( sSecretKey,GCHandleType.Pinned );
// Encrypt the file.
EncryptFile(#"D:\IMAGE\chara\des\aoi2z.jpg", #"D:\IMAGE\chara\des\Encrypted.des", sSecretKey);
// Decrypt the file.
DecryptFile(#"D:\IMAGE\chara\des\Encrypted.des", #"D:\IMAGE\chara\des\aoi2zdes.jpg", sSecretKey);
// Remove the Key from memory.
ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2);
gch.Free();
}
}
}
I've googled it and it says I should use "FlushFinalBlock" and change the encoding
I've tried, still doesnt work
Thanks before

The problem most likely is the usage of the StreamReader when reading the CryptoStream from the encrypted file.
The StreamReader is good for reading a text-representation of the data, which is visible by the data type returned from .ReadToEnd(); (string). Now, strings may not be able to parse specific data, especially binary data used in images. The most common problem (as far as i have experienced) is that images may contain null-bytes (\0) which is the termination character for strings.
To test if this is the problem, you could check if:
- The file size of the decrypted file is smaller than the original file
- If it is smaller, read the bytes of the original file and have a look at the position where the decrypted file ends. If there is the \0-byte, you have the answer.
It is possible that the culprit is another special byte sequence and not the \0, but that doesn't change the fact that using a StreamReader here isn't the right choice.

Related

AES encryptor mangles only first part of input data using initialization vector

Consider the following code (you also may check in sandbox):
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
class EncryptionIVTest
{
private static readonly string Data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
private static readonly byte[] Password = Guid.NewGuid().ToByteArray().Take(32).ToArray();
static void Main()
{
var iv = Guid.NewGuid().ToByteArray().Take(16).ToArray(); // random initialization vector
var iv2 = new byte[16]; // just another zero-filled initialization vector
var encrypted = Encrypt(iv);
Console.WriteLine($"Original: {Data}");
Console.WriteLine($"Encrypted: {encrypted}");
Console.WriteLine($"Decrypted: {Decrypt(encrypted, iv)}");
Console.WriteLine($"Decrypted with another IV: {Decrypt(encrypted, iv2)}"); // It should throw exception or output completely mangled string
}
private static string Encrypt(byte[] iv)
{
var cipher = CreateCipher(iv);
var buf = Encoding.UTF8.GetBytes(Data);
using var ms = new MemoryStream();
using (var stream = new CryptoStream(ms, cipher.CreateEncryptor(), CryptoStreamMode.Write))
stream.Write(buf, 0, buf.Length);
return Convert.ToBase64String(ms.ToArray());
}
private static string Decrypt(string encrypted, byte[] iv)
{
var cipher = CreateCipher(iv);
using var ms = new MemoryStream(Convert.FromBase64String(encrypted));
using var result = new MemoryStream();
using (var stream = new CryptoStream(ms, cipher.CreateDecryptor(), CryptoStreamMode.Read))
stream.CopyTo(result);
return Encoding.UTF8.GetString(result.GetBuffer(), 0, (int)result.Length);
}
private static Aes CreateCipher(byte[] iv)
{
var cipher = Aes.Create();
cipher.Key = Password;
cipher.IV = iv;
cipher.Mode = CipherMode.CBC;
return cipher;
}
}
It outputs:
Original: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Encrypted: EROKh8lVgREvTqzBYXjEm7EbTIT883uR9wsD82lRM14KtiOYr+/+ZpAwz/UfprqSP5mIQ7Du/d43Y88hAPjvkA==
Decrypted: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Decrypted with another IV: ???#?n? ??7║??Paaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
The fourth string is not fully mangled, it contains an untouched trailing. It seems like encryptor only mangle first 16 bytes (size of an initialization vector) and leaves other untouched. By default, encryptor uses CBC CipherMode and it should mangle all data if I understand correctly.
Is it possible to mangle all data, not only the first part?
The purpose of the IV is not to "mangle" data further or to serve as a second encryption key - that would just make it redundant of the actual key.
The purpose is to provide additional entropy so that two sets of plaintext data encrypted with the same key but with different IVs will appear completely different when encrypted. This makes it harder for an attacker to infer anything about the data. For example, without the IV, sophisticated attackers could run statistical analyses based on language patterns and potentially figure out what certain encrypted packets actually are based on how frequently they occur.
So what you're seeing should not be surprising or concerning. The IV is doing its job.
By the way, using a Guid as a key is NOT secure. First of all it's only 16-bytes not 32 so you only have a 128-bit key basically. See https://learn.microsoft.com/en-us/dotnet/standard/security/generating-keys-for-encryption-and-decryption#symmetric-keys for the right apis to use to generate keys and IVs

Correct AesCryptoServiceProvider usage

I'm trying to write some straight forward encryption routines. Here's what I've been able to come up with based on searching the Web.
public string Encrypt(string plainText)
{
byte[] encrypted;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
// 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())
{
msEncrypt.WriteByte((byte)aesAlg.Key.Length);
msEncrypt.Write(aesAlg.Key, 0, aesAlg.Key.Length);
msEncrypt.WriteByte((byte)aesAlg.IV.Length);
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
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 Convert.ToBase64String(encrypted);
}
public string Decrypt(string cipherText)
{
string plaintext = null;
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
{
int l = msDecrypt.ReadByte();
byte[] key = new byte[l];
msDecrypt.Read(key, 0, l);
l = msDecrypt.ReadByte();
byte[] IV = new byte[l];
msDecrypt.Read(IV, 0, l);
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(key, IV);
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;
}
Two questions:
First, most of the examples I found hard coded the Key and IV. So what I'm doing is writing it to the encrypted bytes. This will make my encrypted data larger. Is there a better way?
Also, I'm not using any password. Would one use a password to generate a custom Key? And, if so, how would I know how long that key needed to be?
First, most of the examples I found hard coded the Key and IV. So what I'm doing is writing it to the encrypted bytes. This will make my encrypted data larger. Is there a better way?
Obviously you should not write the key to the unprotected stream, as the key needs to be shared or established in advance and remain secret. This sharing of the secret key can be performed in many ways, ranging from key agreement to key derivation, ratcheting, etc. etc.
Also, I'm not using any password. Would one use a password to generate a custom Key? And, if so, how would I know how long that key needed to be?
That's a possibility. However, remind yourself that passwords are often not that strong, so if password based encryption (PBE) can be avoided, it may be a good idea to do so.
If you derive a key from a password, you should use a Password Based Key Derivation Function (also sometimes called a password hash). In C# there is an implementation of PBKDF2 (badly) called Rfc2898DeriveBytes. By now that's not very state of the art either, but it should suffice - if you set a high enough iteration count anyway.
When you derive a key from a human remembered password then 128 bits is plenty. There is almost no way that the key can be found easier than the password that was used to derive it.

GZip Magic Number Missing After AES Encryption

I am compressing a file using GZip and then encrypting using AES.
When I step through the code, I see that the magic number (1f 8b) is present in the intermediate compressed unencrypted data and then the file is encrypted. When I go to decrypt the file, the intermediate decrypted compressed data does not contain the magic number and the GZipStream fails when decompressing it.
Here is the main code:
private static void CompressThenEncrypt(string inputFileName, string outputFileName, ICryptoTransform encryptor)
{
using (var inputFileStream = new FileStream(inputFileName, FileMode.Open, FileAccess.Read))
{
using (var outputFileStream = new FileStream(outputFileName, FileMode.Create, FileAccess.Write))
using (var cryptoStream = new CryptoStream(outputFileStream, encryptor, CryptoStreamMode.Write))
{
using (var gZipStream = new GZipStream(cryptoStream, CompressionMode.Compress))
{
inputFileStream.CopyTo(gZipStream);
}
}
}
}
private static void DecryptThenDecompress(string inputFileName, string outputFileName, ICryptoTransform decryptor)
{
using (var inputFileStream = new FileStream(inputFileName, FileMode.Open, FileAccess.Read))
{
using (var cryptoStream = new CryptoStream(inputFileStream, decryptor, CryptoStreamMode.Read))
using (var gZipStream = new GZipStream(cryptoStream, CompressionMode.Decompress))
using (var outputFileStream = new FileStream(outputFileName, FileMode.Create, FileAccess.Write))
{
gZipStream.CopyTo(outputFileStream);
}
}
}
Source file is 19000 bytes. When compressed it becomes 603 bytes (with magic number), then encrypted it becomes 608 bytes (due to padding). When decrypted it becomes 603 bytes (no magic number) and I simply can not get beyond this point.
Here is the calling code:
using (var aes = new AesCryptoServiceProvider())
{
ICryptoTransform encryptor = aes.CreateEncryptor();
ICryptoTransform decryptor = aes.CreateDecryptor();
CompressThenEncrypt(OriginalFileName, CompressThenEncryptFileName, encryptor);
DecryptThenDecompress(CompressThenEncryptFileName, DecryptThenDecompressFileName, decryptor);
}
Edit: More Info
Compressed Data (603 bytes):
1F-8B-08-00-00-00-00-00-04-00-ED-CA-B1-0D-00-20-08-00-C1-DE-C4-21-51-64-FF-11-DC-80-84-FE-9A-6F-FE-E2-DC-7C-15-6D-F7-EA-3F-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-D4-44-7D-3F-A6-A4-8A-30-E6-02-00
Encrypted Data (608 bytes):
C3-02-64-A9-15-15-52-A9-9F-2A-62-EF-89-B2-9A-E0-72-9A-BA-E2-A2-C8-35-BA-3C-CF-D7-07-8B-DC-D4-63-65-AF-A8-62-22-E5-CC-C6-7D-6F-9B-64-57-9F-C0-94-75-E7-6C-A9-DB-B3-57-29-01-95-F5-B9-E5-3D-FD-AB-EC-E3-AC-AF-EB-A6-C0-81-B3-47-4A-EB-F6-DD-03-DF-92-0A-82-D9-DD-4E-46-DF-55-2E-EB-34-AC-98-1A-7E-A9-25-94-2D-E8-32-4B-F9-2A-61-64-CB-09-9C-D5-8C-A2-0A-C1-22-90-98-93-26-A6-9F-69-F8-EE-6E-95-96-56-28-71-3B-94-1E-5F-50-DB-15-DF-C6-46-3F-04-57-5E-0B-47-44-BB-13-9F-14-08-FB-87-E6-97-65-1B-CA-50-52-7F-10-5D-AF-CC-2F-5E-D0-39-A6-C4-70-3B-90-5F-63-EA-F0-59-46-9E-99-2D-31-34-66-5D-72-E5-85-D5-00-1E-E7-B2-1C-3B-E0-E8-F8-35-BF-90-24-00-DC-47-09-66-92-2F-43-92-48-CB-42-4C-3C-86-CC-67-33-62-A1-1E-76-D1-D6-AD-5F-50-DC-D9-C7-31-F2-33-FE-77-CB-4C-EE-2A-AE-54-63-46-48-B4-FA-6F-0A-E0-1B-F2-F6-C2-D0-E0-24-A1-79-B8-29-FB-04-F3-D5-4E-CC-64-E8-FA-67-55-7B-E6-CD-FD-D2-13-3D-F0-C4-10-A9-5C-BB-34-66-54-A4-6E-B7-AC-54-7A-21-5F-C3-01-7B-97-AD-71-C5-2A-E9-39-B1-27-C7-F8-AC-BF-76-EA-D6-C8-05-22-54-4B-71-73-F2-FD-8E-6E-D7-D2-F2-F7-83-B3-9F-75-3C-CA-BA-BD-F3-C2-E6-16-37-9E-C1-88-C4-69-F5-95-E8-A5-81-C9-FC-22-73-1D-09-AB-A8-6D-A3-BA-CB-0F-27-4E-C7-8C-7A-6C-9D-9B-9D-1F-45-F2-7C-B7-7B-F6-DF-24-50-71-A7-BA-F7-F2-8C-AC-19-A3-86-77-4A-EC-5A-06-12-1F-00-AD-5D-EE-E0-61-D0-80-B7-2C-72-2E-77-6A-32-24-0C-64-78-63-37-A9-08-A2-90-9D-21-5E-E4-5E-E6-1D-66-7D-F5-E1-FC-3C-F1-DE-76-68-D7-1D-46-70-A5-32-31-2B-F5-02-6A-E4-95-CD-8E-B8-76-8D-6E-0B-98-E9-4A-DD-8D-C3-6F-D8-0C-BE-C7-32-3F-99-26-94-26-41-80-E4-E6-E7-D3-26-E9-2F-C0-5D-7B-98-24-BD-6E-9B-E8-9D-F6-DF-51-90-FE-EE-86-DE-9E-31-9F-1C-BA-1A-C4-5B-DD-5A-84-43-02-B9-99-01-6A-95-7C-FF-86-28-C2-4C-EF-4D-D6-36-BD-08-0F-30-25-E7-FF-D9-BC-DA-A7-87-65-1A-1E-83-55-D2-60-38-EC-51-97-FA-FD-11-70-83-70-66-39-78-47-93-7C-B7-FB-48-96-2F-C6-1E-6E-7D-29-38-F6-AB-06-45-C5-F7-50-D6-C7-44-5C-AB-96-A0-60-7D-0E-63-4E-B2-EA
Decrypted Data (603 Bytes):
66-90-D0-0F-8B-67-60-9B-AC-39-FC-45-04-3F-9D-C5-08-00-C1-DE-C4-21-51-64-FF-11-DC-80-84-FE-9A-6F-FE-E2-DC-7C-15-6D-F7-EA-3F-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-14-45-51-D4-44-7D-3F-A6-A4-8A-30-E6-02-00
As you can see, all data is the same in the compressed format except for the first 16 bytes:
Before Encryption: 1F-8B-08-00-00-00-00-00-04-00-ED-CA-B1-0D-00-20
After Decryption: 66-90-D0-0F-8B-67-60-9B-AC-39-FC-45-04-3F-9D-C5
The magic number is gone and I do not know why.
The file that I am encrypting is a text file with the line abcdefabcdefabcdefabcdefabcdefabcdef repeated 5000 times.
Having just the first 16 bytes (default block size of AES) being incorrect is the signature of another problem which is the fact that the AesCryptoServiceProvider decryptor object cannot be reused as it stores state information from the last decryption which causes the such bizarre results in subsequent decryptions.
The full original calling code included the fatal reuse of the decryptor object.
Full original calling code:
using (var aes = new AesCryptoServiceProvider())
{
ICryptoTransform encryptor = aes.CreateEncryptor();
ICryptoTransform decryptor = aes.CreateDecryptor(); // <-- Decryptor fails on second usage
// Compress/ Encrypt
CompressThenEncrypt(OriginalFileName, CompressThenEncryptFileName, encryptor);
EncryptThenCompress(OriginalFileName, EncryptThenCompressFileName, encryptor);
// Decrypt/ Decompress
DecompressThenDecrypt(EncryptThenCompressFileName, DecompressThenDecryptFileName, decryptor);
DecryptThenDecompress(CompressThenEncryptFileName, DecryptThenDecompressFileName, decryptor);
}
This was a personal exercise I developed to showcase the importance of compressing then encrypting data. I had two scenarios "Compress Then Encrypt" and "Encrypt Then Compress" and I also wrote out the code to perform the reverse operations.
The issue occurred when I reused the ICryptoTransform decryptor object. Despite the fact that the CanReuseTransform property is true - it is false advertisement. According to this answer it appears that there is a bug where the input buffer is not cleared correctly after decryption. The linked answer describes a few workarounds and simply creating a separate decryptor object works.
Revised working calling code:
using (var aes = new AesCryptoServiceProvider())
{
ICryptoTransform encryptor = aes.CreateEncryptor();
ICryptoTransform decryptor = aes.CreateDecryptor();
ICryptoTransform decryptor2 = aes.CreateDecryptor();
// Compress/ Encrypt
CompressThenEncrypt(OriginalFileName, CompressThenEncryptFileName, encryptor);
EncryptThenCompress(OriginalFileName, EncryptThenCompressFileName, encryptor);
// Decrypt/ Decompress
DecompressThenDecrypt(EncryptThenCompressFileName, DecompressThenDecryptFileName, decryptor);
DecryptThenDecompress(CompressThenEncryptFileName, DecryptThenDecompressFileName, decryptor2);
}

encrypt file with BouncyCastle , output look corrupted

so i using this code to encrypt my file
as you can see iam using public PGP
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.2.6 (GNU/Linux)
masdSFVkRBADYxPZYC+nu9nhSVkxcVkVJ5axZKzCRuygqUxka
kZIBy2CAQVKz5dBkRaUkaaksbcyautks7asaov26Fc9cT25Rvnh7
wYIJhcRoIl4cxashdgutasd0qfcOnVB5JVCQDhXclBW7kwCgkoUW
....
...
...
-----END PGP PUBLIC KEY BLOCK-----
the code works fine but i think the data of the encrepted file is corrupted
because it doesnt comes out in this format (like the key)
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.2.6 (GNU/Linux)
masdSFVkRBADYxPZYC+nu9nhSVkxcVkVJ5axZKzCRuygqUxka
kZIBy2CAQVKz5dBkRaUkaaksbcyautks7asaov26Fc9cT25Rvnh7
wYIJhcRoIl4cxashdgutasd0qfcOnVB5JVCQDhXclBW7kwCgkoUW
....
...
...
-----END PGP PUBLIC KEY BLOCK-----
am i wrong?
dont the output should be in the same format ?
using System;
using System.Xml;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Text;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.IO;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Bcpg;
class CPGPencrypt
{
private static PgpPublicKey ReadPublicKey(Stream inputStream)
{
inputStream = PgpUtilities.GetDecoderStream(inputStream);
PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(inputStream);
//
// we just loop through the collection till we find a key suitable for encryption, in the real
// world you would probably want to be a bit smarter about this.
//
//
// iterate through the key rings.
//
foreach (PgpPublicKeyRing kRing in pgpPub.GetKeyRings())
{
foreach (PgpPublicKey k in kRing.GetPublicKeys())
{
if (k.IsEncryptionKey)
{
return k;
}
}
}
throw new ArgumentException("Can't find encryption key in key ring.");
}
private static byte[] EncryptFile(byte[] clearData, string fileName, PgpPublicKey encKey, bool withIntegrityCheck)
{
MemoryStream bOut = new MemoryStream();
PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(
CompressionAlgorithmTag.Zip);
Stream cos = comData.Open(bOut); // open it with the final destination
PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator();
// we want to Generate compressed data. This might be a user option later,
// in which case we would pass in bOut.
Stream pOut = lData.Open(
cos, // the compressed output stream
PgpLiteralData.Binary,
fileName, // "filename" to store
clearData.Length, // length of clear data
DateTime.UtcNow // current time
);
pOut.Write(clearData, 0, clearData.Length);
lData.Close();
comData.Close();
PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, new SecureRandom());
cPk.AddMethod(encKey);
byte[] bytes = bOut.ToArray();
MemoryStream encOut = new MemoryStream();
Stream os = encOut;
Stream cOut = cPk.Open(os, bytes.Length);
cOut.Write(bytes, 0, bytes.Length); // obtain the actual bytes from the compressed stream
cOut.Close();
encOut.Close();
return encOut.ToArray();
}
public static string Encrypt(string file_name,string file_to_read)
{
try
{
byte[] dataBytes = File.ReadAllBytes(file_to_read);
Stream keyIn = File.OpenRead("pgpdata-public.asc");
Stream outStream = File.Create(#"myfolder\"+file_name);
byte[] encrypted = EncryptFile(dataBytes, #"myfolder\"+file_name, ReadPublicKey(keyIn), false);
outStream.Write(encrypted, 0, encrypted.Length);
keyIn.Close();
outStream.Close();
}
catch (Exception e)
{
return e.Message;
}
return file_name;
}
}
There are different encoding schemes in OpenPGP, namely
binary data and
ASCII armored data.
Especially for key exchange, normally the ASCII armored format is preferred as it is more robust and easy to recognize. For mail exchange, it is mandatory (for 7 bit compatibility). The binary version also has advantages, especially regarding performance and storage (bandwith) requirements.
For example, GnuPG will use the binary encoding by default, unless you request the ASCII armored version using the option --ascii or abbreviated -a.
It look like your code is outputting the binary encoding, but works all fine.
You can easily test by trying to decrypt (eg. using GnuPG: gpg --decrypt file.pgp). Alternatively, you can dump the OpenPGP packets the file contains by using gpg --list-packets file.pgp or using the more verbose utility pgpdump, which is available in most (unix) package repositories: pgpdump file.pgp. Unlike gpg --list-packets, it also resolves packet and algorithm identifiers to human readable strings (where gpg --list-packets just dumps their numeric IDs).

Store data permanently without a database

I'm implementing a C# application that needs to save 10 IP addresses in it. So i think it is resource wasting if I integrate a database in to the application. I cannot use XML or text file because those addresses needs to be secure. I sow a suggestion to implement my own file format and use it.1. Is there any suggestion instead implement separate file format2.if there isn't any how to implement new file format and what is the best
Store it in a file and encrypt the file so that it is not readable by other programs.
You can either save details an sqlite database or in a file,
if you want to keep things as private then encrypt the file
Apply Salt on it and save them in Text File or Xml, when its encrypted there is no danger of being data not safe.
See this sample:
using System.Security.Cryptography;
public static string EncodePasswordToBase64(string password)
{ byte[] bytes = Encoding.Unicode.GetBytes(password);
byte[] inArray = HashAlgorithm.Create("SHA1").ComputeHash(bytes);
return Convert.ToBase64String(inArray);
}
Hashing is applied using SHA1 to envcrypt the string in this method.
Encrypt the strings using a strong encryption. here 2 methods i like to use. It strongly encrypt and also add salt to it.
public static string EncryptString(string sData, string sKey)
{
// instance of the Rihndael.
RijndaelManaged RijndaelManagedCipher = new RijndaelManaged();
// string to byte array.
byte[] UnicodeText = System.Text.Encoding.Unicode.GetBytes(sData);
// adign dirt to the string to make it harder to guess using a dictionary attack.
byte[] Dirty = Encoding.ASCII.GetBytes(sKey.Length.ToString());
// The Key will be generated from the specified Key and dirt.
PasswordDeriveBytes FinalKey = new PasswordDeriveBytes(sKey, Dirty);
// Create a encryptor from the existing FinalKey bytes.
ICryptoTransform Encryptor = RijndaelManagedCipher.CreateEncryptor(FinalKey.GetBytes(32), FinalKey.GetBytes(16));
// Create a MemoryStream that is going to hold the encrypted bytes
MemoryStream memoryStream = new MemoryStream();
// Create a CryptoStream
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
// write the encryption
cryptoStream.Write(UnicodeText, 0, UnicodeText.Length);
// write final blocks to the memory stream
cryptoStream.FlushFinalBlock();
// Convert to byte array the encrypted data
byte[] CipherBytes = memoryStream.ToArray();
// Close streams.
memoryStream.Close();
cryptoStream.Close();
// Convert to byte array to string
string EncryptedData = Convert.ToBase64String(CipherBytes);
// Return the encrypted string
return EncryptedData;
}
public static string DecryptString(string sData, string sKey)
{
// instance of rijndael
RijndaelManaged RijndaelCipher = new RijndaelManaged();
// convert to byte aray the encrypted data
byte[] EncryptedData = Convert.FromBase64String(sData);
// add dirt to the key like when encrypthing
byte[] Dirty = Encoding.ASCII.GetBytes(sKey.Length.ToString());
// get the finalkey o be used
PasswordDeriveBytes FinalKey = new PasswordDeriveBytes(sKey, Dirty);
// Create a decryptor with the key
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(FinalKey.GetBytes(32), FinalKey.GetBytes(16));
// load to memory stream the encrypted data
MemoryStream memoryStream = new MemoryStream(EncryptedData);
// Create a CryptoStream on the memory stream holding the data
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
// Length is unknown but need placeholder big enought for decrypted data
// we know the decrypted version cannot ever be longer than the crypted version
// since we added bunch of garbage to it so the length of encrypted data is safe to use
byte[] UnicodeText = new byte[EncryptedData.Length];
// Start decrypting
int DecryptedCount = cryptoStream.Read(UnicodeText, 0, UnicodeText.Length);
//close streams
memoryStream.Close();
cryptoStream.Close();
// load decrypted data to string
string DecryptedData = Encoding.Unicode.GetString(UnicodeText, 0, DecryptedCount);
// Return decrypted string
return DecryptedData;
}
Adding to this
now simply make a class like
public class Settings
{
public const string EncryptionKey = "somekey";
public List<string> IP = new List<string>();
public string getClassEncrypted()
{
return EncryptString(new JavaScriptSerializer().Serialize(this), EncryptionKey);
}
public Settings getClassDecrypted(string sClassEcrypted)
{
return new JavaScriptSerializer().Deserialize<Settings>(DecryptString(sClassEcrypted, EncryptionKey));
}
}
one the Ips are set in just write to a file the Settings.getClassEncrypted();
and then when it's time to get back the values only read the text file and load back up with something like this :
string sFileText = ...; // from the file saved
var setting = new Settings.getClassDecrypted(sFileText);
now you've got all classes you need to do it. And the class is even serialized

Categories

Resources