Как хранить ключ, используемый для шифрования файлов - PullRequest
9 голосов
/ 16 января 2012

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

В настоящее время я использую .NET Framework для шифрования.Я использую класс RijndaelManaged для шифрования / дешифрования и класс PasswordDeriveBytes для получения ключа.

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

Ответы [ 4 ]

14 голосов
/ 17 января 2012

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

Что касается вашего вопроса - API защиты данных (DPAPI), который упоминает Гаурав, является вашим лучшим выбором для Windows. Как: использовать защиту данных

DPAPI предлагает ProtectedMemory и ProtectedData .Первый позволяет защищать секреты в памяти, а второй обеспечивает защиту секретов, сохраненных на диске.API заботится о шифровании и дешифровании для вас и (в зависимости от указанной области) будет защищать ваши данные от доступа / дешифрования другими пользователями или на других компьютерах.

Чтобы использовать DPAPI в вашем сценарии, я 'рекомендую взять пароль пользователя, сгенерировать симметричный ключ шифрования (например, PasswordDeriveBytes ), сохранить его с использованием DPAPI и ограничить доступ для текущего пользователя.

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

Недостатком может быть то, что вредоносное приложение, также выполненное тем же пользователем, потенциально может получитьсекретный ключ.Чтобы защитить от этого сценария, в Protect & Unprotect необходимо указать дополнительную энтропию (фактически, соль).Однако реализация этого, скорее всего, отклонится от вашей цели - потому что теперь вам нужно будет предложить пользователю что-то, что выглядит ужасно похоже на пароль.

Также: интересное чтение:

Вы также можете найти этот пост в Backblaze интересным чтением.Хотя они не объясняют, как они поддерживают ваш сценарий (зашифрованные загрузки, которые провайдер облака не может расшифровать - только то, что они предлагают такую ​​услугу): http://blog.backblaze.com/2008/11/12/how-to-make-strong-encryption-easy-to-use/

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

PS: Не торопитесь, чтобы отметить приемлемые ответы.Сообщество вознаградит вас.

4 голосов
/ 16 января 2012

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

Вы также можете разрешить Windows (на самом деле CryptoAPI) защитить ключ с помощью CspParameters (и правильных флагов) с RSACryptoServiceProvider. В зависимости от ваших флагов у вас может быть ключ, который будет доступен для зарегистрированного пользователя (таким образом, он получает столь же безопасный как пароль для входа пользователя).

1 голос
/ 17 января 2012

DPAPI был разработан для решения этой проблемы.

0 голосов
/ 09 сентября 2014

Я согласен с предложением DPAPI.Вот некоторый код, чтобы продемонстрировать, как использовать класс ProtectedData.Это не совсем уместно для вашего точного сценария, но вы можете экстраполировать.

byte[] GetEncryptionKey()
{
    var path = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
        AppDomain.CurrentDomain.FriendlyName,
        "nothing interesting... move along",
        "top secret encryption key");

    Debug.WriteLine("Encryption Key File: " + path);

    var file = new FileInfo(path);
    if (!file.Directory.Exists)
        file.Directory.Create();

    // determine if current user of machine
    // or any user of machine can decrypt the key
    var scope = DataProtectionScope.CurrentUser;

    // make it a bit tougher to decrypt 
    var entropy = Encoding.UTF8.GetBytes("correct horse battery staple :)");

    if (file.Exists)
    {
        return ProtectedData.Unprotect(
            File.ReadAllBytes(path), entropy, scope);       
    }

    // generate key
    byte[] key;
    using(var rng = RNGCryptoServiceProvider.Create())
        key = rng.GetBytes(1024);

    // encrypt the key
    var encrypted = ProtectedData.Protect(key, entropy, scope);

    // save for later use   
    File.WriteAllBytes(path, encrypted);

    return key;
}
...