C#을 이용해서 프로그램을 작성할 때, 암호화 관련되서는 대부분 CryptSteam 이라는 클래스를 이용하여 작성하곤 했다. 일단 Stream 계열로 작성되기 때문에, 매우 쉽게 접근할 수 있고 제작할 수 있어 매우 마음에 드는 구성이다.

그런데, 이 예제를 MS에서 제공하는 MSDN을 통해서 가져왔는데, 이 기법을 이용해서 빌드를 하게 되면, 중복 Dispose가 불린다는 Warning이 뜬다. 아마도 예제를 만든 사람은 C 계열 개발자 인듯. 매우 공격적으로 자원 해제를 하다가 보니, 중복 Dispose고 나발이고 작성된 것 같다. 프로그램 Run에는 문제가 없으나, 아마도 중복 Dispose로 인한 여러가지 수반되는 문제들이 있을 것은 어렵지 않게 예상된다.

먼저 MS에서 제공하는 예제는 다음 URL을 통해서 볼 수 있다.

CryptoStream Class(https://docs.micro…)

위의 내용 중 예제 부분만 추출하면 아래와 같다.

[ Encryption Part ]

// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{                    
    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
    {      
        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
        {
            //Write all data to the stream.
            swEncrypt.Write(plainText);
        }
        encrypted = msEncrypt.ToArray();
    }
}

[ Decryption Part ]

// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
    {
        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
        {
            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
               plaintext = srDecrypt.ReadToEnd();
        }
    }
}

문제는 위의 예제대로 하면 어김없이 발생한다는 것이다. using 이라는 구분을 쓰게 되는데, 이게 바로 그 문제의 원인.

그래서 고민을 했는데, 아래와 같이 수정하면 된다.

[ Encryption Part ]

// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
    CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
    StreamWriter swEncrypt = new StreamWriter(csEncrypt);
    {
        //Write all data to the stream.
        swEncrypt.Write(plainText);
        encrypted = msEncrypt.ToArray();
    }
}

 

[ Decryption Part ]

// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
    CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
    StreamReader srDecrypt = new StreamReader(csDecrypt);
    {
        // Read the decrypted bytes from the decrypting stream
        // and place them in a string.
        plaintext = srDecrypt.ReadToEnd();
    }    
}

위와 같이 고치면 끝날까? 아직 끝나지 않았다. 그 이유는 Encoding 파트에서 발생된다.

중요 원인은 using이 가지는 특징 때문이다. using은 자체적으로 Dispose도 하지만, 그전에 자원을 모두 정리해주는 특성을 갖는다. 그래서 지금 저 Writer 부분에서 자체적으로 Dispose 하면서 자신이 갖은 데이터를 그대로 부을 수 있도록 해주기도 한다. 그러므로 무조건 using을 없애는 것은 답이 아니다.(실제 Debug로 해보면, Write를 하였음에도 불구하고 데이터가 없는 것 처럼 0 byte가 결과로 나온다.)

그러면 어떻게 해결해야 할까? Stack Overflow에서 확인해본 결과 Close를 해주면 깔끔하게 끝난다고 한다.

 

// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
    CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
    StreamWriter swEncrypt = new StreamWriter(csEncrypt);
    {
        //Write all data to the stream.
        swEncrypt.Write(plainText);
	  swEncrypt.Close();
        encrypted = msEncrypt.ToArray();
    }
}

내 코드에서도 위와 같은 문제가 발견되서 매우 당황했는데, 여튼 이번에 해결하게 되어 블로그로 남긴다.

Decrypt 부분은 위의 Encrypt와는 다르게 Close가 필요없다. 이미 데이터가 들어간 상태이고,  Write는 일단 캐쉬에 먼저 넣기 때문에 실제 데이터가 들어가 있지 않아서 발생된 문제다. 그러므로 그냥 using을 적당히 날리면 문제 없이 코드가 돌아간다.

2019. 11. 8. 오후 2:01

728x90

+ Recent posts