Inheritance: ICryptoTransform
		public static void Encrypt(byte[] masterKey, ArraySegment<byte> plaintext, byte[] output, int outputOffset, ArraySegment<byte>? salt = null, uint counter = 1)
		{
			int ciphertextLength = CONTEXT_BUFFER_LENGTH + plaintext.Count + MAC_LENGTH;
			if (output.Length - outputOffset < ciphertextLength) throw new ArgumentOutOfRangeException("output", "'output' array segment is not big enough for the ciphertext");
			try
			{
				using (var aes = _aesFactory())
				{
					aes.Mode = CipherMode.ECB;
					aes.Padding = PaddingMode.None;
					_cryptoRandom.NextBytes(_contextBuffer.Value);

					Kdf.SP800_108_Ctr.DeriveKey(hmacFactory: _hmacFactory, key: masterKey, label: salt, context: new ArraySegment<byte>(_contextBuffer.Value, 0, CONTEXT_TWEAK_LENGTH), derivedOutput: _sessionKey.Value.AsArraySegment(), counter: counter);

					Utils.BlockCopy(_sessionKey.Value, 0, _macKey.Value, 0, MAC_KEY_LENGTH);
					Utils.BlockCopy(_sessionKey.Value, MAC_KEY_LENGTH, _encKey.Value, 0, ENC_KEY_LENGTH);
					Utils.BlockCopy(_contextBuffer.Value, 0, output, outputOffset, CONTEXT_BUFFER_LENGTH);

					Utils.BlockCopy(_contextBuffer.Value, CONTEXT_TWEAK_LENGTH, _counterBuffer.Value, 0, NONCE_LENGTH);
					using (var ctrTransform = new Cipher.AesCtrCryptoTransform(_encKey.Value, _counterBuffer.Value.AsArraySegment()))
					{
						ctrTransform.TransformBlock(inputBuffer: plaintext.Array, inputOffset: plaintext.Offset, inputCount: plaintext.Count, outputBuffer: output, outputOffset: outputOffset + CONTEXT_BUFFER_LENGTH);
					}// using aesEncryptor
				}// using aes

				using (var hmac = _hmacFactory())
				{
					hmac.Key = _macKey.Value;
					hmac.HashCore(output, outputOffset + CONTEXT_TWEAK_LENGTH, NONCE_LENGTH + plaintext.Count);
					var fullmac = hmac.HashFinal();
					Utils.BlockCopy(fullmac, 0, output, outputOffset + ciphertextLength - MAC_LENGTH, MAC_LENGTH);
				}// using hmac
			}
			finally { EtM_CTR.ClearKeyMaterial(); }
		}// Encrypt()
		}// Encrypt()

		public static void Decrypt(byte[] masterKey, ArraySegment<byte> ciphertext, ref ArraySegment<byte>? outputSegment, ArraySegment<byte>? salt = null, uint counter = 1)
		{
			int cipherLength = ciphertext.Count - CONTEXT_BUFFER_LENGTH - MAC_LENGTH;
			if (cipherLength < 0) { outputSegment = null; return; }
			try
			{
				Kdf.SP800_108_Ctr.DeriveKey(hmacFactory: _hmacFactory, key: masterKey, label: salt, context: new ArraySegment<byte>(ciphertext.Array, ciphertext.Offset, CONTEXT_TWEAK_LENGTH), derivedOutput: new ArraySegment<byte>(_sessionKey.Value), counter: counter);
				Utils.BlockCopy(_sessionKey.Value, 0, _macKey.Value, 0, MAC_KEY_LENGTH);

				using (var hmac = _hmacFactory())
				{
					hmac.Key = _macKey.Value;
					hmac.TransformBlock(ciphertext.Array, ciphertext.Offset + CONTEXT_TWEAK_LENGTH, NONCE_LENGTH + cipherLength, null, 0);
					hmac.TransformFinalBlock(ciphertext.Array, 0, 0);
					var fullmacActual = hmac.HashInner;
					if (!Utils.ConstantTimeEqual(fullmacActual, 0, ciphertext.Array, ciphertext.Offset + ciphertext.Count - MAC_LENGTH, MAC_LENGTH)) { outputSegment = null; return; };
				}// using hmac

				if (outputSegment == null) outputSegment = (new byte[cipherLength]).AsNullableArraySegment();
				Utils.BlockCopy(ciphertext.Array, ciphertext.Offset + CONTEXT_TWEAK_LENGTH, _counterBuffer.Value, 0, NONCE_LENGTH);
				Utils.BlockCopy(_sessionKey.Value, MAC_KEY_LENGTH, _encKey.Value, 0, ENC_KEY_LENGTH);
				using (var ctrTransform = new Cipher.AesCtrCryptoTransform(key: _encKey.Value, counterBufferSegment: _counterBuffer.Value.AsArraySegment(), aesFactory: _aesFactory))
				{
					ctrTransform.TransformBlock(inputBuffer: ciphertext.Array, inputOffset: ciphertext.Offset + CONTEXT_BUFFER_LENGTH, inputCount: cipherLength, outputBuffer: outputSegment.GetValueOrDefault().Array, outputOffset: outputSegment.GetValueOrDefault().Offset);
				}// using aesDecryptor
			}
			finally { EtM_CTR.ClearKeyMaterial(); }
		}// Decrypt()
		public static void Encrypt(byte[] masterKey, ArraySegment<byte> plaintext, byte[] output, int outputOffset, ArraySegment<byte>? salt = null, uint counter = 1)
		{
			int ciphertextLength = CONTEXT_BUFFER_LENGTH + plaintext.Count + MAC_LENGTH;
			if (output.Length - outputOffset < ciphertextLength) throw new ArgumentOutOfRangeException(nameof(output), $"'{nameof(output)}' array segment is not big enough for the ciphertext");
			try
			{
				_cryptoRandom.NextBytes(_contextBuffer.Value);

				Kdf.SP800_108_Ctr.DeriveKey(hmacFactory: _hmacFactory, key: masterKey, label: salt, context: new ArraySegment<byte>(_contextBuffer.Value, 0, CONTEXT_TWEAK_LENGTH), derivedOutput: _sessionKey.Value.AsArraySegment(), counter: counter);

				Utils.BlockCopy(_sessionKey.Value, 0, _macKey.Value, 0, MAC_KEY_LENGTH);
				Utils.BlockCopy(_sessionKey.Value, MAC_KEY_LENGTH, _encKey.Value, 0, ENC_KEY_LENGTH);
				Utils.BlockCopy(_contextBuffer.Value, 0, output, outputOffset, CONTEXT_BUFFER_LENGTH);

				Utils.BlockCopy(_contextBuffer.Value, CONTEXT_TWEAK_LENGTH, _counterBuffer.Value, 0, NONCE_LENGTH);
				using (var ctrTransform = new Cipher.AesCtrCryptoTransform(key: _encKey.Value, counterBufferSegment: _counterBuffer.Value.AsArraySegment(), aesFactory: _aesFactory))
				{
					ctrTransform.TransformBlock(inputBuffer: plaintext.Array, inputOffset: plaintext.Offset, inputCount: plaintext.Count, outputBuffer: output, outputOffset: outputOffset + CONTEXT_BUFFER_LENGTH);
				}// using aesEncryptor

				using (var hmac = _hmacFactory())
				{
					hmac.Key = _macKey.Value;
					hmac.TransformBlock(output, outputOffset + CONTEXT_TWEAK_LENGTH, NONCE_LENGTH + plaintext.Count, null, 0);
					hmac.TransformFinalBlock(output, 0, 0);
					var fullmac = hmac.HashInner;
					Utils.BlockCopy(fullmac, 0, output, outputOffset + ciphertextLength - MAC_LENGTH, MAC_LENGTH);
				}// using hmac
			}
			finally { EtM_CTR.ClearKeyMaterial(); }
		}// Encrypt()
