I've been reading on different cryptography algorithms and I came across the "Diffie Hellman Cryptography Next Generation". I've made a lot of searches about this algorithm and I have found that it is an Asymmetric cryptography system which is in some ways rivaling RSA. I had a look at the .Net's System.Security.Cryptography and I found it provides Diffie-Hellman cryptography as well. So I wen't to MSDN and there I found a very nice example on how to use it in C#, but this example has brought some questions into my mind. Let me copy some part of the code first: (I don't post the full code as my question is mainly about this part)
public static byte[] alicePublicKey;
public static void Main(string[] args)
{
using (ECDiffieHellmanCng alice = new ECDiffieHellmanCng())
{
alice.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
alice.HashAlgorithm = CngAlgorithm.Sha256;
alicePublicKey = alice.PublicKey.ToByteArray();
Bob bob = new Bob();
CngKey k = CngKey.Import(bob.bobPublicKey, CngKeyBlobFormat.EccPublicBlob);
byte[] aliceKey = alice.DeriveKeyMaterial(CngKey.Import(bob.bobPublicKey, CngKeyBlobFormat.EccPublicBlob));
byte[] encryptedMessage = null;
byte[] iv = null;
Send(aliceKey, "Secret message", out encryptedMessage, out iv);
bob.Receive(encryptedMessage, iv);
}
}
private static void Send(byte[] key, string secretMessage, out byte[] encryptedMessage, out byte[] iv)
{
using (Aes aes = new AesCryptoServiceProvider())
{
aes.Key = key;
iv = aes.IV;
// Encrypt the message
using (MemoryStream ciphertext = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ciphertext, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] plaintextMessage = Encoding.UTF8.GetBytes(secretMessage);
cs.Write(plaintextMessage, 0, plaintextMessage.Length);
cs.Close();
encryptedMessage = ciphertext.ToArray();
}
}
}
}
When I look at this, I see that it is the AES that is doing everything, and the ECDiffieHellman is only responsible for providing a key for the AES algorithm. In the meanwhile it itself is based on the SHA256 hashing system.
So my question is, what exactly is this "ECDiffieHellmanCng" doing in this case? What I see is a hybrid cryptography system, one for key exchange and the other for the encryption, this has conflict with what I've read over the internet about this Diffie Hellman algorithm, most sources list it under Asymmetric encryption systems but this example is not showing the same thing. I say this because when I look the AliceKey I see that, it is made based on a Public Key that has been probably made using SHA256 and it itself is not encrypting/ decryption anything.
What you have stumbled upon is actually the "cryptographic development platform" called "Cryptography Next Generation" developed by Microsoft. From a cryptographic point of view there is nothing revolutionary or "next gen" in there, just a new library implementing or wrapping known cryptographic algorithms.
Diffie-Hellman is one of the oldest and most respected asymmetric cryptographic algorithms available to us. It allows two parties to exchange a private key in such a way that a passive eavesdropper of their communication cannot deduce the exchanged key. As such Diffie-Hellman is an important building block for many cryptographic protocols. It's not an encryption algorithm though. After the private key has been deduced by the two parties they still have to use a symmetric algorithm to encrypt their following communication.
This is not unique to Diffie-Hellman though, every asymmetric algorithm is used with many symmetric algorithms to build a working and secure protocol. RSA for example only allows you to use encrypt 256 bytes at a time with a 2048bit key. And for security purposes you should never user raw RSA to encrypt data. I've described one combination to use RSA securely to encrypt arbitrary data in this answer.
Elliptic Curve Diffie-Hellman is a variant of the classic Diffie-Hellman that uses an other mathematical structure - an elliptic curve - as a foundation together with the same fundamental idea behind Diffie-Hellman. It has gained some attention lately as it considerable faster than the classic variant while achieving the same security level.
Related
Recently we done a static security scan using Veracode on one of the applications.
The report indicate an issue
Use of a Broken or Risky Cryptographic Algorithm (CWE ID 327)
It is shown for following code snippet
byte[] CalculateHash(byte[] publicKey) {
SHA1CryptoServiceProvider hashGenerator = new SHA1CryptoServiceProvider();
Byte[] hashInArray = new Byte[32];
PrivateKey.CopyTo(hashInArray,0); // Combine public key and private key
publicKey.CopyTo(hashInArray,16);
return hashGenerator.ComputeHash(hashInArray); // Calculate hash
}
In description it describe SHA1 as a weak algorithm.
I modified the code and used SHA256 instead of SHA1 and performed veracode scanning again but it still show same issue.
What is an alternative for this? any suggestions?
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 tried to encrypt a string with System.Security.Cryptography.DES but I found that every time I run The program the result of encryption changed !
I don't know how to get the same result each time I run the application ? IS there constant key or anything else to add to get the same result ?
I want when I enter "google" in this code
byte[] plaintextBytes = (new UnicodeEncoding()).GetBytes(expireddate);
SymmetricAlgorithm sa = DES.Create();
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, sa.CreateEncryptor(), CryptoStreamMode.Write);
csEncrypt.Write(plaintextBytes, 0, plaintextBytes.Length);
csEncrypt.Close();
byte[] encryptedTextBytes = msEncrypt.ToArray();
get "google" from this code when I entered the result of array of bytes in next time i opened the application ?
MemoryStream msDecrypt = new MemoryStream(decodedlistbyte.ToArray());
CryptoStream csDecrypt = new CryptoStream(msDecrypt, sa.CreateDecryptor(), CryptoStreamMode.Read);
byte[] decryptedTextBytes = new Byte[decodedlistbyte.Count];
csDecrypt.Read(decryptedTextBytes, 0, decodedlistbyte.Count);
csDecrypt.Close();
msDecrypt.Close();
string decrypteddate = (new UnicodeEncoding()).GetString(decryptedTextBytes);
You are generating a cryptographically secure IV (initialization vector) each time you re-encrypt the plain text - this is good, and the value should change each time. The IV can be kept public and should in no way relate to the encryption key.
However Des is not a very secure algorithm any more and I would recommend switching to Rijndael or tripple des.
I recommend you use a strong symmetric key algorithm such as AES (i.e. Rijndael). Have a look at the RijndaelManaged class in .NET. The same key can be used for encryption and decryption, which is why it's a symmetric algorithm. The security of the key is vital, so keep it private and store it securely.
Like #Ross said the encrypted string will be different because a new IV should be used each time.
However you current code is using a new Key and IV each time. If you want to be able to decrypt on another computer then you should set the Key and IV yourself - or keep the one automagically produced while encrypting.
E.g. when encrypting
byte[] key = sa.Key;
byte[] iv = sa.IV;
ICryptoTransform ct = sa.CreateEncryptor ();
E.g. while decrypting (on another computer)
ICryptoTransform ct = sa.CreateDecryptor (key, iv);
You can transmit the IV with the encrypted data. The secret key should, of course, be transmitted/shared out-of-band.
Your problem isn't that he cipher text is different. This is actually an important property of an encryption scheme.
Your problem is either that you are reusing the same symmetric algorithm object without reseting its state or -- more likely, but I can't tell from the snippet, -- reintegrating the symmetric algorithm with a different key and iv.
For decrypt, generate a new symmetric algorithm and then set sa.Key and sa.IV to be the values used in the one you encrypted with. Important, make sure you store the key securely and make sure your IV is random ( you will need to include it in the data you store). Don't hardcode the IV. That is completely insecure.
By the way, DES is rather insecure ( I could try all possible keys in about 3 days 10 years ago). Use AESManaged. Also, crypto is hard and I don't recommend you do it yourself. If you do want to , consider looking at this, it does most of what you want and a little more.
I am trying to use the RSACryptoServiceProvider to encrypt/decrypt. Encrypting works fine, but the Decrypt method throws an exception with the message:
Unknown Error '80007005'.
This is the code:
Byte[] plainData = encoding.GetBytes(plainText);
Byte[] encryptedData;
RSAParameters rsap1;
Byte[] decryptedData;
using (RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider())
{
encryptedData = rsa1.Encrypt(plainData, false);
rsap1 = rsa1.ExportParameters(false);
}
using (RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider())
{
rsa2.ImportParameters(rsap1);
decryptedData = rsa2.Decrypt(encryptedData, false);
}
decryptedText = encoding.GetString(decryptedData, 0, decryptedData.Length);
Is anyone aware of a workaround?
Thanks!
Fixed the code! I guess I do not need to specify a container after all...
Byte[] plainData = encoding.GetBytes(plainText);
Byte[] encryptedData;
Byte[] decryptedData;
using (RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider())
{
RSAParameters rsap1 = rsa1.ExportParameters(false);
using (RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider())
{
rsa2.ImportParameters(rsap1);
encryptedData = rsa2.Encrypt(plainData, false);
}
decryptedData = rsa1.Decrypt(encryptedData, false);
}
decryptedText = encoding.GetString(decryptedData, 0, decryptedData.Length);
rsap1 = rsa1.ExportParameters(false);
By passing false to this method, you're choosing to not export the private key. Without the private key it will be difficult to decrypt the data. Try passing true to the export method.
When using RSA you need to understand the basics of key management. You did not specify what key container to use during encryption. What key do you expect to be used? The default user key? The machine key? Do you understand what the default user key and the machine keys are ? Not to mention the obvious question of why do you encrypt anything with RSA? RSA encryption is used solely for encrypting session keys, and there are dedicated key exchange protocols that take care of this out-of-the-box (stream oriented like TLS or document oriented like S/MIME). You should use one of these out-of-the-box protocols and not roll your own encryption scheme. You will screw up key management, that is guaranteed.
When you attempt to decrypt, does the decryptor has possession of the private key corresponding to the public key used during encryption?
See:
How to: Store Asymmetric Keys in a Key Container
Encrypting Data
Decrypting Data
Note that these are just simple code samples in MSDN and should never be used by anyone without a very deep understanding of cryptography, and specially key management.
I recommend you look into using a high level class like SslStream for encrypting data exchanges. For a document storage encryption scheme you better use the OS facilities or rely on ProtectedData class. Again, do not roll your own encryption unless you really know what you're doing (in which case you wouldn't be asking questions here).
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