0

bouncycastleライブラリを使用してデータを暗号化および復号化しようとしています。データを復号化すると、情報の最初のブロックが正常に復号化できず、最後のブロックが完全に失われたかのように破損します。私はbouncycastleライブラリを初めて使用し、インターネット全体でPKCS7Paddingを使用したCBCモードでのAES暗号化の適切な実装を見つけようとしていますが、多くのドキュメントを見つけることができませんでした。どんな助けでも大歓迎です。また、私はプロの開発者ではなく学生であることに注意する必要があります。ありがとう。

`public class RijndaelCBC
{
    private int _keySize;
    private byte[] _passphrase;

    public byte[] _iv { get; private set; }

    private IBlockCipher blockCipher;
    private PaddedBufferedBlockCipher aesCipher;
    private ParametersWithIV _param;

    public RijndaelCBC(int KeySize, string Passphrase)
    {
        if (Passphrase.Length < KeySize / 8)
            Passphrase = Passphrase.PadRight(KeySize / 8, '0');
        if (Passphrase.Length > KeySize)
            Passphrase = Passphrase.Substring(0, KeySize / 8);

        _passphrase = System.Convert.FromBase64String(Passphrase);
        Array.Resize(ref _passphrase, KeySize / 8);
        _keySize = KeySize;

        Random rnd = new Random();
        _iv = new byte[_keySize / 8];
        for (int t = 0; t < _keySize / 8; t++)
            rnd.Next();
        rnd.NextBytes(_iv);

        if (_keySize != 128 && _keySize != 192 && _keySize != 256)
            throw new Exception(string.Format("Invalid key size of {0} provided, cannot continue with the process.", _keySize));
    }

    public RijndaelCBC(int KeySize, string Passphrase, byte[] iv)
    {
        if (Passphrase.Length < KeySize / 8)
            Passphrase = Passphrase.PadRight(KeySize / 8, '0');
        if (Passphrase.Length > KeySize)
            Passphrase = Passphrase.Substring(0, KeySize / 8);


        _passphrase = System.Convert.FromBase64String(Passphrase);
        Array.Resize(ref _passphrase, KeySize / 8);
        _keySize = KeySize;
        _iv = iv;
        if (_keySize != 128 && _keySize != 192 && _keySize != 256)
            throw new Exception(string.Format("Invalid key size of {0} provided, cannot continue with the process.", _keySize));
    }

    public byte[] Encrypt(byte[] data)
    {
        try
        {
            blockCipher = new CbcBlockCipher(new RijndaelEngine(_keySize));
            _param = new ParametersWithIV(new KeyParameter(_passphrase), _iv);
            blockCipher.Init(true, _param);

            aesCipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
            byte[] cipherTextBlock = null; 
            int blockSize = aesCipher.GetBlockSize();
            List<byte> output = new List<byte>();
            int outputLen = 0;
            int chunkPosition = 0;
            for (chunkPosition = 0; chunkPosition < data.Length; chunkPosition += blockSize)
            {
                byte[] dataToProcess = new byte[blockSize];
                int chunkSize = (data.Length - chunkPosition) < blockSize ? (data.Length - chunkPosition) : blockSize;
                Buffer.BlockCopy(data, chunkPosition, dataToProcess, 0, chunkSize);

                cipherTextBlock = new byte[blockSize];
                outputLen = aesCipher.ProcessBytes(dataToProcess, 0, chunkSize, cipherTextBlock, 0);
                output.AddRange(cipherTextBlock);
            }
            try
            {
                if(chunkPosition < data.Length &&
                    chunkPosition + blockSize > data.Length)
                {
                    byte[] dataToProcess = new byte[blockSize];
                    int chunkSize = (chunkPosition + blockSize) - data.Length;
                    Buffer.BlockCopy(data, chunkPosition, dataToProcess, 0, chunkSize);
                    aesCipher.DoFinal(cipherTextBlock, 0);
                    output.AddRange(cipherTextBlock);
                }
            }
            catch (CryptoException ex)
            {}
            return output.ToArray();
        }
        catch (System.Exception ex)
        { }
        return null;
    }

    public byte[] Decrypt(byte[] data)
    {
        try
        {
            blockCipher = new CbcBlockCipher(new RijndaelEngine(_keySize));
            _param = new ParametersWithIV(new KeyParameter(_passphrase), _iv);
            blockCipher.Init(false, _param);

            aesCipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
            byte[] cipherTextBlock = null;   
            int blockSize = aesCipher.GetBlockSize();
            List<byte> output = new List<byte>();
            int outputLen = 0;
            int chunkPosition = 0;
            for (chunkPosition = 0; chunkPosition < data.Length; chunkPosition += blockSize)
            {
                byte[] dataToProcess = new byte[blockSize];
                int chunkSize = (data.Length - chunkPosition) < blockSize ? (data.Length - chunkPosition) : blockSize;
                Buffer.BlockCopy(data, chunkPosition, dataToProcess, 0, chunkSize);
                cipherTextBlock = new byte[blockSize];

                outputLen = aesCipher.ProcessBytes(dataToProcess, 0, chunkSize, cipherTextBlock, 0);
                output.AddRange(cipherTextBlock);
            }
            try
            {
                if (chunkPosition < data.Length &&
                    chunkPosition + blockSize > data.Length)
                {
                    byte[] dataToProcess = new byte[blockSize];
                    int chunkSize = (chunkPosition + blockSize) - data.Length;
                    Buffer.BlockCopy(data, chunkPosition, dataToProcess, 0, chunkSize);
                    aesCipher.DoFinal(cipherTextBlock, 0);
                    output.AddRange(cipherTextBlock);
                }
            }
            catch (CryptoException ex)
            { }
            return output.ToArray();
        }
        catch (System.Exception ex)
        { }
        return null;
    }
}`

