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()
public static void Encrypt(byte[] masterKey, ArraySegment<byte> plaintext, byte[] output, int outputOffset, ArraySegment<byte>? salt = null, uint counter = 1) { int fullBlockLength = plaintext.Count & (-Cipher.AesConstants.AES_BLOCK_SIZE); int finalBlockLength = plaintext.Count % Cipher.AesConstants.AES_BLOCK_SIZE; int paddingLength = Cipher.AesConstants.AES_BLOCK_SIZE - finalBlockLength; int ciphertextLength = CONTEXT_BUFFER_LENGTH + plaintext.Count + paddingLength + MAC_LENGTH; if (output.Length - outputOffset < ciphertextLength) throw new ArgumentOutOfRangeException(nameof(output), $"'{nameof(output)}' array segment is not big enough for the ciphertext"); try { var iv = _iv.Value; var contextBuffer = _contextBuffer.Value; var encKey = _encKey.Value; var macKey = _macKey.Value; var sessionKey = _sessionKey.Value; using (var aes = _aesFactory()) { EtM_CBC.ValidateAes(aes); _cryptoRandom.NextBytes(contextBuffer, 0, CONTEXT_BUFFER_LENGTH); Utils.BlockCopy(contextBuffer, CONTEXT_TWEAK_LENGTH, iv, 0, AES_IV_LENGTH); Kdf.SP800_108_Ctr.DeriveKey(hmacFactory: _hmacFactory, key: masterKey, label: salt, context: contextBuffer.AsArraySegment(), derivedOutput: sessionKey.AsArraySegment(), counter: counter); Utils.BlockCopy(sessionKey, 0, macKey, 0, MAC_KEY_LENGTH); Utils.BlockCopy(sessionKey, MAC_KEY_LENGTH, encKey, 0, ENC_KEY_LENGTH); Utils.BlockCopy(contextBuffer, 0, output, outputOffset, CONTEXT_BUFFER_LENGTH); using (var aesEncryptor = aes.CreateEncryptor(encKey, iv)) { if (fullBlockLength > 0) aesEncryptor.TransformBlock(inputBuffer: plaintext.Array, inputOffset: plaintext.Offset, inputCount: fullBlockLength, outputBuffer: output, outputOffset: outputOffset + CONTEXT_BUFFER_LENGTH); var finalBlockBuffer = aesEncryptor.TransformFinalBlock(inputBuffer: plaintext.Array, inputOffset: plaintext.Offset + fullBlockLength, inputCount: finalBlockLength); Utils.BlockCopy(finalBlockBuffer, 0, output, outputOffset + CONTEXT_BUFFER_LENGTH + fullBlockLength, finalBlockBuffer.Length); }// using aesEncryptor }// using aes using (var hmac = _hmacFactory()) { hmac.Key = macKey; hmac.TransformBlock(output, outputOffset + CONTEXT_TWEAK_LENGTH, AES_IV_LENGTH + plaintext.Count + paddingLength, 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_CBC.ClearKeyMaterial(); } }// Encrypt()
}// 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()