2016-08-15 6 views
0

Rijndael을 파일 암호화 문제Rijndael을 파일 암호화 문제를

내가 Rijndael을을 사용하여 대용량 파일을 암호화 할

하지만 난 메모리 예외 오류 벗어나 려. 어떤 생각? 여기 첫째, 내 코드를 실제 문제

 public void Rijndael_EncryptFile(string password, string filepath, int opt) 
    { 
     try 
     { 
      byte[] keyBytes; 
      keyBytes = Encoding.Unicode.GetBytes(password); 
      Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(password, keyBytes); 
      RijndaelManaged rijndaelCSP = new RijndaelManaged(); 
      rijndaelCSP.BlockSize = opt; //128 256 
      rijndaelCSP.KeySize = opt; //128 256 
      rijndaelCSP.Key = derivedKey.GetBytes(rijndaelCSP.KeySize/8); 
      rijndaelCSP.IV = derivedKey.GetBytes(rijndaelCSP.BlockSize/8); 
      rijndaelCSP.Mode = CipherMode.CFB; 
      rijndaelCSP.Padding = PaddingMode.Zeros; 
      ICryptoTransform encryptor = rijndaelCSP.CreateEncryptor(); 
      FileStream inputFileStream = new FileStream(filepath, FileMode.Open, FileAccess.Read); 
      byte[] inputFileData = new byte[(int)inputFileStream.Length]; 
      inputFileStream.Read(inputFileData, 0, (int)inputFileStream.Length); 
      FileStream outputFileStream = new FileStream(filepath + ".enc", FileMode.Create, FileAccess.Write); 
      CryptoStream encryptStream = new CryptoStream(outputFileStream, encryptor, CryptoStreamMode.Write); 
      encryptStream.Write(inputFileData, 0, (int)inputFileStream.Length); 
      encryptStream.FlushFinalBlock(); 
      rijndaelCSP.Clear(); 
      encryptStream.Close(); 
      inputFileStream.Close(); 
      outputFileStream.Close(); 
     } 
    } 
+1

CFB 모드의 경우 IV가 * 고유해야합니다. 고정 IV를 사용하지 마십시오. 이는 암호화를 결정 론적으로 만들고 따라서 의미 론적으로 안전하지 않기 때문입니다. 암호문을 관찰하는 침입자는 동일한 메시지 접두어가 언제 전에 전송되었는지를 결정할 수 있습니다. 그리고 심지어 CFB와 같은 스트리밍 모드에서는 공격자가 메시지가 다를지라도 IV가 재사용되는 경우 메시지를 추론 할 수도 있습니다. IV는 비밀이 아니므로 암호문과 함께 보낼 수 있습니다. 대개 암호문 앞에 붙이고 암호 해독 전에 잘라냅니다. –

답변

2

OK입니다.

전체 파일을 메모리로 읽어서 암호화 한 다음 디스크에 씁니다. 큰 바이트 배열은 메모리가 충분하지 않을 수 있습니다 (충분한 "RAM"이 있더라도).

대신 한 번에 데이터 덩어리를 읽어야합니다. 이 청크 크기는 아마도 AES 블록의 크기 인 16 바이트의 배수가 될 것이며 CryptoStream을 사용하여 작성하고 스트림 끝 부분에 도달하면 CryptoStream을 닫아서 모든 패딩을 적용합니다.

다른 것들.

먼저 RijndaelManaged을 사용하지 마십시오. AesManaged을 사용하십시오. Rijndael은 AES로 표준화되기 전에 AES의 이름이었습니다. AES는 128 이외의 블록 크기를 허용하지 않으므로 Rijndael과 동일하므로 블록 크기를 변경하지 마십시오. Rijndael을 사용해야하는 유일한 시간은 기존 시스템과의 호환성을 위해 128 비트 이외의 블록 크기가 필요한 경우입니다.

다음으로 초기화 벡터는 이어야합니다. CFB 모드의 경우입니다. IV는 비밀이 아니며 암호문과 함께 일반 텍스트로 저장할 수 있습니다. 암호에서 파생시키지 마십시오. 결정적으로 IV는 절대로 재사용해서는 안됩니다. 무작위 일 필요는 없습니다. 그것은 간단한 증분 카운터 일 수 있습니다. CBC와 같은 AES의 다른 모드의 경우 IV는 무작위이어야합니다.

2

전체 파일을 메모리로 읽을 필요가 없습니다. 가장 좋은 방법은 입력에서 한 번에 데이터 덩어리를 읽고 그 덩어리를 출력에 쓰는 것입니다.

byte[] keyBytes; 
keyBytes = Encoding.Unicode.GetBytes(password); 
Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(password, keyBytes); 
RijndaelManaged rijndaelCSP = new RijndaelManaged(); 
// setup key parameters, i.e. IV, etc 
ICryptoTransform encryptor = rijndaelCSP.CreateEncryptor(); 
using (FileStream inputFileStream = new FileStream(filepath, FileMode.Open, FileAccess.Read)) 
using (FileStream outputFileStream = new FileStream(filepath + ".enc", FileMode.Create, FileAccess.Write)) 
using (CryptoStream encryptStream = new CryptoStream(outputFileStream, encryptor, CryptoStreamMode.Write)) 
{ 
    byte[] buffer = new byte[bufSize]; 
    int readSize = 0; 
    while ((readSize = inputFileStream.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     encryptStream.Write(buffer, 0, readSize); 
    } 
    encryptStream.FlushFinalBlock(); 
    rijndaelCSP.Clear(); 
} 

UPDATE : (원래의 질문에서 복사) 제거 된 초기화 코드가 확보되지 않기 때문에 나는 아래의 테스트하지 않았습니다 있지만

다음과 같이 뭔가.

+0

초기화 부분은 데모 용입니다. 이것은 정말로 안전하지 않습니다. 키 파생과 임의의 IV에 임의의 소금을 사용해야합니다. 두 가지 모두 비밀이 아니기 때문에 암호문 앞에 쓰여진 후 암호 해독을 실제로 시작하기 전에 암호문을 먼저 읽음으로써 암호문 앞에 사용할 수 있습니다. –

+0

예, 암호화의 올바른 사용을 나타내려는 의도는 아니므로 전체 블록을 메모리로 읽어 들이지 않는 방법에 관한 문제를 해결하는 것과 같습니다. 초기화 코드를 제거하여 답을 명확히하기 위해 답을 업데이트했습니다. –