I'm writing a register form for a application but still having problems with being new to c#.
I am looking to encrypt/hash passwords to md5 or sha-256, preferably sha-256.
Any good examples? I want it to be able to take the information from "string password;" and then hash it and store in the variable "string hPassword;". Any ideas?
Don't use a simple hash, or even a salted hash. Use some sort of key-strengthening technique like bcrypt (with a .NET implementation here) or PBKDF2 (with a built-in implementation).
Here's an example using PBKDF2.
To generate a key from your password...
string password = GetPasswordFromUserInput();
// specify that we want to randomly generate a 20-byte salt
using (var deriveBytes = new Rfc2898DeriveBytes(password, 20))
{
byte[] salt = deriveBytes.Salt;
byte[] key = deriveBytes.GetBytes(20); // derive a 20-byte key
// save salt and key to database
}
And then to test if a password is valid...
string password = GetPasswordFromUserInput();
byte[] salt, key;
// load salt and key from database
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
byte[] newKey = deriveBytes.GetBytes(20); // derive a 20-byte key
if (!newKey.SequenceEqual(key))
throw new InvalidOperationException("Password is invalid!");
}
You're going to want to use the System.Security.Cryptography namespace; specifically, the MD5 class or the SHA256 class.
Drawing a bit from the code on this page, and with the knowledge that both classes have the same base class (HashAlgorithm), you could use a function like this:
public string ComputeHash(string input, HashAlgorithm algorithm)
{
Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);
return BitConverter.ToString(hashedBytes);
}
Then you could call it like this (for MD5):
string hPassword = ComputeHash(password, new MD5CryptoServiceProvider());
Or for SHA256:
string hPassword = ComputeHash(password, new SHA256CryptoServiceProvider());
Edit: Adding Salt Support
As dtb pointed out in the comments, this code would be stronger if it included the ability to add salt. If you're not familiar with it, salt is a set of random bits that are included as an input to the hashing function, which goes a long way to thwart dictionary attacks against a hashed password (e.g., using a rainbow table). Here's a modified version of the ComputeHash function that supports salt:
public static string ComputeHash(string input, HashAlgorithm algorithm, Byte[] salt)
{
Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
// Combine salt and input bytes
Byte[] saltedInput = new Byte[salt.Length + inputBytes.Length];
salt.CopyTo(saltedInput, 0);
inputBytes.CopyTo(saltedInput, salt.Length);
Byte[] hashedBytes = algorithm.ComputeHash(saltedInput);
return BitConverter.ToString(hashedBytes);
}
Hope this has been helpful!
You should always salt the password before hashing when storing them in the database.
Recommended database columns:
PasswordSalt : int
PasswordHash : binary(20)
Most posts you find online will talk about ASCII encoding the salt and hash, but that is not needed and only add unneeded computation. Also if you use SHA-1, then the output will only be 20 bytes so your hash field in the database only needs to be 20 bytes in length. I understand your asking about SHA-256, but unless you have a compelling reason, using SHA-1 with a salt value will be sufficient in most business practices. If you insist on SHA-256, then the hash field in the database needs to be 32 bytes in length.
Below are a few functions that will generate the salt, compute the hash and verify the hash against a password.
The salt function below generates a cryptographically strong salt as an Integer from 4 cryptographically created random bytes.
private int GenerateSaltForPassword()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] saltBytes = new byte[4];
rng.GetNonZeroBytes(saltBytes);
return (((int)saltBytes[0]) << 24) + (((int)saltBytes[1]) << 16) + (((int)saltBytes[2]) << 8) + ((int)saltBytes[3]);
}
The password can then be hashed using the salt with the function below. The salt is concatenated to the password and then the hash is computed.
private byte[] ComputePasswordHash(string password, int salt)
{
byte[] saltBytes = new byte[4];
saltBytes[0] = (byte)(salt >> 24);
saltBytes[1] = (byte)(salt >> 16);
saltBytes[2] = (byte)(salt >> 8);
saltBytes[3] = (byte)(salt);
byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(password);
byte[] preHashed = new byte[saltBytes.Length + passwordBytes.Length];
System.Buffer.BlockCopy(passwordBytes, 0, preHashed, 0, passwordBytes.Length);
System.Buffer.BlockCopy(saltBytes, 0, preHashed, passwordBytes.Length, saltBytes.Length);
SHA1 sha1 = SHA1.Create();
return sha1.ComputeHash(preHashed);
}
Checking the password can be done simply by computing the hash and then comparing it to the expected hash.
private bool IsPasswordValid(string passwordToValidate, int salt, byte[] correctPasswordHash)
{
byte[] hashedPassword = ComputePasswordHash(passwordToValidate, salt);
return hashedPassword.SequenceEqual(correctPasswordHash);
}
TL;DR use Microsoft.AspNetCore.Cryptography.KeyDerivation, implementing PBKDF2 with SHA-512.
The good idea to get started with password hashing is to look at what OWASP guidelines say. The list of recommended algorithms includes Argon2, PBKDF2, scrypt, and bcrypt. All these algorithms can be tuned to adjust the time it takes to hash a password, and, correspondingly, the time to crack it via brute-force. All these algorithms utilize salt to protect from rainbow tables attacks.
Neither of these algorithms is terribly weak, but there are some differences:
bcrypt has been around for almost 20 years, has been widely used and
has withstood the test of time. It is pretty resistant to GPU
attacks, but not to FPGA
Argon2 is the newest addition, being a winner of 2015 Password hashing competition. It has better protection against GPU and FPGA attacks, but is a bit too recent to my liking
I don't know much about scrypt. It has been designed to thwart GPU- and FPGA- accelerated attacks, but I've heard it turned out to be not as strong as originally claimed
PBKDF2 is a family of algorithms parametrized by the different hash
functions. It does not offer a specific protection against GPU or ASIC attacks, especially if a weaker hash function like SHA-1 is used, but it is, however, FIPS-certified if it matters to you, and still acceptable if the number of iterations is large enough.
Based on algorithms alone, I would probably go with bcrypt, PBKDF2 being the least favorable.
However, it's not the full story, because even the best algorithm can be made insecure by a bad implementation. Let's look at what is available for .NET platform:
Bcrypt is available via bcrypt.net. They say the implementation is based on Java jBCrypt. Currently there are 6 contributors and 8 issues (all closed) on github. Overall, it looks good, however, I don't know if anyone has made an audit of the code, and it's hard to tell whether an updated version will be available soon enough if a vulnerability is found. I've heard Stack Overflow moved away from using bcrypt because of such reasons
Probably the best way to use Argon2 is through bindings to the
well-known libsodium library, e.g.
https://github.com/adamcaudill/libsodium-net. The idea is that
the most of the crypto is implemented via libsodium, which has considerable
support, and the 'untested' parts are pretty limited. However, in
cryptography details mean a lot, so combined with Argon2 being
relatively recent, I'd treat it as an experimental option
For a long time, .NET had a built-in an implementation of PBKDF2 via
Rfc2898DeriveBytes class. However, the implementation can only use SHA-1 hash function, which is deemed too fast to be secure nowadays
Finally, the most recent solution is
Microsoft.AspNetCore.Cryptography.KeyDerivation package
available via NuGet. It provides PBKDF2 algorithm with SHA-1, SHA-256, or SHA-512 hash functions, which is considerably better than Rfc2898DeriveBytes. The biggest advantage here is that the implementation is supplied by Microsoft, and while I cannot properly assess cryptographic diligence of Microsoft developers versus BCrypt.net or libsodium developers, it just makes sense to trust it because if you are running a .NET application, you are heavily relying on Microsoft already. We might also expect Microsoft to release updates if security issues are found. Hopefully.
To summarize the research up to this point, while PBKDF2 might be the least preferred algorithm of the four, the availability of Microsoft-supplied implementation trumps that, so the reasonable decision would be to use Microsoft.AspNetCore.Cryptography.KeyDerivation.
The recent package at the moment targets .NET Standard 2.0, so available in .NET Core 2.0 or .NET Framework 4.6.1 or later. If you use earlier framework version, it is possible to use the previous version of the package, 1.1.3, which targets .NET Framework 4.5.1 or .NET Core 1.0. Unfortunately, it is not possible to use it in even earlier versions of .NET.
The documentation and the working example is available at learn.microsoft.com. However, do not copy-paste it as it is, there are still decisions a developer needs to make.
The first decision is what hash function to use. Available options include SHA-1, SHA-256, and SHA-512. Of those, SHA-1 is definitely too fast to be secure, SHA-256 is decent, but I would recommend SHA-512, because supposedly, its 64-bit operations usage makes it harder to benefit from GPU-based attacks.
Then, you need to choose the password hash output length and the salt length. It doesn't make sense to have output longer than the hash function output (e.g. 512 bits for SHA-512), and it would probably be the most secure to have it exactly like that. For the salt length, opinions differ. 128 bits should be enough, but in any case, the length longer than the hash output length surely doesn't provide any benefits.
Next, there is an iteration count. The bigger it is, the harder password hashes are to crack, but the longer it takes to log users in. I'd suggest to choose it so the hashing takes 0.25 - 1 seconds on the typical production system, and in any case, it should not be less than 10000.
Normally, you would get bytes array as salt and hash values. Use Base64 to convert them to strings. You can opt to use two different columns in the database, or combine salt and password in one column using a separator which is not encountered in Base64.
Don't forget to devise a password hashing storage in a way that allows to seamlessly move to a better hashing algorithm in future.
If you are going to be storing the hashed passwords, use bcrypt instead of SHA-256. The problem is that SHA-256 is optimized for speed, which makes it easier for a brute force attack on passwords should someone get access to your database.
Read this article: Enough With The Rainbow Tables: What You Need To Know About Secure Password Schemes and this answer to a previous SO question.
Some quotes from the article:
The problem is that MD5 is fast. So are its modern competitors, like SHA1 and SHA256. Speed is a design goal of a modern secure hash, because hashes are a building block of almost every cryptosystem, and usually get demand-executed on a per-packet or per-message basis.
Speed is exactly what you don’t want in a password hash function.
Finally, we learned that if we want to store passwords securely we have three reasonable options: PHK’s MD5 scheme, Provos-Maziere’s Bcrypt scheme, and SRP. We learned that the correct choice is Bcrypt.
PBKDF2 is using HMACSHA1.......if you want more modern HMACSHA256 or HMACSHA512 implementation and still want key stretching to make the algorithm slower I suggest this API: https://sourceforge.net/projects/pwdtknet/
Here is a full implementation of a persistence unaware SecuredPassword class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public class SecuredPassword
{
private const int saltSize = 256;
private readonly byte[] hash;
private readonly byte[] salt;
public byte[] Hash
{
get { return hash; }
}
public byte[] Salt
{
get { return salt; }
}
public SecuredPassword(string plainPassword)
{
if (string.IsNullOrWhiteSpace(plainPassword))
return;
using (var deriveBytes = new Rfc2898DeriveBytes(plainPassword, saltSize))
{
salt = deriveBytes.Salt;
hash = deriveBytes.GetBytes(saltSize);
}
}
public SecuredPassword(byte[] hash, byte[] salt)
{
this.hash = hash;
this.salt = salt;
}
public bool Verify(string password)
{
if (string.IsNullOrWhiteSpace(password))
return false;
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
byte[] newKey = deriveBytes.GetBytes(saltSize);
return newKey.SequenceEqual(hash);
}
}
}
And tests:
public class SecuredPasswordTests
{
[Test]
public void IsHashed_AsExpected()
{
var securedPassword = new SecuredPassword("password");
Assert.That(securedPassword.Hash, Is.Not.EqualTo("password"));
Assert.That(securedPassword.Hash.Length, Is.EqualTo(256));
}
[Test]
public void Generates_Unique_Salt()
{
var securedPassword = new SecuredPassword("password");
var securedPassword2 = new SecuredPassword("password");
Assert.That(securedPassword.Salt, Is.Not.Null);
Assert.That(securedPassword2.Salt, Is.Not.Null);
Assert.That(securedPassword.Salt, Is.Not.EqualTo(securedPassword2.Salt));
}
[Test]
public void Generates_Unique_Hash()
{
var securedPassword = new SecuredPassword("password");
var securedPassword2 = new SecuredPassword("password");
Assert.That(securedPassword.Hash, Is.Not.Null);
Assert.That(securedPassword2.Hash, Is.Not.Null);
Assert.That(securedPassword.Hash, Is.Not.EqualTo(securedPassword2.Hash));
}
[Test]
public void Verify_WhenMatching_ReturnsTrue()
{
var securedPassword = new SecuredPassword("password");
var result = securedPassword.Verify("password");
Assert.That(result, Is.True);
}
[Test]
public void Verify_WhenDifferent_ReturnsFalse()
{
var securedPassword = new SecuredPassword("password");
var result = securedPassword.Verify("Password");
Assert.That(result, Is.False);
}
[Test]
public void Verify_WhenRehydrated_AndMatching_ReturnsTrue()
{
var securedPassword = new SecuredPassword("password123");
var rehydrated = new SecuredPassword(securedPassword.Hash, securedPassword.Salt);
var result = rehydrated.Verify("password123");
Assert.That(result, Is.True);
}
[Test]
public void Constructor_Handles_Null_Password()
{
Assert.DoesNotThrow(() => new SecuredPassword(null));
}
[Test]
public void Constructor_Handles_Empty_Password()
{
Assert.DoesNotThrow(() => new SecuredPassword(string.Empty));
}
[Test]
public void Verify_Handles_Null_Password()
{
Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(null));
}
[Test]
public void Verify_Handles_Empty_Password()
{
Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(string.Empty));
}
[Test]
public void Verify_When_Null_Password_ReturnsFalse()
{
Assert.That(new SecuredPassword("password").Verify(null), Is.False);
}
}
The System.Security.Cryptography.SHA256 class should do the trick:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256.aspx
Please use this as i have the same issues before but could solve it will the litle code snippet
public static string ComputeHash(string input, HashAlgorithm algorithm, Byte[] salt)
{
Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
// Combine salt and input bytes
Byte[] saltedInput = new Byte[salt.Length + inputBytes.Length];
salt.CopyTo(saltedInput, 0);
inputBytes.CopyTo(saltedInput, salt.Length);
Byte[] hashedBytes = algorithm.ComputeHash(saltedInput);
StringBuilder hex = new StringBuilder(hashedBytes.Length * 2);
foreach (byte b in hashedBytes)
hex.AppendFormat("{0:X2}", b);
return hex.ToString();
}
Related
I am trying to encrypt a string passing the same parameters, but each time it produces the same result.
Currently, each time I call Encrypt("testing"), I am getting an output of "pvsLPLnR3fI=". However, I require the output to be different even if the parameters are the same. For example, calling Encrypt("testing") 3 times could produce output of:
pvsLPLnR3fI=
nR3fIasweds=
PHQHasfdevw=
The method I use to encrypt is as follows:
private const string mysecurityKey = "MyTestSampleKey";
public static string Encrypt(string TextToEncrypt)
{
byte[] MyEncryptedArray = UTF8Encoding.UTF8.GetBytes(TextToEncrypt);
MD5CryptoServiceProvider MyMD5CryptoService = new MD5CryptoServiceProvider();
byte[] MysecurityKeyArray = MyMD5CryptoService.ComputeHash(UTF8Encoding.UTF8.GetBytes(mysecurityKey));
MyMD5CryptoService.Clear();
var MyTripleDESCryptoService = new TripleDESCryptoServiceProvider();
MyTripleDESCryptoService.Key = MysecurityKeyArray;
MyTripleDESCryptoService.Mode = CipherMode.ECB;
MyTripleDESCryptoService.Padding = PaddingMode.PKCS7;
var MyCrytpoTransform = MyTripleDESCryptoService.CreateEncryptor();
byte[] MyresultArray = MyCrytpoTransform.TransformFinalBlock(MyEncryptedArray, 0, MyEncryptedArray.Length);
MyTripleDESCryptoService.Clear();
return Convert.ToBase64String(MyresultArray, 0, MyresultArray.Length);
}
You're getting the same result each time because there are no elements of the operation that are changing - you're using the same key and the same plaintext with the same algorithm. This is expected under the ECB mode of operation.
ECB is inherently insecure, so changing the mode to something like GCM (or CBC if you cannot) will both solve your original problem and improve the security immensely.
Be aware that MD5 and TripleDES are both poor choices for new software - consider using AES with a KDF that isn't a message digest, like Argon2 or PBKDF2.
I suggest you review the code examples in this repository for examples of secure, modern encryption.
I am generating an ID for use in my application, where users can connect to each other. for identification I am using an ID, sort of like teamviewer. I want it to both be unique and cryptographically secure/hard to guess. So I have generated a GUID, as well as 8 bytes of secure data, and simply concatenated them. My question is how secure is this ID specifically against brute force attacks? Example of an ID: dKNqrkHImQ9A9ulu8DOvYDLS3x2U8k0d
My code:
public static string MakeBase64ID()
{
int postkeylength = 8; //bytes
byte[] prekey = CreateCryptographicallySecureGuid().ToByteArray();
byte[] postkey = CryptoRandomByteArr(postkeylength);
byte[] ID = new byte[prekey.Length + postkeylength];
Array.Copy(prekey, ID, prekey.Length);
Array.Copy(postkey, 0, ID, prekey.Length, postkey.Length);
return Convert.ToBase64String(ID);
}
public static Guid CreateCryptographicallySecureGuid()
{
return new Guid(CryptoRandomByteArr(16));
}
public static byte[] CryptoRandomByteArr(int length)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buffer = new byte[length];
rng.GetBytes(buffer);
return buffer;
}
It contains 64 bits of cryptographic randomness. It depends on the brute forcing speed how secure this is. If it's done at 1 million attempts per second you need 2^64/1e6/86400/365=584942 years. That is very secure.
If the brute forcing has to go through the internet then the speed probably drops to 100 attempts per second as well.
64 bits are more secure than most passwords.
I like this scheme from a practical standpoint as well. This is a good system to generate IDs that cannot be guessed.
I looked up msdn and other resources on how to do this but i came up with no clear solutions. This is the best i found http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx?Redirected=true
I would like to hash passwords in C# using either bcrypt or PBKDF2 (which appears to be bcrypt related). I like to experiment with how many rounds it takes for my computer to hash a password. However everything seems to be about encrypting while everyone talks about hashing. I can't figure it out. How do i hash a password? It looks more like PBKDF2 (Rfc2898?) is a random number generator and i use GetBytes(amount) to choose how big my hash size is.
I'm confused. How exactly do i hash a password with bcrypt/PBKDF?
PBKDF2
You were really close actually. The link you have given shows you how you can call the Rfc2898DeriveBytes function to get PBKDF2 hash results. However, you were thrown off by the fact that the example was using the derived key for encryption purposes (the original motivation for PBKDF1 and 2 was to create "key" derivation functions suitable for using as encryption keys). Of course, we don't want to use the output for encryption but as a hash on its own.
You can try the SimpleCrypto.Net library written for exactly this purpose if you want PBKDF2. If you look at the implementation, you can see that it is actually just a thin wrapper around (you guessed it) Rfc2898DeriveBytes.
BCrypt
You can try the C# implementation named (what else) BCrypt.NET if you want to experiment with this variant.
Disclaimer: I have not used or tested any of the libraries that I have linked to... YMMV
First of all, I urge everyone to use a cryptographically verified reference algorithm included with the platform itself.
Do not use 3rd party packages and non-verified OSS components or any other code you just copy-pasted from the Internet.
For .NET use PBKDF2 and not bCrypt because there's no certified implementation of bCrypt for .NET
I don't mean any disrespect for any noble open-source devs (being one myself), but you can never be sure their website won't be hacked in 10 years and you end up getting a malware package from Nuget/npm or other package managers.
More info about verification can be found in this SO answer
Now, back to PBKDF2, here's the simple code
public static byte[] PBKDF2Hash(string input, byte[] salt)
{
// Generate the hash
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(input, salt, iterations: 5000);
return pbkdf2.GetBytes(20); //20 bytes length is 160 bits
}
If you need a string representation of the hash (not byte-array) - you can use this superfast conversion class from this answer http://stackoverflow.com/a/624379/714733
It took me forever (days it took days) to find what to actually code to get hashed passwords to work!! so I put it here for convenience.
You do need to read the documentation and theory1 theory2 and then some or you could be open to security loopholes. Security is a very big topic! Buyer Beware!
Add the NuGet Package BCrypt.Net to the solution
const int WorkFactor = 14;
var HashedPassword = BCrypt.Net.BCrypt.HashPassword(Password, WorkFactor);
You should adjust the WorkFactor to what is appropriate see discussions. Its a log2 function
"The number is log2, so every time computers double in speed, add 1 to the default number."
Then you store the hashed password in your db as passwordFromLocalDB and to test an incoming password like this:
if (BCrypt.Net.BCrypt.Verify(password, passwordFromLocalDB) == true)
Good Luck!
EDIT: As pointed out by #MikeT, the original link and code I posted is no longer considered best practice for hashing passwords to be stored in a datastore.
This article by Scott Brady illustrates how to use PasswordHasher, and also how to use the interface to develop stronger hashing implementations.
So applying the byte-level hashing function yourself is not required any more, but it you want to see how it's done this article explores the PasswordHasher<T> implementation:
Exploring the ASP.NET Core Identity PasswordHasher
A relevant piece of code from the article is shown below:
private static byte[] HashPasswordV2(string password, RandomNumberGenerator rng)
{
const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA1; // default for Rfc2898DeriveBytes
const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes
const int Pbkdf2SubkeyLength = 256 / 8; // 256 bits
const int SaltSize = 128 / 8; // 128 bits
// Produce a version 2 text hash.
byte[] salt = new byte[SaltSize];
rng.GetBytes(salt);
byte[] subkey = KeyDerivation.Pbkdf2(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength);
var outputBytes = new byte[1 + SaltSize + Pbkdf2SubkeyLength];
outputBytes[0] = 0x00; // format marker
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, Pbkdf2SubkeyLength);
return outputBytes;
}
Original answer:
Microsoft has a page up with sample code using PBKDF2 for anyone using .Net Core:
Hash passwords in ASP.NET Core
From the article:
using System;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
public class Program
{
public static void Main(string[] args)
{
Console.Write("Enter a password: ");
string password = Console.ReadLine();
// generate a 128-bit salt using a secure PRNG
byte[] salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");
// derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA1,
iterationCount: 10000,
numBytesRequested: 256 / 8));
Console.WriteLine($"Hashed: {hashed}");
}
}
/*
* SAMPLE OUTPUT
*
* Enter a password: Xtw9NMgx
* Salt: NZsP6NnmfBuYeJrrAKNuVQ==
* Hashed: /OOoOer10+tGwTRDTrQSoeCxVTFr6dtYly7d0cPxIak=
*/
Earlier this year I was looking into the same thing for creating hashes for our ASP.NET Web Forms project, I wanted to do it the same way MVC projects do it out of the box.
I stumbled upon this question => ASP.NET Identity default Password Hasher, how does it work and is it secure?
Then I found the source with the ByteArraysEqual method here => http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-rtm-140327/Release/Default/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core/Crypto.cs?ImageName=Microsoft.AspNet.Identity.Core
i was interested in an answers that didn't involve any libraries.
I read this article https://crackstation.net/hashing-security.htm which links an implementation in different languages C# among them which i will link here too
https://github.com/defuse/password-hashing/blob/master/PasswordStorage.cs
interestingly it uses Rfc2898DeriveBytes as mentioned a few times here.
private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes){
using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt)) {
pbkdf2.IterationCount = iterations;
return pbkdf2.GetBytes(outputBytes);
}
}
For PBKDF2, you might be able to use System.Security.Cryptography.Rfc2898DeriveBytes.
See MSDN here: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx
PBKDF2 uses HMACSHA1, if you would like a more modern and customisable solution you should look at this API using HMACSHA256 or 512 with key stretching just like PBKDF2
https://sourceforge.net/projects/pwdtknet/
Sample GUI included in source code demonstrated how to get a hash from a password including the creation of crypto random salt.....enjoy :)
PBKDF2
In the example in http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx, when you get to the line "Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1,
myIterations);", k1 is the hash. The reason the example is for encryption is that Rfc2898DeriveBytes was originally designed to create encryption keys.
If you do not provide a salt, Rfc2898DeriveBytes will create it's own, but I do not know whether RNGCryptoServiceProvider does a better job of being cryptographically random.
According to OWASP (https://www.owasp.org/index.php/Using_Rfc2898DeriveBytes_for_PBKDF2), the underlying use of SHA1 by Rfc2898DeriveBytes means it's only good for hashes up to 160 bits in length. If you create a longer hash, an attacker still only has to worry about the first 160 bits, but you have made password hashing/authentication more expensive for yourself with no gain.
Here's some example code for Rfc2898DeriveBytes password hashing (store the hash, salt and iterations in the DB):
public class Rfc2898PasswordEncoder
{
private int _byteLength = 160 / 8; // 160 bit hash length
public class EncodedPassword
{
public byte[] Hash { get; set; }
public byte[] Salt { get; set; }
public int Iterations { get; set; }
}
public EncodedPassword EncodePassword(string password, int iterations)
{
var populatedPassword = new EncodedPassword
{
Salt = CreateSalt(),
Iterations = iterations
};
// Add Hash
populatedPassword.Hash = CreateHash(password, populatedPassword.Salt, iterations);
return populatedPassword;
}
public bool ValidatePassword(string password, EncodedPassword encodedPassword)
{
// Create Hash
var testHash = CreateHash(password, encodedPassword.Salt, encodedPassword.Iterations);
return testHash == encodedPassword.Hash;
}
public byte[] CreateSalt()
{
var salt = new byte[_byteLength]; // Salt should be same length as hash
using (var saltGenerator = new RNGCryptoServiceProvider())
{
saltGenerator.GetBytes(salt);
}
return salt;
}
private byte[] CreateHash(string password, byte[] salt, long iterations)
{
byte[] hash;
using (var hashGenerator = new Rfc2898DeriveBytes(password, salt, (int)iterations))
{
hash = hashGenerator.GetBytes(_byteLength);
}
return hash;
}
}
I am completely new to cryptography and I need to sign a byte array of 128 bytes with an RSA key i have generated with C sharp. The key must be 1024 bits.
I have found a few examples of how to use RSA with C sharp and the code I'm currently trying to use is:
public static void AssignParameter()
{
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "SpiderContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
rsa = new RSACryptoServiceProvider(cspParams);
rsa.KeySize = 1024;
}
public static string EncryptData(string data2Encrypt)
{
AssignParameter();
StreamReader reader = new StreamReader(path + "publickey.xml");
string publicOnlyKeyXML = reader.ReadToEnd();
rsa.FromXmlString(publicOnlyKeyXML);
reader.Close();
//read plaintext, encrypt it to ciphertext
byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
return Convert.ToBase64String(cipherbytes);
}
This code works fine with small strings (and thus short byte arrays) but when I try this with a string of 128 characters I get an error saying:
CryptographicException was unhandled: Wrong length
(OK, it might not precisely say 'Wrong length', I get the error in danish, and that is 'Forkert længde' which directly translates to 'Wrong length').
Can anyone tell me how I can encrypt a byte array of 128 bytes with a RSA key of 1024 bits in C sharp?
Thanks in advance,
LordJesus
EDIT:
Ok, just to clarify things a bit: I have a message, from which i make a hash using SHA-256. This gives a 32 byte array. This array is padded using a custom padding, so it ends up being a 128 byte array. This padded hash should then be signed with my private key, so the receiver can use my public key to verify that the message received is the same as the message sent. Can this be done with a key of 1024 bits?
If you want to sign you do not want to encrypt. Signatures and encryption are distinct algorithms. It does not help that there is a well-known signature algorithm called RSA, and a well-known asymmetric encryption algorithm also called RSA, and that the signature algorithm was first presented (and still is in many places) as "you encrypt with the private key". This is just plain confusing.
In RSA encryption, the data to encrypt (with the public key) must be padded with what PKCS#1 (the RSA standard) describes as "Type 2 padding", and the result (which has the same length than the modulus) is then processed through the modular exponentiation which is at the core of RSA (at the core, but RSA is not only a modular exponentiation; the padding is very important for security).
When signing, the data to sign must be hashed, then the hash value is embedded in a structure which describes the hash function which was just used, and the encoded structure is itself padded with a "Type 1 padding" -- not the same padding than the padding for encryption, and that's important, too.
Either way, a normal RSA engine will perform the type 1 or type 2 padding itself, and most RSA signature engines will also handle themselves the structure which identifies the used hash function. A RSA signature engine such as RSACryptoServiceProvider can work either with SignHash(), which expects the hash value (the 32 bytes obtained from SHA-256, without any kind of encapsulating structure or type 1 padding -- RSACryptoServiceProvider handles that itself), or SignData(), which expects the data to be signed (the engine then does the hash computation too).
To sum up, if you do any kind of padding yourself, then you are doing it wrong. If you used Encrypt() to compute a signature, then you are doing it wrong, too.
The minimum key size for encrypting 128 bytes would be 1112 bits, when you are calling Encrypt with OAEP off. Note that setting the key size like this rsa.KeySize = 1024 won't help, you need to actually generate they key of the right size and use them.
This is what worked for me:
using System;
using System.IO;
using System.Security.Cryptography;
namespace SO6299460
{
class Program
{
static void Main()
{
GenerateKey();
string data2Encrypt = string.Empty.PadLeft(128,'$');
string encrypted = EncryptData(data2Encrypt);
string decrypted = DecryptData(encrypted);
Console.WriteLine(data2Encrypt);
Console.WriteLine(encrypted);
Console.WriteLine(decrypted);
}
private const string path = #"c:\";
public static void GenerateKey()
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1112);
string publickKey = rsa.ToXmlString(false);
string privateKey = rsa.ToXmlString(true);
WriteStringToFile(publickKey, path + "publickey.xml");
WriteStringToFile(privateKey, path + "privatekey.xml");
}
public static void WriteStringToFile(string value, string filename)
{
using (FileStream stream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(value);
writer.Flush();
stream.Flush();
}
}
public static string EncryptData(string data2Encrypt)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
StreamReader reader = new StreamReader(path + "publickey.xml");
string publicOnlyKeyXML = reader.ReadToEnd();
rsa.FromXmlString(publicOnlyKeyXML);
reader.Close();
//read plaintext, encrypt it to ciphertext
byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
byte[] cipherbytes = rsa.Encrypt(plainbytes,false);
return Convert.ToBase64String(cipherbytes);
}
public static string DecryptData(string data2Decrypt)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
StreamReader reader = new StreamReader(path + "privatekey.xml");
string key = reader.ReadToEnd();
rsa.FromXmlString(key);
reader.Close();
byte[] plainbytes = rsa.Decrypt(Convert.FromBase64String(data2Decrypt), false);
return System.Text.Encoding.UTF8.GetString(plainbytes);
}
}
}
Note however, that I'm not using a crypto container, and thus, I don't need your AssignParameter, but if you need to use it, modifying the code should be easy enough.
If you ever need to encrypt large quantities of data (much larger than 128 bytes) this article has sample code on how to do this.
Apparently, according to this question — how to use RSA to encrypt files (huge data) in C# — RSA can only encrypt data shorter than its key length.
Bizarre. The MSDN docs for`RSACryptoServiceProvider.Encrypt() say that a CryptographicException may be thrown if the length of the rgb parameter is greater than the maximum allowed length.
Well. That seems odd, especially since there doesn't seem to be much in the way of documentation regarding said maximum.
A little further digging, under Remarks has this:
The following table describes the padding supported by different versions
of Microsoft Windows and the maximum length of rgb allowed by the different
combinations of operating systems and padding.
If you are running XP or later and you're using OAEP padding, then the limit is stated to be
Modulus size -2 -2*hLen, where hLen is the size of the hash
No idea what the "size of the hash" might be, since the docs, AFAICS, don't mention "hash" anywhere except in regards to digital signatures.
If you are running Windows 2000 or later with the "high encryption pack" installed (again, no idea how you find that out), then the limit is stated to be
Modulus size - 11. (11 bytes is the minimum padding possible.)
Otherwise (Windows 98, Millenium or Windows 2000 or later without the aforementioned "high encryption pack" then you get "Direct Encryption and OAEP padding not supported", where the limitation is
The maximum size allowed for a symmetric key.
Say...wait a second... RSA is an asymmetric algorithm, right?
Worthless documentation. Sheesh.
See http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.encrypt.aspx. The exception thrown is probably "The length of the rgb parameter is greater than the maximum allowed length."
Usually RSA encryption has padding, and since your encrypted data size goes to the key size, there is no space for padding. Try to use longer key or less data size to encrypt.
Do you real need the custom padding? If not you could just use RSACryptoServiceProvider.SignData Method
In C# how we can use SHA1 automatically?Is SHA1 better than MD5?(We use hashing for user name and password and need speed for authentication)
Not sure what you mean by automatically, but you should really use SHA256 and higher. Also always use a Salt (code) with your hashes. A side note, after time has passed, using hardened hashes is far better than using a plain speed-based hashing function. I.e.: hashing over a few hundred iterations, or using already proven hashing functions such as bcrypt (which is mentioned below I believe). A code sample for using a SHA256 hash function in .NET is as follows:
byte[] data = new byte[DATA_SIZE];
byte[] result;
using(SHA256 shaM = new SHA256Managed()) {
result = shaM.ComputeHash(data);
}
Will do the trick for you using SHA256 and is found at MSDN.
Sidenote on the "cracking" of SHA1: Putting the cracking of SHA-1 in perspective
SHA1 is stronger than MD5 so if you have the choice it would be better to use it. Here's an example:
public static string CalculateSHA1(string text, Encoding enc)
{
byte[] buffer = enc.GetBytes(text);
SHA1CryptoServiceProvider cryptoTransformSHA1 = new SHA1CryptoServiceProvider();
return BitConverter.ToString(cryptoTransformSHA1.ComputeHash(buffer)).Replace("-", "");
}
Both are too fast to be used, directly at least. Use Key Strengthening to "slow down" the password hashing procedure. Speed is the unfortunately the enemy to password security.
How slow is slow enough? Slowing down a password hash from ~microseconds to ~hundreds of milliseconds will not adversely affect the perceived performance of your application... but will make cracking passwords literally a hundred thousand times slower.
View this article for details:
http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
The problem is that MD5 is fast. So are its modern competitors, like SHA1 and SHA256. Speed is a design goal of a modern secure hash, because hashes are a building block of almost every cryptosystem, and usually get demand-executed on a per-packet or per-message basis.
Speed is exactly what you don’t want in a password hash function.
... snip ...
The password attack game is scored in time taken to crack password X. With rainbow tables, that time depends on how big your table needs to be and how fast you can search it. With incremental crackers, the time depends on how fast you can make the password hash function run.
That said, use BCrypt. SCrypt was recently developed, but I doubt that any stable (or production ready) libraries exist for it yet. Theoretically, SCrypt claims to improve upon BCrypt. "Building your own" is not recommended, but iterating MD5 / SHA1 / SHA256 thousands of times ought to do the trick (ie: Key Strengthening).
And in case you don't know about them, be sure to read up on Rainbow Tables. Basic security stuff.
From MSDN
byte[] data = new byte[DATA_SIZE];
byte[] result;
SHA1 sha = new SHA1CryptoServiceProvider();
// This is one implementation of the abstract class SHA1.
result = sha.ComputeHash(data);
use SHA1 or SHA2 The MD5 algorithm is problematic.
http://userpages.umbc.edu/~mabzug1/cs/md5/md5.html
http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5%28v=vs.85%29.aspx
I'd like use these things.
MD5, SHA1/256/384/512 with an optional Encoding parameter.
Othere HashAlgorithms.Thanks to Darin Dimitrov.
public static string MD5Of(string text)
{
return MD5Of(text, Encoding.Default);
}
public static string MD5Of(string text, Encoding enc)
{
return HashOf<MD5CryptoServiceProvider>(text, enc);
}
public static string SHA1Of(string text)
{
return SHA1Of(text, Encoding.Default);
}
public static string SHA1Of(string text, Encoding enc)
{
return HashOf<SHA1CryptoServiceProvider>(text, enc);
}
public static string SHA384Of(string text)
{
return SHA384Of(text, Encoding.Default);
}
public static string SHA384Of(string text, Encoding enc)
{
return HashOf<SHA384CryptoServiceProvider>(text, enc);
}
public static string SHA512Of(string text)
{
return SHA512Of(text, Encoding.Default);
}
public static string SHA512Of(string text, Encoding enc)
{
return HashOf<SHA512CryptoServiceProvider>(text, enc);
}
public static string SHA256Of(string text)
{
return SHA256Of(text, Encoding.Default);
}
public static string SHA256Of(string text, Encoding enc)
{
return HashOf<SHA256CryptoServiceProvider>(text, enc);
}
public static string HashOf<TP>(string text, Encoding enc)
where TP: HashAlgorithm, new()
{
var buffer = enc.GetBytes(text);
var provider = new TP();
return BitConverter.ToString(provider.ComputeHash(buffer)).Replace("-", "");
}
MD5 is better in performance and SHA1 is better for security. You can get an idea from this comparison