잘못된 비밀번호로 인해 "패딩이 잘못되어 제거할 수 없습니다"라는 메시지가 나타나는 이유는 무엇입니까?
-
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이 사용됩니다(간단한 설명임).
- 모듈러스의 크기가 주어지면 k1 비트를 0으로, k0 비트를 난수로 채웁니다.
- 그런 다음 메시지에 일부 변환을 적용하여 암호화되어 전송되는 패딩된 메시지를 얻습니다.
이는 메시지에 대한 무작위화와 메시지가 쓰레기인지 여부를 테스트하는 방법을 제공합니다.패딩 방식은 가역적이므로 메시지를 해독할 때 메시지 자체의 무결성에 대해 아무 말도 할 수 없지만 실제로 패딩에 대해 몇 가지 주장을 할 수 있으므로 메시지가 올바르게 해독되었는지 알 수 있습니다. 또는 뭔가 잘못하고 있는 중입니다(예: 누군가가 메시지를 변조했거나 잘못된 키를 사용하고 있음).
다른 팁
나는 비슷한 "패딩이 유효하지 않아 제거 할 수 없습니다"를 경험했습니다. 예외, 그러나 나의 경우에는 키 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는 예측할 수 없고 고유해야 합니다. 주어진 키.
실수하기 쉽기 때문에 코드 조각을 사용하여 계속 검토하고 최신 상태로 유지하려고 합니다(의견, 문제 환영).
당신이 그것을 사용한다면 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는 동일해야 합니다.