Exemple #1
0
        private static void Encrypt_ShouldBeReversible_UsingSecureSymmetricKey(SymmetricAlgorithmSpecification algorithm, SecureSymmetricKeyDerivationMode derivationMode)
        {
            using (var randomnessProvider = RandomNumberGenerator.Create())
            {
                // Arrange.
                var binarySerializer = new BinaryPassThroughSerializer();
                var target           = new SymmetricProcessor <Byte[]>(randomnessProvider, binarySerializer);
                var plaintextObject  = new Byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 };

                using (var key = SecureSymmetricKey.New(algorithm, derivationMode))
                {
                    // Act.
                    var ciphertextResult = target.Encrypt(plaintextObject, key);

                    // Assert.
                    ciphertextResult.Should().NotBeNullOrEmpty();
                    ciphertextResult.Count(value => value == 0x00).Should().NotBe(ciphertextResult.Length);

                    // Act.
                    var plaintextResult = target.Decrypt(ciphertextResult, key);

                    // Assert.
                    plaintextResult.Should().NotBeNullOrEmpty();
                    plaintextResult.Length.Should().Be(plaintextObject.Length);
                    plaintextResult.Count(value => value == 0x00).Should().NotBe(plaintextResult.Length);

                    for (var i = 0; i < plaintextResult.Length; i++)
                    {
                        // Assert.
                        plaintextResult[i].Should().Be(plaintextObject[i]);
                    }
                }
            }
        }
        private static void Encrypt_ShouldBeReversible_UsingSecureSymmetricKey(SymmetricAlgorithmSpecification algorithm)
        {
            using (var randomnessProvider = RandomNumberGenerator.Create())
            {
                // Arrange.
                var target          = new SymmetricStringProcessor(randomnessProvider);
                var plaintextObject = "䆟`ಮ䷆ʘ‣⦸⏹ⰄͶa✰ṁ亡Zᨖ0༂⽔9㗰";

                using (var key = SecureSymmetricKey.New(algorithm))
                {
                    // Act.
                    var ciphertext = target.Encrypt(plaintextObject, key);

                    // Assert.
                    ciphertext.Should().NotBeNullOrEmpty();
                    ciphertext.Count(value => value == 0x00).Should().NotBe(ciphertext.Length);

                    // Act.
                    var plaintext = target.Decrypt(ciphertext, key);

                    // Assert.
                    plaintext.Should().NotBeNullOrEmpty();
                    plaintext.Should().Be(plaintextObject);
                }
            }
        }
Exemple #3
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]);
                    }
                }
            }
        }
 /// <summary>
 /// Generates a new <see cref="SecureSymmetricKey" />.
 /// </summary>
 /// <param name="algorithm">
 /// The symmetric-key algorithm that the generated key is derived to interoperate with. The default value is
 /// <see cref="SymmetricAlgorithmSpecification.Aes256Cbc" />.
 /// </param>
 /// <param name="derivationMode">
 /// The mode used to derive the generated key. The default value is
 /// <see cref="SecureSymmetricKeyDerivationMode.XorLayeringWithSubstitution" />.
 /// </param>
 /// <returns>
 /// A new <see cref="SecureSymmetricKey" />.
 /// </returns>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="algorithm" /> is equal to <see cref="SymmetricAlgorithmSpecification.Unspecified" /> or
 /// <paramref name="derivationMode" /> is equal to <see cref="SecureSymmetricKeyDerivationMode.Unspecified" />.
 /// </exception>
 public static SecureSymmetricKey New(SymmetricAlgorithmSpecification algorithm, SecureSymmetricKeyDerivationMode derivationMode)
 {
     using (var keySource = new PinnedBuffer(KeySourceLengthInBytes, true))
     {
         RandomnessProvider.GetBytes(keySource);
         return(New(algorithm, derivationMode, keySource));
     }
 }
Exemple #5
0
 private T Decrypt(Byte[] ciphertext, PinnedBuffer key, SymmetricAlgorithmSpecification algorithm)
 {
     using (var cipher = algorithm.ToCipher(RandomnessProvider))
     {
         using (var pinnedCiphertext = new PinnedBuffer(ciphertext, false))
         {
             using (var plaintext = cipher.Decrypt(pinnedCiphertext, key))
             {
                 return(BinarySerializer.Deserialize(plaintext));
             }
         }
     }
 }
