java bc sicblockcipher直接输出等效于c#[英] Java BC SicBlockCipher direct output equivalent in c#

问题描述

我正在在C#中实施某些内容,为此我有一个单独的规格,并且对我需要做的事情有相当清楚的了解,但是与此同时,作为参考,我有Java实施,并希望遵循Java实现这种情况尽可能接近.

代码涉及加密流,Java源为在这里 相关行在这里:

  private final StreamCipher enc;
...
  BlockCipher cipher;
  enc = new SICBlockCipher(cipher = new AESEngine());
  enc.init(true, new ParametersWithIV(new KeyParameter(secrets.aes), new byte[cipher.getBlockSize()]));
...
...
byte[] ptype = RLP.encodeInt((int) frame.type); //Result can be a single byte long
...
...
enc.processBytes(ptype, 0, ptype.length, buff, 0);
out.write(buff, 0, ptype.length); //encrypt and write a single byte from the SICBlockCipher stream

上面的Java Bouncycastle SicBlockCipher是A StreamCipher,允许处理比AES块大小的单个或少数字节.

在C#Bouncycastle中,SicBlockCipher仅提供ProcessBlock,而BufferedBlockCipher似乎没有提供一种使用ProcessBytes来保证输出的方法.

我需要与C#Bouncycastle库来实现等效功能?

推荐答案

不幸的是,SicBlockCipher本身不是作为流密码实现的,因此(实际上)无法直接可用.

BufferedBlockCipher已经创建了许多不同的操作模式.它可以缓冲输入,而对于SicBlockCipher实现的计数器(CTR)模式,您需要缓冲加密的计数器块.

加密的计数器块构成了键流,然后可以用纯文本进行XOR来创建CipherStream(或者确实是使用Ciphertext再次检索明文,加密是对反模式的解密).

我看到的唯一方法是创建自己的IBlockCipher实现并实现上述功能.


这是计数器模式作为流密码...

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Modes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SicStream
{
    public class SicStreamCipher : IStreamCipher
    {
        private SicBlockCipher parent;
        private int blockSize;

        private byte[] zeroBlock;

        private byte[] blockBuffer;
        private int processed;

        public SicStreamCipher(SicBlockCipher parent)
        {
            this.parent = parent;
            this.blockSize = parent.GetBlockSize();

            this.zeroBlock = new byte[blockSize];

            this.blockBuffer = new byte[blockSize];
            // indicates that no bytes are available: lazy generation of counter blocks (they may not be needed)
            this.processed = blockSize;
        }

        public string AlgorithmName
        {
            get
            {
                return parent.AlgorithmName;
            }
        }

        public void Init(bool forEncryption, ICipherParameters parameters)
        {
            parent.Init(forEncryption, parameters);

            Array.Clear(blockBuffer, 0, blockBuffer.Length);
            processed = blockSize;
        }

        public void ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff)
        {
            int inputProcessed = 0;
            while (inputProcessed < length)
            {
                // NOTE can be optimized further
                // the number of available bytes can be pre-calculated; too much branching
                if (processed == blockSize)
                {
                    // lazilly create a new block of key stream
                    parent.ProcessBlock(zeroBlock, 0, blockBuffer, 0);
                    processed = 0;
                }

                output[outOff + inputProcessed] = (byte)(input[inOff + inputProcessed] ^ blockBuffer[processed]);

                processed++;
                inputProcessed++;
            }
        }

        public void Reset()
        {
            parent.Reset();

            Array.Clear(blockBuffer, 0, blockBuffer.Length);
            this.processed = blockSize;
        }

        public byte ReturnByte(byte input)
        {
            if (processed == blockSize)
            {
                // lazily create a new block of key stream
                parent.ProcessBlock(zeroBlock, 0, blockBuffer, 0);
                processed = 0;
            }
            return (byte)(input ^ blockBuffer[processed++]);
        }
    }
}

...并在这里包装,以便可以在使用块密码操作模式的代码中对其进行翻新...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Modes;

