AesCryptoServiceProvider behaviour when trying to decrypt with the wrong key - c#

I'm using AesCryptoServiceProvider and CryptoStream to encrypt some data and it seems to be working OK when I use the same key for decryption. However, If I try to decrypt it with the wrong key, I don't get an exception, just junk data. I can't find anything in the .Net documentation which says what is supposed to happen but according to this:
http://books.google.co.uk/books?id=_Y0rWd-Q2xkC&pg=PA631
and this:
Why does a bad password cause "Padding is invalid and cannot be removed"?
I should be getting a CryptographicException. Am I doing it wrong? my function is this:
public static byte[] Encrypt(byte[] data, string password, string salt, bool decrypt)
{
SymmetricAlgorithm aes = new AesCryptoServiceProvider();
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));
aes.IV = rfc2898.GetBytes(aes.BlockSize / 8);
aes.Key = rfc2898.GetBytes(256 / 8);
ICryptoTransform enc;
if (decrypt) {
enc = aes.CreateDecryptor();
} else {
enc = aes.CreateEncryptor();
}
using (enc) {
using (MemoryStream ms = new MemoryStream()) {
using (CryptoStream cs = new CryptoStream(ms, enc, CryptoStreamMode.Write)) {
cs.Write(data, 0, data.Length);
return ms.ToArray();
}
}
}

Relying on padding errors is not a good way to determine if a key is correct or not. You should really consider using Authenticated Encryption for this purpose.
I have a public domain snip-it that works in C# for this Modern Examples of Symmetric Authenticated Encryption of a string. that I try to keep up to date and reviewed.
P.S. Also it's not clear if your salt is per domain, per user, or per ciphertext from your sample, but if it's not per ciphertext in your code the IV will be predictable and the same for many ciphertexts which is not good for AES-CBC. Implementing crypto is hard.
I've also worked on a highlevel encryption library , a C# port of Google Keyczar. But that may not work very well for you, it only supports randomly generate keys and keysets, and those keysets can then be password encrypted, but only the keysets. High level encryption frameworks are the best practice for encyption.

If you have no padding set on decryption then the decryption method won't be able to recognise junk. Set padding to PKCS#7 for both encryption and encryption and the decryption method will probably be able to recognise junk.
For full assurance, you will need authentication, as jbtule says. To include authentication and encryption in the one data pass use GCM mode. For separate authentication use HMAC.

I'm going to have to put my hands up here and say False Alarm.
I have no idea what was happening on Friday but now I'm getting what I would expect - most of the time the CryptographicException happens as expected. I've no idea whether I was just hugely unlucky with my test data or whether there was a bug in my test harness which I inadvertently fixed, but it's all behaving as expected now.
Incidentally I did a quick empirical test which validates rossum's 1/256 number but that's acceptable for my purposes. In the general case I completely accept the other comments here about HMACs etc, but what I'm doing is for a test tool

Related

Key, salt and IV when using Rijndael encryption

