I have large xml file with more than 30 000 lines. It has content like
<?xml version="1.0"?>
<Nodes>
<Node>some node name </Node>
<Node>some node name 2 </Node>
...
</Nodes>
I want to send this xml file with encrypted content to the client manually. Client app (wpf) will load this file and encrypt this file on demand without user intervention (all possible keys will be predefined earlier on this client app).
What method should I use to encrypt and decrypt xml file content?
I was thinking to use
http://aspnettutorialonline.blogspot.com/2012/05/encryption-and-decryption-in-aspnet.html
but since I do not have much experience with this subject I'm asking is this good solution or you would recommend something else?
AES encryption is very easy with .NET...
private readonly ICryptoTransform encryptor;
private readonly ICryptoTransform decryptor;
private readonly UTF8Encoding encoder;
var rm = new RijndaelManaged();
encryptor = rm.CreateEncryptor(key, vector);
decryptor = rm.CreateDecryptor(key, vector);
encoder = new UTF8Encoding();
public string Encrypt(string unencrypted)
{
return Convert.ToBase64String(Encrypt(encoder.GetBytes(unencrypted)));
}
public byte[] Encrypt(byte[] buffer)
{
var encryptStream = new MemoryStream();
using (var cs = new CryptoStream(encryptStream, encryptor, CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
}
return encryptStream.ToArray();
}
key and vector are byte[] arrays as expected by the RijndaelManaged.CreateEncryptor() and RijndaelManaged.CreateDecryptor() methods...
The key and vector values will end up being a part of your client app code so hiding the values and obfuscating will protect only against non-sofisticated attackers but if all you need is to hide the xml contents from the non-technical end-users that might be sufficient...
.Net provides many crypto-systems. Depending on your needs you can chose between DES, 3DES, AES or RSA(which is in efficient in your case). DES is the least secure, 3DES is better but I'd go for the AES. to Encrypt:
using System.Security.Cryptography;
...
class AES {
private AesCryptoServiceProvider aes;
public AES (Byte[] IV, Byte[] Key) {
aes = AesCryptoServiceProvider();
aes.Key = Key; // 256 Bits Long
// AES Key can be generated using SHA256
aes.IV = IV; // 128 Bits Long
// IV can be generated using MD5
}
public Byte[] Encrypt(Byte[] FileStream) {
ICryptoTransform Transform = aes.CreateEncryptor();
return Transform.TransformFinalBlock(FileStream, 0, FileStream.Lenght);
}
public Byte[] Decrypt (Byte[] FileStream){
ICryptoTransform Transform = aes.CreateDecryptor();
return Transform.TransformFinalBlock(FileStream, 0, FileStream.Lenght);
}
}
Related
I am searching for C# Code to reproduce the following openssl command.
openssl enc -d -aes-256-cbc -in my_encrypted_file.csv.enc -out my_decrypted_file.csv -pass file:key.bin
Additional information:
The encrypted file in present as byte[]
The key.bin is a byte[] with length of 256 (the key is obtained by a more simple decryption of yet another file, which i managed to realize in C#).
I have been trying out various examples found by searching the web.
The problem is, that all of these examples require an IV (initialization vector). Unfortunately, I don't have an IV and no one on the team knows what this is or how it could be defined.
The openssl command does not seem to need one, so I am a bit confused about this.
Currently, the code, I am trying with, looks as follows:
public static string DecryptAesCbc(byte[] cipheredData, byte[] key)
{
string decrypted;
System.Security.Cryptography.Aes aes = System.Security.Cryptography.Aes.Create();
aes.KeySize = 256;
aes.Key = key;
byte[] iv = new byte[aes.BlockSize / 8];
aes.IV = iv;
aes.Mode = CipherMode.CBC;
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream(cipheredData))
{
using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
decrypted = sr.ReadToEnd();
}
}
return decrypted;
}
}
The code fails saying that my byte[256] key has the wrong length for this kind of algorithm.
Thanks for any help with this!
Cheers, Mike
The posted OpenSSL statement uses the -pass file: option and thus a passphrase (which is read from a file), see openssl enc. This causes the encryption process to first generate a random 8 bytes salt and then, together with the passphrase, derive a 32 bytes key and 16 bytes IV using the (not very secure) proprietary OpenSSL function EVP_BytesToKey. This function uses several parameters, e.g. a digest and an iteration count. The default digest for key derivation is MD5 and the iteration count is 1. Note that OpenSSL version 1.1.0 and later uses SHA256 as default digest, i.e. depending on the OpenSSL version used to generate the ciphertext, the appropriate digest must be used for decryption. Preceding the ciphertext is a block whose first 8 bytes is the ASCII encoding of Salted__, followed by the 8 bytes salt.
Therefore, the decryption must first determine the salt. Based on the salt, together with the passphrase, key and IV must be derived and then the rest of the encrypted data can be decrypted. Thus, first of all an implementation of EVP_BytesToKey in C# is required, e.g. here. Then a possible implementation could be (using MD5 as digest):
public static string DecryptAesCbc(byte[] cipheredData, string passphrase)
{
string decrypted = null;
using (MemoryStream ms = new MemoryStream(cipheredData))
{
// Get salt
byte[] salt = new byte[8];
ms.Seek(8, SeekOrigin.Begin);
ms.Read(salt, 0, 8);
// Derive key and IV
OpenSslCompat.OpenSslCompatDeriveBytes db = new OpenSslCompat.OpenSslCompatDeriveBytes(passphrase, salt, "MD5", 1);
byte[] key = db.GetBytes(32);
byte[] iv = db.GetBytes(16);
using (Aes aes = Aes.Create())
{
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
aes.Key = key;
aes.IV = iv;
// Decrypt
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs, Encoding.UTF8))
{
decrypted = sr.ReadToEnd();
}
}
}
}
return decrypted;
}
Note that the 2nd parameter of DecryptAesCbc is the passphrase (as string) and not the key (as byte[]). Also note that StreamReader uses an encoding (UTF-8 by default), which requires compatible data (i.e. text data, but this should be met for csv files). Otherwise (i.e. for binary data as opposed to text data) StreamReader must not be used.
I have simple symmetric encrypt/decrypt application that works fine:
namespace Crypto
{
class Program
{
public static void EncryptSomeText()
{
string original ="My secretdata!";
using (SymmetricAlgorithm symmetricAlgorithm =
new AesManaged())
{
byte[] encrypted = Encrypt(symmetricAlgorithm, original);
string roundtrip = Decrypt(symmetricAlgorithm, encrypted);
// Displays: My secret data!
Console.WriteLine("Original:{ 0}", original);
Console.WriteLine("RoundTrip:{ 0}", roundtrip);
}
}
static byte[] Encrypt(SymmetricAlgorithm aesAlg, string plainText)
{
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt =
new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
return msEncrypt.ToArray();
}
}
}
static string Decrypt(SymmetricAlgorithm aesAlg, byte[] cipherText)
{
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt =
new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
return srDecrypt.ReadToEnd();
}
}
}
}
static void Main(string[] args)
{
SymmetricAlgorithm sma = SymmetricAlgorithm.Create();
byte[] b = Encrypt(sma,"bla bla");
string s= Decrypt(sma, b);
Console.WriteLine("Decrypted {0}", s);
}
}
}
I'm just wondering regarding key creation. Does it means that it is created in automatic way during symmetric algorithm creation? Is it generated each time different? I suppose, user should pass key for this purpose.
SymmetricAlgorithm sma = SymmetricAlgorithm.Create();
Random key is generated when you access Key property of your SymmetricAlgorithm, assuming you did not set that Key before that to some predefined key. It's not generated during construction of SymmetricAlgorithm itself.
var sma = SymmetricAlgorithm.Create();
// no key generated here yet
var key = sma.Key; // generated key
// accessing `Key` causes random key generation
var sma = SymmetricAlgorithm.Create();
// no key here
sma.Key = myKey;
// you set the key, so no random key is generated
The same is true for IV (nonce) value.
Generating random key makes sense only once, then you have to share it between encrypting\decrypting party in some safe way and use it for future encryptions\decryptions. While you are there, note that IV value should be random for each encryption, so usually you just prepend that IV value to the encrypted binary array and before decrypting you cut that IV from the beginning of encrypted array and use for decryption.
On this github page there is utility class written in Java which performs encryption/decryption using symmetric algorithm, below could be one of encryption flows using symmetric algorithm :
generate secret key using the selected algorithm (DES, 3DES, AES etc)
generate secure random number of seed bytes which is computed with available the seed generation algorithm
probably text message to be encrypted is not the multiples of 8 byte blocks that's why message must be padded with additional bytes to make the text message to be multiples of 8-byte blocks.(e.g. PKCS5Padding padding scheme )
use random generated secure seed bytes as initialization vector as block cipher
initialize cipher function with the symmetric key and block cipher
finish encryption
apply binary to text encoding with selected standard for initialization vector(IV) and encrypted binary data
define message format before sending in order to split the message into IV and encrypted for decryption on recipient side
Why does this code return the weak key error?
static public byte[] TDESDecrypt(byte[] toDecrypt, byte[] key, CipherMode mode = CipherMode.ECB, PaddingMode padding = PaddingMode.None)
{
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = key;
tdes.Mode = mode;
tdes.Padding = padding;
ICryptoTransform cTransform = tdes.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toDecrypt, 0, toDecrypt.Length);
tdes.Clear();
return resultArray;
}
When I try to execute the line "tdes.Key = key", I get the error
deriveSessionKeyIS System.Security.Cryptography.CryptographicException:
Specified key is a known weak key for TripleDES and cannot be used
Why? The key I'm trying is random, but one of the tested keys, for example, is FB13347FE570DC4FFB13347FE570DC4F. Where is the problem?
You can read in wikipedia for example about what is the weak key in cryptography. For triple DES there is a method (TripleDES.IsWeakKey) which checks triple DES key for weakness. In you case, key FB13347FE570DC4FFB13347FE570DC4F is symmetric in a sense that first 8 bytes of it are exactly equal last 8 bytes. That means if you encrypt something with that key, and then encrypt that encrypted info one more time - you will restore original text (because of how this concrete encryption algorithm works), which is obviously dangerous.
So in short .NET protects you from doing dangerous things resulting in cryptographic weakness. If you will use standard GenerateKey() function to generate key (or just don't set Key explicitly) - weak keys won't be generated.
A bit more information about why that key is weak for triple DES. 3DES is named like this because it essentially uses 3 keys and applies pure DES encryption\decryption with those keys 3 times. Each key is 8 bytes long, so 3DES key size is 8*3 = 24 bytes. However, algorithm also allows for first and third keys to be the same, and as such allows to use 16-byte keys (like in your example). In that case first half of those 16-bytes are used as a third key. This option provides less security but is still viable.
Now, when in your case first half and second half of your 16-bytes key are the same, so all three keys which will be used by 3DES are the same. Given that 3DES works like this:
DES encrypt with 3rd(DES Decrypt with 2nd(DES Encrypt with 1st(plaintext)))
You see that in your case you fall back to using simple DES, which defeats whole purpose of using 3DES in the first place.
It is a weak 3DES key because the additional 8-byte will again be repeated as the last 8-bits. Thus the 3DES encryption has reverted to DES and that is weak.
3DES does three operations, in the most common form of ede the data is first encrypted with the first 8-bytes of the key, then decrypted with the second 8-bytes and finally encrypted with the final 8-bytes (which in this case are the first 8-bytes). Note that after the first two operations the data is back to the original data thus the only encryption that is actually performed is the last encryption and that is 8-bytes which is a 56-bit key. That is a weak 3DES key.
I found this solution on MSDN Forum. This solution works perfectly with weak keys.
With the code from the forum I made this:
using System.Security.Cryptography;
using System.IO;
using System.Reflection;
static class MyDES
{
public static byte[] Encrypt(byte[] data, byte[] key, byte[] IV)
{
MemoryStream mStream = new MemoryStream();
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.None;
CryptoStream cStream = new CryptoStream(mStream,
des.CreateWeakEncryptor(key, IV),
CryptoStreamMode.Write);
cStream.Write(data, 0, data.Length);
cStream.FlushFinalBlock();
byte[] ret = mStream.ToArray();
cStream.Close();
mStream.Close();
return ret;
}
public static byte[] Decrypt(byte[] data, byte[] key, byte[] IV)
{
MemoryStream msDecrypt = new MemoryStream(data);
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.None;
CryptoStream csDecrypt = new CryptoStream(msDecrypt,
des.CreateWeakDecryptor(key, IV),
CryptoStreamMode.Read);
byte[] fromEncrypt = new byte[data.Length];
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
return fromEncrypt;
}
#region DESCryptoExtensions
public static ICryptoTransform CreateWeakEncryptor(this DESCryptoServiceProvider cryptoProvider, byte[] key, byte[] iv)
{
MethodInfo mi = cryptoProvider.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
object[] Par = { key, cryptoProvider.Mode, iv, cryptoProvider.FeedbackSize, 0 };
ICryptoTransform trans = mi.Invoke(cryptoProvider, Par) as ICryptoTransform;
return trans;
}
public static ICryptoTransform CreateWeakEncryptor(this DESCryptoServiceProvider cryptoProvider)
{
return CreateWeakEncryptor(cryptoProvider, cryptoProvider.Key, cryptoProvider.IV);
}
public static ICryptoTransform CreateWeakDecryptor(this DESCryptoServiceProvider cryptoProvider, byte[] key, byte[] iv)
{
return CreateWeakEncryptor(cryptoProvider, key, iv);
}
public static ICryptoTransform CreateWeakDecryptor(this DESCryptoServiceProvider cryptoProvider)
{
return CreateWeakDecryptor(cryptoProvider, cryptoProvider.Key, cryptoProvider.IV);
}
#endregion
}
I am using a Java based configuration management tool called Zuul which supports encrypting sensitive configuration information using various encryption schemes.
I have configured it to use below scheme for my data
AES (Bouncy Castle)
Name: PBEWITHSHA256AND128BITAES-CBC-BC
Requirements: Bouncy Castle API and JCE Unlimited Strength Policy Files
Hashing Algorithm: SHA256
Hashing Iterations: 1000
Now when reading my configuration data back, I need to decrypt the information before I can use it and the documentation provides below information around this topic.
The encrypted values produced by Jasypt (and thus Zuul) are are prefixed with the salt (usually 8 or 16 bytes depending on the algorithm requirements). They are then Base64 encoded. Decrypting the results goes something like this:
Convert the Base64 string to bytes
Strip off the first 8 or 16 bytes as the salt
Keep the remaining bytes for the encrypted payload
Invoke the KDF function with the salt, iteration count and the password to create the secret key.
Use the secret key to decrypt the encrypted payload
More details here: Zull Encryption wiki
Based on above details, I have written below code (and my knowledge around security is very limited)
public static string Decrypt(string cipher, string password)
{
const int saltLength = 16;
const int iterations = 1000;
byte[] cipherBytes = Convert.FromBase64String(cipher);
byte[] saltBytes = cipherBytes.Take(saltLength).ToArray();
byte[] encryptedBytes = cipherBytes.Skip(saltLength).ToArray();
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, saltBytes, iterations);
byte[] keyBytes = key.GetBytes(16);
AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider();
aesAlg.KeySize = 256;
aesAlg.BlockSize = 128;
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8);
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
MemoryStream msDecrypt = new MemoryStream(encryptedBytes);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
StreamReader srDecrypt = new StreamReader(csDecrypt);
return srDecrypt.ReadToEnd();
}
I configured Zuul to use below password for the encryption
SimplePassword
And now I have an encrypted string given to me by Zuul and I need to decrypt it
p8C9hAHaoo0F25rMueT0+u0O6xYVpGIkjHmWqFJmTOvpV8+cipoDFIUnaOFF5ElQ
When I try to decrypt this string using above code, I get below exception
System.Security.Cryptography.CryptographicException : Padding is invalid and cannot be removed.
As I mentioned earlier, my knowledge around this topic is limited and I am not able to figure out if the information provided in the documentation is not enough, if I am doing something wrong while writing the decryption routine or should I be using bouncy castle for decryption as well.
Any help with this will be much appreciated.
According to Zuul documentation they are deriving both key and iv from the password/salt.
So you should derive 256+128 bits (i.e. 48 bytes), and use first 32 bytes as the key, and next 16 bytes as IV.
And this should be done in one operation, not as consequent calls to key.DeriveBytes.
I resorted to Bouncy Castle for decryption instead since that is used by Zuul as well.
Here is the code that works
public static string Decrypt(string cipher, string password)
{
const int saltLength = 16;
const int iterations = 1000;
const string algSpec = "AES/CBC/NoPadding";
const string algName = "PBEWITHSHA256AND128BITAES-CBC-BC";
byte[] cipherBytes = Convert.FromBase64String(cipher);
byte[] saltBytes = cipherBytes.Take(saltLength).ToArray();
byte[] encryptedBytes = cipherBytes.Skip(saltLength).ToArray();
char[] passwordChars = password.ToCharArray();
Asn1Encodable defParams = PbeUtilities.GenerateAlgorithmParameters(algName, saltBytes, iterations);
IWrapper wrapper = WrapperUtilities.GetWrapper(algSpec);
ICipherParameters parameters = PbeUtilities.GenerateCipherParameters(algName, passwordChars, defParams);
wrapper.Init(false, parameters);
byte[] keyText = wrapper.Unwrap(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.Default.GetString(keyText);
}
I'd like to encrypt very little data (15 bytes to be exact) into a as short as possible (optimally, no longer than 16 bytes) message using a public key cryptography system.
The standard public key system, RSA, unfortunately produces messages as big as its keys, that is about 100 bytes, depending on key size.
To make things more difficult, I can only use .NET framework libraries, i.e. no third party.
I've read a little about elliptic curve cryptography in the wikipedia and the text there seems to suggest that key sizes there are usually much shorter than RSA keys.
Does this translate to short messages as well? Can the .NET ECDiffieHellmanCng class be used to de/encrypt messages? It seems to feature a different class structure then, say, RSA or the symmetric ciphers.
You can use ECDiffieHellman to encrypt messages. You have two options: Static-static ECDH and static-ephemeral ECDH:
For static-static ECDH the receiver will need to know the senders public key (this might or might not be an option in your application). You should also have some data that is unique for this message (it might be a serial-number you get from somewhere else in the protocol or database-row or whatever or it might be a nonce). You then use ECDH to generate a secret key and use that to encrypt your data. This will give you your desired encrypted data length of 16 bytes, but it is not completely asymmetric: the encryptor is also able to decrypt the messages (again: this might or might not be a problem in your application).
Static-ephemeral is a bit different: here the encryptor generates a temporary (ephemeral) EC keypair. He then uses this keypair together with the receivers public key to generate a secret key which can be used to encrypt the data. Finally he sends the public key of the ephemeral keypair to the receiver together with the encrypted data. This might fit better into your application, but the complete encrypted data will now be 2*32+16=80 bytes using ECDH-256 and AES (as GregS notes you can save 32 bytes by only sending the x-coordinate of the public-key, but I do not believe that .NET exposes the functionality to recalculate the y-coordinate).
Here is a small class that will do static-static ECDH:
public static class StaticStaticDiffieHellman
{
private static Aes DeriveKeyAndIv(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce)
{
privateKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
privateKey.HashAlgorithm = CngAlgorithm.Sha256;
privateKey.SecretAppend = nonce;
byte[] keyAndIv = privateKey.DeriveKeyMaterial(publicKey);
byte[] key = new byte[16];
Array.Copy(keyAndIv, 0, key, 0, 16);
byte[] iv = new byte[16];
Array.Copy(keyAndIv, 16, iv, 0, 16);
Aes aes = new AesManaged();
aes.Key = key;
aes.IV = iv;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
return aes;
}
public static byte[] Encrypt(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce, byte[] data){
Aes aes = DeriveKeyAndIv(privateKey, publicKey, nonce);
return aes.CreateEncryptor().TransformFinalBlock(data, 0, data.Length);
}
public static byte[] Decrypt(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce, byte[] encryptedData){
Aes aes = DeriveKeyAndIv(privateKey, publicKey, nonce);
return aes.CreateDecryptor().TransformFinalBlock(encryptedData,0, encryptedData.Length);
}
}
// Usage:
ECDiffieHellmanCng key1 = new ECDiffieHellmanCng();
ECDiffieHellmanCng key2 = new ECDiffieHellmanCng();
byte[] data = Encoding.UTF8.GetBytes("TestTestTestTes");
byte[] nonce = Encoding.UTF8.GetBytes("whatever");
byte[] encryptedData = StaticStaticDiffieHellman.Encrypt(key1, key2.PublicKey, nonce, data);
Console.WriteLine(encryptedData.Length); // 16
byte[] decryptedData = StaticStaticDiffieHellman.Decrypt(key2, key1.PublicKey, nonce, encryptedData);
Console.WriteLine(Encoding.UTF8.GetString(decryptedData));
ECDiffieHellmanCNG is a derivation of the original Diffie-Hellman Key Exchange Protocol.
It is not intended for encrypting messages but rather calculating the same secret value on both ends.
Here is some information on ECDiffieHellmanCNG and its purpose.