Reputation: 6220
Following the answer available here: https://crypto.stackexchange.com/questions/1662/how-can-one-securely-generate-an-asymmetric-key-pair-from-a-short-passphrase
I've started down the following path:
public static void DeriveKeyPair(string pass, byte[] salt)
{
using (var derived = new Rfc2898DeriveBytes(pass, salt, 10000))
{
var randomNum = new Random(BitConverter.ToInt32(derived.GetBytes(4), 0));
// Can't seem to find an asymmetric implementation that I can supply the seed to
}
}
Ignoring the fact that the return type isn't going to do anything useful, the big problem I'm having is that I can't seem to find an asymmetric crypto provider that I can either seed, or provide the seeded number generator to.
I'm doing this so I don't have to store the private key anywhere, this is a security consideration and aids in portability as the keys can be derived on any machine provided the same password (and salt - which is initially unique and random).
Upvotes: 2
Views: 1297
Reputation: 6220
After some hunting around I decided to settle upon generating a random RSA key-pair, and then symmetrically encrypting the private key using AES.
This leads me to the two following methods:
public static byte[] EncryptData(string pass, byte[] salt, byte[] encryptedPrivateKey, byte[] targetPublicKey,
byte[] iv, byte[] data)
{
using (var rfc = new Rfc2898DeriveBytes(pass, salt, IterationCount))
{
using (var aes = new AesCryptoServiceProvider())
{
aes.KeySize = AesKeySize;
aes.Key = rfc.GetBytes(aes.KeySize / 8);
aes.IV = iv;
using (var dec = aes.CreateDecryptor(aes.Key, aes.IV))
{
using (var ms = new MemoryStream(encryptedPrivateKey))
{
using (var cs = new CryptoStream(ms, dec, CryptoStreamMode.Read))
{
var privKey = new byte[RsaKeySize];
cs.Read(privKey, 0, privKey.Length);
return RsaEncrypt(targetPublicKey, data);
}
}
}
}
}
}
public static byte[] DecryptData(string pass, byte[] salt, byte[] encryptedPrivateKey, byte[] iv, byte[] data)
{
using (var rfc = new Rfc2898DeriveBytes(pass, salt, IterationCount))
{
using (var aes = new AesCryptoServiceProvider())
{
aes.KeySize = AesKeySize;
aes.Key = rfc.GetBytes(aes.KeySize/8);
aes.IV = iv;
using (var dec = aes.CreateDecryptor(aes.Key, aes.IV))
{
using (var ms = new MemoryStream(encryptedPrivateKey))
{
using (var cs = new CryptoStream(ms, dec, CryptoStreamMode.Read))
{
var privKey = new byte[RsaKeySize];
cs.Read(privKey, 0, privKey.Length);
return RsaDecrypt(privKey, data);
}
}
}
}
}
}
Essentially, RSA can only encrypt data that's smaller than the key size
In my new scheme:
This allows me to store all the core information:
pretty much where I want, because the password is needed to actually crack the private key.
Decrypting is relatively simple too:
Upvotes: 2