Exemple #6
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.");
            }
        }
Exemple #7
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.");
            }
        }
        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));
        }
Exemple #9
0
        private Byte[] Encrypt(T plaintextObject, PinnedBuffer key, SymmetricAlgorithmSpecification algorithm, Byte[] initializationVector)
        {
            var plaintext       = BinarySerializer.Serialize(plaintextObject);
            var plaintextLength = plaintext.Length;

            using (var pinnedPlaintext = new PinnedBuffer(plaintextLength, true))
            {
                Array.Copy(plaintext, pinnedPlaintext, plaintextLength);

                using (var cipher = algorithm.ToCipher(RandomnessProvider))
                {
                    switch (cipher.Mode)
                    {
                    case CipherMode.CBC:

                        using (var processedInitializationVector = new PinnedBuffer(cipher.BlockSizeInBytes, true))
                        {
                            if (initializationVector is null)
                            {
                                RandomnessProvider.GetBytes(processedInitializationVector);
                            }
                            else
                            {
                                Array.Copy(initializationVector.RejectIf(argument => argument.Length < cipher.BlockSizeInBytes, nameof(initializationVector)), processedInitializationVector, cipher.BlockSizeInBytes);
                            }

                            return(cipher.Encrypt(pinnedPlaintext, key, processedInitializationVector));
                        }

                    case CipherMode.ECB:

                        return(cipher.Encrypt(pinnedPlaintext, key, null));

                    default:

                        throw new InvalidOperationException($"The specified cipher mode, {cipher.Mode}, is not supported.");
                    }
                }
            }
        }
 /// <summary>
 /// Generates a new <see cref="SecureSymmetricKey" />.
 /// </summary>
 /// <param name="algorithm">
 /// The symmetric-key algorithm that the generated key is derived to interoperate with. The default value is
 /// <see cref="SymmetricAlgorithmSpecification.Aes256Cbc" />.
 /// </param>
 /// <param name="derivationMode">
 /// The mode used to derive the generated key. The default value is
 /// <see cref="SecureSymmetricKeyDerivationMode.XorLayeringWithSubstitution" />.
 /// </param>
 /// <param name="keySource">
 /// A buffer comprising 384 bytes (3,072 bits) from which the private key is derived.
 /// </param>
 /// <returns>
 /// A new <see cref="SecureSymmetricKey" />.
 /// </returns>
 /// <exception cref="ArgumentException">
 /// <paramref name="keySource" /> is not 384 bytes in length.
 /// </exception>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="algorithm" /> is equal to <see cref="SymmetricAlgorithmSpecification.Unspecified" /> -or-
 /// <paramref name="derivationMode" /> is equal to <see cref="SecureSymmetricKeyDerivationMode.Unspecified" />.
 /// </exception>
 public static SecureSymmetricKey New(SymmetricAlgorithmSpecification algorithm, SecureSymmetricKeyDerivationMode derivationMode, PinnedBuffer keySource)
 {
     keySource.RejectIf(argument => argument.Length != KeySourceLengthInBytes, nameof(keySource), $"The key source is not {KeySourceLengthInBytes} bytes in length.");
     return(new SecureSymmetricKey(algorithm, derivationMode, keySource));
 }
 /// <summary>
 /// Generates a new <see cref="SecureSymmetricKey" />.
 /// </summary>
 /// <param name="algorithm">
 /// The symmetric-key algorithm that the generated key is derived to interoperate with. The default value is
 /// <see cref="SymmetricAlgorithmSpecification.Aes256Cbc" />.
 /// </param>
 /// <returns>
 /// A new <see cref="SecureSymmetricKey" />.
 /// </returns>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="algorithm" /> is equal to <see cref="SymmetricAlgorithmSpecification.Unspecified" />.
 /// </exception>
 public static SecureSymmetricKey New(SymmetricAlgorithmSpecification algorithm) => New(algorithm, DefaultDerivationMode);
