从密码导出 public / 密钥对

Deriving public / key pair from passphrase

按照此处提供的答案:https://crypto.stackexchange.com/questions/1662/how-can-one-securely-generate-an-asymmetric-key-pair-from-a-short-passphrase

我开始了以下路径:

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
    }
}

忽略 return 类型不会做任何有用的事实,我遇到的最大问题是我似乎无法找到我可以播种的非对称加密提供程序, 或将种子数生成器提供给。

我这样做是为了不必将私钥存储在任何地方,这是出于安全考虑并有助于便携性,因为密钥可以在提供相同密码(和 salt - 这最初是唯一且随机的)。

四处寻找之后,我决定决定生成随机 RSA 密钥对,然后使用 AES 对称加密私钥。

这使我想到以下两种方法:

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);
                    }
                }
            }
        }
    }
}

RSA 还不够。

本质上,RSA 只能加密更小的数据than the key size

在我的新方案中:

  1. 用户身份是 RSA public 密钥和一个 RSA 私钥,通过使用密码和盐
  2. 派生 AES 密钥,使用 AES 加密
  3. 加密数据涉及:
    1. 生成随机 AES 密钥
    2. 使用该 AES 密钥加密数据
    3. 使用发起者的RSA私钥生成加密数据的RSA签名
    4. 通过使用目标的 public RSA 密钥
    5. 加密随机 AES 密钥的 RSA 授予对数据的访问权限

这让我可以存储所有核心信息:

  1. Public键
  2. 初始化向量
  3. 加密私钥

几乎是我想要的,因为实际破解私钥需要密码。

解密也比较简单:

  1. 接收传入数据
  2. RSA 根据声称的发件人的 RSA public 密钥
  3. 对其进行验证
  4. 从派生密码 + salt AES 密钥解密接收方的 RSA 私钥
  5. 解密访问密钥(嵌入式/托管 AES 密钥)
  6. 使用提供的密钥解密收到的数据