I'm working on a website, where users are able to upload files. I want to encrypt these files, in case there is some kind of security breach where access is granted to them.
When the user wants to download their files, I decrypt directly to the HTTP(S) output stream.
The files are placed on disc, and a record for each is inserted in the website database with some additional data (file name, size, file path, IV and such).
I only have a basic understanding of how to use encryption and therefore have some questions.
I'm using Rfc2898DeriveBytes to generate the bytes for the encryption key. Is it okay to use this class? As far as I know it uses SHA1, which might no longer be secure?
Right now I'm using the same password and salt for each encryption, but a random IV each time. Should I also be randomizing the salt and keep it in the database along with the IV? Will this give additional security?
Should I be using a message authentication code (MAC)? The encrypted files themselves are only stored and never transferred, so I don't know if it's necessary.
I don't really know how to best store the encryption password. I don't want to include it in my website DLL, so I'll probably have it in a file on the server somewhere that isn't in my website folder. How else could I be doing this?
This is my code for encryption. Any obvious security flaws?
const int bufferSize = 1024 * 128;
Guid guid = Guid.NewGuid();
string encryptedFilePath = Path.Combine(FILE_PATH, guid.ToString());
byte[] rgbIV;
using (Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes("PASSWORD HERE", Encoding.ASCII.GetBytes("SALT HERE")))
{
byte[] rgbKey = deriveBytes.GetBytes(256 / 8);
using (FileStream decryptedFileStream = File.OpenRead(decryptedFilePath))
using (FileStream encryptedFileStream = File.OpenWrite(encryptedFilePath))
using (RijndaelManaged algorithm = new RijndaelManaged() { KeySize = 256, BlockSize = 128, Mode = CipherMode.CBC, Padding = PaddingMode.ISO10126 })
{
algorithm.GenerateIV();
rgbIV = algorithm.IV;
using (ICryptoTransform encryptor = algorithm.CreateEncryptor(rgbKey, rgbIV))
using (CryptoStream cryptoStream = new CryptoStream(encryptedFileStream, encryptor, CryptoStreamMode.Write))
{
int read;
byte[] buffer = new byte[bufferSize];
while ((read = decryptedFileStream.Read(buffer, 0, bufferSize)) > 0)
cryptoStream.Write(buffer, 0, read);
cryptoStream.FlushFinalBlock();
}
}
}
I'm using Rfc2898DeriveBytes to generate the bytes for the encryption key. Is it okay to use this class? As far as I know it uses SHA1, which might no longer be secure?
The recent efficient breakage of SHA-1 really only impacts collision resistance which is not needed for PBKDF2 (the algorithm behind Rfc2898DeriveBytes). See: Is PBKDF2-HMAC-SHA1 really broken?
Right now I'm using the same password and salt for each encryption, but a random IV each time. Should I also be randomizing the salt and keep it in the database along with the IV? Will this give additional security?
Maybe it will give additional security, but it certainly won't hurt to do this except if you add a bug. Source: Need for salt with IV
Should I be using a message authentication code (MAC)? The encrypted files themselves are only stored and never transferred, so I don't know if it's necessary.
Usually, a storage system has checks and procedures to prevent and fix data corruption. If you don't have that, then a MAC is a good way to check if the data was corrupted even if this didn't happen maliciously.
If the end user is supposed to receive the data, they can check the MAC themselves and make sure that nobody altered the ciphertext.
I don't really know how to best store the encryption password. I don't want to include it in my website DLL, so I'll probably have it in a file on the server somewhere that isn't in my website folder. How else could I be doing this?
As I understand, you actually want to hold the encryption/decryption key. Anything that you can do is really obfuscation and doesn't provide any actual security. An attacker might just use the same connection to the data storage as your usual code. At best, the attacker will be slowed down a little bit. At worst, they don't even notice that the data was encrypted, because the decryption happened transparently.
It is best to make sure that an attacker cannot get in. Go through the OWASP top 10 and try to follow the advice. Then you can do some security scanning with Nikto or hire a professional penetration tester.
This is my code for encryption. Any obvious security flaws?
Using PaddingMode.ISO10126 doesn't seem like a good idea. You should go with PKCS#7 padding. Source: Why was ISO10126 Padding Withdrawn?
Rfc2898DeriveBytes is essentially PBKDF2 which is NIST recommended.
IF you randomize the salt (a good security practice) would will have top supply it for decryption. A common way is to prefix the encrypted data with the salt and IV.
Yes, you should be using a Mac over the encrypted data and any prepended information such as above.
In order to provide suggestions on securing the encryption key more information on how the the encryption will be used.
Use PKCS#7 padding, sometimes the option is named PKCS#5 for historical reasons.

Rijndael Cryptography Function - Key/IV/Salt Setup