Example #4
0
		}// ClearKeyMaterial()

		public static void Encrypt(byte[] masterKey, ArraySegment<byte> plaintext, byte[] output, int outputOffset, ArraySegment<byte>? salt = null, uint counter = 1)
		{
			int ciphertextLength = CONTEXT_BUFFER_LENGTH + plaintext.Count + MAC_LENGTH;
			if (output.Length - outputOffset < ciphertextLength) throw new ArgumentOutOfRangeException(nameof(output), $"'{nameof(output)}' array segment is not big enough for the ciphertext");

			var counterBuffer = new byte[Cipher.AesConstants.AES_BLOCK_SIZE];
			var contextBuffer = new byte[CONTEXT_BUFFER_LENGTH];
			var encKey = new byte[ENC_KEY_LENGTH];
			var macKey = new byte[MAC_KEY_LENGTH];
			var sessionKey = new byte[HMAC_LENGTH];

			try
			{
				_cryptoRandom.NextBytes(contextBuffer, 0, CONTEXT_BUFFER_LENGTH);

				Kdf.SP800_108_Ctr.DeriveKey(hmacFactory: _hmacFactory, key: masterKey, label: salt, context: new ArraySegment<byte>(contextBuffer, 0, CONTEXT_TWEAK_LENGTH), derivedOutput: sessionKey.AsArraySegment(), counter: counter);

				//Utils.BlockCopy(sessionKey, 0, macKey, 0, MAC_KEY_LENGTH);
				for (int i = 0; i < macKey.Length; ++i) macKey[i] = sessionKey[i];

				//Utils.BlockCopy(sessionKey, MAC_KEY_LENGTH, encKey, 0, ENC_KEY_LENGTH);
				for (int i = 0; i < encKey.Length; ++i) encKey[i] = sessionKey[MAC_KEY_LENGTH + i];

				//Utils.BlockCopy(contextBuffer, 0, output, outputOffset, CONTEXT_BUFFER_LENGTH);
				for (int i = 0; i < contextBuffer.Length; ++i) output[outputOffset + i] = contextBuffer[i];

				//Utils.BlockCopy(contextBuffer, CONTEXT_TWEAK_LENGTH, counterBuffer, 0, NONCE_LENGTH);
				for (int i = 0; i < NONCE_LENGTH; ++i) counterBuffer[i] = contextBuffer[CONTEXT_TWEAK_LENGTH + i];

				using (var ctrTransform = new Cipher.AesCtrCryptoTransform(key: encKey, counterBufferSegment: counterBuffer.AsArraySegment(), aesFactory: _aesFactory))
				{
					ctrTransform.TransformBlock(inputBuffer: plaintext.Array, inputOffset: plaintext.Offset, inputCount: plaintext.Count, outputBuffer: output, outputOffset: outputOffset + CONTEXT_BUFFER_LENGTH);
				}// using aesEncryptor

				using (var hmac = _hmacFactory())
				{
					hmac.Key = macKey;
					hmac.TransformBlock(output, outputOffset + CONTEXT_TWEAK_LENGTH, NONCE_LENGTH + plaintext.Count, null, 0);
					hmac.TransformFinalBlock(output, 0, 0);
					var fullmac = hmac.HashInner;

					//Utils.BlockCopy(fullmac, 0, output, outputOffset + ciphertextLength - MAC_LENGTH, MAC_LENGTH);
					for (int i = 0; i < MAC_LENGTH; ++i) output[outputOffset + ciphertextLength - MAC_LENGTH + i] = fullmac[i];
				}// using hmac
			}
			finally { EtM_CTR.ClearKeyMaterial(encKey, macKey, sessionKey); }
		}// Encrypt()
