/// <summary> /// Decodes source stream into destionation stream as an asynchronous operation. /// </summary> /// <param name="source">The source stream.</param> /// <param name="destination">The destionation stream.</param> /// <param name="keyLocator">The function which is able to locate the keying material based on the keying material identificator.</param> /// <returns>The task object representing the asynchronous operation.</returns> public static async Task DecodeAsync(Stream source, Stream destination, Func <string, byte[]> keyLocator) { ValidateDecodeParameters(source, destination, keyLocator); CodingHeader codingHeader = await ReadCodingHeaderAsync(source).ConfigureAwait(false); byte[] pseudorandomKey = HmacSha256(codingHeader.Salt, keyLocator(codingHeader.KeyId)); byte[] contentEncryptionKey = GetContentEncryptionKey(pseudorandomKey); await DecryptContentAsync(source, destination, codingHeader.RecordSize, pseudorandomKey, contentEncryptionKey).ConfigureAwait(false); }
private static async Task WriteCodingHeaderAsync(Stream destination, CodingHeader codingHeader) { //+----------+---------------+-------------+-----------------+ //| SALT(16) | RECORDSIZE(4) | KEYIDLEN(1) | KEYID(KEYIDLEN) | //+----------+---------------+-------------+-----------------+ await destination.WriteAsync(codingHeader.Salt, 0, codingHeader.Salt.Length).ConfigureAwait(false); WriteRecordSize(destination, codingHeader.RecordSize); destination.WriteByte((byte)codingHeader.KeyId.Length); await destination.WriteAsync(codingHeader.KeyId, 0, codingHeader.KeyId.Length).ConfigureAwait(false); }
private static async Task WriteCodingHeaderAsync(Stream destination, CodingHeader codingHeader) { //+----------+---------------+-------------+-----------------+ //| SALT(16) | RECORDSIZE(4) | KEYIDLEN(1) | KEYID(KEYIDLEN) | //+----------+---------------+-------------+-----------------+ byte[] keyIdBytes = GetKeyIdBytes(codingHeader.KeyId); byte[] recordSizeBytes = GetRecordSizeBytes(codingHeader.RecordSize); byte[] codingHeaderBytes = new byte[SALT_LENGTH + RECORD_SIZE_LENGTH + KEY_ID_LEN_LENGTH + keyIdBytes.Length]; codingHeader.Salt.CopyTo(codingHeaderBytes, SALT_INDEX); recordSizeBytes.CopyTo(codingHeaderBytes, RECORD_SIZE_INDEX); codingHeaderBytes[KEY_ID_LEN_INDEX] = (byte)keyIdBytes.Length; keyIdBytes.CopyTo(codingHeaderBytes, KEY_ID_INDEX); await destination.WriteAsync(codingHeaderBytes, 0, codingHeaderBytes.Length).ConfigureAwait(false); }
/// <summary> /// Encodes source stream into destionation stream as an asynchronous operation. /// </summary> /// <param name="source">The source stream.</param> /// <param name="destination">The destionation stream.</param> /// <param name="salt">The salt.</param> /// <param name="key">The keying material.</param> /// <param name="keyId">The keying material identificator.</param> /// <param name="recordSize">The record size in octets.</param> /// <returns>The task object representing the asynchronous operation.</returns> public static async Task EncodeAsync(Stream source, Stream destination, byte[] salt, byte[] key, string keyId, int recordSize) { ValidateEncodeParameters(source, destination, key, recordSize); CodingHeader codingHeader = new CodingHeader { Salt = CoalesceSalt(salt), RecordSize = recordSize, KeyId = keyId }; // PRK = HMAC-SHA-256(salt, IKM) byte[] pseudorandomKey = HmacSha256(codingHeader.Salt, key); byte[] contentEncryptionKey = GetContentEncryptionKey(pseudorandomKey); await WriteCodingHeaderAsync(destination, codingHeader).ConfigureAwait(false); await EncryptContentAsync(source, destination, codingHeader.RecordSize, pseudorandomKey, contentEncryptionKey).ConfigureAwait(false); }
/// <summary> /// Decodes source stream into destionation stream as an asynchronous operation. /// </summary> /// <param name="source">The source stream.</param> /// <param name="destination">The destionation stream.</param> /// <param name="keyProvider">The function which is able to provide the keying material based on the keying material identificator.</param> /// <returns>The task object representing the asynchronous operation.</returns> public static async Task DecodeAsync(Stream source, Stream destination, Func <byte[], byte[]> keyProvider) { ValidateDecodeParameters(source, destination, keyProvider); CodingHeader codingHeader = await ReadCodingHeaderAsync(source).ConfigureAwait(false); // PRK = HMAC-SHA-256(salt, IKM) byte[] pseudorandomKey = HmacSha256(codingHeader.Salt, keyProvider(codingHeader.KeyId)); byte[] contentEncryptionKeyInfoParameterHash, nonceInfoParameterHash; using (HMACSHA256 pseudorandomKeyHasher = new HMACSHA256(pseudorandomKey)) { // HMAC-SHA-256(PRK, CEK_INFO) contentEncryptionKeyInfoParameterHash = HmacSha256(pseudorandomKeyHasher, _contentEncryptionKeyInfoParameter); // HMAC-SHA-256(PRK, NONCE_INFO) nonceInfoParameterHash = HmacSha256(pseudorandomKeyHasher, _nonceInfoParameter); } await DecryptContentAsync(source, destination, codingHeader.RecordSize, contentEncryptionKeyInfoParameterHash, nonceInfoParameterHash).ConfigureAwait(false); }
/// <summary> /// Encodes source stream into destionation stream as an asynchronous operation. /// </summary> /// <param name="source">The source stream.</param> /// <param name="destination">The destionation stream.</param> /// <param name="salt">The salt.</param> /// <param name="key">The keying material.</param> /// <param name="keyId">The keying material identificator.</param> /// <param name="recordSize">The record size in octets.</param> /// <returns>The task object representing the asynchronous operation.</returns> public static async Task EncodeAsync(Stream source, Stream destination, byte[] salt, byte[] key, byte[] keyId, int recordSize) { ValidateEncodeParameters(source, destination, key, keyId, recordSize); CodingHeader codingHeader = new CodingHeader(CoalesceSalt(salt), recordSize, keyId ?? _arrayPool.Rent(0)); // PRK = HMAC-SHA-256(salt, IKM) byte[] pseudorandomKey = HmacSha256(codingHeader.Salt, key); byte[] contentEncryptionKeyInfoParameterHash, nonceInfoParameterHash; using (HMACSHA256 pseudorandomKeyHasher = new HMACSHA256(pseudorandomKey)) { // HMAC-SHA-256(PRK, CEK_INFO) contentEncryptionKeyInfoParameterHash = HmacSha256(pseudorandomKeyHasher, _contentEncryptionKeyInfoParameter); // HMAC-SHA-256(PRK, NONCE_INFO) nonceInfoParameterHash = HmacSha256(pseudorandomKeyHasher, _nonceInfoParameter); } await WriteCodingHeaderAsync(destination, codingHeader).ConfigureAwait(false); await EncryptContentAsync(source, destination, codingHeader.RecordSize, contentEncryptionKeyInfoParameterHash, nonceInfoParameterHash).ConfigureAwait(false); }