private CascadingSymmetricKey(SecureSymmetricKeyDerivationMode derivationMode, params SymmetricAlgorithmSpecification[] algorithms) : base(ConcurrencyControlMode.SingleThreadLock) { Depth = algorithms.Length; Keys = new SecureSymmetricKey[Depth]; for (var i = 0; i < Depth; i++) { Keys[i] = SecureSymmetricKey.New(algorithms[i], derivationMode); } }
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> /// 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);
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_UsingCascadingSymmetricKey_WithTwoLayers(SecureSymmetricKeyDerivationMode derivationMode, SymmetricAlgorithmSpecification firstLayerAlgorithm, SymmetricAlgorithmSpecification secondLayerAlgorithm) { using (var key = CascadingSymmetricKey.New(derivationMode, firstLayerAlgorithm, secondLayerAlgorithm)) { Encrypt_ShouldBeReversible_UsingCascadingSymmetricKey(key); } }
/// <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> /// <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)); } }