I'm working on a simple utility to encrypt files as a learning experience.
Everything seems to be working fine, but I'm wondering if I have setup the Key/IV/Salt data securely.
I have noticed that when it comes to cryptography most people seem to envision a working environment that is loaded with malware manned by a wizard remotely ready to dive through the memory of a running application/page file to get at these secure files.
Let's pretend that you're on a clean machine and you encrypt some files and turn off your computer.
What I want to know is whether or not someone can take your hard drive and retrieve the contents of the files using the code I have proposed.
The attack vector I am most concerned with is ensuring that the page files/file caches are inaccessible.
I also want to make sure that the Key/IV system used is not going to make a rainbow table/hash based attack feasible.
Entering the Password:
The password is entered using a text box with the passwordchar value set to true.
I'm not really concerned with the string being in memory as long as it is properly removed after the encryption. I read that using SecureString is kind of pointless at this point because if you have malware on your computer already, you could just as easily have a keylogger on there which renders everything else useless.
private static string salt = "02341235XadfaDADFexA8932F7Dz3J3X";
I salt the password using a hard coded 32 character string.
(The above string is just an example.)
To get at it, it will require someone to decompile/view the .exe file itself with a hex editor (something that I know if very easy to do, but an extra step nonetheless).
I have considered making this salt editable, but I'm not sure how I could securely store it. I think it's a little ridiculous to encrypt your salt because then you will have the same issue etc, so just leaving it as a hard coded string inside the exe itself seems to make the most sense to me.
The way this works is if you decide to make your password "thepassword", it is actually saved as "thepasswordfaDADFexA8932F7Dz3J3X".
The main key here is that you always have a 32 character password, regardless of what you enter.
The Key and IV:
The Key and IV are also salted as follows.
This is what I wanted to get some input on, because to be honest I'm not entirely sure what it's doing:
UnicodeEncoding UE = new UnicodeEncoding();
byte[] keysalt = UE.GetBytes("Xjafe231x42X423XadXCadfkhjeAdS"); //Another string of random characters hard coded in the exe
byte[] IVSodium = UE.GetBytes("83Xkda7l78Dkx85KdJazppoqq6SaxDs"); //Another string of random characters hard coded in the exe
byte[] key = new Rfc2898DeriveBytes(password, keysalt).GetBytes(32); //Derive the key using the password and salt
byte[] IV = new Rfc2898DeriveBytes(password, IVSodium).GetBytes(16); //Derive the IV using the password and salt
My main concern here is that the IV is based on the key. Again, I'm not sure if this will cause any issues and I was hoping you guys could let me know if there are issues, what they are.
Also, is this another scenario where hard coding the salt is a bad practice? Should this be stored in the encrypted file, and if so, does it really make it more secure? Should I make this editable as well?
The crypto streams are setup using the using keyword:
using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create))
{
using (RijndaelManaged RMCrypto = new RijndaelManaged())
{
using (CryptoStream cs = new CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, IV), CryptoStreamMode.Write))
{
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
byte[] buffer = new byte[4096]; //4096 is kind of arbitrary - better idea?
int data;
long bytesRead = 0;
while((data = fsIn.Read(buffer, 0, buffer.Length)) > 0)
{
bytesRead += data;
/////////////////////////////////////////
// Handle Aborts and Update Progress Bar
/////////////////////////////////////////
if (!caller.isClosing)
caller.Invoke((MethodInvoker)delegate {
caller.fileProgressBar.Value = ((int)(((double)bytesRead / totalBytes) * 100));
});
else
return false; //Encryption Aborted
/////////////////////////////////////////
cs.Write(buffer, 0, data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
return true;
}
}
}
}
}
Thanks for your time and please let me know if there is a better way to setup the Key/IV/Salt.
I think that it is most likely secure enough as long as there is not a mathematical issue with the IV and Key containing similar characters. If so, should I use a hard coded IV as well? That seems weird.
Note that I'm not saving a hash of the password or anything like that. The password is not saved anywhere. It is just used to generate the Key and the IV.
Thanks for your time.
Edit: Here are the changes recommended for anyone looking in the future.
Note that this is not using a pepper - just a random salt, although it would be easy enough to add
byte[] salt = new byte[32]; //Create a 32 byte salt
rand.NextBytes(salt); //Fill it with random values (use RandomNumberGenerator rand = new RNGCryptoServiceProvider(); to be safe
byte[] IV = new byte[16]; //Create a 16 byte IV
rand.NextBytes(IV); //Fill it with random numbers
byte[] key = new Rfc2898DeriveBytes(password, salt).GetBytes(32); //Derive our Key by mixing our password with the salt
using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create))
{
using (RijndaelManaged RMCrypto = new RijndaelManaged())
{
using (CryptoStream cs = new CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, IV), CryptoStreamMode.Write))
{
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
fsCrypt.Write(salt, 0, salt.Length); //Write our salt to the file
fsCrypt.Write(IV, 0, IV.Length); //Write our IV to the file
fsIn.CopyTo(cs); //Encrypt and Write
}
}
}
}
The salt is used for two purposes:
to prevent rainbow table attacks (and it does if applied correctly);
to prevent identical passwords to generate the same password hash.
To do this the salt needs to be 8 to 16 bytes (not characters) of random data, stored with the password hash. Using a static hash as you do defeats both purposes of the hash.
If you need strings, use base 64 to encode the salt and password hash. If you want you can add static data (sometimes called "pepper") to the salt before calling the password hash function. This may add some security if the program data cannot be easily read by an attacker.
You should never directly mix the salt and the password yourself; the Rfc2898DeriveBytes (which is an implementation of PBKDF2) already mixes the two. You should also never store the password, nor should you have to append any data to it. PBKDF2 can handle any size of input, so it doesn't add any functionality.
Now the IV can be taken from the PBKDF2 function (using GetBytes). There is however a problem, it's likely that this will double the initial amount of iterations of PBKDF2 function, which costs CPU time and reduces the advantage over an attacker. It's probably better to just generate a random IV and prefix it to the ciphertext.
So in the end you should store salt | IV | ciphertext, then use salt | pepper as salt and calculate your key, then encrypt/decrypt using the calculated key and IV.
As far as I know,
IV/Salt does not need to be private. It can be stored in plain-text on the hard drive. In fact, salt must be in plain-text, otherwise you cannot generate the same output with it.
It is not a good idea to use your key information for generating the IV as it may leak your key information.
There is no way you can prevent attacks like rainbow. But with salt, rainbow attack becomes expensive as the talbes only work with this salt value.
There is a standard of key derivation fucntion that may useful to you (http://en.wikipedia.org/wiki/PBKDF2).

encrypt using System.Security.Cryptography using DES class c#

I tried to encrypt a string with System.Security.Cryptography.DES but I found that every time I run The program the result of encryption changed !
I don't know how to get the same result each time I run the application ? IS there constant key or anything else to add to get the same result ?
I want when I enter "google" in this code
byte[] plaintextBytes = (new UnicodeEncoding()).GetBytes(expireddate);
SymmetricAlgorithm sa = DES.Create();
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, sa.CreateEncryptor(), CryptoStreamMode.Write);
csEncrypt.Write(plaintextBytes, 0, plaintextBytes.Length);
csEncrypt.Close();
byte[] encryptedTextBytes = msEncrypt.ToArray();
get "google" from this code when I entered the result of array of bytes in next time i opened the application ?
MemoryStream msDecrypt = new MemoryStream(decodedlistbyte.ToArray());
CryptoStream csDecrypt = new CryptoStream(msDecrypt, sa.CreateDecryptor(), CryptoStreamMode.Read);
byte[] decryptedTextBytes = new Byte[decodedlistbyte.Count];
csDecrypt.Read(decryptedTextBytes, 0, decodedlistbyte.Count);
csDecrypt.Close();
msDecrypt.Close();
string decrypteddate = (new UnicodeEncoding()).GetString(decryptedTextBytes);
You are generating a cryptographically secure IV (initialization vector) each time you re-encrypt the plain text - this is good, and the value should change each time. The IV can be kept public and should in no way relate to the encryption key.
However Des is not a very secure algorithm any more and I would recommend switching to Rijndael or tripple des.
I recommend you use a strong symmetric key algorithm such as AES (i.e. Rijndael). Have a look at the RijndaelManaged class in .NET. The same key can be used for encryption and decryption, which is why it's a symmetric algorithm. The security of the key is vital, so keep it private and store it securely.
Like #Ross said the encrypted string will be different because a new IV should be used each time.
However you current code is using a new Key and IV each time. If you want to be able to decrypt on another computer then you should set the Key and IV yourself - or keep the one automagically produced while encrypting.
E.g. when encrypting
byte[] key = sa.Key;
byte[] iv = sa.IV;
ICryptoTransform ct = sa.CreateEncryptor ();
E.g. while decrypting (on another computer)
ICryptoTransform ct = sa.CreateDecryptor (key, iv);
You can transmit the IV with the encrypted data. The secret key should, of course, be transmitted/shared out-of-band.
Your problem isn't that he cipher text is different. This is actually an important property of an encryption scheme.
Your problem is either that you are reusing the same symmetric algorithm object without reseting its state or -- more likely, but I can't tell from the snippet, -- reintegrating the symmetric algorithm with a different key and iv.
For decrypt, generate a new symmetric algorithm and then set sa.Key and sa.IV to be the values used in the one you encrypted with. Important, make sure you store the key securely and make sure your IV is random ( you will need to include it in the data you store). Don't hardcode the IV. That is completely insecure.
By the way, DES is rather insecure ( I could try all possible keys in about 3 days 10 years ago). Use AESManaged. Also, crypto is hard and I don't recommend you do it yourself. If you do want to , consider looking at this, it does most of what you want and a little more.

