Ejemplo n.º 1
0
 internal virtual byte[] GenerateKey(CosmosEncryptionAlgorithm encryptionAlgorithmId)
 {
     Debug.Assert(encryptionAlgorithmId == CosmosEncryptionAlgorithm.AE_AES_256_CBC_HMAC_SHA_256_RANDOMIZED, "Unexpected encryption algorithm id");
     byte[] rawDek = new byte[32];
     SecurityUtility.GenerateRandomBytes(rawDek);
     return(rawDek);
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Encryption Algorithm
        /// cell_iv = HMAC_SHA-2-256(iv_key, cell_data) truncated to 128 bits
        /// cell_ciphertext = AES-CBC-256(enc_key, cell_iv, cell_data) with PKCS7 padding.
        /// (optional) cell_tag = HMAC_SHA-2-256(mac_key, versionbyte + cell_iv + cell_ciphertext + versionbyte_length)
        /// cell_blob = versionbyte + [cell_tag] + cell_iv + cell_ciphertext
        /// </summary>
        /// <param name="plainText">Plaintext data to be encrypted</param>
        /// <param name="hasAuthenticationTag">Does the algorithm require authentication tag.</param>
        /// <returns>Returns the ciphertext corresponding to the plaintext.</returns>
        protected byte[] EncryptData(byte[] plainText, bool hasAuthenticationTag)
        {
            // Empty values get encrypted and decrypted properly for both Deterministic and Randomized encryptions.
            Debug.Assert(plainText != null);

            byte[] iv = new byte[BlockSizeInBytes];

            // Prepare IV
            // Should be 1 single block (16 bytes)
            if (this.isDeterministic)
            {
                SecurityUtility.GetHMACWithSHA256(plainText, this.dataEncryptionKey.IVKey, iv);
            }
            else
            {
                SecurityUtility.GenerateRandomBytes(iv);
            }

            int numBlocks = (plainText.Length / BlockSizeInBytes) + 1;

            // Final blob we return = version + HMAC + iv + cipherText
            const int hmacStartIndex       = 1;
            int       authenticationTagLen = hasAuthenticationTag ? KeySizeInBytes : 0;
            int       ivStartIndex         = hmacStartIndex + authenticationTagLen;
            int       cipherStartIndex     = ivStartIndex + BlockSizeInBytes; // this is where hmac starts.

            // Output buffer size = size of VersionByte + Authentication Tag + IV + cipher Text blocks.
            int outputBufSize = sizeof(byte) + authenticationTagLen + iv.Length + (numBlocks * BlockSizeInBytes);

            byte[] outBuffer = new byte[outputBufSize];

            // Store the version and IV rightaway
            outBuffer[0] = this.algorithmVersion;
            Buffer.BlockCopy(iv, 0, outBuffer, ivStartIndex, iv.Length);

            AesCryptoServiceProvider aesAlg;

            // Try to get a provider from the pool.
            // If no provider is available, create a new one.
            if (!this.cryptoProviderPool.TryDequeue(out aesAlg))
            {
                aesAlg = new AesCryptoServiceProvider();

                try
                {
                    // Set various algorithm properties
                    aesAlg.Key     = this.dataEncryptionKey.EncryptionKey;
                    aesAlg.Mode    = cipherMode;
                    aesAlg.Padding = paddingMode;
                }
                catch (Exception)
                {
                    if (aesAlg != null)
                    {
                        aesAlg.Dispose();
                    }

                    throw;
                }
            }

            try
            {
                // Always set the IV since it changes from cell to cell.
                aesAlg.IV = iv;

                // Compute CipherText and authentication tag in a single pass
                using (ICryptoTransform encryptor = aesAlg.CreateEncryptor())
                {
                    Debug.Assert(encryptor.CanTransformMultipleBlocks, "AES Encryptor can transform multiple blocks");
                    int count       = 0;
                    int cipherIndex = cipherStartIndex; // this is where cipherText starts
                    if (numBlocks > 1)
                    {
                        count        = (numBlocks - 1) * BlockSizeInBytes;
                        cipherIndex += encryptor.TransformBlock(plainText, 0, count, outBuffer, cipherIndex);
                    }

                    byte[] buffTmp = encryptor.TransformFinalBlock(plainText, count, plainText.Length - count); // done encrypting
                    Buffer.BlockCopy(buffTmp, 0, outBuffer, cipherIndex, buffTmp.Length);
                    cipherIndex += buffTmp.Length;
                }

                if (hasAuthenticationTag)
                {
                    using (HMACSHA256 hmac = new HMACSHA256(this.dataEncryptionKey.MACKey))
                    {
                        Debug.Assert(hmac.CanTransformMultipleBlocks, "HMAC can't transform multiple blocks");
                        hmac.TransformBlock(version, 0, version.Length, version, 0);
                        hmac.TransformBlock(iv, 0, iv.Length, iv, 0);

                        // Compute HMAC on final block
                        hmac.TransformBlock(outBuffer, cipherStartIndex, numBlocks * BlockSizeInBytes, outBuffer, cipherStartIndex);
                        hmac.TransformFinalBlock(versionSize, 0, versionSize.Length);
                        byte[] hash = hmac.Hash;
                        Debug.Assert(hash.Length >= authenticationTagLen, "Unexpected hash size");
                        Buffer.BlockCopy(hash, 0, outBuffer, hmacStartIndex, authenticationTagLen);
                    }
                }
            }
            finally
            {
                // Return the provider to the pool.
                this.cryptoProviderPool.Enqueue(aesAlg);
            }

            return(outBuffer);
        }