internal async Task <(DataEncryptionKeyProperties, InMemoryRawDek)> FetchUnwrappedAsync(
            string id,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            try
            {
                DataEncryptionKeyProperties dekProperties = await this.DekProvider.DekCache.GetOrAddDekPropertiesAsync(
                    id,
                    this.ReadResourceAsync,
                    diagnosticsContext,
                    cancellationToken);

                InMemoryRawDek inMemoryRawDek = await this.DekProvider.DekCache.GetOrAddRawDekAsync(
                    dekProperties,
                    this.UnwrapAsync,
                    diagnosticsContext,
                    cancellationToken);

                return(dekProperties, inMemoryRawDek);
            }
            catch (CosmosException exception)
            {
                throw EncryptionExceptionFactory.EncryptionKeyNotFoundException(
                          $"Failed to retrieve Data Encryption Key with id: '{id}'.",
                          exception);
            }
        }
        /// <summary>
        /// Decryption steps
        /// 1. Validate version byte
        /// 2. (optional) Validate Authentication tag
        /// 3. Decrypt the message
        /// </summary>
        protected byte[] DecryptData(byte[] cipherText, bool hasAuthenticationTag)
        {
            Debug.Assert(cipherText != null);

            byte[] iv = new byte[BlockSizeInBytes];

            int minimumCipherTextLength = hasAuthenticationTag ? MinimumCipherTextLengthInBytesWithAuthenticationTag : MinimumCipherTextLengthInBytesNoAuthenticationTag;

            if (cipherText.Length < minimumCipherTextLength)
            {
                throw EncryptionExceptionFactory.InvalidCipherTextSize(cipherText.Length, minimumCipherTextLength);
            }

            // Validate the version byte
            int startIndex = 0;

            if (cipherText[startIndex] != this.algorithmVersion)
            {
                // Cipher text was computed with a different algorithm version than this.
                throw EncryptionExceptionFactory.InvalidAlgorithmVersion(cipherText[startIndex], this.algorithmVersion);
            }

            startIndex += 1;
            int authenticationTagOffset = 0;

            // Read authentication tag
            if (hasAuthenticationTag)
            {
                authenticationTagOffset = startIndex;
                startIndex += KeySizeInBytes; // authentication tag size is KeySizeInBytes
            }

            // Read cell IV
            Buffer.BlockCopy(cipherText, startIndex, iv, 0, iv.Length);
            startIndex += iv.Length;

            // Read encrypted text
            int cipherTextOffset = startIndex;
            int cipherTextCount  = cipherText.Length - startIndex;

            if (hasAuthenticationTag)
            {
                // Compute authentication tag
                byte[] authenticationTag = this.PrepareAuthenticationTag(iv, cipherText, cipherTextOffset, cipherTextCount);
                if (!SecurityUtility.CompareBytes(authenticationTag, cipherText, authenticationTagOffset, authenticationTag.Length))
                {
                    // Potentially tampered data, throw an exception
                    throw EncryptionExceptionFactory.InvalidAuthenticationTag();
                }
            }

            // Decrypt the text and return
            return(this.DecryptData(iv, cipherText, cipherTextOffset, cipherTextCount));
        }
Exemple #3
0
        /// <summary>
        /// Derives all the required keys from the given root key
        /// </summary>
        internal AeadAes256CbcHmac256EncryptionKey(byte[] rootKey, string algorithmName)
            : base(rootKey)
        {
            this.algorithmName = algorithmName;

            int keySizeInBytes = KeySize / 8;

            // Key validation
            if (rootKey.Length != keySizeInBytes)
            {
                throw EncryptionExceptionFactory.InvalidKeySize(
                          this.algorithmName,
                          rootKey.Length,
                          keySizeInBytes);
            }

            // Derive keys from the root key
            //
            // Derive encryption key
            string encryptionKeySalt = string.Format(
                EncryptionKeySaltFormat,
                this.algorithmName,
                KeySize);

            byte[] buff1 = new byte[keySizeInBytes];
            SecurityUtility.GetHMACWithSHA256(Encoding.Unicode.GetBytes(encryptionKeySalt), this.RootKey, buff1);
            this.encryptionKey = new SymmetricKey(buff1);

            // Derive mac key
            string macKeySalt = string.Format(MacKeySaltFormat, this.algorithmName, KeySize);

            byte[] buff2 = new byte[keySizeInBytes];
            SecurityUtility.GetHMACWithSHA256(Encoding.Unicode.GetBytes(macKeySalt), this.RootKey, buff2);
            this.macKey = new SymmetricKey(buff2);

            // Derive iv key
            string ivKeySalt = string.Format(IvKeySaltFormat, this.algorithmName, KeySize);

            byte[] buff3 = new byte[keySizeInBytes];
            SecurityUtility.GetHMACWithSHA256(Encoding.Unicode.GetBytes(ivKeySalt), this.RootKey, buff3);
            this.ivKey = new SymmetricKey(buff3);
        }