<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Security in SQL Server 2005 and beyond</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/yukondoit/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/yukondoit/feed.xml</link>
    <description>SQL Server 2005 has various new security features, a big improvement over the features in SQL Server 2000. The new release boasts of an enhanced authorization model, a huge set of data encryption capabilities, code signing and a much improved (no more set</description>
    <lastBuildDate>Wed, 17 Apr 2019 04:09:27 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>SQL Server 2005 Encryption – Encryption and data length limitations</title>
      <link>https://docs.microsoft.com/archive/blogs/yukondoit/sql-server-2005-encryption-encryption-and-data-length-limitations</link>
      <pubDate>Wed, 23 Nov 2005 19:25:00 GMT</pubDate>
      <dc:creator><![CDATA[yukondoit]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/yukondoit/2005/11/23/sql-server-2005-encryption-encryption-and-data-length-limitations/</guid>
      <description><![CDATA[&nbsp;&nbsp; SQL Server 2005 encryption solution has some limitations and one of them that has...]]></description>
      <content:encoded><![CDATA[<P><EM>&nbsp;&nbsp; SQL Server 2005 encryption solution has some limitations and one of them that has raised a few questions is the limited amount of plaintext that can be encrypted. I hope this article helps answer this question.</EM></P>
<P><STRONG>What is the limit on the data length that can be encrypted?</STRONG><BR>&nbsp;The answer to this question is a little bit more complex than a simple number: the limit on the input (plaintext) really depends on the output (ciphertext), and it depends on the key you are using and on whether you are using optional features of the encryption builtins. </P>
<P>You can use the following formula to predict the length of the ciphertext that will result from calling EncryptByKey based on the plaintext length, the key algorithm used and whether the optional authenticator parameter is being used or not. Note: this formula is valid only for the DES and AES key families, it is not valid for RC4, and I would recommend to not even use RC4 at all) </P>
<P>@CipherLen = FLOOR( (8 +@PTLen + (@UsesAuth * @HASHLEN) ) / @BLOCK) + 1 )&nbsp; *&nbsp; @BLOCK + 16 + @BLOCK + 4</P>
<P>&nbsp; Where:<BR>@CipherLen:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The ciphertext length in bytes<BR>@PTLen:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The plaintext length in bytes<BR>@UsesAuth:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 if using the optional authenticator parameter, 0 otherwise<BR>@HASHLEN:&nbsp;&nbsp;&nbsp;20 bytes for SHA1 (The authenticator parameter adds a SHA1 hash to the plaintext)<BR>@BLOCK:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The length in bytes per block. 8 for the DES family, 16 for AES</P>
<P>Now let’s explain every part of the formula to make it easier to understand:<BR>FLOOR( (<BR>8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<EM>Encrypted internal header<BR></EM>+@PTLen&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<EM>Plaintext length</EM><BR>+ (@UsesAuth * @HASHLEN)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<EM>If the authenticator parameter is used, the plaintext will include a hash derived from it.<BR></EM>&nbsp;) / @BLOCK) + 1 )&nbsp; *&nbsp; @BLOCK&nbsp;&nbsp;&nbsp; &nbsp;<EM>This portion of the formula as a whole predicts the length of the ciphertext, including padding. Note: If the plaintext length fits exactly in one block, there will be an additional block of padding. This part of the formula reflects this behavior<BR></EM>&nbsp;&nbsp; + 16 &nbsp;&nbsp;&nbsp; Key GUID (not encrypted).&nbsp;&nbsp;&nbsp;&nbsp;<EM>This information is used during decryption to identify the key that needs to be used</EM><BR>&nbsp;&nbsp; + @BLOCK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<EM>Initialization vector (IV)</EM><BR>&nbsp;&nbsp; + 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <EM>Internal header that describes the BLOB version number</EM></P>
<P>&nbsp; Once we have reviewed this formula, we can discuss the limitations on the encryption builtins: The output (ciphertext) is limited to up to 8000 bytes; what does this mean? This means that the plaintext limit is a little bit below the 8000 bytes (i.e. for AES encryption, using the authenticator parameter it should be around 7920 bytes ). If you try to encrypt a larger plaintext, the builtin will fail (return null) as it won’t be able to fit all the output in the available buffer.</P>
<P>&nbsp;&nbsp; For certificates, the way to calculate the maximum length of plaintext we can encrypt, as well as the ciphertext length, is easier because it is based on key modulus. <BR>@Cipher_len&nbsp; = key_modulus (regardless of the plaintext length)<BR>@Max_Plaintext_len = key_modulus – 11</P>
<P>&nbsp;&nbsp; By default, the self-signed certificates created by SQL Server 2005 have a 1024 bit modulus = 128 bytes, therefore the cipher texts are always 128 bytes and the maximum plaintext that can be encrypted is 117 bytes. The same formula applies for any certificate you may want to export into the system (the limit is 3456 bits for the private keys modulus).</P>
<P>&nbsp; For more information on this one, I recommend you to go to <A href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/cryptencrypt.asp">https://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/cryptencrypt.asp</A> and look at the remarks section for CryptEncrypt.</P>
<P><STRONG>&nbsp; Should I always use this formula to calculate the size of my encrypted columns?<BR></STRONG>&nbsp;&nbsp; I strongly recommend against considering the result of the formula as a hardcoded length for your encrypted columns. I would suggest to estimate what would be the expected maximum ciphertext length (either by creating a sample using EncryptByKey directly on your system or by using the formula) and add a little bit of extra space. My personal suggestion would be to reserve at least 1 extra block (8 bytes for DES family, 16 bytes for AES), but it would really depend on the specific scenario.</P>
<P>&nbsp; The formula I shared here is a way to predict the length of the plaintext, but there is no guarantee that this formula will work for future algorithms or even for the existing algorithms in future versions of the product. As you have noticed, SQL Server encryption includes a few fields that are not part of the ciphertext itself, and in future versions of the product there may be a need to include new fields.</P>
<P>&nbsp;&nbsp; <BR><STRONG>&nbsp; But I really need to encrypt BLOBs larger than 8000 bytes! Is there anything I can do?<BR></STRONG>Using the native solution, there is nothing you can do. Your application will need to slice the input before encrypting it.<BR>&nbsp; I have created a small sample code that creates a UDF (user defined function) that is essentially a wrapper around EncryptByKey. It basically partitions the data in different pieces, encrypts them, and then pastes them together in a single BLOB that can be decrypted by its counterpart wrapper UDF for DecryptByKey. I created two different set of UDFs, one for symmetric keys and one for certificates.</P>
<P>&nbsp; The main idea behind this demo is to split the BLOB we want to encrypt in smaller segments that we can encrypt and then concatenate their ciphertexts in such a way that we can recover the individual segments, decrypt them, and paste them again in a single LOB (the original plaintext). </P>
<P><STRONG>Demo<BR></STRONG></P>
<P><FONT face="Courier New" color=#008000 size=2>/***********************************************************************<BR>*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This posting is provided "AS IS" with no warranties, <BR>* and confers no rights.<BR>*<BR>* Authors:&nbsp;&nbsp;Raul Garcia, <BR>* &nbsp;&nbsp;&nbsp;Tanmoy Dutta, <BR>*&nbsp;&nbsp;&nbsp;Pankaj Kamat, <BR>*&nbsp;&nbsp;&nbsp;Laurentiu Cristofor<BR>* Date:&nbsp;&nbsp;&nbsp;11/07/2005<BR>* Description:&nbsp;<BR>* <BR>*&nbsp;&nbsp; Create a scalar functions that allow encryption and decryption <BR>* of large objects (&gt; 8000 bytes).<BR>*<BR>*&nbsp;&nbsp;&nbsp;&nbsp; (c) 2005 Microsoft Corporation. All rights reserved. <BR>*<BR>**********************************************************************/</FONT></P>
<P><FONT face="Courier New" size=2>CREATE DATABASE demo_LobEncryption<BR>go</FONT></P>
<P><FONT face="Courier New" size=2>USE demo_LobEncryption<BR>go</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>--------------------------------------------------------------------<BR>-- Create a new Encryption function – EncryptLob. <BR>--<BR>-- This is a wrapper around the EncryptByKey builtin<BR>-- In order to keep this demo simple, it doesn't support <BR>-- all the options of that builtin<BR>--<BR>-- PARAMETERS<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @key_guid:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Symmetric key GUID, <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; equivalent to EncryptByKey’s first argument.<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This key needs to be already opened <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; before calling the function<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @lob:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The plaintext to encrypt. <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Limits for the datalength are defined<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; by the varbinary(max) data type<BR>-- RETURN VALUE<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; varbinary(max):&nbsp;&nbsp; If the encryption succeeded, <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it will return the encrypted data<BR>--&nbsp;&nbsp;&nbsp;&nbsp; as described in NOTES<BR>--&nbsp;&nbsp;&nbsp;&nbsp; NULL is returned if there is any error<BR>-- NOTES:<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The plaintext will be split in blocks that can be <BR>--&nbsp; encrypted individually and then will be concatenated together: <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ([2 bytes - ciphertext block length][ciphertext block]) <BR>--&nbsp; per plaintext block<BR></FONT>CREATE FUNCTION dbo.EncryptLob( <BR>@key_guid uniqueidentifier, <BR>@lob varbinary(max) )<BR>returns varbinary(max)<BR>as<BR>BEGIN<BR>&nbsp;declare @PtLimit&nbsp;int<BR>&nbsp;declare @Total&nbsp;&nbsp;int<BR>&nbsp;declare @CurPos&nbsp;&nbsp;int<BR>&nbsp;declare @Aux&nbsp;&nbsp;varbinary(8000)<BR>&nbsp;declare @AuxLen&nbsp;&nbsp;int<BR>&nbsp;declare @PlaintextColumnLimit int<BR>&nbsp;declare @Cipher&nbsp;&nbsp;varbinary(max<FONT color=#008000>)</FONT></FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;-- Limit for the PT block</FONT><BR>&nbsp;SET @PtLimit = 7800<BR>&nbsp;SET @CurPos = 1<BR>&nbsp;SET @Total = datalength( @lob )<BR>&nbsp;SET @Cipher = null</FONT></P>
<P><FONT face="Courier New" color=#008000 size=2>&nbsp;---- Simple validation of the input parameters</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;if( <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @lob is not null<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND encryptbykey( @key_guid, 0x00 ) is not null&nbsp; <BR><FONT color=#008000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- Can we encrypt with the key specified by the GUID<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<BR>&nbsp;BEGIN<BR>&nbsp;&nbsp;WHILE @CurPos &lt;= @Total<BR>&nbsp;&nbsp;BEGIN<BR><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Get a new PT block</FONT><BR>&nbsp;&nbsp;&nbsp;SELECT @Aux = substring( @Lob, @CurPos, @PtLimit )<BR>&nbsp;&nbsp;&nbsp;SET @CurPos = @CurPos + @PtLimit</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Encrypt the PT block</FONT><BR>&nbsp;&nbsp;&nbsp;SET @Aux = encryptbykey(@key_guid, @Aux)<BR><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- If any block failed to decrypt, <BR>&nbsp;&nbsp; -- we should just return NULL (failed)<BR></FONT>&nbsp;&nbsp;&nbsp;if( @Aux is null )<BR>&nbsp;&nbsp;&nbsp;&nbsp;return null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Get the ciphertext length<BR>&nbsp;&nbsp;&nbsp;-- 2 bytes should be enough<BR></FONT>&nbsp;&nbsp;&nbsp;SET @AuxLen = datalength( @Aux )<BR>&nbsp;&nbsp;&nbsp;SET @Aux = convert( binary(2), @AuxLen ) + @Aux</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Only set the @Cipher for the first block, <BR>&nbsp;&nbsp; -- otherwise concatenate the existing data <BR>&nbsp;&nbsp; -- with the new cipher block<BR></FONT>&nbsp;&nbsp;&nbsp;if( @Cipher is null )<BR>&nbsp;&nbsp;&nbsp;&nbsp;SET @Cipher = @Aux<BR>&nbsp;&nbsp;&nbsp;ELSE<BR>&nbsp;&nbsp;&nbsp;&nbsp;SET @Cipher = @Cipher + @Aux<BR>&nbsp;&nbsp;END<BR>&nbsp;END</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;return @Cipher<BR>END<BR>go<BR><FONT color=#008000>-------------------------------------------------------------------<BR>-- Create a new Decryption function - DecryptLob. <BR>--<BR>-- This is a wrapper around the decryptByKey builtin.<BR>-- It is the counterpart of the EncryptLob function.<BR>--<BR>-- PARAMETERS<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Cipher:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A ciphertext that was generated by<BR>--&nbsp;&nbsp;&nbsp;&nbsp; EncryptLob. <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The decryption key needs to be already<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; opened before calling the function<BR>-- RETURN VALUE<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; varbinary(max):&nbsp;&nbsp; If the decryption succeeded, it will <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return the plaintext as varbinary(max)<BR>--&nbsp;&nbsp;&nbsp;&nbsp; NULL is returned if there is any error<BR>--<BR>-- NOTES:<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The ciphertext will be split in blocks that can be<BR>--&nbsp; decrypted individually and then concatenated together: <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ([2 bytes - ciphertext block length][ciphertext block]) <BR>--&nbsp; per plaintext block<BR></FONT>CREATE FUNCTION dbo.DecryptLob( @Cipher varbinary(max) )<BR>returns varbinary(max)<BR>as<BR>BEGIN<BR>&nbsp;declare @PtLimit&nbsp;int<BR>&nbsp;declare @Total&nbsp;&nbsp;int<BR>&nbsp;declare @CurPos&nbsp;&nbsp;int<BR>&nbsp;declare @Aux&nbsp;&nbsp;varbinary(8000)<BR>&nbsp;declare @AuxLen&nbsp;&nbsp;int<BR>&nbsp;declare @LobPt&nbsp;&nbsp;varbinary(max)</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;SET @CurPos = 1<BR>&nbsp;SET @Total = datalength( @Cipher )<BR>&nbsp;SET @LobPt = null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;-- No op for null or empty data</FONT><BR>&nbsp;if( @Cipher is not null&nbsp;&nbsp; <BR>&nbsp;&nbsp; AND @Total &gt; 0 <BR>&nbsp;&nbsp;&nbsp; )<BR>&nbsp;BEGIN<BR>&nbsp;&nbsp;WHILE @CurPos &lt;= @Total<BR>&nbsp;&nbsp;BEGIN<BR><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Read the next cipher block length<BR></FONT>&nbsp;&nbsp;&nbsp;SELECT @AuxLen = substring( @Cipher, @CurPos, 2 )<BR>&nbsp;&nbsp;&nbsp;SET @CurPos = @CurPos + 2</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Length field validation. <BR>&nbsp;&nbsp; -- Any unexpected length will result in error<BR></FONT>&nbsp;&nbsp;&nbsp;if( @AuxLen &lt;= 0 OR @AuxLen &gt; 8000 )<BR>&nbsp;&nbsp;&nbsp;&nbsp;return null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Get the next cipher block<BR></FONT>&nbsp;&nbsp;&nbsp;SELECT @Aux = substring( @Cipher, @CurPos, @AuxLen )<BR>&nbsp;&nbsp;&nbsp;SET @CurPos = @CurPos + @AuxLen</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- If there is any discrepancy,&nbsp;<BR>&nbsp;&nbsp;&nbsp;-- it is either a data truncation error <BR>&nbsp;&nbsp; -- (cipher was truncated)<BR>&nbsp;&nbsp;&nbsp;-- or a data corruption error.<BR>&nbsp;&nbsp;&nbsp;-- We will fail the whole operation.<BR></FONT>&nbsp;&nbsp;&nbsp;if( datalength( @Aux ) &lt;&gt; @AuxLen )<BR>&nbsp;&nbsp;&nbsp;&nbsp;return null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Decrypt the current cipher block<BR></FONT>&nbsp;&nbsp;&nbsp;SET @Aux = decryptbykey( @Aux )</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- ... and make sure we could decrypt it.<BR>&nbsp;&nbsp;&nbsp;-- Again, any error here will terminate&nbsp;<BR>&nbsp;&nbsp;&nbsp;-- the operation and return null<BR></FONT>&nbsp;&nbsp;&nbsp;if( @Aux is null )<BR>&nbsp;&nbsp;&nbsp;&nbsp;return null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Either set (if first block) or concatenate<BR>&nbsp;&nbsp; -- to the available PT we already decrypted<BR></FONT>&nbsp;&nbsp;&nbsp;if( @LobPt is null )<BR>&nbsp;&nbsp;&nbsp;&nbsp;SET @LobPt = @Aux<BR>&nbsp;&nbsp;&nbsp;ELSE<BR>&nbsp;&nbsp;&nbsp;&nbsp;SET @LobPt = @LobPt + @Aux<BR>&nbsp;&nbsp;END<BR>&nbsp;END</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;return @LobPt<BR>END<BR>go</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>---------------------- Test</FONT><BR>CREATE SYMMETRIC KEY key1 WITH ALGORITHM = AES_192 ENCRYPTION BY PASSWORD = '|\/|y </FONT><FONT face="Courier New" size=2>p@22\/\/0rD'</FONT><BR><FONT face="Courier New" size=2>go</FONT></P>
<P><FONT face="Courier New" size=2>OPEN SYMMETRIC KEY key1 DECRYPTION BY PASSWORD = '|\/|y </FONT><FONT face="Courier New" size=2>p@22\/\/0rD'</FONT><BR><FONT face="Courier New" size=2>go</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>--------------- Quick Demo</FONT><BR>declare @x varbinary(max)<BR>declare @y varbinary(max)<BR>declare @z varchar(max)<BR>declare @i int<BR>set @i = 0<BR>SET @x = convert( varbinary(max), '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')<BR>while @i &lt; 15 -- PT will be a little bit less than 2MB<BR>BEGIN<BR>&nbsp;SET @i = @i + 1<BR>&nbsp;SET @x = @x + @x<BR>END<BR>SELECT @y = dbo.EncryptLob( key_guid('key1'), @x )<BR>SELECT datalength( @y ) as 'Ciphertext length'<BR>if( @y is not null )<BR>BEGIN<BR>&nbsp;SELECT @z = convert( varchar(max), dbo.DecryptLob( @y ))<BR>&nbsp;<BR>&nbsp;if( @z is not null )<BR>&nbsp;BEGIN<BR>&nbsp;&nbsp;SELECT datalength( @x) as 'original PT len', datalength(@z) as 'decrypted PT len', substring( @z, datalength(@z) - 16, 100) as 'Last 16 chars'<BR>&nbsp;&nbsp;if( @z = @x )<BR>&nbsp;&nbsp;&nbsp;print 'decrypted PT == original PT'<BR>&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;print 'Unexpected error. PTs didn''t match'<BR>&nbsp;END<BR>&nbsp;ELSE<BR>&nbsp;&nbsp;print 'Failed to decrypt. Make sure the key is opened'<BR>END<BR>ELSE<BR>&nbsp;print 'Failed to encrypt. Make sure the key is opened'<BR>go</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>--------------------------------------------------------------------<BR>--------------------------------------------------------------------<BR>--------------------------------------------------------------------<BR>-- Create a new Encryption function - EncryptLobByCert. <BR>--<BR>-- This is a wrapper around EncryptByCert builtin<BR>-- In order to keep this demo simple, it doesn't support<BR>-- all the options EncryptByCert supports.<BR>--<BR>-- PARAMETERS<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @cert_id:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Cert ID, equivalent to EncryptByCert <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; first argument.<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @lob:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The plaintext to encrypt. <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Limits for the datalength are defined<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; by the varbinary(max) data type<BR>-- RETURN VALUE<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; varbinary(max):&nbsp;&nbsp; If the encryption succeeded, <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it will return a byte stream that<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with the encrypted data. The byte stream <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; format is described in NOTES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>--&nbsp;&nbsp;&nbsp;&nbsp;NULL if there is any error<BR>-- NOTES:<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The plaintext will be split in blocks that can be <BR>--&nbsp; encrypted individually and then concatenated together: <BR>--&nbsp; ([2 bytes - ciphertext block length][ciphertext block]) <BR>--&nbsp; per plaintext block<BR>--&nbsp; Remember that asymmetric key encryption/decryption is orders <BR>--&nbsp; of magnitude more expensive than symmetric key<BR>--&nbsp; encryption/decryption. <BR>--&nbsp;&nbsp; We recommend avoiding the use of asymmetric key encryption for <BR>-- large amounts of data, but these functions may be used to <BR>-- protect data &lt; 1000 bytes that are larger than what <BR>-- the SQL builtins are currently supporting<BR>-- (for example, data larger than 117 bytes)<BR></FONT>CREATE FUNCTION dbo.EncryptLobByCert( @cert_id int, @lob varbinary(max) )<BR>returns varbinary(max)<BR>as<BR>BEGIN<BR>&nbsp;declare @PtLimit&nbsp;int<BR>&nbsp;declare @Total&nbsp;&nbsp;int<BR>&nbsp;declare @CurPos&nbsp;&nbsp;int<BR>&nbsp;declare @Aux&nbsp;&nbsp;varbinary(8000)<BR>&nbsp;declare @AuxLen&nbsp;&nbsp;int<BR>&nbsp;declare @PlaintextColumnLimit int<BR>&nbsp;declare @Cipher&nbsp;&nbsp;varbinary(max)</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;SET @Aux = encryptbycert( @cert_id, 0x00 )<BR>&nbsp;if( @Aux is null ) <FONT color=#008000>-- Return null if we cannot encrypt by the specified cert<BR></FONT>&nbsp;&nbsp;return null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;-- Calculate the limit for the PT block</FONT><BR>&nbsp;SET @PtLimit = datalength( @Aux ) - 11</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;SET @CurPos = 1<BR>&nbsp;SET @Total = datalength( @lob )<BR>&nbsp;SET @Cipher = null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;---- Simple validation of the input parameters</FONT><BR>&nbsp;WHILE @CurPos &lt;= @Total<BR>&nbsp;BEGIN<BR><FONT color=#008000>&nbsp;&nbsp;-- Get a new PT block</FONT><BR>&nbsp;&nbsp;SELECT @Aux = substring( @Lob, @CurPos, @PtLimit )<BR>&nbsp;&nbsp;SET @CurPos = @CurPos + @PtLimit</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;-- Encrypt the PT block</FONT><BR>&nbsp;&nbsp;SET @Aux = encryptbycert( @cert_id, @Aux)<BR><FONT color=#008000>&nbsp;&nbsp;-- If any block failed to decrypt, <BR>&nbsp; -- we should just return NULL (failed)<BR></FONT>&nbsp;&nbsp;if( @Aux is null )<BR>&nbsp;&nbsp;&nbsp;return null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;-- Get the ciphertext length<BR>&nbsp;&nbsp;-- 2 bytes should be enough<BR></FONT>&nbsp;&nbsp;SET @AuxLen = datalength( @Aux )<BR>&nbsp;&nbsp;SET @Aux = convert( binary(2), @AuxLen ) + @Aux</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;-- Only set the @Cipher for the first block, <BR>&nbsp; -- otherwise concatenate the existing data with <BR>&nbsp; -- the new cipher block<BR></FONT>&nbsp;&nbsp;if( @Cipher is null )<BR>&nbsp;&nbsp;&nbsp;SET @Cipher = @Aux<BR>&nbsp;&nbsp;ELSE<BR>&nbsp;&nbsp;&nbsp;SET @Cipher = @Cipher + @Aux<BR>&nbsp;END</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;return @Cipher<BR>END<BR>go</FONT></P>
<P><BR><FONT face="Courier New" size=2><FONT color=#008000>---------------------------------------------------------------------<BR>-- Create a new Decryption function - DecryptLobByCert. <BR>--<BR>-- This is a wrapper around DecryptByCert builtin.<BR>-- It is the counterpart of EncryptLobByCert function.<BR>--<BR>-- PARAMETERS<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @cert_id:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Cert ID, equivalent to EncryptByCert <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; first argument.<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Cipher:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A ciphertext that was generated by <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EncryptLobByCert. <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Password for the private key. <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If encrypted by DBMK, you should use null<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for this parameter.<BR>--<BR>-- RETURN VALUE<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; varbinary(max):&nbsp;&nbsp; If the decryption succeeded, it will <BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return the plaintext as varbinary(max)<BR>--<BR>-- NOTES<BR>--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The plaintext will be split in blocks that can be <BR>-- encrypted individually and then concatenated together: <BR>-- ([2 bytes - ciphertext block length][ciphertext block]) <BR>-- per plaintext block<BR></FONT>CREATE FUNCTION dbo.DecryptLobByCert( <BR>@cert_id int, <BR>@Cipher varbinary(max), <BR>@Password nvarchar(4000) )<BR>returns varbinary(max)<BR>as<BR>BEGIN<BR>&nbsp;declare @PtLimit&nbsp;&nbsp;int<BR>&nbsp;declare @Total&nbsp;&nbsp;int<BR>&nbsp;declare @CurPos&nbsp;&nbsp;int<BR>&nbsp;declare @Aux&nbsp;&nbsp;varbinary(8000)<BR>&nbsp;declare @AuxLen&nbsp;&nbsp;int<BR>&nbsp;declare @LobPt&nbsp;&nbsp;varbinary(max)</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;SET @CurPos = 1<BR>&nbsp;SET @Total = datalength( @Cipher )<BR>&nbsp;SET @LobPt = null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;-- No op for null or empty data</FONT><BR>&nbsp;if( @Cipher is not null&nbsp;&nbsp; <BR>&nbsp;&nbsp; AND @Total &gt; 0 <BR>&nbsp;&nbsp;&nbsp; )<BR>&nbsp;BEGIN<BR>&nbsp;&nbsp;WHILE @CurPos &lt;= @Total<BR>&nbsp;&nbsp;BEGIN<BR><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Read the next cipher block length<BR></FONT>&nbsp;&nbsp;&nbsp;SELECT @AuxLen = substring( @Cipher, @CurPos, 2 )<BR>&nbsp;&nbsp;&nbsp;SET @CurPos = @CurPos + 2</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Length field validation. Any unexpected <BR>&nbsp;&nbsp; -- length will result in error<BR></FONT>&nbsp;&nbsp;&nbsp;if( @AuxLen &lt;= 0 OR @AuxLen &gt; 8000 )<BR>&nbsp;&nbsp;&nbsp;&nbsp;return null</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;<FONT color=#008000>-- Get the next cipher block<BR></FONT>&nbsp;&nbsp;&nbsp;SELECT @Aux = substring( @Cipher, @CurPos, @AuxLen )<BR>&nbsp;&nbsp;&nbsp;SET @CurPos = @CurPos + @AuxLen</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- If there is any discrepancy, <BR>&nbsp;&nbsp; -- it is either a data truncation error <BR>&nbsp;&nbsp; -- (cipher was truncated)<BR>&nbsp;&nbsp;&nbsp;-- or a data corruption error.<BR>&nbsp;&nbsp;&nbsp;-- We will fail the whole operation.<BR></FONT>&nbsp;&nbsp;&nbsp;if( datalength( @Aux ) &lt;&gt; @AuxLen )<BR>&nbsp;&nbsp;&nbsp;&nbsp;return null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Decrypt the current cipher block<BR></FONT>&nbsp;&nbsp;&nbsp;SET @Aux = decryptbycert( @cert_id, @Aux, @Password )</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- ... and make sure we could decrypt it.<BR>&nbsp;&nbsp;&nbsp;-- Again, any error here will terminate <BR>&nbsp;&nbsp; -- the operation and return null<BR></FONT>&nbsp;&nbsp;&nbsp;if( @Aux is null )<BR>&nbsp;&nbsp;&nbsp;&nbsp;return null</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>&nbsp;&nbsp;&nbsp;-- Either set (if first block) or concatenate <BR>&nbsp;&nbsp; -- to the available PT we already decrypted<BR></FONT>&nbsp;&nbsp;&nbsp;if( @LobPt is null )<BR>&nbsp;&nbsp;&nbsp;&nbsp;SET @LobPt = @Aux<BR>&nbsp;&nbsp;&nbsp;ELSE<BR>&nbsp;&nbsp;&nbsp;&nbsp;SET @LobPt = @LobPt + @Aux<BR>&nbsp;&nbsp;END<BR>&nbsp;END</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;return @LobPt<BR>END<BR>go</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>------------ Test</FONT><BR>CREATE CERTIFICATE certTest ENCRYPTION BY PASSWORD = 'c3R+ </FONT><FONT face="Courier New" size=2>p@zz\/\/0Rd!'</FONT><FONT face="Courier New" size=2> WITH SUBJECT = 'Demo - LOB encryption'<BR>go</FONT></P>
<P><FONT face="Courier New" size=2>declare @x varbinary(max)<BR>declare @y varbinary(max)<BR>declare @z varchar(max)<BR>declare @i int<BR>set @i = 0<BR>SET @x = convert( varbinary(max), '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')<BR>while @i &lt; 4 -- PT will be a little bit more than 1k<BR>BEGIN<BR>&nbsp;SET @i = @i + 1<BR>&nbsp;SET @x = @x + @x<BR>END<BR>SELECT @y = dbo.EncryptLobByCert( cert_id('CertTest'), @x )<BR>SELECT datalength( @y ) as 'Ciphertext length'<BR><FONT color=#008000>--select @y as CipherTextLob</FONT><BR>if( @y is not null )<BR>BEGIN<BR>&nbsp;SELECT @z = convert( varchar(max), dbo.DecryptLobByCert( cert_id('CertTest'), @y, N'c3R+ </FONT><FONT face="Courier New" size=2>p@zz\/\/0Rd!'</FONT><FONT face="Courier New" size=2> ))<BR>&nbsp;<BR>&nbsp;if( @z is not null )<BR>&nbsp;BEGIN<BR>&nbsp;&nbsp;SELECT datalength( @x) as 'original PT len', datalength(@z) as 'decrypted PT len', substring( @z, datalength(@z) - 16, 100) as 'Last 16 chars'<BR>&nbsp;&nbsp;if( @z = @x )<BR>&nbsp;&nbsp;&nbsp;print 'decrypted PT == original PT'<BR>&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;print 'Unexpected error. PTs didn''t match'<BR>&nbsp;END<BR>&nbsp;ELSE<BR>&nbsp;&nbsp;print 'Failed to decrypt. Make sure the key is opened'<BR>END<BR>ELSE<BR>&nbsp;print 'Failed to encrypt. Make sure the key is opened'<BR>go</FONT></P>
<P><FONT face="Courier New" size=2><FONT color=#008000>------ Test2</FONT><BR>CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'D8|\/||&lt; p455\/\/oRx!'<BR>go</FONT></P>
<P><FONT face="Courier New" size=2>CREATE CERTIFICATE certTest2 WITH SUBJECT = 'Demo - LOB encryption DBMK protected'<BR>go</FONT></P>
<P><BR><FONT face="Courier New" size=2>declare @x varbinary(max)<BR>declare @y varbinary(max)<BR>declare @z varchar(max)<BR>declare @i int<BR>set @i = 0<BR>SET @x = convert( varbinary(max), '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')<BR>while @i &lt; 4 -- PT will be a little more than 1k<BR>BEGIN<BR>&nbsp;SET @i = @i + 1<BR>&nbsp;SET @x = @x + @x<BR>END<BR>SELECT @y = dbo.EncryptLobByCert( cert_id('CertTest2'), @x )<BR>SELECT datalength( @y ) as 'Ciphertext length'<BR><FONT color=#008000>--select @y as CipherTextLob</FONT><BR>if( @y is not null )<BR>BEGIN<BR><FONT color=#008000>&nbsp;-- Use null for the password parameter </FONT><BR>&nbsp;SELECT @z = convert( varchar(max), dbo.DecryptLobByCert( cert_id('CertTest2'), @y, null ))<BR>&nbsp;<BR>&nbsp;if( @z is not null )<BR>&nbsp;BEGIN<BR>&nbsp;&nbsp;SELECT datalength( @x) as 'original PT len', datalength(@z) as 'decrypted PT len', substring( @z, datalength(@z) - 16, 100) as 'Last 16 chars'<BR>&nbsp;&nbsp;if( @z = @x )<BR>&nbsp;&nbsp;&nbsp;print 'decrypted PT == original PT'<BR>&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;print 'Unexpected error. PTs didn''t match'<BR>&nbsp;END<BR>&nbsp;ELSE<BR>&nbsp;&nbsp;print 'Failed to decrypt. Make sure the key is opened'<BR>END<BR>ELSE<BR>&nbsp;print 'Failed to encrypt. Make sure the key is opened'<BR>go<BR><FONT color=#008000>----------------------- CLEANUP</FONT><BR>use master<BR>go</FONT></P>
<P><FONT face="Courier New" size=2>DROP DATABASE demo_LobEncryption<BR>go<BR><FONT color=#008000>----------------------- END OF DEMO -----------------------</FONT><BR></FONT></P>]]></content:encoded>
    </item>
    <item>
      <title>The beginning - Securing Data</title>
      <link>https://docs.microsoft.com/archive/blogs/yukondoit/the-beginning-securing-data</link>
      <pubDate>Thu, 13 Oct 2005 22:17:00 GMT</pubDate>
      <dc:creator><![CDATA[yukondoit]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/yukondoit/2005/10/13/the-beginning-securing-data/</guid>
      <description><![CDATA[I have always wanted to have a blog, and I have always had a lot to blog about, but looking at other...]]></description>
      <content:encoded><![CDATA[<P><FONT face=Verdana size=2>I have always wanted to have a blog, and I have always had a lot to blog about, but looking at other blogs I always felt I wasnt articulate enough to get my thoughts across. Although true, it just is a good excuse for my laziness.</FONT></P>
<P><FONT face=Verdana size=2>Well, not much has changed - I am still lazy as ever, inarticulate as ever - but&nbsp;I have been able to post my first article <a href="https://blogs.msdn.com/yukondoit/articles/480854.aspx" target=_blank><SPAN lang=en-us><U><FONT face=Arial color=#0000ff size=2>https://blogs.msdn.com/yukondoit/articles/480854.aspx</FONT></U></SPAN></A></FONT><FONT face=Verdana size=2>.&nbsp;It is about&nbsp;security considerations while securing data using SQL Server 2005. </FONT></P>]]></content:encoded>
    </item>
    <item>
      <title>How Secure Is Your Data?</title>
      <link>https://docs.microsoft.com/archive/blogs/yukondoit/how-secure-is-your-data</link>
      <pubDate>Thu, 13 Oct 2005 19:17:00 GMT</pubDate>
      <dc:creator><![CDATA[yukondoit]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/yukondoit/2005/10/13/how-secure-is-your-data/</guid>
      <description><![CDATA[End users want their data to be secure and for that SQL Server 2005 has various protection levels to...]]></description>
      <content:encoded><![CDATA[<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">End users want their data to be secure and for that SQL Server 2005 has various protection levels to encrypt the data. The simplest way to encrypt data may not be the best option, as you may not have the desired level of protection. </SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">Books Online is a good resource to know the syntax for encrypting data in various ways. To make my points clear, I will at times give references to certain DDL that you need to use. But my primary goal with this blog&nbsp;is to just emphasize what security guarantee you get depending on what protection mechanism you choose. </SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">It is well known that data in SQL Server 2005 should always be protected by a symmetric key. But you need to carefully choose how to protect this symmetric key. The symmetric key can be protected by a password, a certificate, an asymmetric key or any other user created symmetric key, depending on what level of protection is desired.</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">&nbsp;To make the right decision, end users need to answer the question - <EM>'Whom am I trying to protect my data from?'</EM>&nbsp;<BR><FONT color=#a52a2a>&nbsp;&nbsp;&nbsp;&nbsp;Level 2: From attackers who can get access to the database files (protecting data at rest)<BR>&nbsp;&nbsp;&nbsp;&nbsp;Level 1: Level 2 + From the sysadmin<BR>&nbsp;&nbsp;&nbsp;&nbsp;Level 0: Level 1 + From the dbo</FONT></SPAN></P>
<P dir=ltr style="MARGIN-RIGHT: 0px"><STRONG><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"><FONT color=#a52a2a>The Ultimate Protection. Only I can see my secrets.</FONT></SPAN></STRONG></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">For end users that want the Level 0 protection, the symmetric key should only be protected by a password. This is the most secure option as the sysadmin or the dbo cannot access the symmetric key in any way and the data is truly protected. Data at rest is also protected, as even if an attacker manages to steal the files, he can only decrypt the data if he knows the password. What some may perceive as a disadvantage is that each time you need to encrypt or decrypt the data; you need to ensure that the key is open. But this is only a small price you need to pay to ensure your data is fully protected. </SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">The system view <I style="mso-bidi-font-style: normal">sys.open_keys</I> will show all the open keys in a session at any given time. If the key is not open, then the following DDL statement needs to be issued to open it<BR></SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'">&nbsp; OPEN SYMMETRIC KEY &lt;key_name&gt; DECRYPTION BY PASSWORD = '&lt;password&gt;'</SPAN></P></BLOCKQUOTE>
<P dir=ltr><STRONG><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"><FONT color=#a52a2a>DBO is my friend. Let him know my secrets.</FONT></SPAN></STRONG></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P dir=ltr><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">For end users that want the Level 1 protection, the requirements can be eased slightly. The symmetric key should be protected by a certificate [or an asymmetric key]. The private key of the certificate&nbsp;[or the asymmetric key]&nbsp;need&nbsp;to be&nbsp;protected by the database master key i.e.&nbsp;at the time of creating the certificate do not specify the ENCRYPTION BY PASSWORD&nbsp;option.<BR></SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'">&nbsp; CREATE CERTIFICATE c1 with subject = 'EncrCert'</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">If you have&nbsp;an existing&nbsp;certificate [or the asymmetric key] protected by a password and you would like to use that, you can change the protection to the database master key using the following DDL statement.<BR></SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'">&nbsp; ALTER CERTIFICATE c1 WITH PRIVATE KEY DECRYPTION BY PASSWORD = '&lt;password&gt;'</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">It may not be intuitive but not specifying the ENCRYPTION BY PASSWORD option&nbsp;with the ALTER CERTIFICATE statement, decrypts the private key of the certificate using the password supplied with the&nbsp;DECRYPTION BY PASSWORD option, and re-encrypts it using the database master key.<BR><BR>Now comes the important part, protecting it from sysadmin. The dbo or highly privileged database user needs to make sure that the database master key should only be protected by the password. At creation time, the database master key is encrypted by the service master key by default. The Service Master Key encryption should be dropped explicitly using the following DDL statement.<BR></SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'">&nbsp; ALTER MASTER KEY DROP ENCRYPTION BY SERVICE MASTER KEY</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">By doing so, the database owner does have access to your data as he can use the database master key to decrypt the private key of the certificate, which can then be used to open the symmetric key and decrypt the protected data. However, you are still protected from the sysadmin as he needs to be able to open the database master key in his session, and without the password there is no way to do it once you drop the encryption by the service master key.</SPAN></P></BLOCKQUOTE>
<P><STRONG><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"><FONT color=#a52a2a>I only care about my data that is stolen.</FONT></SPAN></STRONG></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">For end users that want Level 2 protection, things are a piece of cake. He needs to encrypt the data with a symmetric key that is protected by a certificate [or an asymmetric key] as in Level 1 protection. The certificate [or an asymmetric key] is protected by the database master key as demonstrated earlier. </SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">The important difference is&nbsp;that the&nbsp;database owner should not drop the encryption of the database master key by the service master key (that he gets by default at creation time) or needs to re-add the encryption of the service master key using the following DDL statement<BR></SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'">&nbsp; ALTER MASTER KEY ADD ENCRYPTION BY SERVICE MASTER KEY</SPAN></P>
<P dir=ltr><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">The sysadmin then has access to the database master key and to any entity (certificate or asymmetric key) encrypted by the database master key. Of course, this means your data is not protected from the sysadmin or the database owner, but the data at rest is protected. If someone is able to steal the database files, and is able to attach it to his own SQL Server Instance he still cannot decrypt the encrypted data, because he does not have the password to the symmetric key or access to the keys in the hierarchy, that protect the symmetric key.</SPAN></P></BLOCKQUOTE>
<P dir=ltr><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">For Level 1 and Level 2 protection, it is important to remember that you need to be aware if the database master key is protected by the service master key or not. You will also need to be aware that your protection level might get dropped from Level 1 to Level 2, if the owner of your database chooses to add the protection of the service master key back to the database master key.</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">In conclusion, there is this inherent conflict Security seems to always have with Usability. Leveraging on the key hierarchy in SQL Server 2005 eases administrative requirements slightly due to the fact that you DONT need to explicitly open the symmetric key that you use to protect data. You can build <EM><SPAN style="FONT-FAMILY: Verdana">transparent data encryption</SPAN></EM> around that feature, which I will cover in a later blog. But then you need to understand your data is not secure from the sysadmins and database owners.&nbsp; Encrypting symmetric keys with password can make your data super secure, but you need to manage the opening and closing of the key that protects the data. </SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"><EM>Make the choice that suits you best, but understand your security requirements and never compromise on security for usability!</EM></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p>&nbsp;</o:p></P>]]></content:encoded>
    </item>
  </channel>
</rss>