C#Rijndael加密会在解密文件前放置额外的字节

时间:2015-08-19 17:51:07

标签: c# encryption

我正在尝试使用Rijndael加密来加密图像文件,我必须做错事,因为解密后的文件会在文件前面附加额外的数据,最后可能会有一些额外的数据。我对这种加密算法还很陌生,所以我很确定我只是缺少一些简单的东西。

使用文本文件的示例

输入文件

"the quick brown fox jumped over the lazy yellow dog"

当我尝试将生成的IV放在文件的前面时输出文件(\ 0 = null)

"ÚñjÐæƒÊW®ï¡_Ü&ßthe\0 quick brown fox jumped over the lazy yellow dog"

当我尝试在前面放置一个等于我的Key的IV时输出文件

"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0the\0\0\0\0\0\0 quick brown fox jumped over the lazy yellow dog"

当我使用等于我的密钥的IV并且在文件前面没有任何内容时输出文件

"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0the\0\0\0\0\0\0 quick brown fox jumped over the lazy yellow dog"

CODE

private RijndaelManaged GetCipher(byte[] key, bool forEncrypt)
{
    RijndaelManaged rijndaelCipher;

    rijndaelCipher = new RijndaelManaged();
    rijndaelCipher.Mode = CipherMode.CBC;
    rijndaelCipher.Padding = PaddingMode.PKCS7;
    rijndaelCipher.KeySize = 0x80;
    rijndaelCipher.BlockSize = 0x80;
    rijndaelCipher.Key = key;

   /* if (forEncrypt)
        rijndaelCipher.GenerateIV();
    else
    rijndaelCipher.IV = new byte[16];*/
    rijndaelCipher.IV = _imageKey;

    return rijndaelCipher;
}

public void DecryptStamp(Stamp stampToDecrypt, string decrpytedStampFilePath)
{
    RijndaelManaged rijndaelCipher;
    FileStream inputStream = null;
    FileStream outputStream = null;
    CryptoStream encryptSteam = null;
    byte[] block;
    int numberRead;
    ICryptoTransform transform;

    if (!File.Exists(stampToDecrypt.Path))
        throw new FileNotFoundException(stampToDecrypt.Path + " does not exist");

    rijndaelCipher = this.GetCipher(_imageKey, false);
    block = new byte[16];

    try
    {
        inputStream = File.Open(stampToDecrypt.Path, FileMode.Open, FileAccess.Read);
        outputStream = File.Open(decrpytedStampFilePath, FileMode.Create, FileAccess.Write);

        //inputStream.Read(rijndaelCipher.IV, 0, rijndaelCipher.IV.Length);
        transform = rijndaelCipher.CreateDecryptor();                     
        encryptSteam = new CryptoStream(outputStream, transform, CryptoStreamMode.Write);

        while ((numberRead = inputStream.Read(block, 0, block.Length)) > 0)
        {
            Console.WriteLine(numberRead.ToString());
            encryptSteam.Write(block, 0, numberRead);
        }
    }
    finally
    {
        rijndaelCipher.Clear();
        rijndaelCipher.Dispose();
        if (encryptSteam != null)
            encryptSteam.Dispose();
        if (outputStream != null)
            outputStream.Dispose();
        if (inputStream != null)
            inputStream.Dispose();
    }
}