Error in C# encrypt code when decrypting!

A bit more background info as suggested:
I'm finsihing of an Intranet CMS web app where I have to use the products API (ASP.NET based). Because of time constraints and issues with Windows authen' I need another way to ensure staff do not need to re login everytime they visit the site to view personalised content. The way it works is that once a user logs in (username/password), a Session ID storing a new different Security context value is generated that is used to display the personalised content. The API login method called uses the username and password as parameters. The only way I can think of automatically logging in the next time the staff visits the site is by storing the password in a enrypted cookie and checking of its existing when the site is visited and then calling the API login method using the username and decrypted password cookie values.
Any other ideas as an alternative welcomed.
Mo
Hi,
I'm using some code found on the web to encrypt and decrypt a password string. It encrypts fine but when it calls the code below to decrypt the string it throws the error "Length of the data to decrypt is invalid" How can I resolve this?
Thanks in advance.
Mo
System.Text.Encoding enc = System.Text.Encoding.ASCII;
byte[] myByteArray = enc.GetBytes(_pword);
SymmetricAlgorithm sa = DES.Create();
MemoryStream msDecrypt = new MemoryStream(myByteArray);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, sa.CreateDecryptor(), CryptoStreamMode.Read);
byte[] decryptedTextBytes = new Byte[myByteArray.Length];
csDecrypt.Read(decryptedTextBytes, 0, myByteArray.Length);
csDecrypt.Close();
msDecrypt.Close();
string decryptedTextString = (new UnicodeEncoding()).GetString(decryptedTextBytes);
A couple of things here...
You shouldn't encrypt passwords usually. You should hash them.
If you decide to continue down the road of encryption..
You are using the DES algorithm. This is considered insecure and flawed. I'd recommend looking at the AES algorithm.
Depending on how much data you are working with, the CryptoStream might be overkill.
Using the ASCII encoding can cause loss of data that isn't ASCII, like Cyrillic letters. The recommended fix is to use something else, like UTF8.
Here is an example:
string text = "Hello";
using (var aes = new AesManaged())
{
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
byte[] encryptedBytes;
using (var encrypt = aes.CreateEncryptor())
{
encryptedBytes = encrypt.TransformFinalBlock(bytes, 0, bytes.Length);
}
byte[] decryptedBytes;
using (var decrypt = aes.CreateDecryptor())
{
decryptedBytes = decrypt.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
}
var decryptedText = System.Text.Encoding.UTF8.GetString(decryptedBytes);
Console.Out.WriteLine("decryptedText = {0}", decryptedText);
}
This will use a random key every time. It is likely that you will need to encrypt some data, then decrypt it at a later time. When you create the AesManaged object, you can store the Key and IV property. You can re-use the same Key if you'd like, but different data should always be encrypted with a different IV (Initialization Vector). Where you store that key, is up to you. That's why hashing might be a better alternative: there is no key, and no need to worry about storing the key safely.
If you want to go down the hashing route, here is a small example:
var textToHash = "hello";
using (SHA1 sha = new SHA1Managed())
{
var bytesToHash = System.Text.Encoding.UTF8.GetBytes(textToHash);
var hash = sha.ComputeHash(bytesToHash);
string base64hash = Convert.ToBase64String(hash);
}
This uses the SHA1 algorithm, which should work fine for passwords, however you may want to consider SHA256.
The concept is simple: a hash will produce a (mostly) unique output for an input, however the output cannot be converted back to the input - it's destructive. Whenever you want to check if a user should be authenticated, check hash the password they gave you, and check it against the hash of the correct password. That way you aren't storing anything sensitive.
I've actually had this error before and it took me 3 days to figure out the solution. The issue will be the fact that the machine key you need for descryption needs to be registered on your machine itself.
Read fully up on DES encryption, it works by an application key, and a machine-level key. The error you're getting is likely because of the machine key missing.
Compare the bytes used to create the _pword string (in the encryption method) to the bytes retrieved with GetBytes. Probably you will notice a change in the data there.
To store the encrypted bytes, I think you should use Convert.ToBase64String and Convert.FromBase64String turn the encrypted password to/from a string.
I also do not see the code where you set the Key and IV. So I guess you are using a different key to encrypt and decrypt the password.
If the current Key property is null,
the GenerateKey method is called to
create a new random Key. If the
current IV property is null, the
GenerateIV method is called to create
a new random IV.
DES is a block based cipher - only certain lengths of buffers are valid. If I remember correctly, the block size for DES is 64 bits, so you need to ensure that your byte array is a multiple of 8 bytes long.
(That should fix your immediate problem, but I'd reference other peoples advice here - you really ought not to be using DES for any new code, and for passwords it's usually more appropriate to hash than to encrypt).

