Viewing encrypted data using Trace
Today morning I got an email from a customer to review some design recommendation. In the recommendation, another DBA claimed that encrypting the data by using EncryptByKey or EncryptByPassPhrase is not secured because we can trace the data and read it as plain text.
This is not correct and if you have the patience to go through the rest of the post you will get the proof. That goes for both profiler trace and extended events as well. However network sniffing is possible which can be prevented by SSL encryption to the data in the wire but that's outside the scope of this post.
USE master;
GO
Create Database TestEncryption01
GO
USE TestEncryption01;
GO
--Create the seniorEmployees table
IF EXISTS (SELECT name from sys.tables where name='SeniorEmployees')
DROP TABLE dbo.SeniorEmployees
GO
CREATE TABLE dbo.SeniorEmployees
(
ID int NOT NULL,
EmployeeID varbinary(MAX) NOT NULL,
EmployeeSalary decimal(8, 2) NOT NULL,
EmployeePosition varbinary(MAX) NOT NULL
) ON [PRIMARY]
TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE dbo.SeniorEmployees ADD CONSTRAINT
PK_SeniorEmployees PRIMARY KEY CLUSTERED
(
ID
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
--CREATE database master key
CREATE MASTER KEY ENCRYPTION BY PASSWORD ='Str0ngPassw0rd!'
--Create certificate first
CREATE CERTIFICATE EmployeesCert WITH SUBJECT='Certificate for encrypting symmetric keys';
--check the certificate
SELECT * FROM sys.certificates
--now create the symmetric key
CREATE SYMMETRIC KEY EmployeesKey WITH ALGORITHM = AES_256
ENCRYPTION BY CERTIFICATE EmployeesCert;
--Key meta data
SELECT * FROM sys.symmetric_keys WHERE name='EmployeesKey'
Now let's stop here a moment to create a quick trace. I used a small trace definition to track the SQL:batchCompleted event, below is the output for the definition, the trace filters by the database name that we created above.
-- Create a Queue
declare @rc int
declare @TraceID int
declare @maxfilesize bigint
set @maxfilesize = 5
-- Please replace the text InsertFileNameHere, with an appropriate
-- filename prefixed by a path, e.g., c:\MyFolder\MyTrace. The .trc extension
-- will be appended to the filename automatically. If you are writing from
-- remote server to local drive, please use UNC path and make sure server has
-- write access to your network share
exec @rc = sp_trace_create @TraceID output, 0, N'InsertFileNameHere', @maxfilesize, NULL
if (@rc != 0) goto error
-- Client side File and Table cannot be scripted
-- Set the events
declare @on bit
set @on = 1
exec sp_trace_setevent @TraceID, 12, 1, @on
exec sp_trace_setevent @TraceID, 12, 11, @on
exec sp_trace_setevent @TraceID, 12, 12, @on
exec sp_trace_setevent @TraceID, 12, 13, @on
exec sp_trace_setevent @TraceID, 12, 16, @on
exec sp_trace_setevent @TraceID, 12, 35, @on
-- Set the Filters
declare @intfilter int
declare @bigintfilter bigint
exec sp_trace_setfilter @TraceID, 35, 0, 6, N'TestEncryption01'
-- Set the trace status to start
exec sp_trace_setstatus @TraceID, 1
-- display trace id for future references
select TraceID=@TraceID
goto finish
error:
select ErrorCode=@rc
finish:
go
Now after setup the trace and running it, let's go back to management studio to try inserting and selecting from the encrypted column using the keys
--now use the key to insert some records
OPEN SYMMETRIC KEY EmployeesKey DECRYPTION BY CERTIFICATE EmployeesCert;
DECLARE @X INT=1
WHILE @X<=1000
BEGIN
INSERT INTO SeniorEmployees(ID,EmployeeID,EmployeeSalary,EmployeePosition)
VALUES(@X,ENCRYPTBYKEY(KEY_GUID('EmployeesKey'),CONVERT(NVARCHAR(20),CEILING(RAND()*999999)),1,CONVERT(varbinary,@X)),
CEILING(RAND()*999999),
ENCRYPTBYKEY(KEY_GUID('EmployeesKey'),N'BOSS#' + CONVERT(NCHAR(4),@X),1,CONVERT(varbinary,@X)))
SET @X=@X+1;
END
CLOSE SYMMETRIC KEY EmployeesKey;
--Selecting WITH THE KEYS
OPEN SYMMETRIC KEY EmployeesKey DECRYPTION BY CERTIFICATE EmployeesCert;
SELECT ID,CONVERT(NVARCHAR(20),DECRYPTBYKEY(EmployeeID,1,CONVERT(VARBINARY,ID))) as 'EmployeeID',EmployeeSalary,
CONVERT(NVARCHAR(20),DECRYPTBYKEY(EmployeePosition,1,CONVERT(VARBINARY,ID))) as 'EmployeePosition'
FROM SeniorEmployees
CLOSE SYMMETRIC KEY EmployeesKey;
In the trace when we open the file in the profiler here's what we will get. The statement removed for both the insert and select statement and replaced by comments for protecting the encrypted data.
Same goes for the EncryptByPassPhrase function as well, continue with the remaining sample while running the trace
/*
Encrypt by pass phrase.
*/
--Create a new table
IF EXISTS (SELECT name from sys.tables where name='SeniorEmployees2')
DROP TABLE dbo.SeniorEmployees2
GO
CREATE TABLE dbo.SeniorEmployees2
(
ID int NOT NULL,
EmployeeID varbinary(MAX) NOT NULL,
EmployeeSalary decimal(8, 2) NOT NULL,
EmployeePosition varbinary(MAX) NOT NULL
) ON [PRIMARY]
TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE dbo.SeniorEmployees2 ADD CONSTRAINT
PK_SeniorEmployees2 PRIMARY KEY CLUSTERED
(
ID
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
/*Insert by encryptByPassPhrase*/
DECLARE @X INT=1
WHILE @X<=1000
BEGIN
INSERT INTO SeniorEmployees2(ID,EmployeeID,EmployeeSalary,EmployeePosition)
VALUES(@X,EncryptByPassPhrase('This is My Pass Phrase',CONVERT(NVARCHAR(20),CEILING(RAND()*999999)),1,CONVERT(varbinary,@X)),
CEILING(RAND()*999999),
EncryptByPassPhrase('This is My Pass Phrase',N'BOSS#' + CONVERT(NCHAR(4),@X),1,CONVERT(varbinary,@X)))
SET @X=@X+1;
END
/*Select by DecryptByPassPhrase */
SELECT ID,CONVERT(NVARCHAR(20),DecryptByPassPhrase('This is My Pass Phrase',EmployeeID,1,CONVERT(VARBINARY,ID))) as 'EmployeeID',EmployeeSalary,
CONVERT(NVARCHAR(20),DecryptByPassPhrase('This is My Pass Phrase',EmployeePosition,1,CONVERT(VARBINARY,ID))) as 'EmployeePosition'
FROM SeniorEmployees2
And here's the view from the trace.
And for Extended Events as well, here's a quick screenshot of the XE outoupt