public Stamp EncryptStampToStampFolder(string stampFileToEncrpyt)
{
    Configuration config;
    Stamp stampToEncrypt;
    RijndaelManaged rijndaelCipher;
    string encryptedFilePath;

    if (!File.Exists(stampFileToEncrpyt))
        throw new FileNotFoundException(stampFileToEncrpyt + " does not exist");

    config = Configuration.GetProgramInstance();
    encryptedFilePath = Path.Combine(config.StampFolder, Path.GetFileNameWithoutExtension(stampFileToEncrpyt) + ".stmp");

    stampToEncrypt = new Stamp(Path.GetFileNameWithoutExtension(stampFileToEncrpyt), encryptedFilePath);

    rijndaelCipher = this.GetCipher(_imageKey, true);
    ICryptoTransform transform = rijndaelCipher.CreateEncryptor();

    FileStream inputStream = null;
    FileStream outputStream = null;
    CryptoStream encryptSteam = null;
    byte[] block = new byte[16];
    int numberRead;

    try
    {
        inputStream = File.Open(stampFileToEncrpyt, FileMode.Open, FileAccess.Read);
        outputStream = File.Open(encryptedFilePath, FileMode.Create, FileAccess.Write);

        //outputStream.Write(rijndaelCipher.IV, 0, 16);
        encryptSteam = new CryptoStream(outputStream, transform, CryptoStreamMode.Write);

        encryptSteam.Write(block, 0, block.Length);

        while ((numberRead = inputStream.Read(block, 0, block.Length)) > 0)
        {
            encryptSteam.Write(block, 0, numberRead);
        }
    }
    finally
    {
        rijndaelCipher.Clear();
        rijndaelCipher.Dispose();
        if (encryptSteam != null)
            encryptSteam.Dispose();
        if (outputStream != null)
            outputStream.Dispose();
        if (inputStream != null)
            inputStream.Dispose();
    }

    return stampToEncrypt;
}

public struct Stamp
{
    public string Name,
        Path;

    public Stamp(string StampName, string StampPath)
    {
        Name = StampName;
        Path = StampPath;
    }
}

代码修复后

private RijndaelManaged GetCipher(byte[] key, bool forEncrypt)
{
    RijndaelManaged rijndaelCipher;

    rijndaelCipher = new RijndaelManaged();
    rijndaelCipher.Mode = CipherMode.CBC;
    rijndaelCipher.Padding = PaddingMode.PKCS7;
    rijndaelCipher.KeySize = 0x80;
    rijndaelCipher.BlockSize = 0x80;
    rijndaelCipher.Key = key;

    if (forEncrypt)
        rijndaelCipher.GenerateIV();
    else
        rijndaelCipher.IV = new byte[16];
    //rijndaelCipher.IV = _imageKey;

    return rijndaelCipher;
}

public void DecryptStamp(Stamp stampToDecrypt, string decrpytedStampFilePath)
{
    RijndaelManaged rijndaelCipher;
    FileStream inputStream = null;
    FileStream outputStream = null;
    CryptoStream encryptSteam = null;
    byte[] block;
    int numberRead;
    ICryptoTransform transform;

    if (!File.Exists(stampToDecrypt.Path))
        throw new FileNotFoundException(stampToDecrypt.Path + " does not exist");

    rijndaelCipher = this.GetCipher(_imageKey, false);
    block = new byte[16];

    try
    {
        inputStream = File.Open(stampToDecrypt.Path, FileMode.Open, FileAccess.Read);
        outputStream = File.Open(decrpytedStampFilePath, FileMode.Create, FileAccess.Write);

        inputStream.Read(rijndaelCipher.IV, 0, rijndaelCipher.IV.Length);
        transform = rijndaelCipher.CreateDecryptor();                     
        encryptSteam = new CryptoStream(outputStream, transform, CryptoStreamMode.Write);

        while ((numberRead = inputStream.Read(block, 0, block.Length)) > 0)
        {                
            encryptSteam.Write(block, 0, numberRead);
        }
    }
    finally
    {
        rijndaelCipher.Clear();
        rijndaelCipher.Dispose();
        if (encryptSteam != null)
            encryptSteam.Dispose();
        if (outputStream != null)
            outputStream.Dispose();
        if (inputStream != null)
            inputStream.Dispose();
    }
}