出力の例:データの先頭は次のようになります。

本番バージョンのリリース

しかし、最終的には次のようになります。 [¨dZJÊ)uól)ȱýº—ÑÚ〜VE'・ðúœ×ñðersionリリース

データの終わりは次のとおり です。そのような製品について、インテルは一切の責任を負わず、インテル製品の販売および/または使用に関連する明示または黙示の保証を否認します。これには、特定の目的への適合性、商品性に関連する責任または保証が含まれます。または、特許、著作権、またはその他の知的財産権の侵害。インテル製品は、医療、救命、または生命維持の用途での使用を目的としていません。

ただし、最終的には次 のようになります。そのような製品については、インテルは一切の責任を負わず、インテルは、責任または保証を含む、インテル製品の販売および/または使用に関連する明示または黙示の保証を否認します。

私は例を暗号化して復号化しようとしましたが、最後にデータが失われ、最初にデータが適切に復号化されませんでしたが、ファイルの残りの部分52KBは完璧でした。

4

3 に答える 3

3

このコードにはいくつかの問題がありますが、復号化の問題を引き起こしているのはIVの使用です。暗号化中にランダムなIVを生成しますが(良い)、それを破棄します。次に、復号化中に別のランダムIVを生成しますが、これは正しくありません。復号化には暗号化と同じIVを使用する必要があります。通常、IVを暗号文と一緒に渡します(通常、暗号文の前に付けるのが最も簡単です)。

キーの生成も正しくありません。私が知る限り、Base-64エンコーディングの「パスフレーズ」を期待しています。次に、キーの長さで切り落とすか、0で埋めます。これは非常に安全ではありません。あなたは基本的にAES-256をAES-50かそこらに変えています。暗号化されているように見えますが、実際には小さなキースペースがあり、ブルートフォース攻撃を受ける可能性があります。