namespace SicStream
{
    /**
     * A class that implements an online Sic (segmented integer counter mode, or just counter (CTR) mode for short).
     * This class buffers one encrypted counter (representing the key stream) at a time.
     * The encryption of the counter is only performed when required, so that no key stream blocks are generated while they are not required.
     */
    public class StreamingSicBlockCipher : BufferedCipherBase
    {
        private SicStreamCipher parent;
        private int blockSize;

        public StreamingSicBlockCipher(SicBlockCipher parent)
        {
            this.parent = new SicStreamCipher(parent);
            this.blockSize = parent.GetBlockSize();
        }

        public override string AlgorithmName
        {
            get
            {
                return parent.AlgorithmName;
            }
        }

        public override byte[] DoFinal()
        {
            // returns no bytes at all, as there is no input
            return new byte[0];
        }

        public override byte[] DoFinal(byte[] input, int inOff, int length)
        {
            byte[] result = ProcessBytes(input, inOff, length);

            Reset();

            return result;
        }

        public override int GetBlockSize()
        {
            return blockSize;
        }

        public override int GetOutputSize(int inputLen)
        {
            return inputLen;
        }

        public override int GetUpdateOutputSize(int inputLen)
        {
            return inputLen;
        }

        public override void Init(bool forEncryption, ICipherParameters parameters)
        {
            parent.Init(forEncryption, parameters);
        }

        public override byte[] ProcessByte(byte input)
        {
            return new byte[] { parent.ReturnByte(input) };
        }

        public override byte[] ProcessBytes(byte[] input, int inOff, int length)
        {
            byte[] result = new byte[length];
            parent.ProcessBytes(input, inOff, length, result, 0);
            return result;
        }

        public override void Reset()
        {
            parent.Reset();
        }
    }
}

请注意,由于需要创建其他数组,因此最后一个代码效率较低.

其他推荐答案

在基于Maarten Bodewes的流媒体和密码方面有一些顿悟,有用和信息丰富的答案(非常感谢!)我也想到了以下方法.

.NET BC库具有streamblockcipher类,如Java,但在其ctor或initializer中具有后卫,基础密码应具有1.

的块大小.

为了使用StreamBlockCipher,我创建了一个SicblockCipher的子类,该子类内部缓冲Keystream的块.我将其命名为streamablesicblockcipher.它尚未进行测试,但如果存在问题,至少它指向了另一种方式的方向.

 public class StreamableSicBlockCipher : SicBlockCipher
{
    private int blockSize;
    private int position = 0;
    private byte[] zeroBlock;
    private byte[] keyStreamBlock;

    public StreamableSicBlockCipher(IBlockCipher cipher) : base(cipher)
    {
        blockSize=cipher.GetBlockSize();
        zeroBlock = new byte[blockSize];
        keyStreamBlock = new byte[blockSize];
    }



    public override int GetBlockSize()
    {
        return 1;
    }

    public override int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
    {
        int keyStreamBlockOffset = position % blockSize;

        if (0==keyStreamBlockOffset)
        {

            var cipher = GetUnderlyingCipher();
            cipher.ProcessBlock(zeroBlock, 0, keyStreamBlock, 0);

            // Increment the counter
            int j = zeroBlock.Length;
            while (--j >= 0 && ++zeroBlock[j] == 0)
            {
            }
        }

        output[outOff] = (byte)(input[inOff] ^ keyStreamBlock[keyStreamBlockOffset]);

        position++;

        return 1;

    }
    public override void Reset()
    {
        base.Reset();
        this.position = 0;

    }

然后可以使用适当的包装器来调用如下:

StreamBlockCipher EncCipher = new StreamBlockCipher(new StreamableSicBlockCipher(new AesEngine()));

可以使用iBlockCipher的实例进行初始化.下面的示例为空IV,使用'cipher',这是AesEngine的实例.:

 EncCipher.Init(true, new ParametersWithIV(new KeyParameter(cryptoSecret), new byte[Cipher.GetBlockSize()]));

本文地址:https://www.itbaoku.cn/post/978375.html