Search code examples
sql-serversql-server-2008encryption-symmetricaes

SQL Encrypted Columns in WHERE Clause


I am looking to apply SQL column level encryption using symmetric keys. The initial steps needed to create the Database Master Key, Certificates and Symmetric Keys seems straight forward and I have tested encrypting/decrypting data using Symmetric Keys successfully.

However, once the data is encrypted I don't know how best to query it. E.g.

SELECT PlainTextA, PlainTextB, PlainTextC 
WHERE CONVERT(varchar, DECRYPTBYKEY(EncyptedColumn)) = @SearchTerm

would surely result in a full table scan?

Another option I thought might work is encrypting the search criteria first e.g.

SELECT PlainTextA, PlainTextB, PlainTextC 
WHERE EncyptedColumn = ENCRYPTBYKEY(KEY_GUID('KeyName'), @SearchTerm)

but this doesn't work as the encrypted value generated is always different.

Any suggestions would be greatly appreciated.


Solution

  • The typical way is to store both the encrypted value and a one-way hash of the value. When you seek a specific value, you would seek the hash. This way you can query efficiently, w/o having to decrypt every row in order to find the value you're interested:

    create table Table (
    EncryptedColumn varbinary(max),
    HashValue binary(20),
    PlainA int,
    PlainB varchar(256),
    PlainC Datetime);
    
    create index ndxTableHash on Table(HashValue);
    
    select PlainA, plainB, PlainC
    from table
    where HashValue = HashBytes('SHA1', @searchTerm);
    

    In theory, you can have a hash conflict once in a blue moon, to be paranoid-safe you add a double check on the decrypted column:

    select PlainA, plainB, PlainC
    from table
    where HashValue = HashBytes('SHA1', @searchTerm)
    and DecryptByKey(..., EncryptedColumn) = @searchTerm;
    

    Also see Indexing encrypted data and SQL Server 2005: searching encrypted data.