3

私はここで少し必死になっています。シリアル化されたオブジェクトを含む暗号化されたファイルをディスクに書き込み、後でファイルを取得して復号化し、オブジェクトを逆シリアル化しようとしています。

更新:コードを次のようにリファクタリングしました:

using (Stream innerStream = File.Create(this.GetFullFileNameForUser(securityContext.User, applicationName)))
            {
                using (Stream cryptoStream = new CryptoStream(innerStream, GetCryptoProvider().CreateEncryptor(), CryptoStreamMode.Write))
                {
                    // 3. write to the cryptoStream 
                    //BinaryFormatter bf = new BinaryFormatter();
                    //bf.Serialize(cryptoStream, securityContext);
                    XmlSerializer xs = new XmlSerializer(typeof(SecurityContextDTO));
                    xs.Serialize(cryptoStream, securityContext);
                }
            }


 using (Stream innerStream = File.Open(this.GetFullFileNameForUser(user, applicationName), FileMode.Open))
        {
            using (Stream cryptoStream = new CryptoStream(innerStream, GetCryptoProvider().CreateDecryptor(), CryptoStreamMode.Read))
            {
                //BinaryFormatter bf = new BinaryFormatter();
                //return (SecurityContextDTO)bf.Deserialize(cryptoStream);
                XmlSerializer xs = new XmlSerializer(typeof(SecurityContextDTO));
                //CryptographicException here
                return (SecurityContextDTO)xs.Deserialize(cryptoStream);
            }
        }

デシリアライズで暗号化例外が発生します:Bad Data

オリジナル:

私はこれをやっています:

public void StoreToFile(SecurityContextDTO securityContext, string applicationName)
    {
        if (securityContext.LoginResult.IsOfflineMode == false)
        {
            Stream stream = null;
            CryptoStream crStream = null;
            try
            {
                TripleDESCryptoServiceProvider cryptic = GetCryptoProvider();

                stream = File.Open(this.GetFullFileNameForUser(securityContext.User, applicationName), FileMode.Create);
                crStream = new CryptoStream(stream,
                   cryptic.CreateEncryptor(), CryptoStreamMode.Write);

                BinaryFormatter bFormatter = new BinaryFormatter();
                bFormatter.Serialize(crStream, securityContext);
            }
            catch(Exception)
            {
                throw;
            }
            finally
            {
                if (crStream != null)
                    crStream.Close();
            }
        }
    }



public SecurityContextDTO RetrieveFromFile(UserDTO user,string applicationName)
    {
        SecurityContextDTO objectToSerialize;
        Stream stream = null;
        CryptoStream crStream=null;
        try
        {
            stream = File.Open(this.GetFullFileNameForUser(user, applicationName), FileMode.Open);
             crStream= new CryptoStream(stream,
                GetCryptoProvider().CreateDecryptor(), CryptoStreamMode.Read);
            BinaryFormatter bFormatter = new BinaryFormatter();
            //Exception here
            objectToSerialize = (SecurityContextDTO)bFormatter.Deserialize(crStream); 
        }
        catch (Exception)
        {
            objectToSerialize = null;
        }
        finally
        {
            if (crStream!=null)
                crStream.Close();
        }
        return objectToSerialize;
    }


private static TripleDESCryptoServiceProvider GetCryptoProvider()
    {
        TripleDESCryptoServiceProvider cryptic = new TripleDESCryptoServiceProvider();
        try
        {
            cryptic.Key = ASCIIEncoding.ASCII.GetBytes(CrypKey);

            Rfc2898DeriveBytes db = new Rfc2898DeriveBytes("sdddsdsd", 8);
            cryptic.IV = db.GetBytes(8);
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            cryptic.Dispose();
        }
        return cryptic;
    }

暗号化と書き込みは正常に機能し、ファイルはディスクに表示され、コンテンツはそこにあります(もちろん暗号化されています)。しかし、retrieveメソッドを呼び出すと、常にSerializationExceptionが発生します

バイナリストリーム「30」には、有効なBinaryHeaderが含まれていません。考えられる原因は、シリアル化と逆シリアル化の間の無効なストリームまたはオブジェクトのバージョン変更です。

暗号化メソッドを除外すると、すべてが正常に機能します。

4

3 に答える 3

1

そう、

あなたはこのコードでそれを実現します

private static TripleDESCryptoServiceProvider GetCryptoProvider()
{
    TripleDESCryptoServiceProvider cryptic = new TripleDESCryptoServiceProvider();
    try
    {
        cryptic.Key = ASCIIEncoding.ASCII.GetBytes(CrypKey);

        Rfc2898DeriveBytes db = new Rfc2898DeriveBytes("sdddsdsd", 8);
        cryptic.IV = db.GetBytes(8);
    }
    catch (Exception)
    {
        throw;
    }
    finally
    {
        cryptic.Dispose(); // <------- Don't do this until you are done decrypting.
    }
    return cryptic;
}

