PowerShell加密文件后.NET解密报错:输入数据不是完整块
AES解密时抛出“输入数据不是完整块”异常分析
使用PowerShell的AES加密脚本生成加密文件后,.NET 4.8解密函数在关闭CryptoStream时抛出异常:
System.Security.Cryptography.CryptographicException: 'The input data is not a complete block.'
加密脚本(PowerShell)
function Protect-File { [CmdletBinding()] Param( [Parameter(Mandatory=$true, Position=1)] [string]$FileName, [Parameter(Mandatory=$true, Position=2)] [string]$KeyAsPlainText ) $Algorithm = 'AES' $CipherMode = 'CBC' $PaddingMode = 'PKCS7' try { $Crypto = [System.Security.Cryptography.SymmetricAlgorithm]::Create($Algorithm) $Crypto.Key = [System.Convert]::FromBase64String($KeyAsPlainText) $Crypto.GenerateIV() $Crypto.Mode = $CipherMode $Crypto.Padding = $PaddingMode $DestinationFile = $FileName + ".encrypted" $Transform = $Crypto.CreateEncryptor() $CryptoStream = New-Object System.Security.Cryptography.CryptoStream( [System.IO.File]::OpenWrite($DestinationFile), $Transform, [System.Security.Cryptography.CryptoStreamMode]::Write ) try { try { $FileStreamReader = [System.IO.File]::OpenRead($FileName) $FileStreamReader.CopyTo($CryptoStream) } finally { $FileStreamReader.Close() } } finally { $CryptoStream.Close() } # Write IV to the beginning of the encrypted file $FileStreamWriter = [System.IO.File]::OpenWrite($DestinationFile) $FileStreamWriter.Seek(0, [System.IO.SeekOrigin]::Begin) $FileStreamWriter.Write($Crypto.IV, 0, $Crypto.IV.Length) $FileStreamWriter.Close() Write-Output "File encrypted successfully: $DestinationFile" } catch { Write-Error $_ } } Protect-File -Filename "D:\Temp\temp.txt" -KeyAsPlainText "r4EoMu6hxWHlsFgizGf3L2WIEJwwVFIUrADdCU4U9xA="
原解密函数(.NET 4.8)
public static bool UnprotectFile(string sourceFile, string destinationFile, string keyAsPlainText) { try { byte[] encryptionKey = Convert.FromBase64String(keyAsPlainText); // Read IV from the beginning of the encrypted file using (FileStream fileStream = File.OpenRead(sourceFile)) { byte[] iv = new byte[16]; fileStream.Read(iv, 0, iv.Length); // Configure encryption algorithm Aes crypto = Aes.Create(); crypto.Key = encryptionKey; crypto.IV = iv; crypto.Mode = CipherMode.CBC; crypto.Padding = PaddingMode.PKCS7; // Decrypt the file using (ICryptoTransform transform = crypto.CreateDecryptor()) { using (CryptoStream cryptoStream = new CryptoStream( File.OpenWrite(destinationFile), transform, CryptoStreamMode.Write )) { using (FileStream fileStreamReader = File.OpenRead(sourceFile)) { fileStreamReader.CopyTo(cryptoStream); } } } return true; } // catch block removed } catch(Exception ex) { // 异常处理 return false; } }
异常成因
- 加密文件结构:PowerShell脚本先写入加密后的文件内容,再将16字节的IV写入文件开头,最终加密文件结构为:
[IV(16字节)] + [实际加密数据]。 - 解密代码逻辑错误:解密时,代码先读取了开头的16字节IV,但随后重新打开整个加密文件(包含IV),将全部内容传入
CryptoStream进行解密。这相当于把IV也当成了加密数据的一部分处理,导致解密输入的总长度比实际加密数据多了16字节,破坏了AES CBC模式的块对齐要求(AES块大小为16字节),最终抛出“输入数据不是完整块”的异常。
修复后的解密函数
修正读取文件的逻辑,跳过开头的IV部分,只读取实际加密数据:
public static bool UnprotectFile(string sourceFile, string destinationFile, string keyAsPlainText) { try { byte[] encryptionKey = Convert.FromBase64String(keyAsPlainText); using (FileStream fileStream = File.OpenRead(sourceFile)) { byte[] iv = new byte[16]; // 读取IV int bytesRead = fileStream.Read(iv, 0, iv.Length); if (bytesRead != iv.Length) { // IV读取失败,处理异常 return false; } Aes crypto = Aes.Create(); crypto.Key = encryptionKey; crypto.IV = iv; crypto.Mode = CipherMode.CBC; crypto.Padding = PaddingMode.PKCS7; using (ICryptoTransform transform = crypto.CreateDecryptor()) { using (CryptoStream cryptoStream = new CryptoStream( File.OpenWrite(destinationFile), transform, CryptoStreamMode.Write )) { // 跳过IV,复制剩余的加密数据到CryptoStream fileStream.CopyTo(cryptoStream); } } return true; } } catch (Exception ex) { // 添加异常处理逻辑 return false; } }
内容的提问来源于stack exchange,提问作者Optimum8
相关产品推荐
相关产品推荐

