Does anyone know of a way to get a 256 bit key value generated from a pass phrase of any length? The encryption cannot be salted as the encrypted values need to be generated again and compared in the database. So a value must generate the same encrypted string each time it is encrypted.
Currently I'm using a 32 char key working on the possibly incorrect assumption this is 256 bits?
So, I would want 'the quick brown fox' to be converted to a suitable AES 256 bit key?
You can construct the Rfc2898DeriveBytes Class
with an arbitrary sized password and then derive a key of your desired size in this case, 256 bits (32 bytes):
private static byte[] CreateKey(string password, int keyBytes = 32)
{
const int Iterations = 300;
var keyGenerator = new Rfc2898DeriveBytes(password, Salt, Iterations);
return keyGenerator.GetBytes(keyBytes);
}
In order to produce a deterministic output (ie same input will produce the same output) you will need to hard-code the salt. The salt must be at least 8 bytes:
private static readonly byte[] Salt =
new byte[] { 10, 20, 30 , 40, 50, 60, 70, 80};
Probably the best way is to use PBKDF2 using SHA256 (which will generate 256 bit output) and a application specific salt & iteration count. You should be aware that using an application specific salt removed quite a lot of the protection from PBKDF2, so you may require additional protection to alleviate this issue. One method would be to make sure that the database is safe, and that a maximum amount of tries can be used.
You are correct in stipulating that a 32 char passphrase is not a 256 bit key. It does not contain enough entropy, and some bytes may not even have valid character representations.
public static string GenerateBitKey(int letterCount = 44)
{
// Get the number of words and letters per word.
int num_letters = letterCount;
// Make an array of the letters we will use.
char[] letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
// Make a random number generator.
Random rand = new Random();
// Make the words.
// Make a word.
string word = "";
for (int j = 1; j <= num_letters; j++)
{
// Pick a random number between 0 and 25
// to select a letter from the letters array.
int letter_num = rand.Next(0, letters.Length - 1);
// Append the letter.
word += letters[letter_num];
}
return word;
}
private static IBuffer GetMD5Hash(string key)
{
IBuffer bufferUTF8Msg = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf8);
HashAlgorithmProvider hashAlgorithmProvider = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
IBuffer hashBuffer = hashAlgorithmProvider.HashData(bufferUTF8Msg);
if (hashBuffer.Length != hashAlgorithmProvider.HashLength)
{
throw new Exception("There was an error creating the hash");
}
return hashBuffer;
}
#region Static
public static string GenerateKey(string password, int resultKeyLength = 68)
{
if (password.Length < 6)
throw new ArgumentException("password length must atleast 6 characters or above");
string key = "";
var hashKey = GetMD5Hash(password);
var decryptBuffer = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
var AES = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);
var symmetricKey = AES.CreateSymmetricKey(hashKey);
var encryptedBuffer = CryptographicEngine.Encrypt(symmetricKey, decryptBuffer, null);
key = CryptographicBuffer.EncodeToBase64String(encryptedBuffer);
string cleanKey = key.Trim(new char[] { ' ', '\r', '\t', '\n', '/', '+', '=' });
cleanKey = cleanKey.Replace("/", string.Empty).Replace("+", string.Empty).Replace("=", string.Empty);
key = cleanKey;
if(key.Length > resultKeyLength)
{
key = key.Substring(0, Math.Min(key.Length, resultKeyLength));
}
else if(key.Length == resultKeyLength)
{
return key;
}
else if (key.Length < resultKeyLength)
{
key = GenerateKey(key);
}
return key;
}
//Get the first 44 charaters for the AES Key and the remaining chars for AES IV
My version. I just wanted keys without a password.
public static string GenerateBitKey(int letterCount = 44)
{
// Get the number of words and letters per word.
int num_letters = letterCount;
// Make an array of the letters we will use.
char[] letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrsruvwxyz+".ToCharArray();
int lettersLength = letters.Length;
// Make a word.
string word = "";
//Use Cryptography to generate random numbers rather than Psuedo Random Rand
// Deliberate overkill here
byte[] randomBytes = new byte[num_letters*256];
List<int> rands = new List<int>();
do
{
using (System.Security.Cryptography.RNGCryptoServiceProvider rngCsp = new
System.Security.Cryptography.RNGCryptoServiceProvider())
{
// Fill the array with a random value.
rngCsp.GetBytes(randomBytes);
}
// Truncate the set of random bytes to being in range 0 .. (lettersLength-1)
// Nb Using mod of randomBytes will reduce entropy of the set
foreach (var x in randomBytes)
{
if (x < lettersLength)
rands.Add((int)x);
if (rands.Count()==num_letters)
break;
}
}
while (rands.Count < letterCount);
int[] randsArray = rands.ToArray();
// Get random selection of characters from letters
for (int j = 0; j < num_letters; j++)
{
int letter_num = randsArray[j];
// Append the letter.
word += letters[letter_num];
}
return word;
}
您可以使用一些散列函数,从任意长度的输入提供256位输出,例如SHA256。
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.