diff options
author | David Hook <dgh@bouncycastle.org> | 2017-07-06 18:51:02 +1000 |
---|---|---|
committer | David Hook <dgh@bouncycastle.org> | 2017-07-06 18:51:02 +1000 |
commit | f83b8c09c6fe002c5fea009d8a9fb3e5c55856d1 (patch) | |
tree | e3a6965a86878334f1236b785bae39d7a4053b21 | |
parent | DSTU 7624 MAC (diff) | |
download | BouncyCastle.NET-ed25519-f83b8c09c6fe002c5fea009d8a9fb3e5c55856d1.tar.xz |
added KCTR
-rw-r--r-- | crypto/src/crypto/modes/KCtrBlockCipher.cs | 235 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/DSTU7624Test.cs | 9 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/StreamCipherVectorTest.cs | 12 |
3 files changed, 245 insertions, 11 deletions
diff --git a/crypto/src/crypto/modes/KCtrBlockCipher.cs b/crypto/src/crypto/modes/KCtrBlockCipher.cs new file mode 100644 index 000000000..ff0249a6c --- /dev/null +++ b/crypto/src/crypto/modes/KCtrBlockCipher.cs @@ -0,0 +1,235 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * Implements a Gamming or Counter (CTR) mode on top of a DSTU 7624 block cipher. + */ + public class KCtrBlockCipher : IStreamCipher, IBlockCipher + { + private byte[] IV; + private byte[] ofbV; + private byte[] ofbOutV; + private bool initialised; + + private int byteCount; + + private readonly int blockSize; + private readonly IBlockCipher cipher; + + /** + * Basic constructor. + * + * @param cipher the block cipher to be used as the basis of the + * feedback mode. + */ + public KCtrBlockCipher(IBlockCipher cipher) + { + this.cipher = cipher; + this.IV = new byte[cipher.GetBlockSize()]; + this.blockSize = cipher.GetBlockSize(); + + this.ofbV = new byte[cipher.GetBlockSize()]; + this.ofbOutV = new byte[cipher.GetBlockSize()]; + } + + /** + * return the underlying block cipher that we are wrapping. + * + * @return the underlying block cipher that we are wrapping. + */ + public IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + /** + * Initialise the cipher and, possibly, the initialisation vector (IV). + * If an IV isn't passed as part of the parameter, the IV will be all zeros. + * An IV which is too short is handled in FIPS compliant fashion. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.initialised = true; + if (parameters is ParametersWithIV) + { + ParametersWithIV ivParam = (ParametersWithIV)parameters; + byte[] iv = ivParam.GetIV(); + int diff = IV.Length - iv.Length; + + Array.Clear(IV, 0, IV.Length); + Array.Copy(iv, 0, IV, diff, iv.Length); + + parameters = ivParam.Parameters; + } + else + { + throw new ArgumentException("Invalid parameter passed"); + } + + // if it's null, key is to be reused. + if (parameters != null) + { + cipher.Init(true, parameters); + } + + Reset(); + } + + /** + * return the algorithm name and mode. + * + * @return the name of the underlying algorithm followed by "/KCTR" + * and the block size in bits. + */ + public string AlgorithmName + { + get { return cipher.AlgorithmName + "/KCTR"; } + } + + public bool IsPartialBlockOkay + { + get { return true; } + } + + /** + * return the block size we are operating at. + * + * @return the block size we are operating at (in bytes). + */ + public int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + public byte ReturnByte(byte input) + { + return CalculateByte(input); + } + + public void ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff) + { + if (outOff + len > output.Length) + { + throw new DataLengthException("Output buffer too short"); + } + + if (inOff + len > input.Length) + { + throw new DataLengthException("Input buffer too small"); + } + + int inStart = inOff; + int inEnd = inOff + len; + int outStart = outOff; + + while (inStart<inEnd) + { + output[outStart++] = CalculateByte(input[inStart++]); + } + } + + protected byte CalculateByte(byte b) + { + if (byteCount == 0) + { + incrementCounterAt(0); + + checkCounter(); + + cipher.ProcessBlock(ofbV, 0, ofbOutV, 0); + + return (byte)(ofbOutV[byteCount++] ^ b); + } + + byte rv = (byte)(ofbOutV[byteCount++] ^ b); + + if (byteCount == ofbV.Length) + { + byteCount = 0; + } + + return rv; + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param input the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param output the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff) + { + if (input.Length - inOff< GetBlockSize()) + { + throw new DataLengthException("Input buffer too short"); + } + if (output.Length - outOff< GetBlockSize()) + { + throw new DataLengthException("Output buffer too short"); + } + + ProcessBytes(input, inOff, GetBlockSize(), output, outOff); + + return GetBlockSize(); + } + + /** + * reset the chaining vector back to the IV and reset the underlying + * cipher. + */ + public void Reset() + { + if (initialised) + { + cipher.ProcessBlock(IV, 0, ofbV, 0); + } + cipher.Reset(); + byteCount = 0; + } + + private void incrementCounterAt(int pos) + { + int i = pos; + while (i < ofbV.Length) + { + if (++ofbV[i++] != 0) + { + break; + } + } + } + + private void checkCounter() + { + // TODO: + // if the IV is the same as the blocksize we assume the user knows what they are doing + // if (IV.length < ofbV.length) + // { + // for (int i = 0; i != IV.length; i++) + // { + // if (ofbV[i] != IV[i]) + // { + // throw new IllegalStateException("Counter in KCTR mode out of range."); + // } + // } + // } + } + } +} diff --git a/crypto/test/src/crypto/test/DSTU7624Test.cs b/crypto/test/src/crypto/test/DSTU7624Test.cs index 6d55146a4..baced41fd 100644 --- a/crypto/test/src/crypto/test/DSTU7624Test.cs +++ b/crypto/test/src/crypto/test/DSTU7624Test.cs @@ -68,11 +68,12 @@ namespace Org.BouncyCastle.Crypto.Tests new BlockCipherVectorTest(29, new OfbBlockCipher(new Dstu7624Engine(256, 512), 256), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "98E122708FDABB1B1A5765C396DC79D7573221EC486ADDABD1770B147A6DD00B5FBC4F1EC68C59775B7AAA4D43C4CCE4F396D982DF64D30B03EF6C3B997BA0ED940BBC590BD30D64B5AE207147D71086B5", "BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F"), new BlockCipherVectorTest(30, new OfbBlockCipher(new Dstu7624Engine(512, 512), 512), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")), "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0", "CAA761980599B3ED2E945C41891BAD95F72B11C73ED26536A6847458BC76C827357156B4B3FE0DC1877F5B9F17B866C37B21D89531DB48007D05DEC928B06766C014BB9080385EDF0677E48A0A39B5E7489E28E82FFFD1F84694F17296CB701656"), new BlockCipherVectorTest(31, new OfbBlockCipher(new Dstu7624Engine(512, 512), 512), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("7F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "06C061A4A66DFC0910034B3CFBDC4206D8908241C56BF41C4103CFD6DF322210B87F57EAE9F9AD815E606A7D1E8E6BD7CB1EBFBDBCB085C2D06BF3CC1586CB2EE1D81D38437F425131321647E42F5DE309D33F25B89DE37124683E4B44824FC56D", "EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F"), - - - - + //CTR mode + new BlockCipherVectorTest(24, new KCtrBlockCipher(new Dstu7624Engine(128, 128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748", "A90A6B9780ABDFDFF64D14F5439E88F266DC50EDD341528DD5E698E2F000CE21F872DAF9FE1811844A"), + new BlockCipherVectorTest(25, new KCtrBlockCipher(new Dstu7624Engine(128, 128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "B91A7B8790BBCFCFE65D04E5538E98E216AC209DA33122FDA596E8928070BE51"), + new StreamCipherVectorTest(26, new KCtrBlockCipher(new Dstu7624Engine(128, 128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748", "A90A6B9780ABDFDFF64D14F5439E88F266DC50EDD341528DD5E698E2F000CE21F872DAF9FE1811844A"), + new StreamCipherVectorTest(27, new KCtrBlockCipher(new Dstu7624Engine(128, 128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "B91A7B8790BBCFCFE65D04E5538E98E216AC209DA33122FDA596E8928070BE51") }; public override ITestResult Perform() diff --git a/crypto/test/src/crypto/test/StreamCipherVectorTest.cs b/crypto/test/src/crypto/test/StreamCipherVectorTest.cs index ead2f16c3..c807a6841 100644 --- a/crypto/test/src/crypto/test/StreamCipherVectorTest.cs +++ b/crypto/test/src/crypto/test/StreamCipherVectorTest.cs @@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Tests * a basic test that takes a stream cipher, key parameter, and an input * and output string. */ - public class StreamCipherVectorTest: ITest + public class StreamCipherVectorTest: SimpleTest { int id; IStreamCipher cipher; @@ -33,12 +33,12 @@ namespace Org.BouncyCastle.Crypto.Tests this.output = Hex.Decode(output); } - public string Name + public override string Name { get { return cipher.AlgorithmName + " Vector Test " + id; } } - public ITestResult Perform() + public override void PerformTest() { cipher.Init(true, param); @@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Crypto.Tests if (!Arrays.AreEqual(outBytes, output)) { - return new SimpleTestResult(false, Name + ": failed - " + Fail("failed - " + "expected " + Hex.ToHexString(output) + " got " + Hex.ToHexString(outBytes)); } @@ -59,10 +59,8 @@ namespace Org.BouncyCastle.Crypto.Tests if (!Arrays.AreEqual(input, outBytes)) { - return new SimpleTestResult(false, Name + ": failed reversal"); + Fail("failed reversal"); } - - return new SimpleTestResult(true, Name + ": OKAY"); } } } |