FIPS validated algorithm to store passwords in a database? - c#

I am looking for a FIPS validated hash algorithm to store passwords in the database.
I did use the following code but I still get the error
This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms.
SHA1CryptoServiceProvider Testsha1 = new SHA1CryptoServiceProvider();
byte[] hashedBytes;
UTF8Encoding encoder = new UTF8Encoding();
hashed = Testsha1.ComputeHash(encoder.GetBytes(strPassword));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashed.Length; i++)
{
sbuilder.Append(hashed[i].ToString("x2"));
}
string Password = sb.ToString();

Plain SHA-1 should not be used to store passwords. PBKDF2 is a good choice. In .net you can use it with the Rfc2898DeriveBytes class. See https://security.stackexchange.com/questions/2131/reference-implementation-of-c-password-hashing-and-verification/2136#2136
You might need to change the underlying hash function to SHA-256. From what I remember SHA-1 isn't NIST approved.

Adding the following line in web.config under system.web section
<machineKey validationKey="AutoGenerate,IsolateApps" ecryptionKey="AutoGenerate,IsolateApps" validation="3DES" decryption="3DES"/>
solved my problem

I am looking for a FIPS validated hash algorithm to store passwords in the database.
Use one of the hashes from the SHA-2 family. For example, SHA256.
Do not use a managed class - they are not FIPS validated. Instead, use SHA256CryptoServiceProvider and friends.

Related

Key, salt and IV when using Rijndael encryption

I'm working on a website, where users are able to upload files. I want to encrypt these files, in case there is some kind of security breach where access is granted to them.
When the user wants to download their files, I decrypt directly to the HTTP(S) output stream.
The files are placed on disc, and a record for each is inserted in the website database with some additional data (file name, size, file path, IV and such).
I only have a basic understanding of how to use encryption and therefore have some questions.
I'm using Rfc2898DeriveBytes to generate the bytes for the encryption key. Is it okay to use this class? As far as I know it uses SHA1, which might no longer be secure?
Right now I'm using the same password and salt for each encryption, but a random IV each time. Should I also be randomizing the salt and keep it in the database along with the IV? Will this give additional security?
Should I be using a message authentication code (MAC)? The encrypted files themselves are only stored and never transferred, so I don't know if it's necessary.
I don't really know how to best store the encryption password. I don't want to include it in my website DLL, so I'll probably have it in a file on the server somewhere that isn't in my website folder. How else could I be doing this?
This is my code for encryption. Any obvious security flaws?
const int bufferSize = 1024 * 128;
Guid guid = Guid.NewGuid();
string encryptedFilePath = Path.Combine(FILE_PATH, guid.ToString());
byte[] rgbIV;
using (Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes("PASSWORD HERE", Encoding.ASCII.GetBytes("SALT HERE")))
{
byte[] rgbKey = deriveBytes.GetBytes(256 / 8);
using (FileStream decryptedFileStream = File.OpenRead(decryptedFilePath))
using (FileStream encryptedFileStream = File.OpenWrite(encryptedFilePath))
using (RijndaelManaged algorithm = new RijndaelManaged() { KeySize = 256, BlockSize = 128, Mode = CipherMode.CBC, Padding = PaddingMode.ISO10126 })
{
algorithm.GenerateIV();
rgbIV = algorithm.IV;
using (ICryptoTransform encryptor = algorithm.CreateEncryptor(rgbKey, rgbIV))
using (CryptoStream cryptoStream = new CryptoStream(encryptedFileStream, encryptor, CryptoStreamMode.Write))
{
int read;
byte[] buffer = new byte[bufferSize];
while ((read = decryptedFileStream.Read(buffer, 0, bufferSize)) > 0)
cryptoStream.Write(buffer, 0, read);
cryptoStream.FlushFinalBlock();
}
}
}
I'm using Rfc2898DeriveBytes to generate the bytes for the encryption key. Is it okay to use this class? As far as I know it uses SHA1, which might no longer be secure?
The recent efficient breakage of SHA-1 really only impacts collision resistance which is not needed for PBKDF2 (the algorithm behind Rfc2898DeriveBytes). See: Is PBKDF2-HMAC-SHA1 really broken?
Right now I'm using the same password and salt for each encryption, but a random IV each time. Should I also be randomizing the salt and keep it in the database along with the IV? Will this give additional security?
Maybe it will give additional security, but it certainly won't hurt to do this except if you add a bug. Source: Need for salt with IV
Should I be using a message authentication code (MAC)? The encrypted files themselves are only stored and never transferred, so I don't know if it's necessary.
Usually, a storage system has checks and procedures to prevent and fix data corruption. If you don't have that, then a MAC is a good way to check if the data was corrupted even if this didn't happen maliciously.
If the end user is supposed to receive the data, they can check the MAC themselves and make sure that nobody altered the ciphertext.
I don't really know how to best store the encryption password. I don't want to include it in my website DLL, so I'll probably have it in a file on the server somewhere that isn't in my website folder. How else could I be doing this?
As I understand, you actually want to hold the encryption/decryption key. Anything that you can do is really obfuscation and doesn't provide any actual security. An attacker might just use the same connection to the data storage as your usual code. At best, the attacker will be slowed down a little bit. At worst, they don't even notice that the data was encrypted, because the decryption happened transparently.
It is best to make sure that an attacker cannot get in. Go through the OWASP top 10 and try to follow the advice. Then you can do some security scanning with Nikto or hire a professional penetration tester.
This is my code for encryption. Any obvious security flaws?
Using PaddingMode.ISO10126 doesn't seem like a good idea. You should go with PKCS#7 padding. Source: Why was ISO10126 Padding Withdrawn?
Rfc2898DeriveBytes is essentially PBKDF2 which is NIST recommended.
IF you randomize the salt (a good security practice) would will have top supply it for decryption. A common way is to prefix the encrypted data with the salt and IV.
Yes, you should be using a Mac over the encrypted data and any prepended information such as above.
In order to provide suggestions on securing the encryption key more information on how the the encryption will be used.
Use PKCS#7 padding, sometimes the option is named PKCS#5 for historical reasons.

