I am using EncryptStringToBytes_Aes method from MSDN to encrypt some data using custom passphrase like this:
string original = "some data to encrypt";
byte[] encrypted;
using (AesManaged aes = new AesManaged())
{
// Prepare new Key and IV.
string passphrase = "somepassphrase";
byte[] saltArray = Encoding.ASCII.GetBytes("somesalt");
Rfc2898DeriveBytes rfcKey = new Rfc2898DeriveBytes(passphrase, saltArray);
aes.Key = rfcKey.GetBytes(aes.KeySize / 8);
aes.IV = rfcKey.GetBytes(aes.BlockSize / 8);
// Encrypt the string to an array of bytes.
encrypted = EncryptStringToBytes_Aes(original, aes.Key, aes.IV);
// Decrypt the bytes to a string.
string roundtrip = DecryptStringFromBytes_Aes(encrypted, aes.Key, aes.IV);
return Convert.ToBase64String(encrypted);
}
and it works (DecryptStringFromBytes_Aes returns the original string).
My question is how do I decrypt encrypted using JavaScript if I have the same passphrase on the client-side as well? I tried using CryptoJS to decrypt it but had no success. The data gets encrypted in a webservice and I tried passing it to JS as a byte array, string, tried encoding it with various encodings but no matter what I did, I couldn't get the original string. What am I doing wrong here and how can I make this work? Is it even doable like this? Could the saltArray encoding or even the usage of the custom passphrase be the cause of my problems?
Here is for example one of my JS tries (using base64 encoding):
var decoded = CryptoJS.enc.Base64.parse(encrypted);
var decrypted = CryptoJS.AES.decrypt(decoded, "somepassphrase");
(edit: I meant to implement random salt later, once I got everything else wokring since it is easier to track what is going on that way)
try using Stanford Javascript Crypto Library.
Link:http://crypto.stanford.edu/sjcl/
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 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
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.
Does .NET's RC2CryptoServiceProvider conform to OpenSSL. I'm using RC2CryptoServiceProvider with CBC but the encrypted value for the same text (using the same key and init vector) is different from what nodejs crypto library's rc2-cbc produces. Node js crypto library conforms to OpenSSL.
Someone had already asked about this discrepancy but no answers yet - Node.JS RC2-CBC Encryption and Decryption ciphers are not matching with C#
Can someone point me to the complete source code RC2CryptoServiceProvider? Is the encrypt/decrypt code a completely managed one available in C# or does it use C++ underneath?
I'm interested in finding the differences as I'm looking for a way to decrypt a .NET application encrypted string in node js.
Below is the C# code and the corresponding node js code. For the same data (HelloWorld), key and iv, the encrypted values produced are different.
public static string Encrypt(string data, string key, string iv)
{
try
{
byte[] ivBytes = Encoding.ASCII.GetBytes(iv);
byte[] keyBytes = Encoding.ASCII.GetBytes(key);
byte[] dataBytes = Encoding.ASCII.GetBytes(data);
RC2 rc = new RC2CryptoServiceProvider();
rc.Mode = CipherMode.CBC;
rc.Key = keyBytes;
rc.IV = ivBytes;
MemoryStream stream = new MemoryStream();
CryptoStream stream2 = new CryptoStream(stream, rc.CreateEncryptor(), CryptoStreamMode.Write);
stream2.Write(dataBytes, 0, dataBytes.Length);
stream2.Close();
return Convert.ToBase64String(stream.ToArray());
}
catch
{
return string.Empty;
}
}
Below is the node js code.
algo = 'rc2-cbc'
key = '1234567890'
iv = 'someInit'
keyBuffer = new Buffer(key)
ivBuffer = new Buffer(iv)
cipher = crypto.createCipheriv(algo, keyBuffer, ivBuffer)
textBuffer = new Buffer('HelloWorld')
encrypted = cipher.update(textBuffer)
encryptedFinal = cipher.final()
encryptedText = encrypted.toString('base64') + encryptedFinal.toString('base64')
console.log encryptedText
I hit a similar situation. There is existing .NET (core) code using RC2CryptoServiceProvider to decrypt a string. I wanted to replicate this in node.
The .NET code uses keysize 128 (which also appears to be the default) so I assumed the comparable algorithm in node (openssl) would be rc2-128. But this always failed when decrypting.
After some trial and error I discovered that using using the rc2-64 algorithm in node behaves the same as the .NET code using keysize 128. Just don't ask me why!
I'm using this function to Encrypt/Decrypt data using AES because it looked simple and clean (googl'ed code)
public static string Encrypt(string toEncrypt)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes("3a8114db34d5623d4fd1ee0fb0ga7a73"); // 256-AES key
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.CBC;
rDel.Padding = PaddingMode.PKCS7; // better lang support
ICryptoTransform cTransform = rDel.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
public static string Decrypt(string toDecrypt)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes("3a8114db34d5623d4fd1ee0fb0ga7a73"); // AES-256 key
byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.CBC;
rDel.Padding = PaddingMode.PKCS7; // better lang support
ICryptoTransform cTransform = rDel.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return UTF8Encoding.UTF8.GetString(resultArray);
}
I'm trying to encrypt the data "test garbage" and thats what i receive back:
YfhyS3GE/liPCaXR0cMHfQ==
However, I tried the same key/phrase on a lot of online-aes encrypt/decrypt and all of them are returning
U2FsdGVkX184u0/vPgA/B0rxofp5Iuqm7hfn4+QZAhg=
Can anyone actually tell me whats wrong?
"3a8114db34d5623d4fd1ee0fb0ga7a73" is hex encoded 128 bit key not a utf8 encoded 256 bit key.
That said simple and clean doesn't necessarily mean correct. For example, the code your using does use a random IV, but doesn't include it in the wire format, you'll never be able to decrypt what you encrypt.
I have a cut and paste style simple code sample that I try to keep up to date and reviewed that uses authenticated encryption using AES:
Modern Examples of Symmetric Authenticated Encryption of a string. C#
First a few issues with your code. Apparently Google doesn't always return the best code on top.
You are getting a key through the UTF8 encoding, which is silly. This produces a very weak key:
// 256-AES key
byte[] keyArray = UTF8Encoding.UTF8.GetBytes("3a8114db34d5623d4fd1ee0fb0ga7a73");
You are using CBC mode but the IV is not (explicitly) set.
Then you compare to some online-aes encrypt/decrypt services and you see a difference. That's because they probably (hopefully) work different.
The main thing here is that your 2 methods are a match and you can round-trip your data. But a good encryption would use a different way to get Key and IV.
I'm not exactly sure why you see a different (smaller) length encrypted data but that's up to a whole list of settings : Key length, Padding mode etc.