Exemple #12
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>
 /// <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) => Encrypt(plaintextObject, key, algorithm, null);
        internal static Int32 ToKeyBitLength(this SymmetricAlgorithmSpecification target)
        {
            switch (target)
            {
            case SymmetricAlgorithmSpecification.Unspecified:

                return(default(Int32));

            case SymmetricAlgorithmSpecification.Aes128Cbc:

                return(128);

            case SymmetricAlgorithmSpecification.Aes128Ecb:

                return(128);

            case SymmetricAlgorithmSpecification.Aes256Cbc:

                return(256);

            case SymmetricAlgorithmSpecification.Aes256Ecb:

                return(256);

            /* =================================================================================================================
             * Twofish and Threefish are out-of-scope for MVP-01.
             * =================================================================================================================
             * case SymmetricAlgorithmSpecification.Twofish128Cbc:
             *
             *  return 128;
             *
             * case SymmetricAlgorithmSpecification.Twofish128Ecb:
             *
             *  return 128;
             *
             * case SymmetricAlgorithmSpecification.Twofish192Cbc:
             *
             *  return 192;
             *
             * case SymmetricAlgorithmSpecification.Twofish192Ecb:
             *
             *  return 192;
             *
             * case SymmetricAlgorithmSpecification.Twofish256Cbc:
             *
             *  return 256;
             *
             * case SymmetricAlgorithmSpecification.Twofish256Ecb:
             *
             *  return 256;
             *
             * case SymmetricAlgorithmSpecification.Threefish256Cbc:
             *
             *  return 256;
             *
             * case SymmetricAlgorithmSpecification.Threefish256Ecb:
             *
             *  return 256;
             *
             * case SymmetricAlgorithmSpecification.Threefish512Cbc:
             *
             *  return 512;
             *
             * case SymmetricAlgorithmSpecification.Threefish512Ecb:
             *
             *  return 512;
             *
             * case SymmetricAlgorithmSpecification.Threefish1024Cbc:
             *
             *  return 1024;
             *
             * case SymmetricAlgorithmSpecification.Threefish1024Ecb:
             *
             *  return 1024;*/

            default:

                throw new ArgumentException($"{target} is not a supported {nameof(SymmetricAlgorithmSpecification)}.", nameof(target));
            }
        }
        internal static SymmetricKeyCipher ToCipher(this SymmetricAlgorithmSpecification target, RandomNumberGenerator randomnessProvider)
        {
            switch (target)
            {
            case SymmetricAlgorithmSpecification.Unspecified:

                return(null);

            case SymmetricAlgorithmSpecification.Aes128Cbc:

                return(new Aes128CbcCipher(randomnessProvider));

            case SymmetricAlgorithmSpecification.Aes128Ecb:

                return(new Aes128EcbCipher(randomnessProvider));

            case SymmetricAlgorithmSpecification.Aes256Cbc:

                return(new Aes256CbcCipher(randomnessProvider));

            case SymmetricAlgorithmSpecification.Aes256Ecb:

                return(new Aes256EcbCipher(randomnessProvider));

            /* =================================================================================================================
             * Twofish and Threefish are out-of-scope for MVP-01.
             * =================================================================================================================
             * case SymmetricAlgorithmSpecification.Twofish128Cbc:
             *
             *  return new Twofish128CbcCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Twofish128Ecb:
             *
             *  return new Twofish128EcbCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Twofish192Cbc:
             *
             *  return new Twofish192CbcCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Twofish192Ecb:
             *
             *  return new Twofish192EcbCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Twofish256Cbc:
             *
             *  return new Twofish256CbcCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Twofish256Ecb:
             *
             *  return new Twofish256EcbCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Threefish256Cbc:
             *
             *  return new Threefish256CbcCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Threefish256Ecb:
             *
             *  return new Threefish256EcbCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Threefish512Cbc:
             *
             *  return new Threefish512CbcCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Threefish512Ecb:
             *
             *  return new Threefish512EcbCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Threefish1024Cbc:
             *
             *  return new Threefish1024CbcCipher(randomnessProvider);
             *
             * case SymmetricAlgorithmSpecification.Threefish1024Ecb:
             *
             *  return new Threefish1024EcbCipher(randomnessProvider);*/

            default:

                throw new ArgumentException($"{target} is not a supported {nameof(SymmetricAlgorithmSpecification)}.", nameof(target));
            }
        }
 /// <summary>
 /// Generates a new <see cref="CascadingSymmetricKey" />.
 /// </summary>
 /// <param name="derivationMode">
 /// The mode used to derive the generated keys.
 /// </param>
 /// <param name="firstLayerAlgorithm">
 /// The algorithm for the first (inner-most) layer of encryption.
 /// </param>
 /// <param name="secondLayerAlgorithm">
 /// The algorithm for the second layer of encryption.
 /// </param>
 /// <param name="thirdLayerAlgorithm">
 /// The algorithm for the third layer of encryption.
 /// </param>
 /// <param name="fourthLayerAlgorithm">
 /// The algorithm for the fourth (outer-most) layer of encryption.
 /// </param>
 /// <returns>
 /// A new <see cref="CascadingSymmetricKey" />.
 /// </returns>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="derivationMode" /> is equal to <see cref="SecureSymmetricKeyDerivationMode.Unspecified" /> -or- one or
 /// more algorithm layers are equal to <see cref="SymmetricAlgorithmSpecification.Unspecified" />.
 /// </exception>
 public static CascadingSymmetricKey New(SecureSymmetricKeyDerivationMode derivationMode, SymmetricAlgorithmSpecification firstLayerAlgorithm, SymmetricAlgorithmSpecification secondLayerAlgorithm, SymmetricAlgorithmSpecification thirdLayerAlgorithm, SymmetricAlgorithmSpecification fourthLayerAlgorithm) => new CascadingSymmetricKey(derivationMode, firstLayerAlgorithm, secondLayerAlgorithm, thirdLayerAlgorithm, fourthLayerAlgorithm);
 /// <summary>
 /// Decrypts the specified Base64 string ciphertext.
 /// </summary>
 /// <typeparam name="T">
 /// The type of the object that is decrypted.
 /// </typeparam>
 /// <param name="target">
 /// The current <see cref="ISymmetricProcessor{T}" />.
 /// </param>
 /// <param name="ciphertext">
 /// The Base64 string 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="FormatException">
 /// <paramref name="ciphertext" /> is not a valid Base64 string.
 /// </exception>
 /// <exception cref="SecurityException">
 /// An exception was raised during decryption or deserialization.
 /// </exception>
 public static T DecryptFromBase64String <T>(this ISymmetricProcessor <T> target, String ciphertext, SecureBuffer key, SymmetricAlgorithmSpecification algorithm) => target.Decrypt(Convert.FromBase64String(ciphertext), key, algorithm);
 /// <summary>
 /// Encrypts the specified plaintext object to a Base64 string.
 /// </summary>
 /// <typeparam name="T">
 /// The type of the object that is encrypted.
 /// </typeparam>
 /// <param name="target">
 /// The current <see cref="ISymmetricProcessor{T}" />.
 /// </param>
 /// <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>
 /// <returns>
 /// The resulting ciphertext as a Base64 string.
 /// </returns>
 /// <exception cref="SecurityException">
 /// An exception was raised during encryption or serialization.
 /// </exception>
 public static String EncryptToBase64String <T>(this ISymmetricProcessor <T> target, T plaintextObject, SecureBuffer key, SymmetricAlgorithmSpecification algorithm) => Convert.ToBase64String(target.Encrypt(plaintextObject, key, algorithm));
Exemple #18
0
 private static void Encrypt_ShouldBeReversible_UsingCascadingSymmetricKey_WithTwoLayers(SecureSymmetricKeyDerivationMode derivationMode, SymmetricAlgorithmSpecification firstLayerAlgorithm, SymmetricAlgorithmSpecification secondLayerAlgorithm)
 {
     using (var key = CascadingSymmetricKey.New(derivationMode, firstLayerAlgorithm, secondLayerAlgorithm))
     {
         Encrypt_ShouldBeReversible_UsingCascadingSymmetricKey(key);
     }
 }