I've got a weird issue while trying to decrypt an encrypted text file. Basically the contents of the .txt file is "this is a test :)" , when decrypting the output is "this is a test :", spot the missing ")".
This isn't the case when I decrypt the file a byte at a time (while loop), but when using the code bellow it seems to have the above issue.
private static void DecryptFile(string inputFile, string outputFile, string skey)
{
RijndaelManaged aes = new RijndaelManaged();
try
{
byte[] key = ASCIIEncoding.UTF8.GetBytes(skey);
byte[] file = File.ReadAllBytes(inputFile);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(key, key), CryptoStreamMode.Write))
{
cs.Write(file, 0, file.Length);
File.WriteAllBytes(outputFile, ms.ToArray());
aes.Clear();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
aes.Clear();
}
}
Please excuse the sloppy code, it was merely for testing purposes.
A block-cipher CryptoStream can only encrypt or decrypt content in fixed block sizes. You haven't given it enough content to fill the final block so it's waiting for more. This partial incomplete block is getting lost.
You either need to call FlushFinalBlock on your CryptoStream or fall outside the using so that it automatically closes it. Then your MemoryStream should contain the missing characters.
Note that when decrypting your output will now be rounded up to a full block, i.e. you'll get extra zeros padding the end of your data.
Related
I wrote a simple encryption / decryption program, when I decrypted the encrypted text it shows grabridge value end of the decrypted text. my c# code and out put of the code are given below. please help me to get the original text after the decrypt without grabage
public class CrypterText
{
static byte[] chiperbytes;
static byte[] plainbytes;
static byte[] plainKey;
static SymmetricAlgorithm desObj;
public static string encryptData(string ciperData)
{
desObj = Rijndael.Create();
plainbytes = Encoding.ASCII.GetBytes(ciperData);
plainKey = Encoding.ASCII.GetBytes("0123456789abcdef");
desObj.Key = plainKey;
desObj.Mode = CipherMode.CBC;
desObj.Padding = PaddingMode.ISO10126;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
CryptoStream cs = new CryptoStream(ms, desObj.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(plainbytes, 0, plainbytes.Length);
cs.Close();
chiperbytes = ms.ToArray();
ms.Close();
return Encoding.ASCII.GetString(chiperbytes);
}
public static string decrypt() {
MemoryStream ms = new MemoryStream(chiperbytes);
CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read);
cs.Read(chiperbytes, 0, chiperbytes.Length);
plainbytes = ms.ToArray();
cs.Close();
ms.Close();
return Encoding.ASCII.GetString(plainbytes);
}
}
In all likelihood, the padding has been removed, however because you are writing to the same byte array that contains the encrypted data, the bytes of ciphertext after the plaintext are being included in the string. You should decrypt to a separate byte array, and then use that byte array to construct the plaintext string. It's also important to use the return value of Read() during the decryption which will indicate the number of bytes actually decrypted.
There are a number of other significant issues with the code here, such as the fact that your SymmetricAlgorithm is only initialized during the encryption process, making it currently impossible to decrypt without having first encrypted. You should also not attempt to convert the ciphertext into a string via any of the Encoding.GetString() methods - arbitrary byte arrays are generally not valid encoded strings, and it will not be possible to reconstruct the original byte array from the string in order to decrypt. Instead use Convert.ToBase64String() and Convert.FromBase64String() to ensure consistent round-trip from ciphertext byte array to string and back again.
Extra characters are leftover from encrypt process. Move byte arrays from class variables into local variables. After which give encrypted string back to decrypt method as a parameter.
Also personally I think it's not good idea to have non static class that has only static methods. Either make class static or at least some of it's methods non-static, whichever is more appropriate.
Try this
public static string decrypt()
{
byte[] plainbytes = new byte[chiperbytes.Length];
MemoryStream ms = new MemoryStream(chiperbytes);
CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read);
cs.Read(plainbytes, 0, plainbytes.Length);
cs.Close();
ms.Close();
return Encoding.ASCII.GetString(plainbytes).TrimEnd('\0');
}
I am serializing an object to an XML string using the .net XML serializer. That object contains a property of type string, whose content is an encrypyted string. The encryption is done using the Rijndael algorithm also provided by the .net, and the call looks like this:
var encryptedArr = EncryptStringToBytes(plainText, RijndaelKey, RijndaelIv);
return Encoding.Default.GetString(encryptedArr);
Although serialization goes fine, the problem is when trying to deserialize. the serializer throws an exception saying
"There is an error in XML document (1,1130). ' ', hexadecimal value
0x02, is an invalid character. Line..."
The thing is that these characters are to my understanding results of the encryption process so I guess messing with the encrypted string to make it XML-compatible is not an option. I also tried encoding the output string in the above piece of code differently:
UTF-8, Base64(which throws an exception saying the string is base64-incompatible) etc.
I've been looking into it for quite some time now. What do you recommend?
Have you taken a look at the example at the bottom of the RijndaelManaged class on MSDN?
Just wondering as they have a method, with the same name as the code you posted. If you are or arent encrypting via similar means, you could try returning a string instead of a byte array, from your method, by calling MemoryStream.GetString() and returning that value:
static string EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
//...
string cipherText = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
cipherText = msEncrypt.ToString();
}
}
}
// Return the encrypted bytes from the memory stream.
return cipherText;
}
What happens if your plainText goes though that? Maybe more information is needed about the plaintext. Might be the case of: Old Post
I'm trying to make an encryption system with c#. This is the code for the encryption.
public static void EncryptFile(string inFile, string outFile, string #inkey)
{
try
{
UnicodeEncoding ue = new UnicodeEncoding();
byte[] key = ue.GetBytes(inkey);
FileStream fsEncrypt = new FileStream(outFile, FileMode.Create);
RijndaelManaged rmCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsEncrypt, rmCrypto.CreateEncryptor(key, key), CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inFile, FileMode.Open);
int data;
while((data=fsIn.ReadByte()) != 1){
cs.WriteByte((byte)data);
}
fsIn.Close(); cs.Close(); fsEncrypt.Close();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Fail to encrypt", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Now, this code throws exception every time I run it, says
Specified initialization vector(IV) does not match the block size for
this algorithm
I have read on other discussion about this, saying that there is a problem with the number of bytes (my key length passed into this function is 255). But I have tried making the key only 16 bytes and still not working.
After some troubleshooting I found out that this part:
CryptoStream cs = new CryptoStream(fsEncrypt, rmCrypto.CreateEncryptor(key, key), CryptoStreamMode.Write);
throws the exception. I have no idea why. Anyone can help?
You're passing the key twice to CreateEncryptor, but it needs a key and an IV (Initialization Vector). The second parameter should be an array with 128 random bits. 128 bits is the default block size for RijndaelManaged, but it accepts other values as well (such as 256). Read this for more info. And as Grzegorz W pointed out in the comments, you might need to choose a different key size as well.
If you're not familiar with encryption (in which case you should stop and learn more about it before implementing your own solution, or use a ready-made one instead), the function of the IV is prevent that the same message encoded twice produce the same ciphertext. It should be random for each message (and each use of the message), does not need to be kept secret, but you need to store it to be able to decipher the message later (i.e. you can not discard it after encryption).
I'm trying to store a password in a file that I'd like to retrieve for later. Hashing is not an option as I need the password for connecting to a remote server for later.
The following code works well, but it creates a different output each time even though the key is the same. This is bad as when the application shuts down and restarts I won't be able to retrieve my password any more. How can I store passwords in a file and retrieve them later?
public class EncyptDecrypt {
static System.Security.Cryptography.TripleDESCryptoServiceProvider keyProv = new System.Security.Cryptography.TripleDESCryptoServiceProvider();
public static System.Security.Cryptography.TripleDESCryptoServiceProvider KeyProvider {
get {
keyProv.Key = new byte[] { /* redacted with prejudice */ };
return keyProv;
}
}
public static string Encrypt(string text, SymmetricAlgorithm key) {
if (text.Equals(string.Empty)) return text;
// Create a memory stream.
MemoryStream ms = new MemoryStream();
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
// Create a StreamWriter to write a string
// to the stream.
StreamWriter sw = new StreamWriter(encStream);
// Write the plaintext to the stream.
sw.WriteLine(text);
// Close the StreamWriter and CryptoStream.
sw.Close();
encStream.Close();
// Get an array of bytes that represents
// the memory stream.
byte[] buffer = ms.ToArray();
// Close the memory stream.
ms.Close();
// Return the encrypted byte array.
return System.Convert.ToBase64String(buffer);
}
// Decrypt the byte array.
public static string Decrypt(string cypherText, SymmetricAlgorithm key) {
if (cypherText.Equals(string.Empty)) return cypherText;
string val;
try {
// Create a memory stream to the passed buffer.
MemoryStream ms = new MemoryStream(System.Convert.FromBase64String(cypherText));
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Read);
// Create a StreamReader for reading the stream.
StreamReader sr = new StreamReader(encStream);
// Read the stream as a string.
val = sr.ReadLine();
// Close the streams.
sr.Close();
encStream.Close();
ms.Close();
}
catch (System.Exception) {
return string.Empty;
}
return val;
}
}
I believe that what's happening is that the crypto provider is randomly generating an IV. Specify this and it should no longer differ.
Edit: You can do this in your 'keyProvider' by setting the IV property.
According to the docs of CreateEncryptor:
If the current IV property is a null
reference (Nothing in Visual Basic),
the GenerateIV method is called to
create a new random IV.
This will make the ciphertext different every time.
Note: a way around this is discussed here where I suggest you can prepend the plaintext with a mac ... then the first block of ciphertext is effectively the IV, but it's all repeatable
You need to specify an IV (initialization vector), even if you generate a random one. If you use random IV then you must store it along with the ciphertext so you can use it later on decryption, or you can derive an IV from some other data (for example if you're encrypting a password, you can derive the IV from the username).
I needed some simple string encryption, so I wrote the following code (with a great deal of "inspiration" from here):
// create and initialize a crypto algorithm
private static SymmetricAlgorithm getAlgorithm(string password) {
SymmetricAlgorithm algorithm = Rijndael.Create();
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(
password, new byte[] {
0x53,0x6f,0x64,0x69,0x75,0x6d,0x20, // salty goodness
0x43,0x68,0x6c,0x6f,0x72,0x69,0x64,0x65
}
);
algorithm.Padding = PaddingMode.ISO10126;
algorithm.Key = rdb.GetBytes(32);
algorithm.IV = rdb.GetBytes(16);
return algorithm;
}
/*
* encryptString
* provides simple encryption of a string, with a given password
*/
public static string encryptString(string clearText, string password) {
SymmetricAlgorithm algorithm = getAlgorithm(password);
byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
return Convert.ToBase64String(ms.ToArray());
}
/*
* decryptString
* provides simple decryption of a string, with a given password
*/
public static string decryptString(string cipherText, string password) {
SymmetricAlgorithm algorithm = getAlgorithm(password);
byte[] cipherBytes = Convert.FromBase64String(cipherText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
return System.Text.Encoding.Unicode.GetString(ms.ToArray());
}
The code appears to work fine, except that when decrypting data with an incorrect key, I get a CryptographicException - "Padding is invalid and cannot be removed" - on the cs.Close() line in decryptString.
example code:
string password1 = "password";
string password2 = "letmein";
string startClearText = "The quick brown fox jumps over the lazy dog";
string cipherText = encryptString(startClearText, password1);
string endClearText = decryptString(cipherText, password2); // exception thrown
My question is, is this to be expected? I would have thought that decrypting with the wrong password would just result in nonsense output, rather than an exception.
Although this have been already answered I think it would be a good idea to explain why it is to be expected.
A padding scheme is usually applied because most cryptographic filters are not semantically secure and to prevent some forms of cryptoatacks. For example, usually in RSA the OAEP padding scheme is used which prevents some sorts of attacks (such as a chosen plaintext attack or blinding).
A padding scheme appends some (usually) random garbage to the message m before the message is sent. In the OAEP method, for example, two Oracles are used (this is a simplistic explanation):
Given the size of the modulus you padd k1 bits with 0 and k0 bits with a random number.
Then by applying some transformation to the message you obtain the padded message wich is encrypted and sent.
That provides you with a randomization for the messages and with a way to test if the message is garbage or not. As the padding scheme is reversible, when you decrypt the message whereas you can't say anything about the integrity of the message itself you can, in fact, make some assertion about the padding and thus you can know if the message has been correctly decrypted or you're doing something wrong (i.e someone has tampered with the message or you're using the wrong key)
I experienced a similar "Padding is invalid and cannot be removed." exception, but in my case the key IV and padding were correct.
It turned out that flushing the crypto stream is all that was missing.
Like this:
MemoryStream msr3 = new MemoryStream();
CryptoStream encStream = new CryptoStream(msr3, RijndaelAlg.CreateEncryptor(), CryptoStreamMode.Write);
encStream.Write(bar2, 0, bar2.Length);
// unless we flush the stream we would get "Padding is invalid and cannot be removed." exception when decoding
encStream.FlushFinalBlock();
byte[] bar3 = msr3.ToArray();
If you want your usage to be correct, you should add authentication to your ciphertext so that you can verify that it is the correct pasword or that the ciphertext hasn't been modified. The padding you are using ISO10126 will only throw an exception if the last byte doesn't decrypt as one of 16 valid values for padding (0x01-0x10). So you have a 1/16 chance of it NOT throwing the exception with the wrong password, where if you authenticate it you have a deterministic way to tell if your decryption is valid.
Using crypto api's while seemingly easy, actually is rather is easy to make mistakes. For example you use a fixed salt for for you key and iv derivation, that means every ciphertext encrypted with the same password will reuse it's IV with that key, that breaks semantic security with CBC mode, the IV needs to be both unpredictable and unique for a given key.
For that reason of easy to make mistakes, I have a code snippet, that I try to keep reviewed and up to date (comments, issues welcome):
Modern Examples of Symmetric Authenticated Encryption of a string C#.
If you use it's AESThenHMAC.AesSimpleDecryptWithPassword(ciphertext, password) when the wrong password is used, null is returned, if the ciphertext or iv has been modified post encryption null is returned, you will never get junk data back, or a padding exception.
If you've ruled out key-mismatch, then besides FlushFinalBlock() (see Yaniv's answer), calling Close() on the CryptoStream will also suffice.
If you are cleaning up resources strictly with using blocks, be sure to nest the block for the CryptoStream itself:
using (MemoryStream ms = new MemoryStream())
using (var enc = RijndaelAlg.CreateEncryptor())
{
using (CryptoStream encStream = new CryptoStream(ms, enc, CryptoStreamMode.Write))
{
encStream.Write(bar2, 0, bar2.Length);
} // implicit close
byte[] encArray = ms.ToArray();
}
I've been bitten by this (or similar):
using (MemoryStream ms = new MemoryStream())
using (var enc = RijndaelAlg.CreateEncryptor())
using (CryptoStream encStream = new CryptoStream(ms, enc, CryptoStreamMode.Write))
{
encStream.Write(bar2, 0, bar2.Length);
byte[] encArray = ms.ToArray();
} // implicit close -- too late!
Yes, this is to be expected, or at least, its exactly what happens when our crypto routines get non-decryptable data
Another reason of the exception might be a race condition between several threads using decryption logic - native implementations of ICryptoTransform are not thread-safe (e.g. SymmetricAlgorithm), so it should be put to exclusive section, e.g. using lock.
Please refer here for more details: http://www.make-awesome.com/2011/07/system-security-cryptography-and-thread-safety/
There may be some unread bytes in the CryptoStream. Closing before reading the stream completely was causing the error in my program.
I had a similar problem, the issue in decrypt method was initializing an empty memory stream. when it worked when I initialized it with the cipher text byte array like this:
MemoryStream ms = new MemoryStream(cipherText)
The answer updated by the user "atconway" worked for me.
The problem was not with the padding but the key which was different during encryption and decryption.
The key and iv should be same during encypting and decrypting the same value.