protected void RunSegmentedVectorTest(int number, SegmentedVectorTestCase testCase) { CipherConfiguration config = GetCipherConfiguration(testCase); var plaintext = new byte[testCase.IV.Length]; TestVectorSegment lastSegment = testCase.Segments.Last(); int requiredCiphertextLength = lastSegment.Offset + lastSegment.Length; var msCiphertext = new MemoryStream(); using (var cs = new CipherStream(msCiphertext, true, config, testCase.Key, false)) { while (cs.BytesOut < requiredCiphertextLength) { cs.Write(plaintext, 0, plaintext.Length); } } // Now we analyse the ciphertext segment-wise foreach (var segment in testCase.Segments) { msCiphertext.Seek(segment.Offset, SeekOrigin.Begin); var segmentCiphertext = new byte[segment.Length]; msCiphertext.Read(segmentCiphertext, 0, segment.Length); byte[] referenceCiphertext = segment.Ciphertext; // Validate the segment Assert.IsTrue(referenceCiphertext.SequenceEqualShortCircuiting(segmentCiphertext), "Segmented vector test #{0} (\"{1}\") failed at segment {2}!", number, testCase.Name, segment.Name); } }
/// <summary> /// Create a configuration for a stream cipher. /// </summary> /// <param name="cipher">Stream cipher to use.</param> /// <param name="keySize">Key size to use, in bits.</param> /// <returns>Stream cipher configuration DTO.</returns> public static CipherConfiguration CreateStreamCipherConfiguration(StreamCipher cipher, int?keySize = null) { var config = new CipherConfiguration { Type = CipherType.Stream }; int keySizeNonNull = keySize ?? Athena.Cryptography.StreamCiphers[cipher].DefaultKeySizeBits; if (keySize == null || Athena.Cryptography.StreamCiphers[cipher].AllowableKeySizesBits.Contains(keySizeNonNull)) { config.KeySizeBits = keySizeNonNull; } else { throw new CipherKeySizeException(cipher, keySizeNonNull); } config.CipherName = cipher.ToString(); if (Athena.Cryptography.StreamCiphers[cipher].DefaultNonceSizeBits != -1) { config.InitialisationVector = new byte[Athena.Cryptography.StreamCiphers[cipher].DefaultNonceSizeBits / 8]; StratCom.EntropySupplier.NextBytes(config.InitialisationVector); } return(config); }
/// <summary> /// Initialises a stream cipher from cipher configuration DTO. Used by constructor. /// </summary> private static ICipherWrapper InitStreamCipher(bool encrypting, CipherConfiguration config, byte[] key, out int maxDelta) { var streamConfigWrapper = new StreamCipherConfigurationWrapper(config); if (key.Length != streamConfigWrapper.KeySizeBytes) { throw new ArgumentException("Key is not of the length declared in the cipher configuration.", "key"); } StreamCipherEngine streamCipher; try { streamCipher = CipherFactory.CreateStreamCipher(streamConfigWrapper.GetStreamCipher()); streamCipher.Init(encrypting, key, streamConfigWrapper.GetNonce()); } catch (Exception e) { throw new ConfigurationInvalidException("Configuration of stream cipher is invalid.", e.InnerException); } // This should always be 0, but we'll do it anyway... maxDelta = Athena.Cryptography.StreamCiphers[streamCipher.Identity].MaximumOutputSizeDifference(encrypting); return(new StreamCipherWrapper(encrypting, streamCipher, strideIncreaseFactor: 2)); }
/// <summary> /// Initialises a block cipher from cipher configuration DTO. Used by constructor. /// </summary> private static ICipherWrapper InitBlockCipher(bool encrypting, CipherConfiguration config, byte[] key, out int maxDelta) { var blockConfigWrapper = new BlockCipherConfigurationWrapper(config); if (key.Length != blockConfigWrapper.KeySizeBytes) { throw new ArgumentException("Key is not of the length declared in the cipher configuration.", "key"); } BlockCipherBase blockCipherPrimitive = CipherFactory.CreateBlockCipher(blockConfigWrapper.GetBlockCipher(), blockConfigWrapper.GetBlockSizeBits()); // Overlay the cipher with the mode of operation BlockCipherModeBase blockCipher; try { blockCipher = CipherFactory.OverlayBlockCipherWithMode(blockCipherPrimitive, blockConfigWrapper.Mode); } catch (Exception e) { throw new ConfigurationInvalidException( "Configuration of block cipher mode of operation is invalid.", e.InnerException); } IBlockCipherPadding padding = null; BlockCipherPadding paddingEnum = blockConfigWrapper.GetPadding(); if (paddingEnum != BlockCipherPadding.None) { padding = CipherFactory.CreatePadding(paddingEnum); padding.Init(StratCom.EntropySupplier); } maxDelta = Athena.Cryptography.BlockCiphers[blockCipherPrimitive.Identity].MaximumOutputSizeDifference(encrypting); blockCipher.Init(encrypting, key, blockConfigWrapper.GetInitialisationVector()); return(new BlockCipherWrapper(encrypting, blockCipher, padding)); }
// Performance testing resources (not called in this base class, but called from derived classes) protected void RunPerformanceTest(CipherConfiguration config, byte[] overrideKey = null) { MemoryStream msInputPlaintext = LargeBinaryFile; byte[] key = overrideKey ?? CreateRandomByteArray(config.KeySizeBits); var msCiphertext = new MemoryStream((int)(msInputPlaintext.Length * 1.1)); var sw = new Stopwatch(); // TEST STARTS HERE using (var cs = new CipherStream(msCiphertext, true, config, key, false)) { sw.Start(); msInputPlaintext.CopyTo(cs, GetBufferSize()); } sw.Stop(); TimeSpan encryptionElapsed = sw.Elapsed; var msOutputPlaintext = new MemoryStream((int)msInputPlaintext.Length); msCiphertext.Seek(0, SeekOrigin.Begin); sw.Reset(); using (var cs = new CipherStream(msCiphertext, false, config, key, false)) { sw.Start(); cs.CopyTo(msOutputPlaintext, GetBufferSize()); } sw.Stop(); TimeSpan decryptionElapsed = sw.Elapsed; // TEST ENDS HERE // TEST OUTPUT PLAINTEXT VALIDITY msInputPlaintext.Seek(0, SeekOrigin.Begin); msOutputPlaintext.Seek(0, SeekOrigin.Begin); int failurePosition; Assert.IsTrue(StreamsContentMatches(msInputPlaintext, msOutputPlaintext, (int)msInputPlaintext.Length, out failurePosition), "Input and output plaintext does not match. First failure observed at position # " + failurePosition); // OUTPUT SUCCESS STATISTICS double encSpeed = ((double)msInputPlaintext.Length / 1048576) / encryptionElapsed.TotalSeconds, decSpeed = ((double)msInputPlaintext.Length / 1048576) / decryptionElapsed.TotalSeconds; Assert.Pass("{0:N0} ms ({1:N2} MB/s) : {2:N0} ms ({3:N2} MB/s)", encryptionElapsed.TotalMilliseconds, encSpeed, decryptionElapsed.TotalMilliseconds, decSpeed); }
/// <summary> /// Create a configuration for a block cipher. /// </summary> /// <param name="cipher">Block cipher to use.</param> /// <param name="mode">Mode of operation for the cipher.</param> /// <param name="padding">Padding scheme to use with the mode, where necessary (e.g. CBC).</param> /// <param name="keySize">Key size to use, in bits.</param> /// <param name="blockSize">Cipher block size to use, in bits.</param> /// <returns>Block cipher configuration DTO.</returns> public static CipherConfiguration CreateBlockCipherConfiguration(BlockCipher cipher, BlockCipherMode mode, BlockCipherPadding padding, int?keySize = null, int?blockSize = null) { var config = new CipherConfiguration { Type = CipherType.Block }; // Set the key size int keySizeNonNull = keySize ?? Athena.Cryptography.BlockCiphers[cipher].DefaultKeySizeBits; if (keySize == null || Athena.Cryptography.BlockCiphers[cipher].AllowableKeySizesBits.Contains(keySizeNonNull)) { config.KeySizeBits = keySizeNonNull; } else { throw new CipherKeySizeException(cipher, keySizeNonNull); } // Set the block size int blockSizeNonNull = blockSize ?? Athena.Cryptography.BlockCiphers[cipher].DefaultBlockSizeBits; if (blockSize == null || Athena.Cryptography.BlockCiphers[cipher].AllowableBlockSizesBits.Contains(blockSizeNonNull)) { config.BlockSizeBits = blockSizeNonNull; } else { throw new BlockSizeException(cipher, blockSizeNonNull); } // Set the mode if (Athena.Cryptography.BlockCipherModes[mode].PaddingRequirement == PaddingRequirement.Always && padding == BlockCipherPadding.None) { throw new ArgumentException(mode + " mode must be used with padding or errors will occur when plaintext length is not equal to or a multiple of the block size."); } config.ModeName = mode.ToString(); config.PaddingName = padding.ToString(); config.CipherName = cipher.ToString(); config.InitialisationVector = new byte[config.BlockSizeBits.Value / 8]; StratCom.EntropySupplier.NextBytes(config.InitialisationVector); return(config); }
public BlockCipherConfigurationWrapper(CipherConfiguration config) : base(config) { if (config == null) { throw new ArgumentNullException("config"); } if (config.Type == CipherType.None) { throw new ConfigurationInvalidException("Cipher configuration specifies Type = None."); } if (config.Type != CipherType.Block) { throw new ArgumentException("Configuration is not for a block cipher."); } }
protected void RunDiscreteVectorTest(int number, DiscreteVectorTestCase testCase) { CipherConfiguration config = GetCipherConfiguration(testCase); byte[] plaintext = testCase.Plaintext; byte[] ciphertext; using (var msCiphertext = new MemoryStream()) { using (var cs = new CipherStream(msCiphertext, true, config, testCase.Key, false)) { cs.Write(plaintext, 0, plaintext.Length); } ciphertext = msCiphertext.ToArray(); } Assert.IsTrue(testCase.Ciphertext.SequenceEqualShortCircuiting(ciphertext), "Test #{0} (\"{1}\") failed!", number, testCase.Name); }
public void StreamCipherConfiguration() { var inputObj = new CipherConfiguration() { Type = CipherType.Stream, CipherName = StreamCipher.Salsa20.ToString(), KeySizeBits = 256, InitialisationVector = new byte[] { 0x01, 0x02, 0x03 } }; var stream = SerialiseToMemory(inputObj); stream.Seek(0, SeekOrigin.Begin); var outputObj = DeserialiseFromMemory <CipherConfiguration>(stream); Assert.IsTrue(inputObj.Equals(outputObj)); }
private byte[] _opOutBuffer; // freshly-encrypted or decrypted data /// <summary> /// Initialises the stream and its associated cipher for operation automatically from provided configuration /// object. /// </summary> /// <param name="binding">Stream to be written/read to/from.</param> /// <param name="encrypting">Specifies whether the stream is for writing (encrypting) or reading (decryption).</param> /// <param name="config">Configuration object describing how to set up the internal cipher and associated services.</param> /// <param name="key">Derived cryptographic key for the internal cipher to operate with.</param> /// <param name="closeOnDispose">Set to <c>true</c> to also close the base stream when closing, or vice-versa.</param> public CipherStream(System.IO.Stream binding, bool encrypting, CipherConfiguration config, byte[] key, bool closeOnDispose) { #if INCLUDE_CONTRACTS Contract.Requires(binding != null); Contract.Requires(config != null); Contract.Requires(key != null); #endif if (key.IsNullOrZeroLength()) { throw new ArgumentException("No key provided.", "key"); } Writing = encrypting; _streamBinding = binding; _closeOnDispose = closeOnDispose; switch (config.Type) { case CipherType.None: throw new ConfigurationInvalidException( "Cipher type is never set to None in a valid cipher configuration."); case CipherType.Block: _cipher = InitBlockCipher(encrypting, config, key, out _maxCipherOutputDelta); break; case CipherType.Stream: _cipher = InitStreamCipher(encrypting, config, key, out _maxCipherOutputDelta); break; default: throw new ArgumentException("Not a valid cipher configuration."); } _opSize = _cipher.OperationSize; // Initialise the buffers _opInBuffer = new byte[_opSize]; _opOutBuffer = new byte[(_opSize + _maxCipherOutputDelta) * 2]; _inBuffer = new ConcurrentRingBuffer(16384); _outBuffer = new ConcurrentRingBuffer(16384); // LSH 8 upscales (256x) : 8 (64 bits) to 2048 [2kB], 16 (128) to 4096 [4kB], 32 (256) to 8192 [8kB] }
public void BlockCipherConfiguration() { var inputObj = new CipherConfiguration() { Type = CipherType.Block, CipherName = BlockCipher.Aes.ToString(), KeySizeBits = 128, InitialisationVector = new byte[] { 0x01, 0x02, 0x03 }, ModeName = BlockCipherMode.Ctr.ToString(), BlockSizeBits = 128, PaddingName = BlockCipherPadding.None.ToString() }; var stream = SerialiseToMemory(inputObj); stream.Seek(0, SeekOrigin.Begin); var outputObj = DeserialiseFromMemory <CipherConfiguration>(stream); Assert.IsTrue(inputObj.Equals(outputObj)); }
public AESCipher(CipherConfiguration configuration) { aes.Mode = configuration.CipherMode; aes.KeySize = configuration.KeySize; aes.BlockSize = configuration.BlockSize; }
protected CipherConfigurationWrapper(CipherConfiguration config) { Configuration = config; }