Example #5
0
		}// Encrypt()

		public static void Decrypt(byte[] masterKey, ArraySegment<byte> ciphertext, ref ArraySegment<byte>? outputSegment, ArraySegment<byte>? salt = null, uint counter = 1)
		{
			int cipherLength = ciphertext.Count - CONTEXT_BUFFER_LENGTH - MAC_LENGTH;
			if (cipherLength < 0) { outputSegment = null; return; }

			var counterBuffer = new byte[Cipher.AesConstants.AES_BLOCK_SIZE];
			var encKey = new byte[ENC_KEY_LENGTH];
			var macKey = new byte[MAC_KEY_LENGTH];
			var sessionKey = new byte[HMAC_LENGTH];

			try
			{
				var ciphertextArray = ciphertext.Array;
				var ciphertextOffset = ciphertext.Offset;

				Kdf.SP800_108_Ctr.DeriveKey(hmacFactory: _hmacFactory, key: masterKey, label: salt, context: new ArraySegment<byte>(ciphertextArray, ciphertextOffset, CONTEXT_TWEAK_LENGTH), derivedOutput: sessionKey.AsArraySegment(), counter: counter);

				//Utils.BlockCopy(sessionKey, 0, macKey, 0, MAC_KEY_LENGTH);
				for (int i = 0; i < macKey.Length; ++i) macKey[i] = sessionKey[i];

				using (var hmac = _hmacFactory())
				{
					hmac.Key = macKey;
					hmac.TransformBlock(ciphertextArray, ciphertextOffset + CONTEXT_TWEAK_LENGTH, NONCE_LENGTH + cipherLength, null, 0);
					hmac.TransformFinalBlock(ciphertextArray, 0, 0);
					var fullmacActual = hmac.HashInner;
					if (!Utils.ConstantTimeEqual(fullmacActual, 0, ciphertextArray, ciphertextOffset + ciphertext.Count - MAC_LENGTH, MAC_LENGTH)) { outputSegment = null; return; };
				}// using hmac

				if (outputSegment == null) outputSegment = (new byte[cipherLength]).AsNullableArraySegment();

				//Utils.BlockCopy(ciphertext.Array, ciphertext.Offset + CONTEXT_TWEAK_LENGTH, counterBuffer, 0, NONCE_LENGTH);
				for (int i = 0; i < NONCE_LENGTH; ++i) counterBuffer[i] = ciphertextArray[ciphertextOffset + CONTEXT_TWEAK_LENGTH + i];

				//Utils.BlockCopy(sessionKey, MAC_KEY_LENGTH, encKey, 0, ENC_KEY_LENGTH);
				for (int i = 0; i < encKey.Length; ++i) encKey[i] = sessionKey[MAC_KEY_LENGTH + i];

				using (var ctrTransform = new Cipher.AesCtrCryptoTransform(key: encKey, counterBufferSegment: counterBuffer.AsArraySegment(), aesFactory: _aesFactory))
				{
					ctrTransform.TransformBlock(inputBuffer: ciphertextArray, inputOffset: ciphertextOffset + CONTEXT_BUFFER_LENGTH, inputCount: cipherLength, outputBuffer: outputSegment.GetValueOrDefault().Array, outputOffset: outputSegment.GetValueOrDefault().Offset);
				}// using aesDecryptor
			}
			finally { EtM_CTR.ClearKeyMaterial(encKey, macKey, sessionKey); }
		}// Decrypt()
		}// Encrypt()

		public static void Decrypt(byte[] masterKey, ArraySegment<byte> ciphertext, ref ArraySegment<byte>? outputSegment, ArraySegment<byte>? salt = null, uint counter = 1)
		{
			int cipherLength = ciphertext.Count - CONTEXT_BUFFER_LENGTH - MAC_LENGTH;
			if (cipherLength < 0) { outputSegment = null; return; }
			try
			{
				Kdf.SP800_108_Ctr.DeriveKey(hmacFactory: _hmacFactory, key: masterKey, label: salt, context: new ArraySegment<byte>(ciphertext.Array, ciphertext.Offset, CONTEXT_TWEAK_LENGTH), derivedOutput: new ArraySegment<byte>(_sessionKey.Value), counter: counter);
				Utils.BlockCopy(_sessionKey.Value, 0, _macKey.Value, 0, MAC_KEY_LENGTH);

				using (var hmac = _hmacFactory())
				{
					hmac.Key = _macKey.Value;
					hmac.HashCore(ciphertext.Array, ciphertext.Offset + CONTEXT_TWEAK_LENGTH, NONCE_LENGTH + cipherLength);
					var fullmacActual = hmac.HashFinal();
					if (!Utils.ConstantTimeEqual(fullmacActual, 0, ciphertext.Array, ciphertext.Offset + ciphertext.Count - MAC_LENGTH, MAC_LENGTH)) { outputSegment = null; return; };
				}// using hmac

				if (outputSegment == null) outputSegment = (new byte[cipherLength]).AsNullableArraySegment();
				Utils.BlockCopy(ciphertext.Array, ciphertext.Offset + CONTEXT_TWEAK_LENGTH, _counterBuffer.Value, 0, NONCE_LENGTH);
				Utils.BlockCopy(_sessionKey.Value, MAC_KEY_LENGTH, _encKey.Value, 0, ENC_KEY_LENGTH);
				using (var aes = _aesFactory())
				{
					aes.Mode = CipherMode.ECB;
					aes.Padding = PaddingMode.None;
					using (var ctrTransform = new Cipher.AesCtrCryptoTransform(_encKey.Value, _counterBuffer.Value.AsArraySegment()))
					{
						ctrTransform.TransformBlock(inputBuffer: ciphertext.Array, inputOffset: ciphertext.Offset + CONTEXT_BUFFER_LENGTH, inputCount: cipherLength, outputBuffer: outputSegment.Value.Array, outputOffset: outputSegment.Value.Offset);
					}// using aesDecryptor
				}// using aes
			}
			finally { EtM_CTR.ClearKeyMaterial(); }
		}// Decrypt()