I've already searched on the internet and on Stack Overflow, but I couldn't find a solution to the following question:
I want to encrypt and decrypt data with AES algorithm in CFB mode. As far as I've read, CFB mode doesn't require padding and the encrypted data has the same size as the unencrypted data. However, when I set Padding to None and keep the standard Feedback Size at 128 bits, I get an exception saying that the length of the data to write/encrypt is invalid.
When I change the Feedback Size to 8 bits, everything works fine. But this is an extremly inefficent and therefore slow encryption process. As far as I understood, CFB can use standard Feedback Size and handle data that is shorter than the full length of a block.
Init-Code:
RijndaelManaged aes_algorithm = new RijndaelManaged();
ICryptoTransform crypto_transform;
CryptoStream crypto_stream;
aes_algorithm.Mode = CipherMode.CFB;
aes_algorithm.Padding = PaddingMode.None;
aes_algorithm.FeedbackSize = 128;
aes_algorithm.KeySize = aes_key.Length * 8;
aes_algorithm.BlockSize = aes_iv.Length * 8;
crypto_transform = aes_algorithm.CreateEncryptor(aes_key, aes_iv);
Encryption
MemoryStream Memory = new MemoryStream();
crypto_stream = new CryptoStream(Memory, crypto_transform, CryptoStreamMode.Write);
crypto_stream.Write(Input, 0, Input.Length);
crypto_stream.FlushFinalBlock();
crypto_stream.Dispose();
crypto_transform.Dispose();
byte[] Output = Memory.ToArray();
Memory.Dispose();
So what am I doing wrong or is that a bug in .NET? I've just found this topic C# AES-128 CFB Error, but there was also no real solution, except for the manual shortening of the encrypted data (which is not a nice solution, but merely a workaround).
CFB mode is usually implemented as CFB-8, that is, it encrypts 8 bits at a time.
See Wikipedia: Cipher feedback
Related
We have a C# library that encrypts and decrypts using Rijndael
_algorithm = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.ISO10126 };
public override byte[] Encrypt(byte[] bytes)
{
// a new iv must be generated every time
_algorithm.GenerateIV();
var iv = _algorithm.IV;
var memoryStream = new MemoryStream();
using (var encryptor = _algorithm.CreateEncryptor(_key, iv))
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
memoryStream.Write(iv, 0, iv.Length);
cryptoStream.Write(bytes, 0, bytes.Length);
cryptoStream.FlushFinalBlock();
return memoryStream.ToArray();
}
}
There is a corresponding decrypt method in C# that decrypts what is encrypted by the above code. Now there comes a need that a node application will send an encrypted data using exactly the same algorithm.
However, I believe because of the iv, the C# code is not able to decrypt it
Any idea
CryptoJS.AES.encrypt(
value,
key,
{
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Iso10126,
}
);
const decryptedString= CryptoJS.enc.Base64.stringify(result.ciphertext);
The C# library generates a random IV. As that IV is 128 bits in size, it is impossible to generate an identical one using CryptoJS. And you don't need to: for decryption you simply send the IV together with the ciphertext. You can then directly set it instead for decryption.
You can do the same when going the other way: generate a random IV on the CryptoJS site, send the IV together with the ciphertext to the C# side and send it to the C# implementation.
Generally the IV is simply prefixed to the ciphertext. For CBC mode the size of the IV is always exactly one block: 128 bits / 16 bytes for AES. So the size is known, which makes it easy to retrieve it from the start of the ciphertext.
Note that:
using CBC without HMAC is entirely insecure for transport mode security - not only can an adversary make you receive invalid plaintext, CBC is also vulnerable against plaintext / padding oracle attacks;
CBC requires a unpredictable IV which is different for each plaintext when using the same key - generally this means generating a random IV;
ISO/IEC 10126 compatible padding is largely deprecated, everybody uses PKCS#7 compatible padding by now, for CBC anyways: most other modes don't require padding at all (but .NET has pretty bad support for other modes of operation).
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.
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
I have a set of encrypted documents encoded with TripleDES coming from a remote system. I need to decode the data in C# and I have no control over the key or encoding algorithm. All I have is the key and the mode (CBC) and the data located in a file.
The TripleDESCryptoServiceProvider is easy enough to use, but I can't figure out how to use the Decryptor without an Initialization Vector.
We have a have 24 byte (192bit) key to decrypt with, but nothing else.
string key = "1468697320656E6372797174696F6E206973737265206933";
byte[] keyData = ParseHex(key); // key is OK at 24 bytes
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.Mode = CipherMode.CBC;
des.GenerateIV();
var decryptor = des.CreateDecryptor(keyData,null); // des.IV
var encoded = File.ReadAllBytes(#"..\..\..\..\test.tdes");
byte[] output = decryptor.TransformFinalBlock(encoded, 0, encoded.Length);
This fails outright with Bad data. If I switch to TransformBlock the code at least runs but produces just gibberish:
byte[] output = new byte[10000];
var count = decryptor.TransformBlock(encoded, 0, encoded.Length, output, 0);
So the questions are:
If I only have a key is the InitializationVector required?
If not is null the right thing to pass?
What else would I possibly need to set beyond the key and mode?
Why does TransformBlock at least work and TransformFinalBlock just fails?
Update - found the problem
It turns out the decoding problem was caused, not by the missing Initialization Vector, but by incorrect information from the provider of the encrypted data. The updated working code looks like this:
// Read the test data
byte[] encoded = File.ReadAllBytes(#"..\..\..\..\test.tdes");
// Get the key into a byte array
string key = "1468697320656E6372797174696F6E206973737265206933";
byte[] keyData = ParseHex(key);
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.Mode = CipherMode.ECB; // Make sure this is correct!!!
des.Padding = PaddingMode.Zeros; // Make sure this is correct!!!
des.Key = keyData;
var decryptor = des.CreateDecryptor();
byte[] output = decryptor.TransformFinalBlock(encoded, 0, encoded.Length);
string dataString = Encoding.Default.GetString(encoded);
Console.WriteLine(dataString);
Console.WriteLine("\r\n\r\nDecoded:");
string result = Encoding.Default.GetString(output);
Console.WriteLine(result);
Console.Read();
The key in our case was using the proper CipherMode and Padding. Fixing the padding made TransformFinalBlock() work without Bad Data errors. Fixing the CipherMode made properly unencrypted the data.
Moral of the story: In CipherMode.ECB mode at least an Initialization Vector you don't need to provide an initialization vector. If no IV is provided the provider will auto-generate one, but the decryption still works (at least with ECB).
In the end it's CRUCIAL to make sure you have all the information from the provider that encrypted the data.
Trying to answer each point:
The Initialization Vector is required in CBC mode. It is not required to be a secret (unlike the key) so it should be sent from the remote system.
Since you need the IV, null is not the right thing to pass.
Padding mode. You need to know which padding mode is used.
TransformFinalBlock probably fails because the Padding mode is wrong.
Edit
The difference between ECB (Electronic Code Book) and CBC (Cipher Block Chaining) is illustrated below:
As you can see no IV is used in ECB mode. So even if you provide one it will be ignored.
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