public Stamp EncryptStampToStampFolder(string stampFileToEncrpyt)
{
    Configuration config;
    Stamp stampToEncrypt;
    RijndaelManaged rijndaelCipher;
    string encryptedFilePath;

    if (!File.Exists(stampFileToEncrpyt))
        throw new FileNotFoundException(stampFileToEncrpyt + " does not exist");

    config = Configuration.GetProgramInstance();
    encryptedFilePath = Path.Combine(config.StampFolder, Path.GetFileNameWithoutExtension(stampFileToEncrpyt) + ".stmp");

    stampToEncrypt = new Stamp(Path.GetFileNameWithoutExtension(stampFileToEncrpyt), encryptedFilePath);

    rijndaelCipher = this.GetCipher(_imageKey, true);
    ICryptoTransform transform = rijndaelCipher.CreateEncryptor();

    FileStream inputStream = null;
    FileStream outputStream = null;
    CryptoStream encryptSteam = null;
    byte[] block = new byte[16];
    int numberRead;

    try
    {
        inputStream = File.Open(stampFileToEncrpyt, FileMode.Open, FileAccess.Read);
        outputStream = File.Open(encryptedFilePath, FileMode.Create, FileAccess.Write);

        outputStream.Write(rijndaelCipher.IV, 0, 16);
        encryptSteam = new CryptoStream(outputStream, transform, CryptoStreamMode.Write);

        //encryptSteam.Write(block, 0, block.Length); this line was the problem in the orginal code

        while ((numberRead = inputStream.Read(block, 0, block.Length)) > 0)
        {
            encryptSteam.Write(block, 0, numberRead);
        }
    }
    finally
    {
        rijndaelCipher.Clear();
        rijndaelCipher.Dispose();
        if (encryptSteam != null)
            encryptSteam.Dispose();
        if (outputStream != null)
            outputStream.Dispose();
        if (inputStream != null)
            inputStream.Dispose();
    }

    return stampToEncrypt;
}

public struct Stamp
{
    public string Name,
        Path;

    public Stamp(string StampName, string StampPath)
    {
        Name = StampName;
        Path = StampPath;
    }
}

新代码的输出

“7p¶¼oò¾½G€9 = hfox \ 0 \ 0跳过懒惰的黄狗”

2 个答案:

答案 0 :(得分:2)

问题是三折。 1)加密期间写入的额外数据 2)文件开头的IV被覆盖 3)在解密时没有正确读取IV

CODE已修复

private RijndaelManaged GetCipher(byte[] key, bool forEncrypt)
{
    RijndaelManaged rijndaelCipher;

    rijndaelCipher = new RijndaelManaged();
    rijndaelCipher.Mode = CipherMode.CBC;
    rijndaelCipher.Padding = PaddingMode.PKCS7;
    rijndaelCipher.KeySize = 0x80;
    rijndaelCipher.BlockSize = 0x80;
    rijndaelCipher.Key = key;

    if (forEncrypt)
        rijndaelCipher.GenerateIV();
    else
        rijndaelCipher.IV = new byte[16];
    //rijndaelCipher.IV = _imageKey;

    return rijndaelCipher;
}

public void DecryptStamp(Stamp stampToDecrypt, string decrpytedStampFilePath)
{
    RijndaelManaged rijndaelCipher;
    FileStream inputStream = null;
    FileStream outputStream = null;
    CryptoStream encryptSteam = null;
    byte[] block;
    int numberRead;
    ICryptoTransform transform;

    if (!File.Exists(stampToDecrypt.Path))
        throw new FileNotFoundException(stampToDecrypt.Path + " does not exist");

    rijndaelCipher = this.GetCipher(_imageKey, false);
    block = new byte[16];

    try
    {
        inputStream = File.Open(stampToDecrypt.Path, FileMode.Open, FileAccess.Read);
        outputStream = File.Open(decrpytedStampFilePath, FileMode.Create, FileAccess.Write);

        //This line was wrong because rijndaelCipher.IV never filled
        //inputStream.Read(rijndaelCipher.IV, 0, rijndaelCipher.IV.Length); 

        inputStream.Read(block, 0, block.Length);
        rijndaelCipher.IV = block;
        block = new byte[16];
        transform = rijndaelCipher.CreateDecryptor();                     
        encryptSteam = new CryptoStream(outputStream, transform, CryptoStreamMode.Write);

        while ((numberRead = inputStream.Read(block, 0, block.Length)) > 0)
        {                
            encryptSteam.Write(block, 0, numberRead);
        }
    }
    finally
    {
        rijndaelCipher.Clear();
        rijndaelCipher.Dispose();
        if (encryptSteam != null)
            encryptSteam.Dispose();
        if (outputStream != null)
            outputStream.Dispose();
        if (inputStream != null)
            inputStream.Dispose();
    }
}

