Procurei online o que essa exceção significa em relação ao meu programa, mas não consigo encontrar uma solução ou o motivo pelo qual ela está acontecendo com meu programa específico. Tenho usado o exemplo fornecido por meu msdn para criptografar e descriptografar um XmlDocument usando o algoritmo Rijndael. A criptografia funciona bem, mas quando tento descriptografar, obtenho a seguinte exceção:
O preenchimento é inválido e não pode ser removido
Alguém pode me dizer o que posso fazer para resolver esse problema? Meu código abaixo é onde obtenho a chave e outros dados. Se cryptoMode for falso, ele chamará o método decrypt, que é onde ocorre a exceção:
public void Cryptography(XmlDocument doc, bool cryptographyMode)
{
RijndaelManaged key = null;
try
{
// Create a new Rijndael key.
key = new RijndaelManaged();
const string passwordBytes = "Password1234"; //password here
byte[] saltBytes = Encoding.UTF8.GetBytes("SaltBytes");
Rfc2898DeriveBytes p = new Rfc2898DeriveBytes(passwordBytes, saltBytes);
// sizes are devided by 8 because [ 1 byte = 8 bits ]
key.IV = p.GetBytes(key.BlockSize/8);
key.Key = p.GetBytes(key.KeySize/8);
if (cryptographyMode)
{
Ecrypt(doc, "Content", key);
}
else
{
Decrypt(doc, key);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
// Clear the key.
if (key != null)
{
key.Clear();
}
}
}
private void Decrypt(XmlDocument doc, SymmetricAlgorithm alg)
{
// Check the arguments.
if (doc == null)
throw new ArgumentNullException("Doc");
if (alg == null)
throw new ArgumentNullException("alg");
// Find the EncryptedData element in the XmlDocument.
XmlElement encryptedElement = doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;
// If the EncryptedData element was not found, throw an exception.
if (encryptedElement == null)
{
throw new XmlException("The EncryptedData element was not found.");
}
// Create an EncryptedData object and populate it.
EncryptedData edElement = new EncryptedData();
edElement.LoadXml(encryptedElement);
// Create a new EncryptedXml object.
EncryptedXml exml = new EncryptedXml();
// Decrypt the element using the symmetric key.
byte[] rgbOutput = exml.DecryptData(edElement, alg); <---- I GET THE EXCEPTION HERE
// Replace the encryptedData element with the plaintext XML element.
exml.ReplaceData(encryptedElement, rgbOutput);
}
c#
cryptography
Amor marrom
fonte
fonte
Respostas:
Rijndael / AES é uma cifra de bloco. Ele criptografa dados em blocos de 128 bits (16 caracteres). O preenchimento criptográfico é usado para garantir que o último bloco da mensagem sempre tenha o tamanho correto.
Seu método de descriptografia espera o preenchimento padrão e não o encontra. Como @NetSquirrel diz, você precisa definir explicitamente o preenchimento para criptografia e descriptografia. A menos que você tenha um motivo para fazer o contrário, use o preenchimento PKCS # 7.
fonte
alg.Padding = PaddingMode.PKCS7;
Certifique-se de que as chaves que você usa para criptografar e descriptografar são as mesmas . O método de preenchimento, mesmo se não definido explicitamente, deve permitir a descriptografia / criptografia adequada (se não definido, eles serão os mesmos). No entanto, se você, por algum motivo, estiver usando um conjunto de chaves diferente para criptografar daquele usado para criptografar , receberá este erro:
Se você estiver usando algum algoritmo para gerar chaves dinamicamente, isso não funcionará. Eles precisam ser os mesmos para criptografia e descriptografia. Uma maneira comum é fazer com que o chamador forneça as chaves no construtor da classe de métodos de criptografia, para evitar que o processo de criptografia / descriptografia tenha qualquer influência na criação desses itens. Ele se concentra na tarefa em questão (criptografar e descriptografar dados) e requer que
iv
ekey
seja fornecido pelo chamador.fonte
Para o benefício das pessoas que procuram, pode valer a pena verificar a entrada que está sendo descriptografada. No meu caso, as informações enviadas para descriptografia estavam (erroneamente) entrando como uma string vazia. Isso resultou no erro de preenchimento.
Isso pode estar relacionado à resposta do rossum, mas achou que vale a pena mencionar.
fonte
Se a mesma chave e o mesmo vetor de inicialização forem usados para codificação e decodificação, esse problema não virá da decodificação de dados, mas da codificação de dados.
Depois de chamar o método Write em um objeto CryptoStream, você deve SEMPRE chamar o método FlushFinalBlock antes do método Close.
A documentação do MSDN sobre o método CryptoStream.FlushFinalBlock diz:
" Chamar o método Close chamará FlushFinalBlock ... "
https://msdn.microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs .110) .aspx
Isso está errado. Chamar o método Close apenas fecha o CryptoStream e o fluxo de saída.
Se você não chamar FlushFinalBlock antes de Close depois de gravar os dados a serem criptografados, ao descriptografar os dados, uma chamada para o método Read ou CopyTo em seu objeto CryptoStream lançará uma exceção CryptographicException (mensagem: "Preenchimento é inválido e não pode ser removido").
Isso provavelmente é verdadeiro para todos os algoritmos de criptografia derivados de SymmetricAlgorithm (Aes, DES, RC2, Rijndael, TripleDES), embora eu apenas tenha verificado isso para AesManaged e um MemoryStream como fluxo de saída.
Portanto, se você receber esta exceção CryptographicException na descriptografia, leia o valor da propriedade Stream Length de saída depois de gravar seus dados para serem criptografados e, em seguida, chame FlushFinalBlock e leia seu valor novamente. Se mudou, você sabe que chamar FlushFinalBlock NÃO é opcional.
E você não precisa executar nenhum preenchimento programaticamente ou escolher outro valor de propriedade de preenchimento. O preenchimento é um trabalho do método FlushFinalBlock.
.........
Observação adicional para Kevin:
Sim, CryptoStream chama FlushFinalBlock antes de chamar Close, mas é tarde demais: quando o método CryptoStream Close é chamado, o fluxo de saída também é fechado.
Se o fluxo de saída for um MemoryStream, você não poderá ler seus dados depois de fechado. Portanto, você precisa chamar FlushFinalBlock em seu CryptoStream antes de usar os dados criptografados gravados no MemoryStream.
Se o fluxo de saída for um FileStream, as coisas são piores porque a gravação é armazenada em buffer. A consequência é que os últimos bytes gravados podem não ser gravados no arquivo se você fechar o fluxo de saída antes de chamar Flush em FileStream. Portanto, antes de chamar Close no CryptoStream, você precisa primeiro chamar FlushFinalBlock em seu CryptoStream e, em seguida, chamar Flush em seu FileStream.
fonte
Stream.Close()
chamadasthis.Dispose(true)
. O código paraCryptoStream.Dispose(bool)
é:if (disposing) { if (!this._finalBlockTransformed) { this.FlushFinalBlock(); } this._stream.Close(); }
A tempos servais de luta, finalmente resolvi o problema.
(Observação: eu uso AES padrão como algoritmo simétrico. Esta resposta pode não ser adequada para todos.)
RijndaelManaged
classe porAESManaged
uma.KeySize
classe de algoritmo, deixe-os como padrão.(Esta é a etapa muito importante. Acho que há um bug na propriedade KeySize.)
Aqui está uma lista que você deseja verificar qual argumento você pode ter perdido:
(matriz de bytes, o comprimento deve ser exatamente um de 16, 24, 32 bytes para tamanhos de chave diferentes).
(matriz de bytes, 16 bytes)
(um de CBC, CFB, CTS, ECB, OFB)
(um de ANSIX923, ISO10126, Nenhum, PKCS7, Zeros)
fonte
KeySize
corrigiu para mim imediatamente. Ah, as peculiaridades do .NET :-(Meu problema era que a senha de criptografia não correspondia à senha de descriptografia ... então gerava esse erro ... um pouco enganador.
fonte
A solução que consertou o meu foi que eu inadvertidamente apliquei chaves diferentes aos métodos de criptografia e descriptografia.
fonte
Encontrei este erro ao tentar passar um caminho de arquivo não criptografado para o método de descriptografar. A solução foi verificar se o arquivo transmitido está criptografado antes de tentar descriptografar
fonte
Outro cenário, novamente para o benefício das pessoas que procuram.
Para mim, esse erro ocorreu durante o método Dispose (), que mascarou um erro anterior não relacionado à criptografia.
Depois que o outro componente foi corrigido, essa exceção foi embora.
fonte
Eu encontrei este erro de preenchimento quando eu editei manualmente as strings criptografadas no arquivo (usando o bloco de notas) porque eu queria testar como a função de descriptografia se comportaria se meu conteúdo criptografado fosse alterado manualmente.
A solução para mim foi colocar um
Como eu disse, meu erro de preenchimento foi porque eu estava digitando manualmente sobre o texto descriptografado usando o bloco de notas. Pode ser minha resposta pode guiá-lo para sua solução.
fonte
Eu tive o mesmo erro. No meu caso, foi porque armazenei os dados criptografados em um banco de dados SQL. A tabela em que os dados são armazenados tem um tipo de dados binário (1000). Ao recuperar os dados do banco de dados, ele descriptografaria esses 1000 bytes, enquanto lá estavam, na verdade, 400 bytes. Portanto, remover os zeros à direita (600) do resultado corrigiu o problema.
fonte
Eu tive este erro e estava definindo explicitamente o tamanho do bloco:
aesManaged.BlockSize = 128;
Depois de remover isso, funcionou.
fonte
Tive o mesmo problema ao tentar portar um programa Go para C #. Isso significa que muitos dados já foram criptografados com o programa Go. Esses dados agora devem ser descriptografados com C #.
A solução final foi
PaddingMode.None
ou melhorPaddingMode.Zeros
.Os métodos criptográficos em Go:
... e ...
Agora, descriptografia em C #:
Como o problema com o preenchimento pode ser explicado? Antes da criptografia, o programa Go verifica o preenchimento:
A parte importante é esta:
Uma nova matriz é criada com um comprimento apropriado, de modo que o comprimento seja um múltiplo do tamanho do bloco. Esta nova matriz é preenchida com zeros. O método de cópia então copia os dados existentes para ele. É garantido que o novo array é maior do que os dados existentes. Conseqüentemente, existem zeros no final da matriz.
Assim, o código C # pode usar
PaddingMode.Zeros
. A alternativaPaddingMode.None
simplesmente ignora qualquer preenchimento, o que também funciona. Espero que esta resposta seja útil para quem precisa portar o código Go para C #, etc.fonte
Sou relatado o mesmo erro pelo cliente. Eu pessoalmente não posso reproduzi-lo. Olhando para o código dos métodos Encrypt e Decrypt , ambos têm Padding definido como PaddingMode.PKCS7 . Decifrar se parece com isso e não consigo ver o problema com ele em relação a ' FlushFinalBlock '. Alguém poderia lançar alguma luz sobre isso?
fonte
Eu tive o mesmo erro. No meu caso, a senha fornecida é maior que 16 significa que ela criptografou, mas durante a descriptografia estou recebendo este erro. Criptografia:
Descriptografar:
fonte