Veracode vulnerable Cryptographic issue

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/

Veracode Cryptography issue

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?

pbkdf2 computation not consistent between C# and JavaScript

Hi my question is I've Encrypted a password with crypto.pbkdf2 on windows azure server side Javascript I'm pretty sure that there is a public library which you can look up. The problem is I'm trying to encrypt the same password in C# on my system because I want the credentials to be universal but despite using Rfc2898DeriveBytes and the salt generated the first time I'm not able to get back to the same hashed password.
Thank you for your help :)
function hash(text, salt, callback) {
crypto.pbkdf2(text, salt, iterations, bytes, function(err, derivedKey){
if (err) { callback(err); }
else {
var h = new Buffer(derivedKey).toString('base64');
callback(null, h);
}
});
}
And the C# code:
byte[] salt = Convert.FromBase64String(user.salt);
using (var deriveBytes = new System.Security.Cryptography.Rfc2898DeriveBytes(password, salt, 1000))
{
byte[] newKey = deriveBytes.GetBytes(32);
// user is the user object drawn from the database in existence
if (Convert.ToBase64String(newKey).Equals(user.password))
{
FormsAuthentication.RedirectFromLoginPage(Request.Form["username"], false);
}
}
hex generated by C# = 3lRSQF5ImYlQg20CGFy2iGUpWfdP5TD0eq2cTHhLono=
hex generated by JS = w4PDh8K6YMKGwr3DgcObRsOsFFUgDMOJw5PCnkdAwrTCgcOOV8OCKMKFdcKRwrLCqMK2VA==
Salt generated by JS and used at both = /Ij0hgDsvAC1DevM7xkdGUVlozdCxXVd0lgfK2xEh2A=
All the above info is in base64 format
Another thing that might be useful
item.salt = new Buffer(crypto.randomBytes(bytes)).toString('base64'); crypto.pbkdf2(text, salt, iterations, bytes, function(err, derivedKey){
which means the JS function accepts a string
I want the credentials to be universal but despite using Rfc2898DeriveBytes and the salt generated the first time I'm not able to get back to the same hashed password.
The obvious stuff is hash algorithm, salt, and iteration count. Can you confirm (for both languages):
the hash algorithm
the salt
the iteration count
The non-obvious is the encoding of the password and possibly salt. I included the salt because its often stored as a string.
To keep it portable among languages, you should use UTF-8. That's because you could encounter a default encoding, a UTF16-BE, UTF16-LE or any number of other encoding.
In C#, the setup would be:
byte[] utf8_salt = Encoding.UTF8.GetBytes(salt);
byte[] utf8_pass = Encoding.UTF8.GetBytes(password);
You would then pass utf8_salt and utf8_pass to the PBKDF2 function.
I don't know how to do the same in Javascript.
Alright kids daddy has figured out the answer.. took long enough..
Buffer(encodedPassword, 'binary').toString('base64')
on Javascript side will suffice now the tutorial I looked at was clearly not accurate.. the 'binary' was missing.
Thank you all for the help :)
and happy new year

Error in C# encrypt code when decrypting!

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).

Categories