/// <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); } }
/// <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="serverName"></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); }
/// <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) { throw SQL.NullCipherText(); } return(cipherText); }
/// <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); }