2012-02-11 2 views
15

대용량 파일을 암호화하고 저장 한 다음 나중에 해독해야합니다. 그 일을하는 가장 좋은 방법은 무엇입니까? 나는 RSA 암호화가 비싸다고 들었고 RSA를 사용하여 AES 키를 암호화 한 다음 AES 키를 사용하여 대용량 파일을 암호화하는 것이 좋습니다. 예를 들어 어떤 제안이라도 좋을 것입니다.대용량 파일 암호화/암호 해독 (.NET)

+0

은 예입니다 [블로그 포스팅 (http://www.technical-recipes.com/2013/using-rsa-to- (Cryptographic-Large-data-files-in-c /)와 다운로드 할 수있는 [Visual Studio 2010 프로젝트] (http://www.technical-recipes.com/Downloads/crypt.7z)를 제공합니다. – AndyUK

답변

10

일반적으로 설명한 전략은 서버와 같은 한 컴퓨터에서 데이터를 암호화 한 다음 다른 컴퓨터 (클라이언트)에서 데이터를 해독 할 때 사용됩니다. 서버는 새로 생성 된 키로 대칭 키 암호화 (성능 향상 용)를 사용하여 데이터를 암호화하고이 대칭 키를 공개 키 (클라이언트의 개인 키와 일치)로 암호화합니다. 서버는 암호화 된 데이터와 암호화 된 대칭 키를 클라이언트에 보냅니다. 클라이언트는 개인 키로 대칭 키를 해독 한 다음 데이터 해독에이 대칭 키를 사용할 수 있습니다. 동일한 컴퓨터에서 데이터를 암호화 및 암호 해독하는 경우 다른 컴퓨터에 암호화 키를 전달하지 않으려는 것처럼 RSA 및 AES를 모두 사용하는 것이 좋습니다.

+1

고마워,하지만 내 문제는 약간 다르다. 대용량 파일을 암호화하고 저장하려고합니다. 저장소가 손상되는 경우 암호화 (즉, 보안)가 필요합니다. RSA로 암호화 된 AES 키를 보내는 클라이언트 서버 통신의 경우, 시나리오에서 어떻게 변환됩니까? 대칭 키 암호화 blob의 보류 중이거나 추가중인 바이트의 일부로 AES 키를 저장합니까? – kalrashi

+0

좋은 예가 실제로 X509Certificate2 MSDN Doc (RSACryptoProvider 및 관련 클래스를 찾고있었습니다)에 있습니다. – kalrashi

8

우리가 그것을 볼 때 우리 모두가 비싸다고 알고 있지만, 한 생물체는 큰 몸집이 크다. 윙크 윙크.

편집 2012년 2월 13일 :

하는 것은 당신이에있어 어디에 있는지 사용자 환경에서 다음과 같은 벤치마킹을 시도하는 코드가 업데이트되었습니다 내가 될 것 같은를 (눈에 보이지) 스마트와도 주목 들쭉날쭉 한 몇 가지 cut'n'paste 오류. Mea culpa. 당신은 RSA 같은 비대칭 암호화 들었다처럼

using System; 
using System.IO; 
using System.Security.Cryptography; 
using System.Text; 

... 

    // Rfc2898DeriveBytes constants: 
    public readonly byte[] salt = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Must be at least eight bytes. MAKE THIS SALTIER! 
    public const int iterations = 1042; // Recommendation is >= 1000. 

    /// <summary>Decrypt a file.</summary> 
    /// <remarks>NB: "Padding is invalid and cannot be removed." is the Universal CryptoServices error. Make sure the password, salt and iterations are correct before getting nervous.</remarks> 
    /// <param name="sourceFilename">The full path and name of the file to be decrypted.</param> 
    /// <param name="destinationFilename">The full path and name of the file to be output.</param> 
    /// <param name="password">The password for the decryption.</param> 
    /// <param name="salt">The salt to be applied to the password.</param> 
    /// <param name="iterations">The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption.</param> 
    public void DecryptFile(string sourceFilename, string destinationFilename, string password, byte[] salt, int iterations) 
    { 
     AesManaged aes = new AesManaged(); 
     aes.BlockSize = aes.LegalBlockSizes[0].MaxSize; 
     aes.KeySize = aes.LegalKeySizes[0].MaxSize; 
     // NB: Rfc2898DeriveBytes initialization and subsequent calls to GetBytes must be eactly the same, including order, on both the encryption and decryption sides. 
     Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt, iterations); 
     aes.Key = key.GetBytes(aes.KeySize/8); 
     aes.IV = key.GetBytes(aes.BlockSize/8); 
     aes.Mode = CipherMode.CBC; 
     ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV); 

     using (FileStream destination = new FileStream(destinationFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None)) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write)) 
      { 
       try 
       { 
        using (FileStream source = new FileStream(sourceFilename, FileMode.Open, FileAccess.Read, FileShare.Read)) 
        { 
         source.CopyTo(cryptoStream); 
        } 
       } 
       catch (CryptographicException exception) 
       { 
        if (exception.Message == "Padding is invalid and cannot be removed.") 
         throw new ApplicationException("Universal Microsoft Cryptographic Exception (Not to be believed!)", exception); 
        else 
         throw; 
       } 
      } 
     } 
    } 

    /// <summary>Encrypt a file.</summary> 
    /// <param name="sourceFilename">The full path and name of the file to be encrypted.</param> 
    /// <param name="destinationFilename">The full path and name of the file to be output.</param> 
    /// <param name="password">The password for the encryption.</param> 
    /// <param name="salt">The salt to be applied to the password.</param> 
    /// <param name="iterations">The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption.</param> 
    public void EncryptFile(string sourceFilename, string destinationFilename, string password, byte[] salt, int iterations) 
    { 
     AesManaged aes = new AesManaged(); 
     aes.BlockSize = aes.LegalBlockSizes[0].MaxSize; 
     aes.KeySize = aes.LegalKeySizes[0].MaxSize; 
     // NB: Rfc2898DeriveBytes initialization and subsequent calls to GetBytes must be eactly the same, including order, on both the encryption and decryption sides. 
     Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt, iterations); 
     aes.Key = key.GetBytes(aes.KeySize/8); 
     aes.IV = key.GetBytes(aes.BlockSize/8); 
     aes.Mode = CipherMode.CBC; 
     ICryptoTransform transform = aes.CreateEncryptor(aes.Key, aes.IV); 

     using (FileStream destination = new FileStream(destinationFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None)) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write)) 
      { 
       using (FileStream source = new FileStream(sourceFilename, FileMode.Open, FileAccess.Read, FileShare.Read)) 
       { 
        source.CopyTo(cryptoStream); 
       } 
      } 
     } 
    } 
