{"id":271,"date":"2016-07-27T10:51:57","date_gmt":"2016-07-27T09:51:57","guid":{"rendered":"https:\/\/sqldoubleg.live-website.com\/?p=271"},"modified":"2016-07-30T20:44:19","modified_gmt":"2016-07-30T19:44:19","slug":"sql-server-2016-double-or-nothing-always-encrypted-with-temporal-tables","status":"publish","type":"post","link":"https:\/\/www.sqldoubleg.com\/es\/2016\/07\/27\/sql-server-2016-double-or-nothing-always-encrypted-with-temporal-tables\/","title":{"rendered":"SQL Server 2016, Double or Nothing, Always Encrypted with temporal tables"},"content":{"rendered":"<p>This week&#8217;s post I&#8217;ll talk about two new features that don&#8217;t seem to get on well. Let&#8217;s make them behave and work together as a team&nbsp; Among the overwhelming amount of new features available for SQL Server 2016, there was one I really wanted to try, maybe because I have never worked with encryption further than hashing passwords for a website.<\/p>\n<p>This feature is, you name it: Always Encrypted.<\/p>\n<p>So I got to it and downloaded the new sample databases <a href=\"https:\/\/msdn.microsoft.com\/library\/mt734199(v=sql.1).aspx\" target=\"_blank\">WideWorldImporters <\/a> to start writing some queries, but a bit of background is always useful, rather than blindly try do something you have no idea \ud83d\ude42<\/p>\n<p>First thing that I found surprising is that <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/mt163865.aspx?f=255&#038;mspperror=-2147217396#Anchor_3\" target=\"_blank\">there is no T-SQL to encrypt a column or columns<\/a>&#8230; great! but there is GUI and powershell, which can be also generated from the GUI, so it&#8217;s not too bad time to learn some powershell (or not)<\/p>\n<p><strong><del>*Note that BOL is wrong and both, column master keys and column encryption keys can be created using T-SQL.<\/del><\/strong><br \/>\n<strong>Please see comments for details<\/strong><\/p>\n<p>The easiest way to configure Always Encrypted is using the wizard so for the shake of simplicity, that is my first shot, but with such bad luck that I tried with a temporal table.<\/p>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/01_contextual_menu_disabled.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/01_contextual_menu_disabled.png\" alt=\"01_contextual_menu_disabled\" width=\"696\" height=\"453\" class=\"aligncenter size-full wp-image-272\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/01_contextual_menu_disabled.png 696w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/01_contextual_menu_disabled-300x195.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/01_contextual_menu_disabled-150x98.png 150w\" sizes=\"(max-width: 696px) 100vw, 696px\" \/><\/a><\/p>\n<p>Hm, disabled&#8230; let&#8217;s try the wizard from Database &rarr; Tasks &rarr; Encrypt columns <\/p>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/02_database_encrypt_columns.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/02_database_encrypt_columns.png\" alt=\"02_database_encrypt_columns\" width=\"700\" height=\"310\" class=\"aligncenter size-full wp-image-273\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/02_database_encrypt_columns.png 700w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/02_database_encrypt_columns-300x133.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/02_database_encrypt_columns-150x66.png 150w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/03_wizard_disabled.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/03_wizard_disabled.png\" alt=\"03_wizard_disabled\" width=\"715\" height=\"371\" class=\"aligncenter size-full wp-image-285\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/03_wizard_disabled.png 715w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/03_wizard_disabled-300x156.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/03_wizard_disabled-150x78.png 150w\" sizes=\"(max-width: 715px) 100vw, 715px\" \/><\/a><\/p>\n<p>Again the wall. There is no way you can choose a temporal table and apply encryption to a column or columns using the wizard.<\/p>\n<p>I tried then using the powershell (after manually creating the keys) as this is true the only way to encrypt existing columns, just in case. <\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\n# Generated by SQL Server Management Studio at 08:37 on 25\/07\/2016\r\n\r\nImport-Module SqlServer\r\n# Load reflected assemblies\r\n\r\n[reflection.assembly]::LoadwithPartialName('System.Data.SqlClient') | Out-Null\r\n[reflection.assembly]::LoadwithPartialName('Microsoft.SQLServer.SMO') | Out-Null\r\n[reflection.assembly]::LoadwithPartialName('Microsoft.SQLServer.ConnectionInfo') | Out-Null\r\n\r\n# Set up connection and database SMO objects\r\n\r\n$sqlConnectionString = 'Data Source=localhost\\MSSQL2016;Integrated Security=True;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=True;Packet Size=4096;Application Name=&quot;Microsoft SQL Server Management Studio&quot;'\r\n$sqlConnection = New-Object 'System.Data.SqlClient.SqlConnection' $sqlConnectionString\r\n$serverConnection = New-Object 'Microsoft.SqlServer.Management.Common.ServerConnection' $sqlConnection\r\n$smoServer = New-Object 'Microsoft.SqlServer.Management.Smo.Server' $serverConnection\r\n$smoDatabase = $smoServer.Databases['WideWorldImporters']\r\n\r\n# If your encryption changes involve keys in Azure Key Vault, uncomment one of the lines below in order to authenticate:\r\n#   * Prompt for a username and password:\r\n#Add-SqlAzureAuthenticationContext -Interactive\r\n\r\n#   * Enter a Client ID, Secret, and Tenant ID:\r\n#Add-SqlAzureAuthenticationContext -ClientID '&lt;Client ID&gt;' -Secret '&lt;Secret&gt;' -Tenant '&lt;Tenant ID&gt;'\r\n\r\n# Change encryption schema\r\n\r\n$encryptionChanges = @()\r\n\r\n# Add changes for table [Application].[SystemParameters]\r\n$encryptionChanges += New-SqlColumnEncryptionSettings -ColumnName Application.People.LogonName -EncryptionType Randomized -EncryptionKey CEK_Auto1\r\n\r\nSet-SqlColumnEncryption -ColumnEncryptionSettings $encryptionChanges -InputObject $smoDatabase\r\n\r\n<\/pre>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/04_powershell_error.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/04_powershell_error.png\" alt=\"04_powershell_error\" width=\"1168\" height=\"146\" class=\"aligncenter size-full wp-image-274\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/04_powershell_error.png 1168w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/04_powershell_error-300x38.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/04_powershell_error-1024x128.png 1024w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/04_powershell_error-150x19.png 150w\" sizes=\"(max-width: 1168px) 100vw, 1168px\" \/><\/a><\/p>\n<p><span style=\"color:red\">System-versioned temporal tables with always encrypted columns are not supported.<\/span><br \/>\nWhat a disappointment! <\/p>\n<p>Now it&#8217;s when my brain started boiling trying to find a way to make it work, because how nice would it be to be able to track changes regardless the data is encrypted or not.<\/p>\n<p>&nbsp;<br \/>\n<strong>Not always in SQL A+B = B+A<\/strong><\/p>\n<p>I know it&#8217;s kind of weird, but SQL is not maths and sometimes this happens.<\/p>\n<p>If I cannot encrypt columns in a temporal table, can I make temporal a table that contains encrypted columns? Let&#8217;s see&#8230; First I&#8217;ll create a table and put some data, then we&#8217;ll encrypt a column.<\/p>\n<pre class=\"brush: tsql; title: ; notranslate\" title=\"\">\r\nUSE [master]\r\nGO\r\nIF DB_ID('temporal_demo') IS NOT NULL BEGIN \r\n\tALTER DATABASE [temporal_demo] SET SINGLE_USER WITH ROLLBACK IMMEDIATE\r\n\tDROP DATABASE [temporal_demo]\r\nEND\r\nGO\r\nCREATE DATABASE [temporal_demo]\r\nGO\r\n\r\n\r\nUSE [temporal_demo]\r\nGO\r\nCREATE TABLE [dbo].[People](\r\n\t[PersonID] [int] NOT NULL PRIMARY KEY,\r\n\t[FullName] [nvarchar](50) NOT NULL,\r\n\t[LogonName] [nvarchar](50) NULL,\r\n\t[HashedPassword] [nvarchar](50) NULL,\r\n\t[ValidFrom] [datetime2](7) GENERATED ALWAYS AS ROW START NOT NULL,\r\n\t[ValidTo] [datetime2](7) GENERATED ALWAYS AS ROW END NOT NULL,\r\n\tPERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo])\r\n) ON [PRIMARY] \r\n\r\nGO\r\n\r\nINSERT INTO dbo.[People] (PersonID, FullName, LogonName, HashedPassword)\r\n\tVALUES (1, 'john', 'jonny', 'J0nny!')\r\n\t\t, (2, 'Edward', 'eddy', '3DDy!')\r\nGO\r\n\r\nSELECT * FROM dbo.People\r\nGO\r\nSELECT name, temporal_type, temporal_type_desc FROM sys.tables \r\nGO\r\n<\/pre>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/05_select_sys_tables.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/05_select_sys_tables.png\" alt=\"05_select_sys_tables\" width=\"864\" height=\"151\" class=\"aligncenter size-full wp-image-276\" \/><\/a><\/p>\n<p>The table we just created looks very similar to a temporal table, but as you can see, it&#8217;s not. <\/p>\n<p>This point is important, because we need to create our table with a similar structure as it was temporal to be able to convert it later on.<\/p>\n<p>Now we can try encrypt a column from our table to see what happens.<\/p>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/06_encript_table.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/06_encript_table.png\" alt=\"06_encript_table\" width=\"525\" height=\"460\" class=\"aligncenter size-full wp-image-277\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/06_encript_table.png 525w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/06_encript_table-300x263.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/06_encript_table-150x131.png 150w\" sizes=\"(max-width: 525px) 100vw, 525px\" \/><\/a><\/p>\n<p>See how now the option is available, so we can proceed to encrypt our column.<\/p>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/07_encript_table_wizard.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/07_encript_table_wizard.png\" alt=\"07_encript_table_wizard\" width=\"729\" height=\"413\" class=\"aligncenter size-full wp-image-282\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/07_encript_table_wizard.png 729w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/07_encript_table_wizard-300x170.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/07_encript_table_wizard-150x85.png 150w\" sizes=\"(max-width: 729px) 100vw, 729px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/08_encript_table_wizard.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/08_encript_table_wizard.png\" alt=\"08_encript_table_wizard\" width=\"728\" height=\"459\" class=\"aligncenter size-full wp-image-281\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/08_encript_table_wizard.png 728w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/08_encript_table_wizard-300x189.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/08_encript_table_wizard-150x95.png 150w\" sizes=\"(max-width: 728px) 100vw, 728px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/09_encript_table_wizard.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/09_encript_table_wizard.png\" alt=\"09_encript_table_wizard\" width=\"729\" height=\"518\" class=\"aligncenter size-full wp-image-280\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/09_encript_table_wizard.png 729w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/09_encript_table_wizard-300x213.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/09_encript_table_wizard-150x107.png 150w\" sizes=\"(max-width: 729px) 100vw, 729px\" \/><\/a><\/p>\n<p>Just a few clicks later when we have finished the process, we can see how our data is actually encrypted.<\/p>\n<pre class=\"brush: tsql; title: ; notranslate\" title=\"\">\r\n\r\nSELECT * FROM dbo.People\r\nGO\r\n<\/pre>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/10_select_encrypted.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/10_select_encrypted.png\" alt=\"10_select_encrypted\" width=\"977\" height=\"137\" class=\"aligncenter size-full wp-image-283\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/10_select_encrypted.png 977w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/10_select_encrypted-300x42.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/10_select_encrypted-150x21.png 150w\" sizes=\"(max-width: 977px) 100vw, 977px\" \/><\/a><\/p>\n<p>You can observe how the data in the [HashedPassword] column is now encrypted.<\/p>\n<p>&nbsp;<br \/>\n<strong>Making the encrypted table a temporal table<\/strong><\/p>\n<p>The next step is to get the table with the encrypted column to hold historical changes as temporal tables do, so we have to ALTER TABLE as explained in <a href=\"https:\/\/msdn.microsoft.com\/en-gb\/library\/ms190273.aspx#Anchor_16\" target=\"_blank\">BOL<\/a>. <\/p>\n<p>Remember we have the table ready with ROW START, ROW END and PERIOD FOR SYSTEM TIME, so the only we need to do now is to convert it.<\/p>\n<pre class=\"brush: tsql; title: ; notranslate\" title=\"\">\r\nALTER TABLE [dbo].[People] SET (\r\nSYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.[People_Archive] , DATA_CONSISTENCY_CHECK = ON )\r\n)\r\nGO\r\n\r\nUPDATE dbo.People SET LogonName = 'jonnybegood'\r\nWHERE PersonID = 1\r\nGO\r\n\r\nUPDATE dbo.People SET LogonName = 'eddievanhalen'\r\nWHERE PersonID = 2\r\nGO\r\n\r\nSELECT * FROM dbo.People\r\nFOR SYSTEM_TIME ALL\r\nGO\r\n\r\n<\/pre>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/11_select_encrypted_temporal.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/07\/11_select_encrypted_temporal.png\" alt=\"11_select_encrypted_temporal\" width=\"981\" height=\"200\" class=\"aligncenter size-full wp-image-284\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/11_select_encrypted_temporal.png 981w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/11_select_encrypted_temporal-300x61.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/07\/11_select_encrypted_temporal-150x31.png 150w\" sizes=\"(max-width: 981px) 100vw, 981px\" \/><\/a><\/p>\n<p>You can see how there is no problems at all and both features work together as we were expecting.<\/p>\n<p>&nbsp;<br \/>\n<strong><strong><span style=\"color:red\">Caveat<\/span><\/strong><\/strong><\/p>\n<p>There is a big caveat though. <\/p>\n<p>Once you have started this way, you won&#8217;t be able to encrypt any pre existing data as it will fail due to these two features \u00abincompatibility\u00bb.<\/p>\n<p>You can create new tables with encrypted columns and dump your existing data there, and it will work, but existing data won&#8217;t be encrypted.<\/p>\n<p>&nbsp;<br \/>\n<strong>Conclusion<\/strong><\/p>\n<p>Just to wrap up let&#8217;s see what is allowed and what is not.<\/p>\n<ul>\n<li>Encrypt temporal table &rarr; Not allowed (by design)<\/li>\n<li>Make temporal a table with encrypted columns &rarr; Allowed<\/li>\n<li>Create temporal table with encrypted columns &rarr; Allowed<\/li>\n<li>Encrypt existing columns if you have any temporal table with encrypted columns &rarr; Not Allowed<\/li>\n<\/ul>\n<p>&nbsp;<br \/>\nI can imagine why this two features work together when you build temporal on top of encrypted and not vice versa, but I&#8217;m happy I found the way to workaround it.<\/p>\n<p>So far I found these caveats explained above, but if you see any other, please feel free to tell me and I&#8217;ll update this post. <\/p>\n<p>I really look forward to your comments and keep investigating more about these awesome features.<\/p>\n<p>Thanks  for reading.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This week&#8217;s post I&#8217;ll talk about two new features that don&#8217;t seem to get on well. Let&#8217;s make them behave and work together as a team&nbsp; Among the overwhelming amount of new&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,19],"tags":[45,23,44],"_links":{"self":[{"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/posts\/271"}],"collection":[{"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/comments?post=271"}],"version-history":[{"count":0,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/posts\/271\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/media?parent=271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/categories?post=271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/tags?post=271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}