Encrypt in Java and Decrypt in C# with Rijndael

Using the Rijndael algorithm is it possible to encrypt a config file (or section(s) in a config file) and then decrypt that file in Java? Assumptions can be made such as:
Pass in IV (not Autogenerated idea :: GenerateIV(); )
Pass in Key
BlockSize is 128 (standard)
Assuming this can be done, my next question on this would be:
Can the keySize be 256? I know 128 is AES but we would like to use 256. I also don't know if Java has that provider for 256 or if I need to use BouncyCastle
What is the Padding? PKCS7?
I assume the CiperMode would be CBC
Something like this in c#? But, no clue if it can be decrypted in Java...perhaps even my c# is wrong?
public static void initCrypt()
{
byte[] keyBytes = System.Text.UTF8Encoding.UTF8.GetBytes("abcdefghijklmnop");
rijndaelCipher = new RijndaelManaged();
PasswordDeriveBytes pdb = new PasswordDeriveBytes(keyBytes, new SHA1CryptoServiceProvider().ComputeHash(keyBytes));
byte[] key = pdb.GetBytes(32);
byte[] iv = pdb.GetBytes(16);
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7; //PaddingMode.PKCS7 or None or Zeros
rijndaelCipher.KeySize = 256; //192, 256
rijndaelCipher.BlockSize = 128;
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = iv;
}
I'd check if an external library such as keyczar supports this.
As Jeff Atwood has taught us in his blog recently, 99% of developers shouldn't be concerning themselves with the low level details of encryption routines (because we will probably screw them up).
Depending on your usage of this config file, you may want to use an external program.
For example, if you want to protect the config file while it resides on disk, but you're okay with its contents being held in memory while the program is running, you could use gpg to encrypt the file, decrypt it into memory using a user-supplied password required by the program when you start it, and then clear out the memory when you shut down the program.[1]
[1] It's worthwhile to note that there's no real way to guarantee the contents won't be written to disk because of memory paging and the like. That's dependent on operating system and a lot of factors you can look up if you are interested in it.
Q1 : It have to be 128 or you will have to use BouncyCastle
Q2 : Yes PKCS7
Q3 : Yes CBC
If your question is not dead I could give you working examples c# and java

Categories