Example #1
0
        /* =================================================================================================================
         * Twofish and Threefish are out-of-scope for MVP-01.
         * =================================================================================================================
         * [TestMethod]
         * public void Encrypt_ShouldReproduceTestVector_ForTwofish128Ecb()
         * {
         *  // Arrange.
         *  var algorithm = SymmetricAlgorithmSpecification.Twofish128Ecb;
         *  var blockLengthInBits = 128;
         *  var cipherMode = CipherMode.ECB;
         *  var key = new Byte[] { 0x9f, 0x58, 0x9f, 0x5c, 0xf6, 0x12, 0x2c, 0x32, 0xb6, 0xbf, 0xec, 0x2f, 0x2a, 0xe8, 0xc3, 0x5a };
         *  var initializationVector = (Byte[])null;
         *  var plaintext = new Byte[] { 0xd4, 0x91, 0xdB, 0x16, 0xe7, 0xb1, 0xc3, 0x9e, 0x86, 0xcb, 0x08, 0x6b, 0x78, 0x9f, 0x54, 0x19 };
         *  var ciphertext = new Byte[] { 0x01, 0x9f, 0x98, 0x09, 0xde, 0x17, 0x11, 0x85, 0x8f, 0xaa, 0xc3, 0xa3, 0xba, 0x20, 0xfb, 0xc3 };
         *
         *  // Assert.
         *  Encrypt_ShouldReproduceTestVector(algorithm, blockLengthInBits, cipherMode, key, initializationVector, plaintext, ciphertext);
         * }*/

        private static void Encrypt_ShouldReproduceTestVector(SymmetricAlgorithmSpecification algorithm, Int32 blockLengthInBits, CipherMode cipherMode, Byte[] key, Byte[] initializationVector, Byte[] plaintext, Byte[] ciphertext)
        {
            using (var randomnessProvider = RandomNumberGenerator.Create())
            {
                using (var secureKey = new SecureBuffer(key.Length))
                {
                    // Arrange.
                    var blockLengthInBytes = (blockLengthInBits / 8);
                    var target             = new SymmetricBinaryProcessor(randomnessProvider);
                    secureKey.Access(keyBuffer =>
                    {
                        Array.Copy(key, keyBuffer, key.Length);
                    });

                    // Act.
                    var encryptResult = target.Encrypt(plaintext, secureKey, algorithm, initializationVector);

                    // Assert.
                    encryptResult.Should().NotBeNullOrEmpty();

                    // Arrange.
                    var processedEncryptResult = cipherMode == CipherMode.CBC ? encryptResult.Skip(blockLengthInBytes).Take(ciphertext.Length).ToArray() : encryptResult.Take(ciphertext.Length).ToArray();

                    // Assert.
                    processedEncryptResult.Length.Should().Be(ciphertext.Length);

                    for (var i = 0; i < ciphertext.Length; i++)
                    {
                        // Assert.
                        processedEncryptResult[i].Should().Be(ciphertext[i]);
                    }
                }
            }
        }
        public void FunctionalLifeSpanTest_ShouldProduceDesiredResults()
        {
            // Arrange.
            var length           = 17;
            var bufferReference  = (Byte[])null;
            var bufferSubsegment = new Byte[3];

            using (var target = new SecureBuffer(length))
            {
                // Act.
                target.Access(buffer =>
                {
                    // Assert.
                    buffer.Length.Should().Be(length);
                    buffer.Should().OnlyContain(value => value == 0x00);

                    for (var i = 0; i < length; i++)
                    {
                        buffer[i] = (Byte)i;
                    }

                    // Arrange.
                    bufferReference = buffer;
                    Array.Copy(buffer, 1, bufferSubsegment, 0, 3);
                });

                // Act.
                target.Access(buffer =>
                {
                    // Assert.
                    buffer.Length.Should().Be(length);
                    buffer[0].Should().Be(0x00);
                    buffer[4].Should().Be(0x04);
                    buffer[8].Should().Be(0x08);
                });
            }

            // Assert.
            bufferReference.Length.Should().Be(length);
            bufferReference.Should().OnlyContain(value => value == 0x00);
            bufferSubsegment[0].Should().Be(0x01);
            bufferSubsegment[1].Should().Be(0x02);
            bufferSubsegment[2].Should().Be(0x03);
        }
        /// <summary>
        /// Converts the value of the current <see cref="CascadingSymmetricKey" /> to its equivalent binary representation.
        /// </summary>
        /// <returns>
        /// A binary representation of the current <see cref="CascadingSymmetricKey" />.
        /// </returns>
        public SecureBuffer ToBuffer()
        {
            var result = new SecureBuffer(SerializedLength);

            try
            {
                using (var controlToken = StateControl.Enter())
                {
                    result.Access(pinnedResultBuffer =>
                    {
                        var keyLength = SecureSymmetricKey.SerializedLength;

                        for (var i = 0; i < MaximumDepth; i++)
                        {
                            if (i < Depth)
                            {
                                using (var keyBuffer = Keys[i].ToBuffer())
                                {
                                    keyBuffer.Access(pinnedKeyBuffer =>
                                    {
                                        // Copy the key buffers out to the result buffer.
                                        Array.Copy(pinnedKeyBuffer, 0, pinnedResultBuffer, (keyLength * i), keyLength);
                                    });
                                }

                                continue;
                            }

                            // Fill the unused segments with random bytes.
                            var randomBytes = new Byte[keyLength];
                            HardenedRandomNumberGenerator.Instance.GetBytes(randomBytes);
                            Array.Copy(randomBytes, 0, pinnedResultBuffer, (keyLength * i), keyLength);
                        }

                        // Append the depth as a 16-bit integer.
                        Buffer.BlockCopy(BitConverter.GetBytes(Convert.ToUInt16(Depth)), 0, pinnedResultBuffer, (SerializedLength - sizeof(UInt16)), sizeof(UInt16));
                    });

                    return(result);
                }
            }
            catch
            {
                result.Dispose();
                throw new SecurityException("Key serialization failed.");
            }
        }