public Stamp EncryptStampToStampFolder(string stampFileToEncrpyt)
{
    Configuration config;
    Stamp stampToEncrypt;
    RijndaelManaged rijndaelCipher;
    string encryptedFilePath;

    if (!File.Exists(stampFileToEncrpyt))
        throw new FileNotFoundException(stampFileToEncrpyt + " does not exist");

    config = Configuration.GetProgramInstance();
    encryptedFilePath = Path.Combine(config.StampFolder, Path.GetFileNameWithoutExtension(stampFileToEncrpyt) + ".stmp");

    stampToEncrypt = new Stamp(Path.GetFileNameWithoutExtension(stampFileToEncrpyt), encryptedFilePath);

    rijndaelCipher = this.GetCipher(_imageKey, true);
    ICryptoTransform transform = rijndaelCipher.CreateEncryptor();

    FileStream inputStream = null;
    FileStream outputStream = null;
    CryptoStream encryptSteam = null;
    byte[] block = new byte[16];
    int numberRead;

    try
    {
        inputStream = File.Open(stampFileToEncrpyt, FileMode.Open, FileAccess.Read);
        outputStream = File.Open(encryptedFilePath, FileMode.Create, FileAccess.Write);

        outputStream.Write(rijndaelCipher.IV, 0, IV.Length);
        //This had to be changed so that the IV was not overwitten
        //encryptSteam = new CryptoStream(outputStream, transform, CryptoStreamMode.Write); 
        encryptSteam = new CryptoStream(inputStream, transform, CryptoStreamMode.Read);

        //this line was a problem in the orginal code that caused extra data to be added to the encrypted file
        //encryptSteam.Write(block, 0, block.Length); 

        while ((numberRead = encryptSteam.Read(block, 0, block.Length)) > 0)
        {
            outputStream.Write(block, 0, numberRead);
        }
    }
    finally
    {
        rijndaelCipher.Clear();
        rijndaelCipher.Dispose();
        if (encryptSteam != null)
            encryptSteam.Dispose();
        if (outputStream != null)
            outputStream.Dispose();
        if (inputStream != null)
            inputStream.Dispose();
    }

    return stampToEncrypt;
}

public struct Stamp
{
    public string Name,
        Path;

    public Stamp(string StampName, string StampPath)
    {
        Name = StampName;
        Path = StampPath;
    }
}

答案 1 :(得分:0)

这是我要做的解密:

    private RijndaelManaged GetAesProvider(Stream stm, bool isEncryption)
    {
        byte[] finalKey = GetFinalKey();
        // GetIV either gets salt on encryption and writes it into stm
        // or reads it from stm if it's decryption
        byte[] iv = GetIV(stm, isEncryption);
        RijndaelManaged aes = new RijndaelManaged();
        aes.BlockSize = kAesBlockSizeInBytes * 8;
        aes.IV = iv;
        aes.Key = finalKey;
        aes.Mode = CipherMode.CBC;
        return aes;
    }

    public override Stream GetDecryptionStream(Stream source)
    {
        if (source.Length <= kIVSize)
        {
            return new EmptyStream();
        }
        RijndaelManaged aes = GetAesProvider(source, false);
        ICryptoTransform xform = aes.CreateDecryptor(aes.Key, aes.IV);
        return new CryptoStream(source, xform, CryptoStreamMode.Read);
    }