人間が入力したパスワードをAESキーに変換する正しい方法は、PBKDF2と呼ばれるアルゴリズムを使用することです。私は弾む城に特に精通しておらず、彼らがPBKDF2にどのプロバイダーを使用しているかわかりません。弾む城に固有の詳細については、Javaの弾む城を備えたPBKDF2を参照してください。

于 2012-10-04T19:33:41.827 に答える
2

コードを機能させるために私がやったことは、パディングされたブロック暗号をバッファリングされたブロック暗号に変更することでした。これを行うことの悪影響があるかどうかはわかりませんが、誰かがそれを必要とする場合に備えて、コードを含めました。 C#でbouncycastleの例を見つける

public class RijndaelCBC
{
    private int _keyBitSize;
    public byte[] _iv { get; private set; }

    private BufferedBlockCipher cipher;
    private KeyParameter key;
    private ParametersWithIV IVkey;

    public RijndaelCBC(int KeySize, byte[] salt, string Passphrase)
    {
    _keyBitSize = KeySize;

        Random rnd = new Random();

        _iv = new byte[_keyBitSize / 8];
        for (int t = 0; t < _keyBitSize / 8; t++)
            rnd.Next();
        rnd.NextBytes(_iv);

        PbeParametersGenerator generator = new Pkcs5S2ParametersGenerator();
        generator.Init(PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes((Passphrase).ToCharArray()), salt, 1000);
        key = (KeyParameter)generator.GenerateDerivedParameters("AES", _keyBitSize);
    }

    public RijndaelCBC(int KeySize, byte[] salt, string Passphrase, byte[] iv)
    {
        _iv = iv;

        PbeParametersGenerator generator = new Pkcs5S2ParametersGenerator();
        generator.Init(PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes((Passphrase).ToCharArray()), salt, 1000);
        key = (KeyParameter)generator.GenerateDerivedParameters("AES", _keyBitSize);
    }


    public byte[] Encrypt(byte[] data)
    {
        IBlockCipher theCipher = null;
        theCipher = new RijndaelEngine(_keyBitSize);
        cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(theCipher));
        IVkey = new ParametersWithIV(key, _iv);
        cipher.Init(true, IVkey);

        int size = cipher.GetOutputSize(data.Length);
        byte[] result = new byte[size];
        int olen = cipher.ProcessBytes(data, 0, data.Length, result, 0);
        olen += cipher.DoFinal(result, olen);

        if (olen < size)
        {
            byte[] tmp = new byte[olen];
            Array.Copy(result, 0, tmp, 0, olen);
            result = tmp;
        }

        return result;
    }

    public byte[] Decrypt(byte[] data)
    {
        IBlockCipher theCipher = null;
        theCipher = new RijndaelEngine(_keyBitSize);
        cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(theCipher));
        IVkey = new ParametersWithIV(key, _iv);
        cipher.Init(false, IVkey);

        int size = cipher.GetOutputSize(data.Length);
        byte[] result = new byte[size];
        int olen = cipher.ProcessBytes(data, 0, data.Length, result, 0);
        olen += cipher.DoFinal(result, olen);

        if (olen < size)
        {
            byte[] tmp = new byte[olen];
            Array.Copy(result, 0, tmp, 0, olen);
            result = tmp;
        }

        return result;
    }
}

上記のクラスの初期化の問題に関して、最初のコンストラクターは、暗号化に使用できるランダムデータを使用してIVを生成します。このIVの生成後、_ivプロパティにアクセスしてIVを取得できます。または、2番目のクラスのコンストラクターを使用して、暗号化および/または復号化中にIVを渡すことができます。

于 2012-10-09T19:13:37.813 に答える
1

最初のブロックを正しく取得できない理由は、IV値またはバッファ処理の問題である必要があります。DoFinal間違った方法を使用したために最後が欠落しているため、最後の1つは予想よりも論理的である可能性があります。出力バッファの代わりに入力バッファを提供します。

于 2012-10-05T08:33:55.480 に答える