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?
Related
I am facing cryptographic security issue which has noted by Veracode. Kindly check below and help me out from this.
System.Security.Cryptography.MD5CryptoServiceProvider crypthandler =
new System.Security.Cryptography.MD5CryptoServiceProvider();
MD5 is considered an insecure or 'broken' hashing function. Assuming you're getting a CWE 327 (Use of a Broken or Risky Cryptographic Algorithm) you can fix this by updating to the SHA-2 family of hash functions.
I would recommend SHA-256, SHA-384, or SHA-512 for future proofing.
Example:
using (SHA512CryptoServiceProvider crypthandler = new SHA512CryptoServiceProvider())
{
...
}
Use of a Broken or Risky Cryptographic Algorithm (CWE ID 327)
Description
The use of a broken or risky cryptographic algorithm is an unnecessary risk that may result in the disclosure of
sensitive information.
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
SHA512CryptoServiceProvider hashmd5 = new SHA512CryptoServiceProvider();
Ref below link:
http://bestanswers.in/2016/06/30/fix-veracode-flaw-cwe-id-327-use-broken-risky-cryptographic-algorithm/
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.
Ive been having some Crypto troubles cant see find what I've done wrong. I'm trying to encrypt an AESkey using RSA on Android and Decrypt it server side using C#, but keep getting a "Bad Data" exception.
I used Base64encoding to move the encrypted key from client to server and noticed that after moving it from the client(Android App) using a JSON POST request there were a number of "\u000a" in the key making the encrypted data length 941 which led to a "Data to large for decryption" when removed in brought the length to 920 which allowed for 80 8 byte iterations and got me to where I am now with the Bad Data problem.
I have checked that the key Length and Algorithm are correct and both are set for 2048 bit key and using PKCS1Padding.
"Bad Data" Exception
This exception will be thrown in the following scenarios.
a) The RSA private key used for decryption does not match with the RSA public key that is used for encryption.
b) The binary data passed in to Decrypt() method is incorrect. This could happen if the application code made assumptions about the length of encrypted data or the data passed in does not match the exact bytes that is returned from Encrypt() method.
I get the public key on android by pulling it from the server with a GET which returns RSACryptoServiceProvider.ToXMLString(false); And use the same keystore for the private key so cant see it being 1.
And as far as I know the c# decrypter Isn't making any assumptions about the size of the encrypted data. Possibly my setting block size to 8 but thats after i knew the size of the encrypted AESkey.
I've been looking around for a solution and couldn't find one so would be grateful for any assistance. Apologies if I'm being stupid and missed something simple but I have my blinkers on if I am and just cant see it.
Java Encryption
private byte[] encryptRSA(byte [] data) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
//instance of singleton PublicKey
AppPublicKey currKey = AppPublicKey.getInstance();
Log.d("ENCRYPT.MOD: ", currKey.getModBytes().toString());
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(new BigInteger(1,currKey.getModBytes()), new BigInteger(1,currKey.getExpBytes()));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
Log.d("RSAENCRYPTION: ",Base64.encodeToString(cipherData, 1));
return cipherData;
}
C# Decrypt
public string DecryptString(string inputString, int dwKeySize)
{
// TODO: Add Proper Exception Handlers
CspParameters cp = new CspParameters();
cp.KeyContainerName = "real_Keystore";
RSACryptoServiceProvider rsaCryptoServiceProvider
= new RSACryptoServiceProvider(dwKeySize,cp);
int base64BlockSize = 8;
int iterations = inputString.Length / base64BlockSize;
ArrayList arrayList = new ArrayList();
for (int i = 0; i < iterations; i++)
{
byte[] encryptedBytes = Convert.FromBase64String(
inputString.Substring(base64BlockSize * i, base64BlockSize));
//Array.Reverse(encryptedBytes);
arrayList.AddRange(rsaCryptoServiceProvider.Decrypt(
encryptedBytes, false));
}
return Encoding.UTF32.GetString(arrayList.ToArray(
Type.GetType("System.Byte")) as byte[]);
}
It is not possible to feed a few bytes at a time to the RSA operation.
Furthermore it seems unlikely that the code performs the right amount of base 64 iterations (as you defined NO_PADDING for base 64 in your android, using 1 instead of the constant). Normally the output of RSA encryption won't be a multiple of 3 bytes, so you are at least one block off the mark.
You may want to take a closer look at the API functions you are using and take some time to study RSA examples on .NET. Normally RSA is only used to encrypt small amounts of data (such as symmetric data encryption keys) so you should be able to decode all of the base64 data in one go.
Please test your input and output in a debugger. Encryption/decryption problems normally require that the exact input and output of the encryption/decryption algorithms are compared .
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
A bit more background info as suggested:
I'm finsihing of an Intranet CMS web app where I have to use the products API (ASP.NET based). Because of time constraints and issues with Windows authen' I need another way to ensure staff do not need to re login everytime they visit the site to view personalised content. The way it works is that once a user logs in (username/password), a Session ID storing a new different Security context value is generated that is used to display the personalised content. The API login method called uses the username and password as parameters. The only way I can think of automatically logging in the next time the staff visits the site is by storing the password in a enrypted cookie and checking of its existing when the site is visited and then calling the API login method using the username and decrypted password cookie values.
Any other ideas as an alternative welcomed.
Mo
Hi,
I'm using some code found on the web to encrypt and decrypt a password string. It encrypts fine but when it calls the code below to decrypt the string it throws the error "Length of the data to decrypt is invalid" How can I resolve this?
Thanks in advance.
Mo
System.Text.Encoding enc = System.Text.Encoding.ASCII;
byte[] myByteArray = enc.GetBytes(_pword);
SymmetricAlgorithm sa = DES.Create();
MemoryStream msDecrypt = new MemoryStream(myByteArray);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, sa.CreateDecryptor(), CryptoStreamMode.Read);
byte[] decryptedTextBytes = new Byte[myByteArray.Length];
csDecrypt.Read(decryptedTextBytes, 0, myByteArray.Length);
csDecrypt.Close();
msDecrypt.Close();
string decryptedTextString = (new UnicodeEncoding()).GetString(decryptedTextBytes);
A couple of things here...
You shouldn't encrypt passwords usually. You should hash them.
If you decide to continue down the road of encryption..
You are using the DES algorithm. This is considered insecure and flawed. I'd recommend looking at the AES algorithm.
Depending on how much data you are working with, the CryptoStream might be overkill.
Using the ASCII encoding can cause loss of data that isn't ASCII, like Cyrillic letters. The recommended fix is to use something else, like UTF8.
Here is an example:
string text = "Hello";
using (var aes = new AesManaged())
{
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
byte[] encryptedBytes;
using (var encrypt = aes.CreateEncryptor())
{
encryptedBytes = encrypt.TransformFinalBlock(bytes, 0, bytes.Length);
}
byte[] decryptedBytes;
using (var decrypt = aes.CreateDecryptor())
{
decryptedBytes = decrypt.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
}
var decryptedText = System.Text.Encoding.UTF8.GetString(decryptedBytes);
Console.Out.WriteLine("decryptedText = {0}", decryptedText);
}
This will use a random key every time. It is likely that you will need to encrypt some data, then decrypt it at a later time. When you create the AesManaged object, you can store the Key and IV property. You can re-use the same Key if you'd like, but different data should always be encrypted with a different IV (Initialization Vector). Where you store that key, is up to you. That's why hashing might be a better alternative: there is no key, and no need to worry about storing the key safely.
If you want to go down the hashing route, here is a small example:
var textToHash = "hello";
using (SHA1 sha = new SHA1Managed())
{
var bytesToHash = System.Text.Encoding.UTF8.GetBytes(textToHash);
var hash = sha.ComputeHash(bytesToHash);
string base64hash = Convert.ToBase64String(hash);
}
This uses the SHA1 algorithm, which should work fine for passwords, however you may want to consider SHA256.
The concept is simple: a hash will produce a (mostly) unique output for an input, however the output cannot be converted back to the input - it's destructive. Whenever you want to check if a user should be authenticated, check hash the password they gave you, and check it against the hash of the correct password. That way you aren't storing anything sensitive.
I've actually had this error before and it took me 3 days to figure out the solution. The issue will be the fact that the machine key you need for descryption needs to be registered on your machine itself.
Read fully up on DES encryption, it works by an application key, and a machine-level key. The error you're getting is likely because of the machine key missing.
Compare the bytes used to create the _pword string (in the encryption method) to the bytes retrieved with GetBytes. Probably you will notice a change in the data there.
To store the encrypted bytes, I think you should use Convert.ToBase64String and Convert.FromBase64String turn the encrypted password to/from a string.
I also do not see the code where you set the Key and IV. So I guess you are using a different key to encrypt and decrypt the password.
If the current Key property is null,
the GenerateKey method is called to
create a new random Key. If the
current IV property is null, the
GenerateIV method is called to create
a new random IV.
DES is a block based cipher - only certain lengths of buffers are valid. If I remember correctly, the block size for DES is 64 bits, so you need to ensure that your byte array is a multiple of 8 bytes long.
(That should fix your immediate problem, but I'd reference other peoples advice here - you really ought not to be using DES for any new code, and for passwords it's usually more appropriate to hash than to encrypt).