.NET으로 암호화할 때의 주의점 ~ 이렇게 당신은 함정에 끼친다

15407 단어 .NETCoreC#.NET

소개



갑작스럽지만, 지금부터 닮은 코드를 2 종류 제시합니다.
둘 중 하나가 올바르게 움직이고 둘 중 하나가 런타임 오류입니다.



패턴 A.cs
public static class Cipher
{
    private static readonly byte[] InitialzationVector = Encoding.UTF8.GetBytes(@"xxxxxxxxxxxxxxxx");
    private static readonly byte[] SharedKey = Encoding.UTF8.GetBytes(@"xxxxxxxxxxxxxxxx");
    private static readonly int BlockSize = InitialzationVector.Length * 8;
    private static readonly int KeySize = SharedKey.Length * 8;

    public static string Encrypt(string plainText)
    {
        using var rijndael = new RijndaelManaged
        {
            BlockSize = BlockSize,
            KeySize = KeySize,
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
            IV = InitialzationVector,
            Key = SharedKey,
        };

        using var encryptor = rijndael.CreateEncryptor();
        var bytes = Encoding.UTF8.GetBytes(plainText);
        return Convert.ToBase64String(encryptor.TransformFinalBlock(bytes, 0, bytes.Length));
    }

    public static string Decrypt(string cipherText)
    {
        using var rijndael = new RijndaelManaged
        {
            BlockSize = BlockSize,
            KeySize = KeySize,
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
            IV = InitialzationVector,
            Key = SharedKey,
        };

        using var decryptor = rijndael.CreateDecryptor();
        var bytes = Convert.FromBase64String(cipherText);
        var plain = decryptor.TransformFinalBlock(bytes, 0, bytes.Length);
        return Encoding.UTF8.GetString(plain);
    }
}

B



패턴 B.cs
public static class Cipher
{
    private static readonly byte[] InitialzationVector = Encoding.UTF8.GetBytes(@"xxxxxxxxxxxxxxxx");
    private static readonly byte[] SharedKey = Encoding.UTF8.GetBytes(@"xxxxxxxxxxxxxxxx");
    private static readonly int BlockSize = InitialzationVector.Length * 8;
    private static readonly int KeySize = SharedKey.Length * 8;

    public static string Encrypt(string plainText)
    {
        using var rijndael = new RijndaelManaged
        {
            IV = InitialzationVector,
            Key = SharedKey,
            BlockSize = BlockSize,
            KeySize = KeySize,
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
        };

        using var encryptor = rijndael.CreateEncryptor();
        var bytes = Encoding.UTF8.GetBytes(plainText);
        return Convert.ToBase64String(encryptor.TransformFinalBlock(bytes, 0, bytes.Length));
    }

    public static string Decrypt(string cipherText)
    {
        using var rijndael = new RijndaelManaged
        {
            IV = InitialzationVector,
            Key = SharedKey
            BlockSize = BlockSize,
            KeySize = KeySize,
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
        };

        using var decryptor = rijndael.CreateDecryptor();
        var bytes = Convert.FromBase64String(cipherText);
        var plain = decryptor.TransformFinalBlock(bytes, 0, bytes.Length);
        return Encoding.UTF8.GetString(plain);
    }
}

결과



대답은 A가 올바르게 작동하는 것이 었습니다.
이상! !

... 그냥 외롭기 때문에 조금만 보충합니다.

덧붙여서 차이점은 BlockSize/KeySize를 먼저 초기화하는지, IV/Key를 먼저 초기화하는지의 차이 밖에 없습니다.

발생하는 예외



예외는 분명히 Decrypt 때 발생하는 것 같습니다.


그래서 공식 문서 을 보러 보면 분명히이 예외는 "inputCount 매개 변수의 길이가 입력 블록 크기로 나눌 수없는 경우"에 발생하는 것 같습니다.

그럼, 실제로 어떻게 되어 있는지 변수를 워치 해 보았습니다.


이미지에서는 닫고 있는 항목도 비교해 보았습니다만 같은 값이었습니다 😇

분명히 현지 시계에서는 보이지 않는 곳에서 아무것도 이상한 일을하는 것 같습니다.
어둠에 한쪽 다리를 밀어넣을 것 같아서 더 이상 쫓는 것을 그만뒀습니다.

결론



프로퍼티에 setter 를 마련하는 경우는, 이용자측이 어떤 순서로 값을 넣어 가는지는 부정이므로, 이러한 설계를 해서는 안됩니다.

이것은 분명히 나쁜 설계이므로 자신이 클래스를 만들 때는 조심합시다.
만약 만일 이런 제작을 해 버린 경우는, 문서에 반드시 호출 순서의 규약을 명기해 둡시다.

그것이 없으면 아무도 사양을 모르고, 당신의 생각하고있는 것 등 에스퍼가 아니기 때문에 아무도 알아주지 않습니다.

또, 요즘의 트렌드로 말하면 원래 Immutable 로 해 가자고 하는 흐름이므로, setter 등이라고 하는 제악의 근원인 기능을 사용해서는 안됩니다 (과격파).

자계도 담아 간에 명명해 둡시다.

좋은 웹페이지 즐겨찾기