잘못된 비밀번호로 인해 "패딩이 잘못되어 제거할 수 없습니다"라는 메시지가 나타나는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/11762

  •  08-06-2019
  •  | 
  •  

문제

간단한 문자열 암호화가 필요했기 때문에 다음 코드를 작성했습니다. 여기):

    // create and initialize a crypto algorithm
    private static SymmetricAlgorithm getAlgorithm(string password) {
        SymmetricAlgorithm algorithm = Rijndael.Create();
        Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(
            password, new byte[] {
            0x53,0x6f,0x64,0x69,0x75,0x6d,0x20,             // salty goodness
            0x43,0x68,0x6c,0x6f,0x72,0x69,0x64,0x65
        }
        );
        algorithm.Padding = PaddingMode.ISO10126;
        algorithm.Key = rdb.GetBytes(32);
        algorithm.IV = rdb.GetBytes(16);
        return algorithm;
    }

    /* 
     * encryptString
     * provides simple encryption of a string, with a given password
     */
    public static string encryptString(string clearText, string password) {
        SymmetricAlgorithm algorithm = getAlgorithm(password);
        byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
        cs.Write(clearBytes, 0, clearBytes.Length);
        cs.Close();
        return Convert.ToBase64String(ms.ToArray());
    }

    /*
     * decryptString
     * provides simple decryption of a string, with a given password
     */
    public static string decryptString(string cipherText, string password) {
        SymmetricAlgorithm algorithm = getAlgorithm(password);
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write);
        cs.Write(cipherBytes, 0, cipherBytes.Length);
        cs.Close();            
        return System.Text.Encoding.Unicode.GetString(ms.ToArray());
    }

잘못된 키로 데이터를 해독할 때 decryptString의 cs.Close() 줄에서 CryptographicException - "패딩이 유효하지 않으며 제거할 수 없습니다."라는 점을 제외하면 코드가 제대로 작동하는 것 같습니다.

예제 코드:

    string password1 = "password";
    string password2 = "letmein";
    string startClearText = "The quick brown fox jumps over the lazy dog";
    string cipherText = encryptString(startClearText, password1);
    string endClearText = decryptString(cipherText, password2);     // exception thrown

내 질문은 이것이 예상되는 것입니까?잘못된 비밀번호로 복호화하면 예외가 아닌 말도 안되는 출력 결과가 나올 것이라고 생각했을 것입니다.

도움이 되었습니까?

해결책

이미 답변을 드렸지만 설명을 해주시면 좋을 것 같습니다. 그것은 예상됩니다.

대부분의 암호화 필터는 의미상 안전하지 않고 일부 형태의 암호화 공격을 방지하기 때문에 패딩 방식이 일반적으로 적용됩니다.예를 들어, 일반적으로 RSA에서는 OAEP 특정 종류의 공격(예: 선택된 일반 텍스트 공격 또는 눈이 멀다).

패딩 방식은 메시지가 전송되기 전에 메시지 m에 일부(일반적으로) 임의의 쓰레기를 추가합니다.예를 들어 OAEP 방법에서는 두 개의 Oracle이 사용됩니다(간단한 설명임).

  1. 모듈러스의 크기가 주어지면 k1 비트를 0으로, k0 비트를 난수로 채웁니다.
  2. 그런 다음 메시지에 일부 변환을 적용하여 암호화되어 전송되는 패딩된 메시지를 얻습니다.

이는 메시지에 대한 무작위화와 메시지가 쓰레기인지 여부를 테스트하는 방법을 제공합니다.패딩 방식은 가역적이므로 메시지를 해독할 때 메시지 자체의 무결성에 대해 아무 말도 할 수 없지만 실제로 패딩에 대해 몇 가지 주장을 할 수 있으므로 메시지가 올바르게 해독되었는지 알 수 있습니다. 또는 뭔가 잘못하고 있는 중입니다(예: 누군가가 메시지를 변조했거나 잘못된 키를 사용하고 있음).

다른 팁

나는 비슷한 "패딩이 유효하지 않아 제거 할 수 없습니다"를 경험했습니다. 예외, 그러나 나의 경우에는 키 IV와 패딩이 정확했습니다.

암호화 스트림을 플러시하는 것이 누락된 전부라는 것이 밝혀졌습니다.

