Получение пары открытый / ключевой из ключевой фразы

После ответа, доступного здесь: 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
    }
}

Игнорируя тот факт, что возвращаемый тип не собирается делать ничего полезного, большая проблема, с которой я сталкиваюсь, заключается в том, что я не могу найти асимметричного криптографического провайдера, которому я мог бы либо засеять, либо предоставить генератор засеянных чисел.

Я делаю это, поэтому мне не нужно нигде хранить закрытый ключ, это соображение безопасности и помогает в переносимости, поскольку ключи могут быть получены на любой машине с одним и тем же паролем (и солью, которая изначально уникальна и случайна. ).


person Clint    schedule 26.09.2015    source источник


Ответы (1)


После некоторой охоты я решил остановиться на генерации случайной пары ключей 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 может шифровать только данные меньшего размера , чем размер ключа

В моей новой схеме:

  1. Идентификатор пользователя - это открытый ключ RSA и закрытый ключ RSA, зашифрованный с помощью AES путем получения ключа AES с использованием пароля и соли.
  2. Encrypting data involves:
    1. Generating a random AES key
    2. Шифрование данных с помощью этого ключа AES
    3. Создание подписи RSA для зашифрованных данных с использованием закрытого ключа RSA отправителя
    4. Доступ к данным предоставляется RSA, шифруя случайный ключ AES с открытым ключом RSA цели.

Это позволяет мне хранить всю основную информацию:

  1. Открытый ключ
  2. Поваренная соль
  3. Вектор инициализации
  4. Зашифрованный закрытый ключ

в основном там, где я хочу, потому что пароль нужен, чтобы действительно взломать закрытый ключ.

Расшифровка тоже относительно проста:

  1. Получать входящие данные
  2. RSA сверяет его с открытым ключом RSA предполагаемого отправителя.
  3. Расшифровать закрытый ключ RSA получателя из производного пароля + солевого ключа AES
  4. Расшифровать ключ доступа (встроенный / размещенный ключ AES)
  5. Расшифровать полученные данные с помощью предоставленного ключа
person Clint    schedule 26.09.2015