Ejemplo n.º 1
0
        /// <summary>
        /// Decrypts the ciphertext.
        /// </summary>
        internal static byte[] DecryptWithKey(byte[] cipherText, SqlCipherMetadata md, string serverName)
        {
            Debug.Assert(serverName != null, @"serverName should not be null in DecryptWithKey.");

            // Initialize cipherAlgo if not already done.
            if (!md.IsAlgorithmInitialized())
            {
                SqlSecurityUtility.DecryptSymmetricKey(md, serverName);
            }

            Debug.Assert(md.IsAlgorithmInitialized(), "Decryption Algorithm is not initialized");
            try {
                byte[] plainText = md.CipherAlgorithm.DecryptData(cipherText); // this call succeeds or throws.
                if (null == plainText)
                {
                    throw SQL.NullPlainText();
                }

                return(plainText);
            }
            catch (Exception e) {
                // compute the strings to pass
                string keyStr = GetBytesAsString(md.EncryptionKeyInfo.Value.encryptedKey, fLast: true, countOfBytes: 10);
                string valStr = GetBytesAsString(cipherText, fLast: false, countOfBytes: 10);
                throw SQL.ThrowDecryptionFailed(keyStr, valStr, e);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Decrypt the keys that need to be sent to the enclave
        /// </summary>
        /// <param name="keysTobeSentToEnclave">Keys that need to sent to the enclave</param>
        /// <param name="sqlConnection">active connection</param>
        /// <returns></returns>
        private List <ColumnEncryptionKeyInfo> GetDecryptedKeysToBeSentToEnclave(Dictionary <int, SqlTceCipherInfoEntry> keysTobeSentToEnclave, string serverName)
        {
            List <ColumnEncryptionKeyInfo> decryptedKeysToBeSentToEnclave = new List <ColumnEncryptionKeyInfo>();

            foreach (SqlTceCipherInfoEntry cipherInfo in keysTobeSentToEnclave.Values)
            {
                SqlClientSymmetricKey sqlClientSymmetricKey   = null;
                SqlEncryptionKeyInfo? encryptionkeyInfoChosen = null;
                SqlSecurityUtility.DecryptSymmetricKey(cipherInfo, serverName, out sqlClientSymmetricKey,
                                                       out encryptionkeyInfoChosen);

                if (sqlClientSymmetricKey == null)
                {
                    throw SQL.NullArgumentInternal("sqlClientSymmetricKey", ClassName, GetDecryptedKeysToBeSentToEnclaveName);
                }
                if (cipherInfo.ColumnEncryptionKeyValues == null)
                {
                    throw SQL.NullArgumentInternal("ColumnEncryptionKeyValues", ClassName, GetDecryptedKeysToBeSentToEnclaveName);
                }
                if (!(cipherInfo.ColumnEncryptionKeyValues.Count > 0))
                {
                    throw SQL.ColumnEncryptionKeysNotFound();
                }

                //cipherInfo.CekId is always 0, hence used cipherInfo.ColumnEncryptionKeyValues[0].cekId. Even when cek has multiple ColumnEncryptionKeyValues
                //the cekid and the plaintext value will remain the same, what varies is the encrypted cek value, since the cek can be encrypted by
                //multiple CMKs
                decryptedKeysToBeSentToEnclave.Add(new ColumnEncryptionKeyInfo(sqlClientSymmetricKey.RootKey,
                                                                               cipherInfo.ColumnEncryptionKeyValues[0].databaseId,
                                                                               cipherInfo.ColumnEncryptionKeyValues[0].cekMdVersion, cipherInfo.ColumnEncryptionKeyValues[0].cekId));
            }
            return(decryptedKeysToBeSentToEnclave);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Encrypts the plaintext.
        /// </summary>
        internal static byte[] EncryptWithKey (byte[] plainText, SqlCipherMetadata md, string serverName) {
            Debug.Assert(serverName != null, @"serverName should not be null in EncryptWithKey.");

            // Initialize cipherAlgo if not already done.
            if (!md.IsAlgorithmInitialized()) {
                SqlSecurityUtility.DecryptSymmetricKey(md, serverName);
            }

            Debug.Assert(md.IsAlgorithmInitialized(), "Encryption Algorithm is not initialized");
            byte[] cipherText = md.CipherAlgorithm.EncryptData(plainText); // this call succeeds or throws.
            if (null == cipherText || 0 == cipherText.Length) {
                SQL.NullCipherText();
            }

            return cipherText;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// <para> Retrieves the query metadata for a specific query from the cache.</para>
        /// </summary>
        internal bool GetQueryMetadataIfExists(SqlCommand sqlCommand)
        {
            // Return immediately if caching is disabled.
            if (!SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled)
            {
                return(false);
            }

            // Check the cache to see if we have the MD for this query cached.
            string cacheLookupKey = GetCacheLookupKeyFromSqlCommand(sqlCommand);

            if (cacheLookupKey == null)
            {
                IncrementCacheMisses();
                return(false);
            }

            Dictionary <string, SqlCipherMetadata> ciperMetadataDictionary = _cache.Get(cacheLookupKey) as Dictionary <string, SqlCipherMetadata>;

            // If we had a cache miss just return false.
            if (ciperMetadataDictionary == null)
            {
                IncrementCacheMisses();
                return(false);
            }

            // Iterate over all the parameters and try to get their cipher MD.
            foreach (SqlParameter param in sqlCommand.Parameters)
            {
                SqlCipherMetadata paramCiperMetadata;
                bool found = ciperMetadataDictionary.TryGetValue(param.ParameterNameFixed, out paramCiperMetadata);

                // If we failed to identify the encryption for a specific parameter, clear up the cipher MD of all parameters and exit.
                if (!found)
                {
                    foreach (SqlParameter paramToCleanup in sqlCommand.Parameters)
                    {
                        paramToCleanup.CipherMetadata = null;
                    }

                    IncrementCacheMisses();
                    return(false);
                }

                // Cached cipher MD should never have an initialized algorithm since this would contain the key.
                Debug.Assert(paramCiperMetadata == null || !paramCiperMetadata.IsAlgorithmInitialized());

                // We were able to identify the cipher MD for this parameter, so set it on the param.
                param.CipherMetadata = paramCiperMetadata;
            }

            // Create a copy of the cipherMD in order to load the key.
            // The key shouldn't be loaded in the cached version for security reasons.
            foreach (SqlParameter param in sqlCommand.Parameters)
            {
                SqlCipherMetadata cipherMdCopy = null;

                if (param.CipherMetadata != null)
                {
                    cipherMdCopy = new SqlCipherMetadata(
                        param.CipherMetadata.EncryptionInfo,
                        0,
                        param.CipherMetadata.CipherAlgorithmId,
                        param.CipherMetadata.CipherAlgorithmName,
                        param.CipherMetadata.EncryptionType,
                        param.CipherMetadata.NormalizationRuleVersion);
                }

                param.CipherMetadata = cipherMdCopy;

                if (cipherMdCopy != null)
                {
                    // Try to get the encryption key. If the key information is stale, this might fail.
                    // In this case, just fail the cache lookup.
                    try {
                        SqlSecurityUtility.DecryptSymmetricKey(cipherMdCopy, sqlCommand.Connection.DataSource);
                    }
                    catch (Exception ex) {
                        // Invalidate the cache entry.
                        InvalidateCacheEntry(sqlCommand);

                        // If we get one of the expected exceptions, just fail the cache lookup, otherwise throw.
                        if (ex is SqlException || ex is ArgumentException || ex is ArgumentNullException)
                        {
                            foreach (SqlParameter paramToCleanup in sqlCommand.Parameters)
                            {
                                paramToCleanup.CipherMetadata = null;
                            }

                            IncrementCacheMisses();
                            return(false);
                        }

                        throw;
                    }
                }
            }

            IncrementCacheHits();
            return(true);
        }