I encrypted a file using DES then After decrypting it successfully at the server and using
System.IO.File.WriteAllBytes(#"c:\test\" + fileName, decryptedFile);
method the file data changed a little it the text is "Encrypting and Decrypting usind DES blah blah blah blah"
the text in the end file after decrypting is " k$nlng and Decrypting usind DES blah blah blah blah"
and i also tried this:
using (BinaryWriter binWriter =
new BinaryWriter(File.Open(#"C:\Test\" + fileName, FileMode.Create)))
{
binWriter.Write(decryptedFile);
}
the text still not the same
encrypting by :
public byte [] DESEncrypt(byte [] fileBytes)
{
CryptoStreamMode mode = CryptoStreamMode.Write;
// Set up streams and encrypt
MemoryStream memStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memStream,
cryptoProvider.CreateEncryptor(cryptoProvider.Key, cryptoProvider.Key), mode);
cryptoStream.Write(fileBytes, 0, fileBytes.Length);
cryptoStream.FlushFinalBlock();
// Read the encrypted message from the memory stream
byte[] encryptedMessageBytes = new byte[memStream.Length];
memStream.Position = 0;
memStream.Read(encryptedMessageBytes, 0, encryptedMessageBytes.Length);
MessageBox.Show("encrypted DES");
return encryptedMessageBytes;
}
decrypting by:
static public byte[] DESdecrypt(byte [] fileBytes)
{
ICryptoTransform decryptor = cryptoProvider.CreateDecryptor();
byte[] originalAgain = decryptor.TransformFinalBlock(fileBytes, 0, fileBytes.Length);
return originalAgain;
}
Thanks
You are passing the same value for your "key" and "iv" value. Each time you call the function, your "iv" value gets updated (thus, your key gets changed).
So you basically are doing this:
key = "key"
Encrypt (key, key)
-- key has now changed.
What you need to do is:
key = "key"
iv = copy of key
Encrypt (key, iv)
hard to say, not an expert on the subject but compare your bytes before encrypting and after encrypting and decrypting. If they are identical no issues with the process. WriteALLBytes might not be the only thing. think MIME type . a similar issue is i had to specifically say what type of file i am saving.
Related
Im trying to encrypt a large file (Camtasia.exe) with the AES encryption.
Now for some reason I get a "Out of Memory" Exception. Im really new to this and I don't know how I could possibly fix that. This is my code
I use this to call my encryption method.
bytes = File.ReadAllBytes("Camtasia.exe");
Cryptography.Encryption.EncryptAES(System.Text.Encoding.Default.GetString(bytes), encryptionKey);
This is the AES encryption itself
public static string EncryptAES(string content, string password)
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
using (SymmetricAlgorithm crypt = Aes.Create())
using (HashAlgorithm hash = MD5.Create())
using (MemoryStream memoryStream = new MemoryStream())
{
crypt.Key = hash.ComputeHash(Encoding.UTF8.GetBytes(password));
// This is really only needed before you call CreateEncryptor the second time,
// since it starts out random. But it's here just to show it exists.
crypt.GenerateIV();
using (CryptoStream cryptoStream = new CryptoStream(
memoryStream, crypt.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(bytes, 0, bytes.Length);
}
string base64IV = Convert.ToBase64String(crypt.IV);
string base64Ciphertext = Convert.ToBase64String(memoryStream.ToArray());
return base64IV + "!" + base64Ciphertext;
}
}
Here is the error again that I get when calling the function "EncryptAES" at the top. I would be glad if someone could explain how this happens and how to solve it
https://imgur.com/xqcLsKW
You're reading the entire exe into memory, interpreting it as a UTF-16 string (??!), turning that back into UTF-8 bytes, and encrypting those. This converting to/from a string is horifically broken. An executable file is not a human-readable string, and even if it was, you're in a real muddle as to which encoding you're using. I think you can drop the whole string thing.
You're also reading the entire thing into memory (several times in fact, because of the whole string thing), which is wasteful. You don't need to do that: you can encrypt it bit-by-bit. To do this, use a Stream.
Something like this should work (untested): at least it gets the general concept across. We set up a series of streams which lets us read the data out of the input file bit-by-bit, and write them out to the output file bit-by-bit.
// The file we're reading from
using var inputStream = File.OpenRead("Camtasia.exe");
// The file we're writing to
using var outputStream = File.OpenWrite("EncryptedFile.txt");
using var HashAlgorithm hash = MD5.Create();
using var aes = Aes.Create();
aes.Key = hash.ComputeHash(Encoding.UTF8.GetBytes(password));
// Turn the IV into a base64 string, add "!", encode as UTF-8, and write to the file
string base64IV = Convert.ToBase64String(aes.IV) + "!";
byte[] base64IVBytes = Encoding.UTF8.GetBytes(base64IV);
outputStream.Write(base64IVBytes, 0, base64IVBytes.Length);
// Create a stream which, when we write bytes to it, turns those into
// base64 characters and writes them to outputStream
using var base64Stream = new CryptoStream(outputStream, new ToBase64Transform(), CryptoStreamMode.Write);
// Create a stream which, when we write bytes to it, encrypts them and sends them to
// base64Stream
using var encryptStream = new CryptoStream(base64Stream, aes.CreateEncryptor(), CryptoStreamMode.Write);
// Copy the entirety of our input file into encryptStream. This will encrypt them and
// push them into base64Stream, which will base64-encode them and push them into
// outputStream
inputStream.CopyTo(encryptStream);
Note, that using MD5 to derive key bytes isn't best practice. Use Rfc2898DeriveBytes.
Also note that you don't necessarily need to base64-encode the encrypted result before writing it to a file -- you can just write the encrypted bytes straight out. To go this, get rid of base64Stream, and tell the encryptStream to write straight to outputStream.
I am using this function to encrypt data in my UWP project:
public string Encrypt(string text, string key)
{
byte[] buffer = Encoding.UTF8.GetBytes(text);
byte[] sessionKey = Encoding.UTF8.GetBytes(key);
Aes myAes = Aes.Create();
myAes.Mode = CipherMode.ECB;
myAes.KeySize = 128;
myAes.Key = sessionKey;
myAes.Padding = PaddingMode.PKCS7;
ICryptoTransform encryptor = myAes.CreateEncryptor();
buffer = encryptor.TransformFinalBlock(buffer, 0, buffer.Length);
return Convert.ToBase64String (buffer);
}
But upon decrypting the data returned from Encrypt() , I get a different result (not equal to the text parameter of Encrypt() ). I am using the following code:
public string Decrypt(string text, string key)
{
byte[] buffer = Convert.FromBase64String(text);
byte[] sessionKey = Encoding.UTF8.GetBytes(key);
Aes myAes = Aes.Create();
myAes.Mode = CipherMode.ECB;
myAes.KeySize = 128;
myAes.Key = sessionKey;
myAes.Padding = PaddingMode.PKCS7;
ICryptoTransform decryptor = myAes.CreateDecryptor();
buffer = decryptor.TransformFinalBlock(buffer, 0, buffer.Length);
return Convert.ToBase64String(buffer);
}
I am using the same key for both encryption and decryption
UPDATE:
text parameter passed to Encrypt() : 450131283::0300DC98050044C406000100040052C40100626B02007E810900660F
Return text from Encrypt():
"lzkPu35Hq7j52IiMWRYSS6j7Vg84abVmhXmNpSxHShJDTbOqkZRFtsPZkEzTsjgRT4MzRHCQUS6MCiq1e5JCune4bZZi1nxxwHtEjZLKZ9E="
the same (above) value I pass to the Decrypt() method and I get the following:
"NDUwMTMxMjgzOjowMzAwREM5ODA1MDA0NEM0MDYwMDAxMDAwNDAwNTJDNDAxMDA2MjZCMDIwMDdFODEwOTAwNjYwRg=="
The problem is what you're doing with the end of the decryption:
return Convert.ToBase64String(buffer);
You actually want to convert the decrypted binary data back into a string in a way that mirrors the original way you converted it from a string into plaintext binary data, so you want:
return Encoding.UTF8.GetString(buffer);
This sort of problem is usually best addressed by looking at every step in the transformation chain each direction, and make sure that they're balanced. So it should look like this:
Text
(Encode with UTF-8)
Non-encrypted binary data
(Encrypt)
Encrypted binary data
(Convert to base64)
Encrypted data as base64 text
(Store or whatever...)
Encrypted data as base64 text
(Convert from base64)
Encrypted binary data
(Decrypt)
Non-encrypted binary data
(Decode with UTF-8)
Text
Where I've got "decode with UTF-8" you've got "Convert to base64" so the decoding steps don't match the encoding steps.
I am writing an application, which would receive encrypted byte array, consisting of file name and file bytes, with the following protocol: file_name_and_extension|bytes. Byte array is then decrypted and passing into Encoding.UTF8.getString(decrypted_bytes) would be preferable, because I would like to trim file_name_and_extension from the received bytes to save actual file bytes into file_name_and_extension.
I simplified my application, to only receive file bytes which are then passed into Encoding.UTF8.GetString() and back into byte array with Encoding.UTF8.getBytes(). After that, I am trying to write a zip file, but the file is invalid. It works when using ASCII or Base64.
private void Decryption(byte[] encryptedMessage, byte[] iv)
{
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();
string decryptedBytesString = Encoding.UTF8.GetString(decryptedBytes.ToArray()); //corrupts the zip
//string decryptedBytesString = Encoding.ASCII.GetString(decryptedBytes.ToArray()); //works
//String decryptedBytesString = Convert.ToBase64String(decryptedBytes.ToArray()); //works
byte[] fileBytes = Encoding.UTF8.GetBytes(decryptedBytesString);
//byte[] fileBytes = Encoding.ASCII.GetBytes(decryptedBytesString);
//byte[] fileBytes = Convert.FromBase64String(decryptedBytesString);
File.WriteAllBytes("RECEIVED\\received.zip", fileBytes);
}
}
}
}
Because one shouldn't try to interpret raw bytes as symbols in some encoding unless he actually knows/can deduce the encoding used.
If you receive some nonspecific raw bytes, then process them as raw bytes.
But why it works/doesn't work?
Because:
Encoding.Ascii seems to ignore values greater than 127 and return them as they are. So no matter the encoding/decoding done, raw bytes will be the same.
Base64 is a straightforward encoding that won't change the original data in any way.
UTF8 - theoretically with those bytes not being proper UTF8 string we may have some conversion data loss (though it would more likely result in an exception). But the most probable reason is a BOM being added during Encoding.UTF8.GetString call that would remain there after Encoding.UTF8.GetBytes.
In any case, I repeat - do not encode/decode anything unless it is actually string data/required format.
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
C#
string keystr = "0123456789abcdef0123456789abcdef";
string plainText = "www.bouncycastle.org";
RijndaelManaged crypto = new RijndaelManaged();
crypto.KeySize = 128;
crypto.Mode = CipherMode.CBC;
crypto.Padding = PaddingMode.PKCS7;
crypto.Key = keystr.ToCharArray().Select(c=>(byte)c).ToArray();
// get the IV and key for writing to a file
byte[] iv = crypto.IV;
byte[] key = crypto.Key;
// turn the message into bytes
// use UTF8 encoding to ensure that Java can read in the file properly
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText.ToCharArray());
// Encrypt the Text Message using AES (Rijndael) (Symmetric algorithm)
ICryptoTransform sse = crypto.CreateEncryptor();
MemoryStream encryptedFs = new MemoryStream();
CryptoStream cs = new CryptoStream(encryptedFs, sse, CryptoStreamMode.Write);
try
{
cs.Write(plainBytes, 0, plainBytes.Length);
cs.FlushFinalBlock();
encryptedFs.Position = 0;
string result = string.Empty;
for (int i = 0; i < encryptedFs.Length; i++)
{
int read = encryptedFs.ReadByte();
result += read.ToString("x2");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
encryptedFs.Close();
cs.Close();
}
}
Java:
private String key = "0123456789abcdef0123456789abcdef";
private String plainText = "www.bouncycastle.org";
cipherText = performEncrypt(Hex.decode(key.getBytes()), plainText);
private byte[] performEncrypt(byte[] key, String plainText)
{
byte[] ptBytes = plainText.getBytes();
final RijndaelEngine rijndaelEngine = new RijndaelEngine();
cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(rijndaelEngine));
String name = cipher.getUnderlyingCipher().getAlgorithmName();
message("Using " + name);
byte[]iv = new byte[16];
final KeyParameter keyParameter = new KeyParameter(key);
cipher.init(true, keyParameter);
byte[] rv = new byte[cipher.getOutputSize(ptBytes.length)];
int oLen = cipher.processBytes(ptBytes, 0, ptBytes.length, rv, 0);
try
{
cipher.doFinal(rv, oLen);
}
catch (CryptoException ce)
{
message("Ooops, encrypt exception");
status(ce.toString());
}
return rv;
}
C# produces: ff53bc51c0caf5de53ba850f7ba08b58345a89a51356d0e030ce1367606c5f08
java produces: 375c52fd202696dba679e57f612ee95e707ccb05aff368b62b2802d5fb685403
Can somebody help me to fix my code?
In the Java code, you do not use the IV.
I am not savvy enough in C# to help you directly, but I can give some information.
Rijndael, aka "the AES", encrypts blocks of 16 bytes. To encrypt a long message (e.g. your test message, when encoding, is 20 bytes long), Rijndael must be invoked several times, with some way to chain the invocations together (also, there is some "padding" to make sure that the input length is a multiple of 16). The CBC mode performs such chaining.
In CBC, each block of data is combined (bitwise XOR) with the previous encrypted block prior to being itself encrypted. Since the first block of data has no previous block, we add a new conventional "zero-th block" called the IV. The IV should be chosen as 16 random bytes. The decrypting party will need the IV. The IV needs not be secret (that's the difference between the IV and the key) so it is often transmitted along the message.
In your Java code, you do not specify the IV, you just create a variable called iv and do not use it. So the Rijndael implementation is on its own for that. Chances are that it generated a random IV. Similarly, you do not give an IV to the Rijndael implementation in the C# code. So it is quite plausible that there again a random IV was selected. But not the same than the one in the Java code, hence the distinct results.
(Note: you 20-byte input string is padded to 32 bytes. You give two "results" in hexadecimal, of length 32 bytes each. This is coherent but means that those results do not include the IV -- otherwise they would be 48-byte long.)
I think the algorithm is built in slighty different way and/or the salt key is interpered in different way.