Example #4
0
        /// <summary>
        /// Encrypts the specified plaintext object.
        /// </summary>
        /// <param name="plaintextObject">
        /// The plaintext object to encrypt.
        /// </param>
        /// <param name="key">
        /// The key derivation bits used to transform the object.
        /// </param>
        /// <param name="algorithm">
        /// The algorithm specification used to transform the object.
        /// </param>
        /// <param name="initializationVector">
        /// An initialization vector with length greater than or equal to the block size for the specified cipher (extra bytes are
        /// ignored), or <see langword="null" /> to generate a random initialization vector.
        /// </param>
        /// <returns>
        /// The resulting ciphertext.
        /// </returns>
        /// <exception cref="SecurityException">
        /// An exception was raised during encryption or serialization.
        /// </exception>
        public Byte[] Encrypt(T plaintextObject, SecureBuffer key, SymmetricAlgorithmSpecification algorithm, Byte[] initializationVector)
        {
            try
            {
                var ciphertext = (Byte[])null;

                key.Access(keyBuffer =>
                {
                    ciphertext = Encrypt(plaintextObject, keyBuffer, algorithm, initializationVector);
                });

                return(ciphertext);
            }
            catch
            {
                throw new SecurityException("The encryption operation failed.");
            }
        }
Example #5
0
        /// <summary>
        /// Decrypts the specified ciphertext.
        /// </summary>
        /// <param name="ciphertext">
        /// The ciphertext to decrypt.
        /// </param>
        /// <param name="key">
        /// The key derivation bits used to transform the ciphertext.
        /// </param>
        /// <param name="algorithm">
        /// The algorithm specification used to transform the ciphertext.
        /// </param>
        /// <returns>
        /// The resulting plaintext object.
        /// </returns>
        /// <exception cref="SecurityException">
        /// An exception was raised during decryption or deserialization.
        /// </exception>
        public T Decrypt(Byte[] ciphertext, SecureBuffer key, SymmetricAlgorithmSpecification algorithm)
        {
            try
            {
                var plaintext = default(T);

                key.Access(keyBuffer =>
                {
                    plaintext = Decrypt(ciphertext, keyBuffer, algorithm);
                });

                return(plaintext);
            }
            catch
            {
                throw new SecurityException("The decryption operation failed.");
            }
        }
        private SecureSymmetricKey(SymmetricAlgorithmSpecification algorithm, SecureSymmetricKeyDerivationMode derivationMode, PinnedBuffer keySource)
            : base(ConcurrencyControlMode.SingleThreadLock)
        {
            Algorithm          = algorithm.RejectIf().IsEqualToValue(SymmetricAlgorithmSpecification.Unspecified, nameof(algorithm));
            DerivationMode     = derivationMode.RejectIf().IsEqualToValue(SecureSymmetricKeyDerivationMode.Unspecified, nameof(derivationMode));
            KeySource          = new SecureBuffer(KeySourceLengthInBytes);
            LazyPbkdf2Provider = new Lazy <Rfc2898DeriveBytes>(InitializePbkdf2Algorithm, LazyThreadSafetyMode.ExecutionAndPublication);

            // Gather information about the derived key.
            var keyBitLength = algorithm.ToKeyBitLength();

            DerivedKeyLength = (keyBitLength / 8);
            BlockWordCount   = (keyBitLength / 32);
            BlockCount       = (KeySourceWordCount / BlockWordCount);

            // Copy in the key source bits.
            KeySource.Access(buffer => Array.Copy(keySource, buffer, buffer.Length));
        }
        /// <summary>
        /// Converts the value of the current <see cref="SecureSymmetricKey" /> to its equivalent binary representation.
        /// </summary>
        /// <returns>
        /// A binary representation of the current <see cref="SecureSymmetricKey" />.
        /// </returns>
        public SecureBuffer ToBuffer()
        {
            var resultBuffer = new SecureBuffer(SerializedLength);

            try
            {
                using (var controlToken = StateControl.Enter())
                {
                    using (var plaintextBuffer = new PinnedBuffer(SerializedPlaintextLength, true))
                    {
                        KeySource.Access(pinnedKeySourceBuffer =>
                        {
                            Array.Copy(pinnedKeySourceBuffer, 0, plaintextBuffer, KeySourceBufferIndex, KeySourceLengthInBytes);
                        });

                        plaintextBuffer[AlgorithmBufferIndex]      = (Byte)Algorithm;
                        plaintextBuffer[DerivationModeBufferIndex] = (Byte)DerivationMode;

                        using (var cipher = BufferEncryptionAlgorithm.ToCipher(RandomnessProvider))
                        {
                            using (var initializationVector = new PinnedBuffer(cipher.BlockSizeInBytes, true))
                            {
                                RandomnessProvider.GetBytes(initializationVector);

                                resultBuffer.Access(pinnedResultBuffer =>
                                {
                                    using (var ciphertext = cipher.Encrypt(plaintextBuffer, BufferEncryptionKey, initializationVector))
                                    {
                                        Array.Copy(ciphertext, 0, pinnedResultBuffer, 0, SerializedLength);
                                    }
                                });
                            }
                        }
                    }
                }

                return(resultBuffer);
            }
            catch
            {
                resultBuffer.Dispose();
                throw new SecurityException("Key serialization failed.");
            }
        }
        /// <summary>
        /// Creates a new instance of a <see cref="CascadingSymmetricKey" /> using the specified buffer.
        /// </summary>
        /// <param name="buffer">
        /// A binary representation of a <see cref="CascadingSymmetricKey" />.
        /// </param>
        /// <returns>
        /// A new instance of a <see cref="CascadingSymmetricKey" />.
        /// </returns>
        /// <exception cref="ArgumentException">
        /// <paramref name="buffer" /> is invalid.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="buffer" /> is <see langword="null" />.
        /// </exception>
        public static CascadingSymmetricKey FromBuffer(SecureBuffer buffer)
        {
            buffer.RejectIf().IsNull(nameof(buffer)).OrIf(argument => argument.Length != SerializedLength, nameof(buffer), "The specified buffer is invalid.");

            try
            {
                var keys = (SecureSymmetricKey[])null;

                buffer.Access(pinnedBuffer =>
                {
                    // Interrogate the final 16 bits to determine the depth.
                    var keyLength = SecureSymmetricKey.SerializedLength;
                    var depth     = BitConverter.ToUInt16(pinnedBuffer, (SerializedLength - sizeof(UInt16)));
                    keys          = new SecureSymmetricKey[depth];

                    for (var i = 0; i < depth; i++)
                    {
                        using (var secureBuffer = new SecureBuffer(keyLength))
                        {
                            secureBuffer.Access(keyBuffer =>
                            {
                                // Copy out the key buffers.
                                Array.Copy(pinnedBuffer, (keyLength * i), keyBuffer, 0, keyLength);
                            });

                            keys[i] = SecureSymmetricKey.FromBuffer(secureBuffer);
                        }
                    }
                });

                return(new CascadingSymmetricKey(keys));
            }
            catch
            {
                throw new ArgumentException("The specified buffer is invalid.", nameof(buffer));
            }
        }
        /// <summary>
        /// Creates a new instance of a <see cref="SecureSymmetricKey" /> using the specified buffer.
        /// </summary>
        /// <param name="buffer">
        /// A binary representation of a <see cref="SecureSymmetricKey" />.
        /// </param>
        /// <returns>
        /// A new instance of a <see cref="SecureSymmetricKey" />.
        /// </returns>
        /// <exception cref="ArgumentException">
        /// <paramref name="buffer" /> is invalid.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="buffer" /> is <see langword="null" />.
        /// </exception>
        public static SecureSymmetricKey FromBuffer(SecureBuffer buffer)
        {
            buffer.RejectIf().IsNull(nameof(buffer)).OrIf(argument => argument.Length != SerializedLength, nameof(buffer), "The specified buffer is invalid.");

            try
            {
                var result = (SecureSymmetricKey)null;

                buffer.Access(pinnedCiphertext =>
                {
                    using (var plaintextBuffer = new PinnedBuffer(SerializedPlaintextLength, true))
                    {
                        using (var cipher = BufferEncryptionAlgorithm.ToCipher(RandomnessProvider))
                        {
                            using (var plaintext = cipher.Decrypt(pinnedCiphertext, BufferEncryptionKey))
                            {
                                Array.Copy(plaintext, 0, plaintextBuffer, 0, SerializedPlaintextLength);
                            }
                        }

                        using (var keySource = new PinnedBuffer(KeySourceLengthInBytes, true))
                        {
                            Array.Copy(plaintextBuffer, KeySourceBufferIndex, keySource, 0, KeySourceLengthInBytes);
                            var algorithm      = (SymmetricAlgorithmSpecification)plaintextBuffer[AlgorithmBufferIndex];
                            var derivationMode = (SecureSymmetricKeyDerivationMode)plaintextBuffer[DerivationModeBufferIndex];
                            result             = new SecureSymmetricKey(algorithm, derivationMode, keySource);
                        }
                    }
                });

                return(result);
            }
            catch
            {
                throw new ArgumentException("The specified buffer is invalid.", nameof(buffer));
            }
        }