/* ================================================================================================================= * 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."); } }
/// <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."); } }
/// <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)); } }