Hi I'm just trying to encrypt a string but i want to reverse the decryption method to create exactly encrypted key
decryption was
public string newSample(string s)
{
byte[] buffer = Convert.FromBase64String(s);
Encoding utF8 = Encoding.UTF8;
byte[] bytes1 = utF8.GetBytes("key1");
byte[] bytes2 = utF8.GetBytes("key2");
RijndaelManaged rijndaelManaged1 = new RijndaelManaged();
rijndaelManaged1.Mode = CipherMode.CBC;
rijndaelManaged1.Padding = PaddingMode.Zeros;
rijndaelManaged1.BlockSize = 128;
rijndaelManaged1.KeySize = 128;
RijndaelManaged rijndaelManaged2 = rijndaelManaged1;
ICryptoTransform transform = (ICryptoTransform)null;
transform = rijndaelManaged2.CreateDecryptor(bytes2, bytes1);
byte[] bytes3 = (byte[])null;
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(buffer, 0, buffer.GetLength(0));
cryptoStream.FlushFinalBlock();
}
rijndaelManaged2.Clear();
bytes3 = memoryStream.ToArray();
}
return new string(Encoding.UTF8.GetChars(bytes3));
}
is it possible to reverse the code and create encryption key ? if so
how could be the encryption should look lik for this decryption method ??
thanks
This is the problem - or at least the initial problem:
return new string(Encoding.UTF8.GetChars(bytes3));
The result of encryption is not a UTF-8-encoded byte array... it's arbitrary bytes. By assuming it's valid UTF-8-encoded text, you're losing information.
Instead, you should use a hex or base64 approach, both of which are designed to convert arbitrary binary data to text in a lossless fashion. For example:
return Convert.ToBase64String(bytes3);
Now, your decryption code should start with:
byte[] encryptedData = Convert.FromBase64String(base64EncryptedText);
(Where base64EncryptedText is the value returned from your encryption method.)
From there, it should be a matter of just reversing each step, and there are numerous examples around. You may well find that you've got a problem due to the padding mode, however - you may need to separately record the length of the original data.
As an aside, it's not clear why your method takes a string in the first place. It's odd for an encryption method to take a base64-encoded piece of data. It's more common for it to take either a normal plain text string which is converted into bytes using something like Encoding.UTF8, or for it to take a byte[] to start with.
Related
I am working in a C# application. We have common methods to store data on a file. These methods encrypt the data and store them on the file system. when we need the data, ReadData method decrypts the data and returns me plain text.
This code works fine in normal cases if size of the text in small. but for a example text given below, the decryption code is throwing exception - length of the data to decrypt is invalid.
The exception occurs at line
// close the CryptoStream
x_cryptostream.Close();
I tried different ways but no luck. Can some pls help.
Why am I encrypting already encrypted data - I am just trying to store in a file using common method of the huge application. The common methods storedata(key,data) nad readdata(key) do the encryption/decryption I can't avoid.
public static byte[] Decrypt(byte[] ciphertext, string Key, string IV)
{
byte[] k = Encoding.Default.GetBytes(Key);
byte[] iv = Encoding.Default.GetBytes(IV);
// create the encryption algorithm
SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael");
x_alg.Padding = PaddingMode.PKCS7;
// create an ICryptoTransform that can be used to decrypt data
ICryptoTransform x_decryptor = x_alg.CreateDecryptor(k, iv);
// create the memory stream
MemoryStream x_memory_stream = new MemoryStream();
// create the CryptoStream that ties together the MemoryStream and the
// ICryptostream
CryptoStream x_cryptostream = new CryptoStream(x_memory_stream,
x_decryptor, CryptoStreamMode.Write);
// write the ciphertext out to the cryptostream
x_cryptostream.Write(ciphertext, 0, ciphertext.Length);
// close the CryptoStream
x_cryptostream.Close();
// get the plaintext from the MemoryStream
byte[] x_plaintext = x_memory_stream.ToArray();
Below is the code of encrypt method.
public static byte[] Encrypt(string strplain, string Key, string IV)
{
byte[] k = Encoding.Default.GetBytes(Key);
byte[] iv = Encoding.Default.GetBytes(IV);
byte[] plaintext = Encoding.Default.GetBytes(strplain);
// create the encryption algorithm
SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael");
x_alg.Padding = PaddingMode.PKCS7;
// create an ICryptoTransform that can be used to encrypt data
ICryptoTransform x_encryptor = x_alg.CreateEncryptor(k, iv);
// create the memory stream
MemoryStream x_memory_stream = new MemoryStream();
// create the CryptoStream that ties together the MemoryStream and
// the ICryptostream
CryptoStream x_cryptostream = new CryptoStream(x_memory_stream,
x_encryptor, CryptoStreamMode.Write);
// write the plaintext out to the cryptostream
x_cryptostream.Write(plaintext, 0, plaintext.Length);
// close the CryptoStream
x_cryptostream.Close();
// get the ciphertext from the MemoryStream
byte[] x_ciphertext = x_memory_stream.ToArray();
// close memory stream
x_memory_stream.Close();
// convert from array to string
string cipher_Tx = Encoding.Default.GetString(x_ciphertext,
0, x_ciphertext.Length);
x_encryptor.Dispose();
x_alg.Clear();
byte[] cipher = Encoding.Default.GetBytes(cipher_Tx);
return cipher;
}
Your problem is string cipher_Tx = Encoding.Default.GetString(x_ciphertext, 0, x_ciphertext.Length);.
x_ciphertext is not a valid byte representation of text, it has many unpresentable characters and when you do your byte[] to string conversion you are losing information. The correct way to do it is use a string format that is designed to represent binary data using something like Convert.ToBase64String(byte[]) and Convert.FromBase64String(string).
string cipher_Tx = Convert.ToBase64String(x_ciphertext)
x_encryptor.Dispose();
x_alg.Clear();
byte[] cipher = Convert.FromBase64String(cipher_Tx)
That being said, there is a lot of other "odd" things about your code, for example you don't use using statements and you really should. Also that whole conversion to string and back is totally unnecessary, just return x_ciphertext. There may be other problems with the code too (like where did the strings for Key and IV come from) and many other best practices (like you should be generating a random IV and writing it out in to the output and the key should be generated using a key derivation function not straight from user text), but I stopped checking after I found the string conversion issue.
Your code above works as long as the key and iv used to decrypt match the key and iv used to encrypt. Try this:
byte[] test = new byte[1000000];
for (int i = 0; i < 256; i++)
{
test[i] = (byte)i;
}
var ciphertext = Encrypt(Encoding.Default.GetString(test), "0000000000000000", "0000000000000000");
byte[] check = Decrypt(ciphertext, "0000000000000000", "0000000000000000");
for (int i = 0; i < 256; i++)
{
Debug.Assert(check[i] == (byte)i, "round trip");
}
As you can see, one million bytes encrypt and decrypt just fine with your code, so I don't think it has anything to do with data size.
However, change the IV like this:
byte[] check = Decrypt(ciphertext, "0000000000000000", "000000000000000X"); // note X
and the Debug.Assert will fire -- the decryption will not match. However, x_cryptostream.Close() succeeds.
Next, try changing the key like this:
byte[] check = Decrypt(ciphertext, "000000000000000X", "0000000000000000"); // note X
Now, x_cryptostream.Close() will fail with a CryptographicException, probably, "Padding is invalid and cannot be removed."
Corrupting the key will cause the decryption to fail, and x_cryptostream.Close() to fail.
I think the problem is in your saving and later restoring the key bytes.
BTW: Hopefully you are using the full binary range of the key, and not basing it only on ASCII characters, otherwise you don't really have a strong key.
I'm attempting to replace PasswordDerivedBytes with Rfc2898DerivedBytes but I'm having a problem with the latter when getting back a unicode encoded result.
Take this code for example:
[TestMethod]
public void DerivedBytesTest()
{
string encrypted = "y4Ijqo9Ga/mHlFbLHDdDUkYZlyu7CHF4PVXGLnb8by7FAVtCgPLhFSiA9Et6hDac";
string key = "{00B3403A-3C29-4f26-A9CC-14C411EA8547}";
string salt = "gT5M07XB9hHl3l1s";
string expected = "4552065703414505";
string decrypted;
decrypted = Decrypt(encrypted, key, salt, true);
Assert.IsTrue(decrypted == expected); // Works
decrypted = Decrypt(encrypted, key, salt, false);
Assert.IsTrue(decrypted == expected); // Doesn't work, get wrong unicode characters in 24 character string
}
private string Decrypt(string encrypted, string key, string salt, bool legacy = false)
{
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] encryptedDataBytes = Convert.FromBase64String(encrypted);
byte[] saltBytes = encoding.GetBytes(salt);
RijndaelManaged encryption = new RijndaelManaged();
DeriveBytes secretKey;
if (legacy)
{
secretKey = new PasswordDeriveBytes(key, saltBytes) {IterationCount = 100};
encryption.Padding = PaddingMode.PKCS7;
}
else
{
secretKey = new Rfc2898DeriveBytes(key, saltBytes, 100);
encryption.Padding = PaddingMode.Zeros; // This is the only one that doesn't throw the "Padding is invalid and cannot be removed" exception, but gives me a non-ASCII result
}
ICryptoTransform decryptor = encryption.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));
string decryptedText = "";
using (MemoryStream memoryStream = new MemoryStream(encryptedDataBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] bytes = new byte[encryptedDataBytes.Length];
int decryptedCount = cryptoStream.Read(bytes, 0, bytes.Length);
decryptedText = encoding.GetString(bytes, 0, decryptedCount);
if (!legacy)
{
// Something more to do with result?
}
}
}
return decryptedText;
}
I wonder if anyone can advise where I'm going wrong?
PasswordDeriveBytes is a badly implemented extension of PBKDF1, while Rfc2898DeriveBytes is the implementation of PBKDF2. Both derive a key from a password, but they are two different algorithms and therefore they derive two different results. As they are using cryptographically secure hashes underneath, there is no way to convert one to another.
If you can spare a few bytes of storage you could still derive the key using PKBDF1 and then encrypt that key using the result of PBKDF2. If the output size is identical you could even use XOR encryption for that (a one-time-pad) but AES would of course also work. So then the decryption becomes: calculate PBKDF2 result, decrypt data key, use data key to decrypt ciphertext.
Otherwise you will have to decrypt and then re-encrypt the result.
If you want to compare the decryption result then compare the resulting bytes; do not first convert it into a string. Using authenticated encryption or a MAC is highly advised so that a authentication tag can be validated instead. Just ignoring padding exceptions by using Zero Padding is not the way to go. These padding errors occur because the key is wrong.
Generic notes:
PasswordDeriveBytes should not be used for any amount of bytes > 20 bytes as the Mickeysoft extension of PBKDF1 is horribly insecure, even repeating bytes in the output (!). If you do the same for PBKDF2 then any adversary will have to do half the work that you have to do so that's not a good idea either.
The iteration count in the question is very low, but as you seem to use a highly random UID instead of a password that should be OK.
I have searched online but have not been able to find any solutions to my problem.
I am using previously written methods to encrypt and ecrypt text using the Rijndael class.
I use these functions to encrypt and decrypt usernames and emails for a web application I have been working on.
The encryption/decryption works perfectly, but every once in a while I get this error:
System.Security.Cryptography.CryptographicException: Length of the data to decrypt is invalid.
Currently, I am getting this error with a specific email address and I can't reproduce the error even if I replace some of the letters in the email.
Here are the encryption/decrytpion functions. The IV and Key are defined as read only strings.
static public string Encrypting(string Source)
{
byte[] bytIn = System.Text.ASCIIEncoding.ASCII.GetBytes(Source);
// create a MemoryStream so that the process can be done without I/O files
System.IO.MemoryStream ms = new System.IO.MemoryStream();
byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
byte[] KEYBytes = Encoding.ASCII.GetBytes(KEY);
Rijndael rijndael = Rijndael.Create();
rijndael.IV = IVBytes;
rijndael.Key = KEYBytes;
// create Crypto Stream that transforms a stream using the encryption
CryptoStream cs = new CryptoStream(ms, rijndael.CreateEncryptor(), CryptoStreamMode.Write);
// write out encrypted content into MemoryStream
cs.Write(bytIn, 0, bytIn.Length);
cs.FlushFinalBlock();
// get the output and trim the '\0' bytes
byte[] bytOut = ms.GetBuffer();
int i = 0;
for (i = 0; i < bytOut.Length; i++)
if (bytOut[i] == 0)
break;
// convert into Base64 so that the result can be used in xml
return System.Convert.ToBase64String(bytOut, 0, i);
}
static public string Decrypting(string Source)
{
// convert from Base64 to binary
byte[] bytIn = System.Convert.FromBase64String(Source);
// create a MemoryStream with the input
System.IO.MemoryStream ms = new System.IO.MemoryStream(bytIn, 0, bytIn.Length);
byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
byte[] KEYBytes = Encoding.ASCII.GetBytes(KEY);
Rijndael rijndael = Rijndael.Create();
rijndael.IV = IVBytes;
rijndael.Key = KEYBytes;
// create Crypto Stream that transforms a stream using the decryption
CryptoStream cs = new CryptoStream(ms, rijndael.CreateDecryptor(), CryptoStreamMode.Read);
// read out the result from the Crypto Stream
System.IO.StreamReader sr = new System.IO.StreamReader(cs);
return sr.ReadToEnd();
}
FYI - I am very new to cryptography and security.
Can these functions be fixed to avoid special cases that cause the error, or should I scrap these and use the RijndaelManaged class?
Sites I found that use RijndaelManaged:
SeeSharp
TekEye
The issue is almost certainly nothing to do with Rijndael vs. RijndaelManaged (or any other such implementation), but instead because the encrypted data contains a 0x00, and you are incorrectly assuming that the the ciphertext ends at the first 0x00 byte. Since the ciphertext can legitimately contain any byte value you should instead use the stream's Length property to determine the length of the ciphertext.
Eliminate the section you've commented: "get the output and trim the '\0' bytes" and replace the return ... statement with:
return System.Convert.ToBase64String(ms.GetBuffer(), 0, ms.Length);
It should be noted that there are many other issues with your use of cryptography here, e.g. the use of a key generated directly from the ASCII encoding of a string, and the fact you're using a fixed IV both negatively impact security.
The norm for the error is a padding issue. What version of .NET are you using? It is more common to use the AES classes (AES, or Advanced Encryption Standard, which is Rijndael). There are plenty of AES implementations you can find as samples.
If you need some proof AES is Rijndael: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
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'm trying to encrypt a stream and decrypt it again. When encrypting, I store the salt and IV (8 and 16 bytes) first into the target stream. When decrypting, I get a padding error in the line where CopyTo() is called. The full source of the class can be found in a Gist.
The relevant code snippet for encryption is:
// Set position to start of stream.
encryptedOutStream.Seek (0, SeekOrigin.Begin);
// Store the salt in the output stream. The salt is not a secret. Salt is used to generate different keys for identical passwords.
var keyInfo = GenerateKey (password);
encryptedOutStream.Write (keyInfo.Salt, 0, keyInfo.Salt.Length);
// Store the IV in the output stream. The IV is randomly generated if not set explicitly. It is not a secret and used to create
// different encrypted output for identical plaintext input when using CBC cipher mode.
encryptedOutStream.Write (aesAlgo.IV, 0, aesAlgo.IV.Length);
// Let the algorithm know our key.
aesAlgo.Key = keyInfo.Key;
// Get an encrypting ICryptoTransform interface from the algorithm.
using(var cryptoTransform = aesAlgo.CreateEncryptor ())
// Pump the input stream through a crypto stream wrapping a memory stream.
using(var encryptionStream = new CryptoStream(encryptedOutStream, cryptoTransform, CryptoStreamMode.Write))
{
plainInStream.CopyTo (encryptionStream);
}
and for decryption:
// Read the salt.
byte[] salt = new byte[8];
encryptedInStream.Read (salt, 0, 8);
// Read the IV.
byte[] iv = new byte[16];
encryptedInStream.Read (iv, 0, 16);
aesAlgo.IV = iv;
// Generate the key from the password and the salt.
var keyInfo = GenerateKey (password, salt);
aesAlgo.Key = keyInfo.Key;
// Get a decrypting ICryptoTransform interface from the algorithm.
using(var cryptoTransform = aesAlgo.CreateDecryptor ())
// Pump the input stream through a crypto stream wrapping a memory stream.
using(var decryptionStream = new CryptoStream(encryptedInStream, cryptoTransform, CryptoStreamMode.Read))
{
decryptionStream.CopyTo (decryptedOutStream);
}
I suspect an issue involving the EncryptString and DecryptString methods, specifically the lines:
encryptedString = Encoding.UTF8.GetString(encryptedOutStream.ToArray());
and
using (var encryptedInStream = new MemoryStream(Encoding.UTF8.GetBytes(s)))
Effectively, this code incorrectly attempts to use text encoding on ciphertext, which is binary data. This will introduce errors when the binary data does not happen to be a legal UTF8 sequence, corrupting the ciphertext and introducing padding issues. Instead, a binary encoding method needs to be used (most simply, base64).
To correct the issue, change the above lines to:
// change line 281:
// encryptedString = Encoding.UTF8.GetString(encryptedOutStream.ToArray());
// to:
encryptedString = Convert.ToBase64String(encryptedOutStream.ToArray());
// change line 251:
// using (var encryptedInStream = new MemoryStream(Encoding.UTF8.GetBytes(s)))
// to:
using (var encryptedInStream = new MemoryStream(Convert.FromBase64String(s)))
With this change, the conversion appears to work. A simple driver to encrypt and then decrypt the plaintext "payload" with the password "password" prints the desired output:
string password = "password";
SymmetricCrypto c = new SymmetricCrypto();
string ct = c.EncryptString("payload", password);
Console.WriteLine(ct); // prints sLSZfzVQGCoML29... (ciphertext will vary)
string dt = c.DecryptString(ct, password);
Console.WriteLine(dt); // prints "payload"