2016-11-16 12 views
1

Я работаю над реализацией SCrypt Csharp SCrypt в VS2015. Мне нужно зашифровать/дешифровать текстовые файлы, предназначенные для отправки в виде вложений электронной почты. Первоначально я использовал AES, но учитывая, что HMAC-SHA1 устарел, я решил использовать SCrypt для хэширования паролей. Однако SCrypt не раскрывает общедоступные методы для самого шифрования данных, так что имеет смысл передавать AES-пароль SCrypt, а затем использовать последнее для шифрования данных? Или, может быть, есть лучший подход?CryptSharp SCrypt реализация в C#

В этом случае, я бы себе представить, что-то вроде этого, но я должен был бы найти способ надежно рандомизации IV ...

private static Aes SetAes(string userName, string password) 
    {    
     var passBytes = Encoding.UTF8.GetBytes(password); 
     var saltBytes = Encoding.UTF8.GetBytes(userName); 
     var cost = 131072; // around 5 secs with block at 16(on Xeon 1241 v3) 
     var blockSize = 16; // 8 is default but might not suffice against modern GPUs(?) 
     var parallel = 1; 
     var maxThreads = (int?)null; 
     byte[] derivedKey = new byte[32]; // 256 bits 

     SCrypt.ComputeKey(passBytes, saltBytes, cost, blockSize, parallel, maxThreads, derivedKey);            

     Aes aes = new AesManaged(); 
     aes.Padding = PaddingMode.PKCS7;    
     aes.Key = derivedKey; 
     byte[] IV = new byte[16]; 
     Array.Copy(derivedKey, IV, 16); // how to reliably randomize the IV? 
     aes.IV = IV; 
     return aes; 
    } 

Тогда для шифрования файлов:

internal static void EncryptText(string text, string userName, string password, string file) 
    { 
     // omitting argument checks for readability 
     using (Aes aes = SetAes(userName, password)) 
     { 
      using (FileStream fileStream = new FileStream(file, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) 
      { 
       using (CryptoStream cryptoStream = new CryptoStream(fileStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) 
       {       
        BinaryFormatter bf = new BinaryFormatter(); 
        bf.Serialize(cryptoStream, text); // I'm using a class to wrap the text for serialization, not shown here for readability       
       } 
      } 
     } 
    } 

Несмотря на то, что это работает, я не уверен, что это имеет смысл, поэтому большое спасибо за понимание.

EDIT:

В соответствии с рекомендациями vcsjones, функция SetAes предпочел бы выглядеть, если я правильно понимаю:

private static Aes SetAes(string userName, string password, byte[] IV = null) 
    {    
     var passBytes = Encoding.UTF8.GetBytes(password); 
     var saltBytes = Encoding.UTF8.GetBytes(userName); 
     var cost = 131072; 
     var blockSize = 16; 
     var parallel = 1; 
     var maxThreads = (int?)null; 
     byte[] derivedKey = new byte[32]; 

     SCrypt.ComputeKey(passBytes, saltBytes, cost, blockSize, parallel, maxThreads, derivedKey);            

     Aes aes = new AesManaged(); 
     aes.Padding = PaddingMode.PKCS7;    
     aes.Key = derivedKey; 
     if (IV == null) // when encrypting, generate IV 
     { 
      RandomNumberGenerator rn = RandomNumberGenerator.Create(); 
      rn.GetBytes(aes.IV); 
     } 
     else aes.IV = IV; // when decrypting, read IV from file and pass it to aes through IV parameter for decryption          
     return aes; 
    } 
+0

Отредактировано для отражения рекомендаций vcsjones. – Frank

ответ

2

Однако Scrypt не предоставляет открытые методы для самого шифрования данных , так что имеет смысл передавать пароль хэш-кода SCrypt для AES

SCrypt - это функция деривации ключа, поэтому да , это приемлемая вещь.

как надежно рандомизировать IV?

Не используйте выход KDF в IV. IV должен быть случайным для AES-CBC, поэтому используйте RandomNumberGenerator.Create() для создания CSPRNG для IV. Использование выхода KDF как части IV фактически утечки ключа, поскольку IV хранится в открытом тексте.

IV в AES-CBC должно быть случайным, и его не следует использовать повторно. Не выводите его из пароля. Вам нужно где-то хранить IV. Поскольку похоже, что вы пытаетесь зашифровать файлы, вы можете просто захотеть включить IV в начале файла. IV не является секретом - все в порядке, если кто-то может его прочитать. Затем, когда придет время для дешифрования файла, прочитайте IV из файла, а затем расшифруйте все, что прошло после IV.

Я также рекомендовал бы вам MAC-файл, а также, так как прямо сейчас ваше приложение не authenticate the encryption.

+0

Много полезной информации, большое вам спасибо! – Frank