我的一些应用用户在解密序列化文件时报告错误。
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和PADDING,因此它将是默认值CipherMode.CBC和PaddingMode.PKCS7。我还检查了SerialKEY和SerialIV以确认它不会改变。事实上,有几个序列化文件,但只有一个面临这个问题。
我试图减少异常。我试过了:
但我不能得到例外:
CryptographicException: Bad PKCS7 padding. Invalid length 137.
只会收到另一个错误:
Unexpected binary element: 100
我也在谷歌搜索过,在stackoverflow中发现了一些类似的问题:
CryptographicException: Bad PKCS7 padding
但我没有得到有用的建议。
答案 0 :(得分:2)
创建序列化文件的方法存在一个相当微妙的错误。您正在打开文件以像这样创建
FileStream fs = new FileStream(FilePath, FileMode.OpenOrCreate);
如果您这样做,您的代码将起作用:
FileStream fs = new FileStream(FilePath, FileMode.Create);
通过打开OpenOrCreate
中的文件打开文件,如果您的数据集完全缩小,您将在文件末尾有一些额外的数据。对于序列化对象来说,这通常不是问题,但是CBC和PKCS7的组合使得这个致命。
您可以毫无问题地解码大部分数据,但您编写的较小文件的最后一个块将解码正常,但填充不会被删除。那没关系,但是之前较大文件的下一个段将被读取和解码。因为CBC更新IV对解码这个块几乎肯定是错误的,它会解码为无意义。 BinaryFormatter
可能对这个垃圾数据没问题,但是当解码文件的最后一个块时,PKCS7填充将启动,并且因为解码后的值是垃圾,所以很可能它不是有效的填充数据,解码器会抛出你看到的异常。
答案 1 :(得分:0)
如果我在这里发帖,我很抱歉,但我的代表很低,我无法添加评论。 我相信你的加密机制可能有问题。