I came across a case where I need to encrypt an object in order to send it for delivery over a .NET Remoting connection. I have already implemented string encryption in our code, so I used a similar design for encrypting the object:
public static byte[] Encrypt(object obj)
{
byte[] bytes = ToByteArray(toEncrypt); // code below
using (SymmetricAlgorithm algo = SymmetricAlgorithm.Create())
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
byte[] key = Encoding.ASCII.GetBytes(KEY);
byte[] iv = Encoding.ASCII.GetBytes(IV);
using (CryptoStream cs = new CryptoStream(ms, algo.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
cs.Write(bytes, 0, bytes.Length);
cs.Close();
return ms.ToArray();
}
}
}
}
private static byte[] ToByteArray(object obj)
{
byte[] bytes = null;
if (obj != null)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
bytes = ms.ToArray();
}
}
return bytes;
}
Is there anything I need to watch out for by serializing and encrypting the object in this way?
What exactly is the aim here? If you are only interested in the security of the data over-the-wire, then since you are using .NET remoting which supports transparent encryption, why not use that, rather than go to the trouble of implementing it yourself?
If you do insist on performing your own encryption, then it's worth noting that you appear to be using a constant IV, which is incorrect. The IV should be a random byte array, and different for each encrypted message. This is generally prepended to the encrypted message before transmission for use in the decryption process.
As a further note, since your key and IV are both converted from strings using Encoding.ASCII.GetBytes, which is intend for 7 bit ASCII input, you are reducing the effective key space significantly.
The only thing I can think of, is that generally after encrypting the data you should write over the plain-text array with NULLs. This is so that the plain-text isn't recoverable in memory, and if it is written out to disk in a page file or swap, it won't be recoverable by a malicious program/user. If the sensitivity of the data is not a concern though, this may not be necessary, but it is a good habit to get into.
EDIT:
That being said however, never roll your own if you don't have to (which you rarely ever do). Chances are very good you'll screw it up and make it vulnerable to attack unless you really know what you're doing. If you don't understand or don't like the built-in APIs, the gents over at Bouncy Castle have done outstanding work at creating libraries for you to use, and in many different languages.
Related
I have to compute hash for huge payload, so I am using streams not to load all request content in memory. The question is what are the differences between this code:
using (var md5 = MD5.Create())
using (var stream = await authenticatableRequest.request.Content.ReadAsStreamAsync())
{
return md5.ComputeHash(stream);
}
And that one:
using (var md5 = MD5.Create())
using (var stream = new MemoryStream())
{
await authenticatableRequest.request.Content.CopyToAsync(stream);
stream.Position = 0;
return md5.ComputeHash(stream);
}
I expect the same behavior internally, but maybe I am missing something.
The first version looks Ok, let the hasher handle the stream reading. It was designed for that.
ComputeHash(stream) will read blocks in a while loop and call TransformBlock() repeatedly.
But the second piece of code will load everything into memory, so don't do that:
using (var stream = new MemoryStream())
{
await authenticatableRequest.request.Content.CopyToAsync(stream);
The second snippet will not only load everything into memory, it will use more memory than HttpContent.ReadAsByteArrayAsync().
A MemoryStream is a Stream API over a byte[] buffer whose initial size is zero. As data gets written into it, the buffer has to be reallocated into a buffer twice as large as the original. This can create a lot of temporary buffer objects whose size exceeds the final content.
This can be avoided by allocating the maximum expected buffer size from the beginning by providing the capacity parameter to the MemoryStream() constructor.
At best, this will be similar to calling :
var bytes = authenticatableRequest.request.Content.ReadAsByteArrayAsync();
return md5.ComputeHash(bytes);
I expect the same behavior internally,
Why? I mean, in one case you must load all into memory (because guess what, you define a memory stream). In the other case not necessarily.
I've run into a confusing use of AES with Rfc2898DeriveBytes. Here's the code that I've found....
public static string Decrypt(string encryptionKey, string cipherValue)
{
byte[] cipherBytes = Convert.FromBase64String(cipherValue);
using (var encryptor = Aes.Create())
{
var pdb = new Rfc2898DeriveBytes(encryptionKey, new byte[] { (13 element byte array) });
if (encryptor != null)
{
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherValue = Encoding.Unicode.GetString(ms.ToArray());
}
}
}
return cipherValue;
}
So, "cipherValue" is an encrypted string...as well as "encryptionKey". The other examples of how to use AES and Rfc2898Derive bytes don't seem to fit this code. The other examples I've seen have something very plain-text in place of the "encryptionKey" parameter up above, but those examples are usually demonstrating encryption rather than decryption.
This code is being used to decrypt a password in the config file of my application. The encryption has already been done and I have no resources available to me to tell me how it was accomplished. I'm assuming that the password was encrypted using the indicated "encryptionKey" and the salt value, along with the default 1000 iterations and the max size Key and IV.
I'm curious mostly about how the "encryptionKey" parameter figures into things. The "cipherValue" is what's being decrypted and is giving me the right output. What methodology was at work here, and what advantages, if any, does this have over the other examples I've seen?
Encryption and security aren't my strong suits yet...let me know if I've left out anything important that might shed more light on this. Thanks in advance!
RFC2898DeriveBytes is a poorly-named implementation of PBKDF2, which is defined in RFC 2898. (Part of why it's poorly named is RFC 2898 also describes the PBKDF1 algorithm, which is what PasswordDeriveBytes uses)
You can read the full algorithm in the linked RFC section, but what it does is use the password as an HMAC key, then take the HMAC of the salt and some state data, then take the HMAC of that, and of that, up to iterations HMACs.
The purpose is to take an input password (low entropy) and predictably turn it into a cryptographic key (with high entropy) in a manner that makes it hard to figure out what the original password is.
As long as all the inputs are the same, it produces the same answer. But changing any input just a little makes a wildly different answer.
If the other approaches you've seen turn the password into a key by just using Encoding.UTF8.GetBytes() (or similar), then yes: this is a better approach (it's harder to break, and it doesn't care how long your password is).
My question is, how do I encrypt and decrypt a file in C# using the RC4 encryption algorithm?
This is not a duplicate of these questions:
What is a NullReferenceException, and how do I fix it?
RC4 Algorithm: Unable to Encrypt / Decrypt data where client uses Javascript and Server c#
RC4 128 bit encryption in C#
I do however acknowledge that at first glance, this question will appear like a duplicate of this question, however, it is around 7 months old, and still has no answer with working code that solves the question directly.
I have however referred to the below links, but none of them answers the question fully, or in fact, at all.
http://www.codeproject.com/Articles/5719/Simple-encrypting-and-decrypting-data-in-C
http://www.codeproject.com/Articles/5068/RC-Encryption-Algorithm-C-Version
I do know that the built-in System.Security.Cryptography library in Visual Studio 2013 supports RC2, but what I want to focus on right now is RC4, as part of a research. I know it is weak yes, but I'm still using it. No important data is going to be using this encryption.
Preferably with a code example, that accepts a stream as an input. I have caused great confusion, as I did not describe my concerns properly. I am opting for a stream input, due to the concern that any kind of other input may cause a decrease in the speed of processing large files.
Specifications: NET Framework 4.5, C#, WinForms.
Disclaimer: While this code works, it might not be correctly implemented and/or secure.
Here's an example of file encryption/decryption using the BouncyCastle's RC4Engine:
// You encryption/decryption key as a bytes array
var key = Encoding.UTF8.GetBytes("secretpassword");
var cipher = new RC4Engine();
var keyParam = new KeyParameter(key);
// for decrypting the file just switch the first param here to false
cipher.Init(true, keyParam);
using (var inputFile = new FileStream(#"C:\path\to\your\input.file", FileMode.Open, FileAccess.Read))
using (var outputFile = new FileStream(#"C:\path\to\your\output.file", FileMode.OpenOrCreate, FileAccess.Write))
{
// processing the file 4KB at a time.
byte[] buffer = new byte[1024 * 4];
long totalBytesRead = 0;
long totalBytesToRead = inputFile.Length;
while (totalBytesToRead > 0)
{
// make sure that your method is marked as async
int read = await inputFile.ReadAsync(buffer, 0, buffer.Length);
// break the loop if we didn't read anything (EOF)
if (read == 0)
{
break;
}
totalBytesRead += read;
totalBytesToRead -= read;
byte[] outBuffer = new byte[1024 * 4];
cipher.ProcessBytes(buffer, 0, read, outBuffer,0);
await outputFile.WriteAsync(outBuffer,0,read);
}
}
The resulting file was tested using this website and it appears to be working as expected.
So this is how I am doing encryption right now:
public static byte[] Encrypt(byte[] Data, string Password, string Salt)
{
char[] converter = Salt.ToCharArray();
byte[] salt = new byte[converter.Length];
for (int i = 0; i < converter.Length; i++)
{
salt[i] = (byte)converter[i];
}
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, salt);
MemoryStream ms = new MemoryStream();
Aes aes = new AesManaged();
aes.Key = pdb.GetBytes(aes.KeySize / 8);
aes.IV = pdb.GetBytes(aes.BlockSize / 8);
CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(Data, 0, Data.Length);
cs.Close();
return ms.ToArray();
}
I am using this algorithm on data streaming over a network. The problem is it is a bit slow for what I am trying to do. So I was wondering if anyone has better way of doing it? I am no expert on encryption this method was pieced together from different sources. I am not entirely sure how it works.
I have clocked it at about 0.5-1.5ms and I need to get it down to about 0.1ms any ideas?
I'm pretty sure that performance is the least of your problems here.
Is the salt re-used for each packet? If so, you're using a strong cypher in a weak fashion. You're starting each packet with the cypher in exactly the same state. This is a security flaw. Someone skilled in cryptography would be able to crack your encryption after only a couple thousand packets.
I'm assuming you're sending a stream of packets to the same receiver. In that case, your use of AES will be much stronger if you keep the Aes object around and re-use it. That will make your use of the cypher much, much stronger and speed things up greatly.
As to the performance question, most of your time is being spent initializing the cypher. If you don't re-initialize it every time, you'll speed up quite a lot.
aes.KeySize>>3 would be faster than aes.KeySize / 8.
Basically i want to use System.Security.Cryptography.AesManaged (or a better class, if you think there is one?) to take one byte array and create another encrypted byte array, using a given symmetric key (i assume i'll need one?).
I also will need the way to reverse this procedure.
The point of this is so i can encrypt stored passwords. I assume there's a simple way to do this?
Thanks
EDIT: You really should generate a random IV each time you encrypt, unlike my ancient code below:
Here's what i did in the end, inspired by (an older version of) michael's answer:
private string Encrypt(string input)
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(input)));
}
private byte[] Encrypt(byte[] input)
{
PasswordDeriveBytes pdb = new PasswordDeriveBytes("hjiweykaksd", new byte[] { 0x43, 0x87, 0x23, 0x72, 0x45, 0x56, 0x68, 0x14, 0x62, 0x84 });
MemoryStream ms = new MemoryStream();
Aes aes = new AesManaged();
aes.Key = pdb.GetBytes(aes.KeySize / 8);
aes.IV = pdb.GetBytes(aes.BlockSize / 8);
CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(input, 0, input.Length);
cs.Close();
return ms.ToArray();
}
private string Decrypt(string input)
{
return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(input)));
}
private byte[] Decrypt(byte[] input)
{
PasswordDeriveBytes pdb = new PasswordDeriveBytes("hjiweykaksd", new byte[] { 0x43, 0x87, 0x23, 0x72, 0x45, 0x56, 0x68, 0x14, 0x62, 0x84 });
MemoryStream ms = new MemoryStream();
Aes aes = new AesManaged();
aes.Key = pdb.GetBytes(aes.KeySize / 8);
aes.IV = pdb.GetBytes(aes.BlockSize / 8);
CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(input, 0, input.Length);
cs.Close();
return ms.ToArray();
}
EDIT: Noticed eed3si9n's edit... I agree, symmetric encryption is a bad choice for passwords. Use hashes (and not MD5) instead. Here's a very complete example.
A simple example:
byte[] clear = GetCleartext();
HashAlgorithm sha2 = SHA256CryptoServiceProvider.Create();
byte[] hashed = sha2.ComputeHash(clear);
To validate a correct password, you would run the same computation over the provided password, and compare the result to the hash you have in your database.
It's good practice to add salt (random data) to the cleartext to avoid rainbow table attacks. Basically, append a known randomly-generated value, unique to that user, to the cleartext before hashing.
Simple encrypting and decrypting data in C#.
Edit: For passwords, I would recommend using BCrypt instead of doing a two-way encryption, unless you really need to recover the original password. Normally you just need the fact that someone knew the password, not the password itself.
There is a pretty nice C# implementation of symmetric key encryption at https://web.archive.org/web/20120326090435/http://www.superstarcoders.com/blogs/posts/symmetric-encryption-in-c-sharp.aspx . It supports AES, Triple DES, and Rijndael. It has easy to follow functions in the form:
string Encrypt(string plaintext, string password, string salt)
The OP states they have to pass the credentials to another service, which is a completely different issue than password storage and verification.
Depending on how much control you have over the partner service, or what they expose, the best solutions involve a vendor provided or industry standard approaches such as Kerberos, SAML or other stable, secure bearer token means to flow trust. This is a deep topic.
But let's assume you need to pass credentials via Basic Auth SSL/TLS. So now you need to store them securely in a reversible manner. To solve this problem, I have had success with the secret key being conveyed using a certificate private key. This affords some protection of your secret by the operating system and allows for OPS folks to manage the keys, which is desirable. The account used to run your process must be granted rights to see the private key, which then terminates the trust chain at the OS.
You still might have to think about key rotation, which will require you to store a version number with the cipher text.
Also, SecureString might be of interest, but until all .NET API's allow SecureString to be passed as part of a credential, often times you end up with a string on the managed heap you cannot destroy.
Anyway, this isn't a spoon fed answer with code, but from experience, I have found that managing the chain of secrets is always a problem, and if you cannot terminate at a hardened infrastructure such as Active Directory, certificates are the next best thing.