常にプロバイダーを破棄します。つまり、常にランダムなキーと iv を使用しています。

于 2011-08-11T17:21:56.020 に答える
0

あなたは近くにいます。ただし、CryptoStream の作成に渡すストリームは、常に、常に、最終結果を保持するバッファーです。暗号化または復号化するデータを保持するのはストリームではありません。私はこれを初めて学んだことを覚えていて、あなたがしていたことを正確にやったので、そこに重点を置きました. だからここに:

// this is for encryption
var memStreamEncryptedData = new MemoryStream();
var encryptStream = new CryptoStream(memStreamEncryptedData, 
   transform, CryptoStreamMode.Write);

// this is for decryption
var memStreamDecryptedData = new MemoryStream();
var decryptStream = new CryptoStream(memStreamDecryptedData, 
   transform, CryptoStreamMode.Write);

どちらの場合も、CryptoStream は空白の出力ストリームで初期化されていることに注意してください。あなたのストリームは、後になって初めて登場します。そのため、書き込み中に次のことを行います。

encryptStream.Write(dataToBeEncrypted);
encryptStream.FlushFinalBlock();
encryptStream.Close();
// memStreamEncryptedData now safely holds your encrypted data

読みながら、次のことを行います。

decryptStream.Write(dataToBeDecrypted);
encryptStream.FlushFinalBlock();
encryptStream.Close();
// memStreamDecryptedData now safely holds your decrypted data

そこで、手間を省くために、暗号化と復号化の両方を実行するシンプルで優れた対称メソッドを次に示します。これとあなたのものの唯一の違いは、私がバイト配列で直接作業していることですが、おそらくその拡張は演習になる可能性があります。

public static byte[] Symmetric(bool encrypt, byte[] plaintext, string ikey)
{
    if (plaintext.Length == 0) return plaintext;

    // setting up the services can be very expensive, so I'll cache them
    // into a static dictionary.
    SymmetricSetup setup;
    if (!_dictSymmetricSetup.TryGetValue(ikey, out setup))
    {
        setup = new SymmetricSetup();
        setup.des = new DESCryptoServiceProvider { Mode = CipherMode.CBC, 
            Padding = PaddingMode.Zeros };
        setup.hash = Hash(Encoding.ASCII.GetBytes(ikey));
        setup.key = setup.hash.ForceLength(8, 0);
        setup.IV = Encoding.ASCII.GetBytes("init vec");
        setup.des.Key = setup.key;
        setup.des.IV = setup.IV;

        setup.encrypt = setup.des.CreateEncryptor(setup.des.Key, setup.des.IV);
        setup.decrypt = setup.des.CreateDecryptor(setup.des.Key, setup.des.IV);
        _dictSymmetricSetup[ikey] = setup;
    }

    var transform = encrypt ? setup.encrypt : setup.decrypt;

    var memStreamEncryptedData = new MemoryStream();

    var encStream = new CryptoStream(memStreamEncryptedData, transform, CryptoStreamMode.Write);

    if (encrypt)
        encStream.Write(new[] {(byte) ((8 - (plaintext.Length + 1)%8)%8)}, 0, 1);

    encStream.Write(plaintext, 0, plaintext.Length);
    encStream.FlushFinalBlock();
    encStream.Close();

    memStreamEncryptedData.Flush();

    var ciphertext = memStreamEncryptedData.ToArray();

    byte b;

    if (!encrypt)
        if (byte.TryParse("" + ciphertext[0], out b))
            ciphertext = ciphertext.Skip(1).Take(ciphertext.Length - b - 1).ToArray();

    return ciphertext;
}

それを呼び出すには、次のようにします。

static public byte[] DecryptData(this byte[] source, string password) {
    return Symmetric(false, source, password);
}

static public byte[] EncryptData(this byte[] source, string password) {
    return Symmetric(true, source, password);
}

ここでも、ストリームを操作するために少し異なることを行いますが、要点を理解していただければ幸いです。MemoryStream の代わりに、シリアライザーにフィードする必要があるストリームになります。

于 2011-08-11T16:26:49.613 に答える
0

使用できるいくつかの以前の投稿:

RijndaelManaged と PKCS5 パディングを使用して vb.net で文字列を暗号化するにはどうすればよいですか?

BinaryFormatter は圧縮を適用しますか?

後で、シリアライゼーションを伴う暗号化と圧縮をどのように積み重ねたかを見ることができます。そして、それは機能します。

于 2011-08-11T17:32:04.313 に答える