+0

이 예제는 AES를 사용하여 만 암호화/해독합니다.RSA와 프로파일을 가지고 비슷한 것을 시도해보십시오. – kalrashi

+0

그것은 당신에게 달려 있습니다. 귀하의 질문은 데이터, 파일의 크기, 네트워크 전송 또는 관련 노출, 사용 가능한 처리 리소스 등에 대해 감지 된 위협을 설명하지 않았습니다. 이 경우 사용자 환경의 암호화 비용에 대한 벤치 마크 데이터를 적어도 수집하고 거기에서 작업하는 것이 좋습니다. 다른 사람들은 공개 키 대 개인 키 암호 및 다른 알고리즘의 상대적 강도에 대해 다루었습니다. – HABO

+2

"채우기가 유효하지 않으므로 제거 할 수 없습니다." 예외적으로, 암호화 측은'source.CopyTo (crytoStream); '다음에'source.FlushFinalBlock()'을 호출해야합니다. 그렇지 않으면 실제로 마지막 블록을 잘못 읽었을 것입니다. – DipSwitch

3

은 대칭 암호화 (예 : AES)보다 훨씬 느립니다하지만 는 장점 (예를 들어 보호하기 위해 하나의 개인 키 간단한 키 관리)의을 가지고있다.

키 (말장난 의도)는 다른 (많은 비밀 키와 느린 속도)의 불편 함을 무시하면서 두 가지 (비대칭 및 비대칭의 개인 키)의 장점을 사용하는 것입니다.

