加密异常:错误的 PKCS7 填充.长度无效 137

本文关键字:无效 填充 PKCS7 异常 错误 加密 | 更新日期: 2023-09-27 17:56:52

我的一些应用程序用户在解密序列化文件时报告错误。

Exception   LocalTime: 07/08/2016 21:22:16 ServerTime: 07/08/2016 21:22:16  508 CryptographicException: Bad PKCS7 padding. Invalid length 137.
Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException (PaddingMode padding, Int32 length, Int32 position)
Mono.Security.Cryptography.SymmetricTransform.FinalDecrypt (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
Mono.Security.Cryptography.SymmetricTransform.TransformFinalBlock (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock (System.Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
System.Security.Cryptography.CryptoStream.Read (System.Byte[] buffer, Int32 offset, Int32 count)
System.IO.BinaryReader.FillBuffer (Int32 numBytes)
System.IO.BinaryReader.ReadInt32 ()
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadArrayOfPrimitiveType (System.IO.BinaryReader reader, System.Int64& objectId, System.Object& val)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject (System.IO.BinaryReader reader)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph (BinaryElement elem, System.IO.BinaryReader reader, Boolean readHeaders,System.Object& result, System.Runtime.Remoting.Messaging.Header[]& headers)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream)

这是我正在使用的代码:

public void Serialiable(){
    if (!Directory.Exists (DirectoryPath)) {
        Directory.CreateDirectory(DirectoryPath);
    }
    FileStream fs = new FileStream (FilePath, FileMode.OpenOrCreate);
    CryptoStream cryptStream = new CryptoStream(fs, Encryptor, CryptoStreamMode.Write); 
    BinaryFormatter formatter = new BinaryFormatter ();
    try{
        formatter.Serialize(cryptStream,this);
    }catch(System.Exception e){
        Debug.LogError("Failed to serialize. Reason:  "+e.Message);
    }finally{
        cryptStream.Close();
        fs.Close();
    }
}
public SerializableBase Deserialize(){
    SerializableBase t = null;
    if (File.Exists (FilePath)) {
        FileStream fs = new FileStream (FilePath, FileMode.Open);
        CryptoStream cryptStream  = new CryptoStream(fs, Decryptor,CryptoStreamMode.Read);
        try {
            BinaryFormatter formatter = new BinaryFormatter ();
            t = (SerializableBase)formatter.Deserialize (cryptStream);
            t.Refresh();
        } catch(System.Exception e){
            Debug.LogError("Failed to deserialize. Reason: "+e.Message);
            t = null;
        }
        finally {
            if(cryptStream!=null){
                cryptStream.Close();
            }
            fs.Close ();
        }
    } 
    return t;
}
[NonSerialized]
ICryptoTransform _Encryptor;
ICryptoTransform Encryptor {
    get{
        if(_Encryptor==null){
            _Encryptor = RMCrypto.CreateEncryptor(RuntimeGlobalVariables.SerialKEY,RuntimeGlobalVariables.SerialIV);
        }
        return _Encryptor;
    }
}
[NonSerialized]
ICryptoTransform _Decryptor ;
ICryptoTransform Decryptor {
    get{
        if(_Decryptor==null){
            _Decryptor = RMCrypto.CreateDecryptor(RuntimeGlobalVariables.SerialKEY,RuntimeGlobalVariables.SerialIV);
        }
        return _Decryptor;
    }
}
[NonSerialized]
RijndaelManaged _RMCrypto;
RijndaelManaged RMCrypto
{
    get
    {
        if (_RMCrypto == null)
        {
            _RMCrypto = new RijndaelManaged();
        }
        return _RMCrypto;
    }
}
string DirectoryPath
{
    get
    {
        return Application.persistentDataPath + "/dat";
    }
}
string FilePath {
    get{
        return DirectoryPath + "/" + FileName;
    }
}

我没有设置MODE和填充,所以它将是默认值CipherMode.CBC和PaddingMode.PKCS7。我还检查了 SerialKEY 和 SerialIV 以确认它不会 change.in 事实,有几个序列化文件,但只有一个面临问题。

我试图重现异常。我试过:

  1. 通过记事本编辑序列化文件并稍作更改
  2. 使用不同的填充或模式进行加密/解密
  3. 使用不同的串行密钥或串行IV进行加密/解密

但我不能得到例外:

 CryptographicException: Bad PKCS7 padding. Invalid length 137.

只会收到另一个错误,例如:

 Unexpected binary element: 100

我也通过谷歌搜索,在stackoverflow中发现了一些类似的问题:

加密异常:错误的 PKCS7 填充

但我没有得到有用的建议。

加密异常:错误的 PKCS7 填充.长度无效 137

在创建序列化文件的方式中存在一个相当微妙的错误。 您正在打开文件以像这样创建

FileStream fs = new FileStream(FilePath, FileMode.OpenOrCreate);

如果改为执行此操作,则代码将起作用:

FileStream fs = new FileStream(FilePath, FileMode.Create);

通过在OpenOrCreate中打开文件来打开文件,如果您的数据集完全缩小,您将在文件末尾有一些额外的数据。 对于序列化对象来说,这通常不是问题,但 CBC 和 PKCS7 的组合使这致命。

您将毫无问题地解码大部分数据,但您编写的较小文件的最后一个块将解码正常,但填充不会被删除。 没关系,但是之前较大的文件的下一段将被读取和解码。 因为CBC更新的IV几乎肯定解码这个块是错误的,所以它会解码为废话。 BinaryFormatter可能会接受这些垃圾数据,但是当需要解码文件的最后一个块时,PKCS7 填充将启动,并且由于解码值是垃圾,因此很可能它不是有效的填充数据,解码器会抛出您看到的异常。

如果我

在这里发帖,我很抱歉,但我的代表很少,我无法添加评论。我相信您的加密机制可能有问题。

您是否检查过:Rijndael 填充或长度无效