加密和解密文件 - 导致 "Bad Data"

Encrypting and decrypting File - Lead to "Bad Data"

我目前正在使用一个小对象来帮助我加密文件然后解密它,return 它作为 MemoryStream。但是,当我解密时,我不断收到 "Bad data".

"ExceptionMessage": "Bad Data.\ \ ",
"ExceptionType": "System.Security.Cryptography.CryptographicException",

Class如下

public class SignatureService {
    private readonly DESCryptoServiceProvider _desCryptoServiceProvider;
    private static byte[] _key = { 5, 6, 7, 2, 3, 4, 8, 1 };
    private static byte[] _iv = { 5, 2, 3, 4, 1, 7, 4, 2 };

    public SignatureService () {
        _desCryptoServiceProvider = new DESCryptoServiceProvider();
    }

    public void SaveSignatureOnDisk ( Stream stream ) {
        using ( var fs = new FileStream( "filepath", FileMode.Create, FileAccess.Write ) ) {
            var cryptoStream = new CryptoStream( fs, _desCryptoServiceProvider.CreateEncryptor( _key, _iv ), CryptoStreamMode.Write );
            var bytearrayinput = new byte[ stream.Length - 1 ];
            stream.Read( bytearrayinput, 0, bytearrayinput.Length );
            cryptoStream.Write( bytearrayinput, 0, bytearrayinput.Length );
        }
 }

    public Stream ReadSignatureOnDisk () {
        Stream returnedStream;
        using ( var fs = new FileStream( "filepath", FileMode.Open, FileAccess.Read ) ) {
            var cryptoStream = new CryptoStream( fs, _desCryptoServiceProvider.CreateDecryptor( _key, _iv ), CryptoStreamMode.Read );

            string contents = new StreamReader( cryptoStream ).ReadToEnd();
            byte[] unicodes = Encoding.Unicode.GetBytes( contents );
            returnedStream = new MemoryStream( unicodes );
        }

        return returnedStream;
    }
}

您犯了一些错误,应该处理 CreateDecryptorCreateEncryptor 中的 CryptoStream 和 ICryptoTransform。此外,您的 stream.Read 不可靠, Read 不能保证实际读取您要求的所有字节。您必须循环直到读取 returns 0 或使用 .CopyTo( 如果您使用的是具有它的 .NET 版本。

public void SaveSignatureOnDisk ( Stream stream ) 
{
    using (var fs = new FileStream("filepath", FileMode.Create, FileAccess.Write))
    using (var encryptor = _desCryptoServiceProvider.CreateEncryptor( _key, _iv))
    using (var cryptoStream = new CryptoStream(fs, encryptor, CryptoStreamMode.Write))
    {
        stream.CopyTo(cryptoStream);
    }
}

你的ReadSignatureOnDisk也有同样的错误,同样需要修复。

public Stream ReadSignatureOnDisk ()
{
    Stream returnedStream = new MemoryStream();
    using (var fs = new FileStream("filepath", FileMode.Open, FileAccess.Read))
    using (var decryptor = _desCryptoServiceProvider.CreateDecryptor(_key, _iv))
    using (var cryptoStream = new CryptoStream(fs, decryptor, CryptoStreamMode.Read);
    {
        cryptoStream.CopyTo(returnedStream);
    }

    returnedStream.Position = 0
    return returnedStream;
}

如果您愿意,可以使用我的 ReturnableCryptoStream class I wrote for another answer,它允许您 return 原始加密流并让调用者处理它。

/// <summary>
/// Creates a class that creates a <see cref="CryptoStream"/> and wraps the disposing action of all the associated objects 
/// </summary>
class ReturnableCryptoStream : CryptoStream
{
    private readonly ICryptoTransform _transform;
    private readonly IDisposable _algorithom;

    public ReturnableCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode, IDisposable algorithom) 
        : base(stream, transform, mode)
    {
        _transform = transform;
        _algorithom = algorithom;
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        if (disposing)
        {
            if (_transform != null)
                _transform.Dispose();

            if (_algorithom != null)
                _algorithom.Dispose();
        }
    }
}

一样使用
public Stream ReadSignatureOnDisk ()
{
    var fs = new FileStream("filepath", FileMode.Open, FileAccess.Read);
    var serviceProvider = new DESCryptoServiceProvider()
    var decryptor = serviceProvider.CreateDecryptor(_key, _iv);
    var cryptoStream = new ReturnableCryptoStream(fs, 
             decryptor, 
             CryptoStreamMode.Read, 
             serviceProvider); 
    //note that I now make my own local copy of the service provider, you could use your 
    //existing one and pass in null to the ReturnableCryptoStream.

    return cryptoStream ;
}