이와 같이:

            MemoryStream msr3 = new MemoryStream();
            CryptoStream encStream = new CryptoStream(msr3, RijndaelAlg.CreateEncryptor(), CryptoStreamMode.Write);
            encStream.Write(bar2, 0, bar2.Length);
            // unless we flush the stream we would get "Padding is invalid and cannot be removed." exception when decoding
            encStream.FlushFinalBlock();
            byte[] bar3 = msr3.ToArray();

올바른 사용법을 원하면 다음을 추가해야 합니다. 입증 암호문이 올바른지 또는 암호문이 수정되지 않았는지 확인할 수 있도록 암호문에 추가합니다.사용하고 있는 패딩 ISO10126 마지막 바이트가 패딩(0x01-0x10)에 대한 16개의 유효한 값 중 하나로 해독되지 않는 경우에만 예외가 발생합니다.따라서 잘못된 비밀번호로 예외를 발생시키지 않을 확률은 1/16입니다. 인증하면 해독이 유효한지 확인할 수 있는 결정적인 방법이 있습니다.

암호화 API를 사용하는 것은 쉬워 보이지만 실제로는 실수하기 쉽습니다.예를 들어 키 및 IV 파생에 대해 고정 솔트를 사용합니다. 즉, 동일한 비밀번호로 암호화된 모든 암호문은 해당 키와 함께 IV를 재사용하므로 CBC 모드의 의미 보안이 깨집니다. IV는 예측할 수 없고 고유해야 합니다. 주어진 키.

실수하기 쉽기 때문에 코드 조각을 사용하여 계속 검토하고 최신 상태로 유지하려고 합니다(의견, 문제 환영).

문자열 C#의 대칭 인증 암호화의 최신 예입니다.

당신이 그것을 사용한다면 AESThenHMAC.AesSimpleDecryptWithPassword(ciphertext, password) 잘못된 비밀번호를 사용했을 때, null 암호화 후 암호문 또는 iv가 수정된 경우 반환됩니다. null 반환되면 정크 데이터나 패딩 예외가 반환되지 않습니다.

키 불일치를 배제했다면, 게다가 FlushFinalBlock() (Yaniv의 답변 참조), 전화 Close()CryptoStream 또한 충분할 것입니다.

엄격하게 리소스를 정리하는 경우 using 블록을 사용하려면 해당 블록을 중첩해야 합니다. CryptoStream 그 자체:

using (MemoryStream ms = new MemoryStream())
using (var enc = RijndaelAlg.CreateEncryptor())
{
  using (CryptoStream encStream = new CryptoStream(ms, enc, CryptoStreamMode.Write))
  {
    encStream.Write(bar2, 0, bar2.Length);
  } // implicit close
  byte[] encArray = ms.ToArray();
}

나는 이것(또는 유사한 것)에 물렸습니다:

using (MemoryStream ms = new MemoryStream())
using (var enc = RijndaelAlg.CreateEncryptor())
using (CryptoStream encStream = new CryptoStream(ms, enc, CryptoStreamMode.Write))
{
  encStream.Write(bar2, 0, bar2.Length);
  byte[] encArray = ms.ToArray();
} // implicit close -- too late!

예, 이는 예상된 것입니다. 또는 적어도 암호화 루틴이 해독할 수 없는 데이터를 얻을 때 정확히 일어나는 일입니다.

예외의 또 다른 이유는 암호 해독 논리를 사용하는 여러 스레드 간의 경쟁 조건일 수 있습니다. ICryptoTransform의 기본 구현은 다음과 같습니다. 스레드로부터 안전하지 않음 (예:SymmetricAlgorithm)이므로 독점 섹션에 배치해야 합니다.사용하여 잠그다.자세한 내용은 여기를 참조하세요. http://www.make-awesome.com/2011/07/system-security-cryptography-and-thread-safety/

CryptoStream에 읽지 않은 바이트가 있을 수 있습니다.스트림을 완전히 읽기 전에 닫으면 내 프로그램에 오류가 발생했습니다.

비슷한 문제가 있었는데, 암호 해독 방법의 문제는 빈 메모리 스트림을 초기화하는 것이었습니다.다음과 같이 암호 텍스트 바이트 배열로 초기화했을 때 작동했을 때:

MemoryStream ms = new MemoryStream(cipherText)

"atconway" 사용자가 업데이트한 답변이 저에게 효과적이었습니다.

문제는 패딩에 있는 것이 아니라 암호화와 복호화 중에 다른 키에 있었습니다.동일한 값을 암호화하고 복호화하는 동안 키와 iv는 동일해야 합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top