대용량 파일을 암호화하는 데 (훨씬 빠른) 사용되는 (대칭) 비밀 키를 암호화하기 위해 파일 당 한 번 RSA를 사용하면 성능상의 영향이 없습니다. 이 * 은 대칭 키을 래핑하므로 하나의 개인 키만 관리 할 수 ​​있습니다.

여기에 C#과 .NET 프레임 워크 (Microsoft of Mono)를 사용하여 예제를 제공하는 내 오래된 (그러나 여전히 true) blog post에 대한 링크가 있습니다. 이 도움이 될 수

+0

감사. 이 예는 상당히 도움이되었습니다. – kalrashi

10

/// Encrypts a file using Rijndael algorithm. 
///</summary> 
///<param name="inputFile"></param> 
///<param name="outputFile"></param> 
private void EncryptFile(string inputFile, string outputFile) 
{ 

    try 
    { 
     string password = @"myKey123"; // Your Key Here 
     UnicodeEncoding UE = new UnicodeEncoding(); 
     byte[] key = UE.GetBytes(password); 

     string cryptFile = outputFile; 
     FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create); 

     RijndaelManaged RMCrypto = new RijndaelManaged(); 

     CryptoStream cs = new CryptoStream(fsCrypt, 
      RMCrypto.CreateEncryptor(key, key), 
      CryptoStreamMode.Write); 

     FileStream fsIn = new FileStream(inputFile, FileMode.Open); 

     int data; 
     while ((data = fsIn.ReadByte()) != -1) 
      cs.WriteByte((byte)data); 


     fsIn.Close(); 
     cs.Close(); 
     fsCrypt.Close(); 
    } 
    catch 
    { 
     MessageBox.Show("Encryption failed!", "Error"); 
    } 
} 

/// 
/// Decrypts a file using Rijndael algorithm. 
///</summary> 
///<param name="inputFile"></param> 
///<param name="outputFile"></param> 
private void DecryptFile(string inputFile, string outputFile) 
{ 

    { 
     string password = @"myKey123"; // Your Key Here 

     UnicodeEncoding UE = new UnicodeEncoding(); 
     byte[] key = UE.GetBytes(password); 

     FileStream fsCrypt = new FileStream(inputFile, FileMode.Open); 

     RijndaelManaged RMCrypto = new RijndaelManaged(); 

     CryptoStream cs = new CryptoStream(fsCrypt, 
      RMCrypto.CreateDecryptor(key, key), 
      CryptoStreamMode.Read); 

     FileStream fsOut = new FileStream(outputFile, FileMode.Create); 

     int data; 
     while ((data = cs.ReadByte()) != -1) 
      fsOut.WriteByte((byte)data); 

     fsOut.Close(); 
     cs.Close(); 
     fsCrypt.Close(); 

    } 
} 

출처 : 여기에 http://www.codeproject.com/Articles/26085/File-Encryption-and-Decryption-in-C

+2

이 코드에는 몇 가지 심각한 문제가 있습니다. a) 암호의 길이가 충분하지 않지만 암호가 일반적으로 낮은 엔트로피이므로 키로 직접 사용할 수 없다는 것이 문제입니다. b) IV를 키로 사용하는 것은 결정 론적 암호화를 의미하므로 의미 론적으로 안전하지 못합니다. IV는 무작위로 생성되어야합니다. 비밀은 아니지만 예측할 수 없으므로 암호문 앞에 간단하게 기록하고 암호 해독 중에 사용할 수 있습니다. c) 인증 없음! 수신자가 이것을 발견하지 않고 암호문을 변경할 수 있습니다. –