<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Security in SQL Server 2005 and beyond</title><link>http://blogs.msdn.com/yukondoit/default.aspx</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 setuser!) set of execution context features.

</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>SQL Server 2005 Encryption – Encryption and data length limitations</title><link>http://blogs.msdn.com/yukondoit/archive/2005/11/24/496521.aspx</link><pubDate>Thu, 24 Nov 2005 03:25:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:496521</guid><dc:creator>yukondoit</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/yukondoit/comments/496521.aspx</comments><wfw:commentRss>http://blogs.msdn.com/yukondoit/commentrss.aspx?PostID=496521</wfw:commentRss><description>&lt;P&gt;&lt;EM&gt;&amp;nbsp;&amp;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.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;What is the limit on the data length that can be encrypted?&lt;/STRONG&gt;&lt;BR&gt;&amp;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. &lt;/P&gt;
&lt;P&gt;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) &lt;/P&gt;
&lt;P&gt;@CipherLen = FLOOR( (8 +@PTLen + (@UsesAuth * @HASHLEN) ) / @BLOCK) + 1 )&amp;nbsp; *&amp;nbsp; @BLOCK + 16 + @BLOCK + 4&lt;/P&gt;
&lt;P&gt;&amp;nbsp; Where:&lt;BR&gt;@CipherLen:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;The ciphertext length in bytes&lt;BR&gt;@PTLen:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;The plaintext length in bytes&lt;BR&gt;@UsesAuth:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1 if using the optional authenticator parameter, 0 otherwise&lt;BR&gt;@HASHLEN:&amp;nbsp;&amp;nbsp;&amp;nbsp;20 bytes for SHA1 (The authenticator parameter adds a SHA1 hash to the plaintext)&lt;BR&gt;@BLOCK:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;The length in bytes per block. 8 for the DES family, 16 for AES&lt;/P&gt;
&lt;P&gt;Now let’s explain every part of the formula to make it easier to understand:&lt;BR&gt;FLOOR( (&lt;BR&gt;8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;EM&gt;Encrypted internal header&lt;BR&gt;&lt;/EM&gt;+@PTLen&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;EM&gt;Plaintext length&lt;/EM&gt;&lt;BR&gt;+ (@UsesAuth * @HASHLEN)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;EM&gt;If the authenticator parameter is used, the plaintext will include a hash derived from it.&lt;BR&gt;&lt;/EM&gt;&amp;nbsp;) / @BLOCK) + 1 )&amp;nbsp; *&amp;nbsp; @BLOCK&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;EM&gt;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&lt;BR&gt;&lt;/EM&gt;&amp;nbsp;&amp;nbsp; + 16 &amp;nbsp;&amp;nbsp;&amp;nbsp; Key GUID (not encrypted).&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;EM&gt;This information is used during decryption to identify the key that needs to be used&lt;/EM&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; + @BLOCK&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;EM&gt;Initialization vector (IV)&lt;/EM&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; + 4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;EM&gt;Internal header that describes the BLOB version number&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&amp;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.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;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. &lt;BR&gt;@Cipher_len&amp;nbsp; = key_modulus (regardless of the plaintext length)&lt;BR&gt;@Max_Plaintext_len = key_modulus – 11&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;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).&lt;/P&gt;
&lt;P&gt;&amp;nbsp; For more information on this one, I recommend you to go to &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/cryptencrypt.asp"&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/cryptencrypt.asp&lt;/A&gt; and look at the remarks section for CryptEncrypt.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp; Should I always use this formula to calculate the size of my encrypted columns?&lt;BR&gt;&lt;/STRONG&gt;&amp;nbsp;&amp;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.&lt;/P&gt;
&lt;P&gt;&amp;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.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&lt;STRONG&gt;&amp;nbsp; But I really need to encrypt BLOBs larger than 8000 bytes! Is there anything I can do?&lt;BR&gt;&lt;/STRONG&gt;Using the native solution, there is nothing you can do. Your application will need to slice the input before encrypting it.&lt;BR&gt;&amp;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.&lt;/P&gt;
&lt;P&gt;&amp;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). &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Demo&lt;BR&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;/***********************************************************************&lt;BR&gt;*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; This posting is provided "AS IS" with no warranties, &lt;BR&gt;* and confers no rights.&lt;BR&gt;*&lt;BR&gt;* Authors:&amp;nbsp;&amp;nbsp;Raul Garcia, &lt;BR&gt;* &amp;nbsp;&amp;nbsp;&amp;nbsp;Tanmoy Dutta, &lt;BR&gt;*&amp;nbsp;&amp;nbsp;&amp;nbsp;Pankaj Kamat, &lt;BR&gt;*&amp;nbsp;&amp;nbsp;&amp;nbsp;Laurentiu Cristofor&lt;BR&gt;* Date:&amp;nbsp;&amp;nbsp;&amp;nbsp;11/07/2005&lt;BR&gt;* Description:&amp;nbsp;&lt;BR&gt;* &lt;BR&gt;*&amp;nbsp;&amp;nbsp; Create a scalar functions that allow encryption and decryption &lt;BR&gt;* of large objects (&amp;gt; 8000 bytes).&lt;BR&gt;*&lt;BR&gt;*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (c) 2005 Microsoft Corporation. All rights reserved. &lt;BR&gt;*&lt;BR&gt;**********************************************************************/&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;CREATE DATABASE demo_LobEncryption&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;USE demo_LobEncryption&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;--------------------------------------------------------------------&lt;BR&gt;-- Create a new Encryption function – EncryptLob. &lt;BR&gt;--&lt;BR&gt;-- This is a wrapper around the EncryptByKey builtin&lt;BR&gt;-- In order to keep this demo simple, it doesn't support &lt;BR&gt;-- all the options of that builtin&lt;BR&gt;--&lt;BR&gt;-- PARAMETERS&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @key_guid:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Symmetric key GUID, &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; equivalent to EncryptByKey’s first argument.&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; This key needs to be already opened &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; before calling the function&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @lob:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; The plaintext to encrypt. &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Limits for the datalength are defined&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; by the varbinary(max) data type&lt;BR&gt;-- RETURN VALUE&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; varbinary(max):&amp;nbsp;&amp;nbsp; If the encryption succeeded, &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; it will return the encrypted data&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; as described in NOTES&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; NULL is returned if there is any error&lt;BR&gt;-- NOTES:&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; The plaintext will be split in blocks that can be &lt;BR&gt;--&amp;nbsp; encrypted individually and then will be concatenated together: &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ([2 bytes - ciphertext block length][ciphertext block]) &lt;BR&gt;--&amp;nbsp; per plaintext block&lt;BR&gt;&lt;/FONT&gt;CREATE FUNCTION dbo.EncryptLob( &lt;BR&gt;@key_guid uniqueidentifier, &lt;BR&gt;@lob varbinary(max) )&lt;BR&gt;returns varbinary(max)&lt;BR&gt;as&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;declare @PtLimit&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @Total&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @CurPos&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @Aux&amp;nbsp;&amp;nbsp;varbinary(8000)&lt;BR&gt;&amp;nbsp;declare @AuxLen&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @PlaintextColumnLimit int&lt;BR&gt;&amp;nbsp;declare @Cipher&amp;nbsp;&amp;nbsp;varbinary(max&lt;FONT color=#008000&gt;)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;-- Limit for the PT block&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;SET @PtLimit = 7800&lt;BR&gt;&amp;nbsp;SET @CurPos = 1&lt;BR&gt;&amp;nbsp;SET @Total = datalength( @lob )&lt;BR&gt;&amp;nbsp;SET @Cipher = null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#008000 size=2&gt;&amp;nbsp;---- Simple validation of the input parameters&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;if( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @lob is not null&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AND encryptbykey( @key_guid, 0x00 ) is not null&amp;nbsp; &lt;BR&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- Can we encrypt with the key specified by the GUID&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;BR&gt;&amp;nbsp;BEGIN&lt;BR&gt;&amp;nbsp;&amp;nbsp;WHILE @CurPos &amp;lt;= @Total&lt;BR&gt;&amp;nbsp;&amp;nbsp;BEGIN&lt;BR&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Get a new PT block&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT @Aux = substring( @Lob, @CurPos, @PtLimit )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @CurPos = @CurPos + @PtLimit&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Encrypt the PT block&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @Aux = encryptbykey(@key_guid, @Aux)&lt;BR&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- If any block failed to decrypt, &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- we should just return NULL (failed)&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( @Aux is null )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Get the ciphertext length&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- 2 bytes should be enough&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @AuxLen = datalength( @Aux )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @Aux = convert( binary(2), @AuxLen ) + @Aux&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Only set the @Cipher for the first block, &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- otherwise concatenate the existing data &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- with the new cipher block&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( @Cipher is null )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @Cipher = @Aux&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;ELSE&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @Cipher = @Cipher + @Aux&lt;BR&gt;&amp;nbsp;&amp;nbsp;END&lt;BR&gt;&amp;nbsp;END&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;return @Cipher&lt;BR&gt;END&lt;BR&gt;go&lt;BR&gt;&lt;FONT color=#008000&gt;-------------------------------------------------------------------&lt;BR&gt;-- Create a new Decryption function - DecryptLob. &lt;BR&gt;--&lt;BR&gt;-- This is a wrapper around the decryptByKey builtin.&lt;BR&gt;-- It is the counterpart of the EncryptLob function.&lt;BR&gt;--&lt;BR&gt;-- PARAMETERS&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Cipher:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; A ciphertext that was generated by&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EncryptLob. &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; The decryption key needs to be already&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; opened before calling the function&lt;BR&gt;-- RETURN VALUE&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; varbinary(max):&amp;nbsp;&amp;nbsp; If the decryption succeeded, it will &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return the plaintext as varbinary(max)&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; NULL is returned if there is any error&lt;BR&gt;--&lt;BR&gt;-- NOTES:&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; The ciphertext will be split in blocks that can be&lt;BR&gt;--&amp;nbsp; decrypted individually and then concatenated together: &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ([2 bytes - ciphertext block length][ciphertext block]) &lt;BR&gt;--&amp;nbsp; per plaintext block&lt;BR&gt;&lt;/FONT&gt;CREATE FUNCTION dbo.DecryptLob( @Cipher varbinary(max) )&lt;BR&gt;returns varbinary(max)&lt;BR&gt;as&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;declare @PtLimit&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @Total&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @CurPos&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @Aux&amp;nbsp;&amp;nbsp;varbinary(8000)&lt;BR&gt;&amp;nbsp;declare @AuxLen&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @LobPt&amp;nbsp;&amp;nbsp;varbinary(max)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;SET @CurPos = 1&lt;BR&gt;&amp;nbsp;SET @Total = datalength( @Cipher )&lt;BR&gt;&amp;nbsp;SET @LobPt = null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;-- No op for null or empty data&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;if( @Cipher is not null&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp; AND @Total &amp;gt; 0 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;BR&gt;&amp;nbsp;BEGIN&lt;BR&gt;&amp;nbsp;&amp;nbsp;WHILE @CurPos &amp;lt;= @Total&lt;BR&gt;&amp;nbsp;&amp;nbsp;BEGIN&lt;BR&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Read the next cipher block length&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT @AuxLen = substring( @Cipher, @CurPos, 2 )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @CurPos = @CurPos + 2&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Length field validation. &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- Any unexpected length will result in error&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( @AuxLen &amp;lt;= 0 OR @AuxLen &amp;gt; 8000 )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Get the next cipher block&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT @Aux = substring( @Cipher, @CurPos, @AuxLen )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @CurPos = @CurPos + @AuxLen&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- If there is any discrepancy,&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- it is either a data truncation error &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- (cipher was truncated)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- or a data corruption error.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- We will fail the whole operation.&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( datalength( @Aux ) &amp;lt;&amp;gt; @AuxLen )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Decrypt the current cipher block&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @Aux = decryptbykey( @Aux )&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- ... and make sure we could decrypt it.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Again, any error here will terminate&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- the operation and return null&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( @Aux is null )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Either set (if first block) or concatenate&lt;BR&gt;&amp;nbsp;&amp;nbsp; -- to the available PT we already decrypted&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( @LobPt is null )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @LobPt = @Aux&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;ELSE&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @LobPt = @LobPt + @Aux&lt;BR&gt;&amp;nbsp;&amp;nbsp;END&lt;BR&gt;&amp;nbsp;END&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;return @LobPt&lt;BR&gt;END&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;---------------------- Test&lt;/FONT&gt;&lt;BR&gt;CREATE SYMMETRIC KEY key1 WITH ALGORITHM = AES_192 ENCRYPTION BY PASSWORD = '|\/|y &lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;p@22\/\/0rD'&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New" size=2&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;OPEN SYMMETRIC KEY key1 DECRYPTION BY PASSWORD = '|\/|y &lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;p@22\/\/0rD'&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="Courier New" size=2&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;--------------- Quick Demo&lt;/FONT&gt;&lt;BR&gt;declare @x varbinary(max)&lt;BR&gt;declare @y varbinary(max)&lt;BR&gt;declare @z varchar(max)&lt;BR&gt;declare @i int&lt;BR&gt;set @i = 0&lt;BR&gt;SET @x = convert( varbinary(max), '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')&lt;BR&gt;while @i &amp;lt; 15 -- PT will be a little bit less than 2MB&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;SET @i = @i + 1&lt;BR&gt;&amp;nbsp;SET @x = @x + @x&lt;BR&gt;END&lt;BR&gt;SELECT @y = dbo.EncryptLob( key_guid('key1'), @x )&lt;BR&gt;SELECT datalength( @y ) as 'Ciphertext length'&lt;BR&gt;if( @y is not null )&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;SELECT @z = convert( varchar(max), dbo.DecryptLob( @y ))&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;if( @z is not null )&lt;BR&gt;&amp;nbsp;BEGIN&lt;BR&gt;&amp;nbsp;&amp;nbsp;SELECT datalength( @x) as 'original PT len', datalength(@z) as 'decrypted PT len', substring( @z, datalength(@z) - 16, 100) as 'Last 16 chars'&lt;BR&gt;&amp;nbsp;&amp;nbsp;if( @z = @x )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;print 'decrypted PT == original PT'&lt;BR&gt;&amp;nbsp;&amp;nbsp;else&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;print 'Unexpected error. PTs didn''t match'&lt;BR&gt;&amp;nbsp;END&lt;BR&gt;&amp;nbsp;ELSE&lt;BR&gt;&amp;nbsp;&amp;nbsp;print 'Failed to decrypt. Make sure the key is opened'&lt;BR&gt;END&lt;BR&gt;ELSE&lt;BR&gt;&amp;nbsp;print 'Failed to encrypt. Make sure the key is opened'&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;--------------------------------------------------------------------&lt;BR&gt;--------------------------------------------------------------------&lt;BR&gt;--------------------------------------------------------------------&lt;BR&gt;-- Create a new Encryption function - EncryptLobByCert. &lt;BR&gt;--&lt;BR&gt;-- This is a wrapper around EncryptByCert builtin&lt;BR&gt;-- In order to keep this demo simple, it doesn't support&lt;BR&gt;-- all the options EncryptByCert supports.&lt;BR&gt;--&lt;BR&gt;-- PARAMETERS&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @cert_id:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Cert ID, equivalent to EncryptByCert &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; first argument.&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @lob:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; The plaintext to encrypt. &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Limits for the datalength are defined&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; by the varbinary(max) data type&lt;BR&gt;-- RETURN VALUE&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; varbinary(max):&amp;nbsp;&amp;nbsp; If the encryption succeeded, &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; it will return a byte stream that&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; with the encrypted data. The byte stream &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; format is described in NOTES&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NULL if there is any error&lt;BR&gt;-- NOTES:&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; The plaintext will be split in blocks that can be &lt;BR&gt;--&amp;nbsp; encrypted individually and then concatenated together: &lt;BR&gt;--&amp;nbsp; ([2 bytes - ciphertext block length][ciphertext block]) &lt;BR&gt;--&amp;nbsp; per plaintext block&lt;BR&gt;--&amp;nbsp; Remember that asymmetric key encryption/decryption is orders &lt;BR&gt;--&amp;nbsp; of magnitude more expensive than symmetric key&lt;BR&gt;--&amp;nbsp; encryption/decryption. &lt;BR&gt;--&amp;nbsp;&amp;nbsp; We recommend avoiding the use of asymmetric key encryption for &lt;BR&gt;-- large amounts of data, but these functions may be used to &lt;BR&gt;-- protect data &amp;lt; 1000 bytes that are larger than what &lt;BR&gt;-- the SQL builtins are currently supporting&lt;BR&gt;-- (for example, data larger than 117 bytes)&lt;BR&gt;&lt;/FONT&gt;CREATE FUNCTION dbo.EncryptLobByCert( @cert_id int, @lob varbinary(max) )&lt;BR&gt;returns varbinary(max)&lt;BR&gt;as&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;declare @PtLimit&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @Total&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @CurPos&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @Aux&amp;nbsp;&amp;nbsp;varbinary(8000)&lt;BR&gt;&amp;nbsp;declare @AuxLen&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @PlaintextColumnLimit int&lt;BR&gt;&amp;nbsp;declare @Cipher&amp;nbsp;&amp;nbsp;varbinary(max)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;SET @Aux = encryptbycert( @cert_id, 0x00 )&lt;BR&gt;&amp;nbsp;if( @Aux is null ) &lt;FONT color=#008000&gt;-- Return null if we cannot encrypt by the specified cert&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;return null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;-- Calculate the limit for the PT block&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;SET @PtLimit = datalength( @Aux ) - 11&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;SET @CurPos = 1&lt;BR&gt;&amp;nbsp;SET @Total = datalength( @lob )&lt;BR&gt;&amp;nbsp;SET @Cipher = null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;---- Simple validation of the input parameters&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;WHILE @CurPos &amp;lt;= @Total&lt;BR&gt;&amp;nbsp;BEGIN&lt;BR&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;-- Get a new PT block&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;SELECT @Aux = substring( @Lob, @CurPos, @PtLimit )&lt;BR&gt;&amp;nbsp;&amp;nbsp;SET @CurPos = @CurPos + @PtLimit&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;-- Encrypt the PT block&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;SET @Aux = encryptbycert( @cert_id, @Aux)&lt;BR&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;-- If any block failed to decrypt, &lt;BR&gt;&amp;nbsp; -- we should just return NULL (failed)&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;if( @Aux is null )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;-- Get the ciphertext length&lt;BR&gt;&amp;nbsp;&amp;nbsp;-- 2 bytes should be enough&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;SET @AuxLen = datalength( @Aux )&lt;BR&gt;&amp;nbsp;&amp;nbsp;SET @Aux = convert( binary(2), @AuxLen ) + @Aux&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;-- Only set the @Cipher for the first block, &lt;BR&gt;&amp;nbsp; -- otherwise concatenate the existing data with &lt;BR&gt;&amp;nbsp; -- the new cipher block&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;if( @Cipher is null )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @Cipher = @Aux&lt;BR&gt;&amp;nbsp;&amp;nbsp;ELSE&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @Cipher = @Cipher + @Aux&lt;BR&gt;&amp;nbsp;END&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;return @Cipher&lt;BR&gt;END&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;---------------------------------------------------------------------&lt;BR&gt;-- Create a new Decryption function - DecryptLobByCert. &lt;BR&gt;--&lt;BR&gt;-- This is a wrapper around DecryptByCert builtin.&lt;BR&gt;-- It is the counterpart of EncryptLobByCert function.&lt;BR&gt;--&lt;BR&gt;-- PARAMETERS&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @cert_id:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Cert ID, equivalent to EncryptByCert &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; first argument.&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Cipher:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; A ciphertext that was generated by &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EncryptLobByCert. &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Password:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Password for the private key. &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; If encrypted by DBMK, you should use null&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for this parameter.&lt;BR&gt;--&lt;BR&gt;-- RETURN VALUE&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; varbinary(max):&amp;nbsp;&amp;nbsp; If the decryption succeeded, it will &lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return the plaintext as varbinary(max)&lt;BR&gt;--&lt;BR&gt;-- NOTES&lt;BR&gt;--&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; The plaintext will be split in blocks that can be &lt;BR&gt;-- encrypted individually and then concatenated together: &lt;BR&gt;-- ([2 bytes - ciphertext block length][ciphertext block]) &lt;BR&gt;-- per plaintext block&lt;BR&gt;&lt;/FONT&gt;CREATE FUNCTION dbo.DecryptLobByCert( &lt;BR&gt;@cert_id int, &lt;BR&gt;@Cipher varbinary(max), &lt;BR&gt;@Password nvarchar(4000) )&lt;BR&gt;returns varbinary(max)&lt;BR&gt;as&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;declare @PtLimit&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @Total&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @CurPos&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @Aux&amp;nbsp;&amp;nbsp;varbinary(8000)&lt;BR&gt;&amp;nbsp;declare @AuxLen&amp;nbsp;&amp;nbsp;int&lt;BR&gt;&amp;nbsp;declare @LobPt&amp;nbsp;&amp;nbsp;varbinary(max)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;SET @CurPos = 1&lt;BR&gt;&amp;nbsp;SET @Total = datalength( @Cipher )&lt;BR&gt;&amp;nbsp;SET @LobPt = null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;-- No op for null or empty data&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;if( @Cipher is not null&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp; AND @Total &amp;gt; 0 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;BR&gt;&amp;nbsp;BEGIN&lt;BR&gt;&amp;nbsp;&amp;nbsp;WHILE @CurPos &amp;lt;= @Total&lt;BR&gt;&amp;nbsp;&amp;nbsp;BEGIN&lt;BR&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Read the next cipher block length&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT @AuxLen = substring( @Cipher, @CurPos, 2 )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @CurPos = @CurPos + 2&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Length field validation. Any unexpected &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- length will result in error&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( @AuxLen &amp;lt;= 0 OR @AuxLen &amp;gt; 8000 )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT color=#008000&gt;-- Get the next cipher block&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT @Aux = substring( @Cipher, @CurPos, @AuxLen )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @CurPos = @CurPos + @AuxLen&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- If there is any discrepancy, &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- it is either a data truncation error &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- (cipher was truncated)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- or a data corruption error.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- We will fail the whole operation.&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( datalength( @Aux ) &amp;lt;&amp;gt; @AuxLen )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Decrypt the current cipher block&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @Aux = decryptbycert( @cert_id, @Aux, @Password )&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- ... and make sure we could decrypt it.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Again, any error here will terminate &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- the operation and return null&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( @Aux is null )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- Either set (if first block) or concatenate &lt;BR&gt;&amp;nbsp;&amp;nbsp; -- to the available PT we already decrypted&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( @LobPt is null )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @LobPt = @Aux&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;ELSE&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET @LobPt = @LobPt + @Aux&lt;BR&gt;&amp;nbsp;&amp;nbsp;END&lt;BR&gt;&amp;nbsp;END&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;nbsp;return @LobPt&lt;BR&gt;END&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;------------ Test&lt;/FONT&gt;&lt;BR&gt;CREATE CERTIFICATE certTest ENCRYPTION BY PASSWORD = 'c3R+ &lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;p@zz\/\/0Rd!'&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt; WITH SUBJECT = 'Demo - LOB encryption'&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;declare @x varbinary(max)&lt;BR&gt;declare @y varbinary(max)&lt;BR&gt;declare @z varchar(max)&lt;BR&gt;declare @i int&lt;BR&gt;set @i = 0&lt;BR&gt;SET @x = convert( varbinary(max), '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')&lt;BR&gt;while @i &amp;lt; 4 -- PT will be a little bit more than 1k&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;SET @i = @i + 1&lt;BR&gt;&amp;nbsp;SET @x = @x + @x&lt;BR&gt;END&lt;BR&gt;SELECT @y = dbo.EncryptLobByCert( cert_id('CertTest'), @x )&lt;BR&gt;SELECT datalength( @y ) as 'Ciphertext length'&lt;BR&gt;&lt;FONT color=#008000&gt;--select @y as CipherTextLob&lt;/FONT&gt;&lt;BR&gt;if( @y is not null )&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;SELECT @z = convert( varchar(max), dbo.DecryptLobByCert( cert_id('CertTest'), @y, N'c3R+ &lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;p@zz\/\/0Rd!'&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt; ))&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;if( @z is not null )&lt;BR&gt;&amp;nbsp;BEGIN&lt;BR&gt;&amp;nbsp;&amp;nbsp;SELECT datalength( @x) as 'original PT len', datalength(@z) as 'decrypted PT len', substring( @z, datalength(@z) - 16, 100) as 'Last 16 chars'&lt;BR&gt;&amp;nbsp;&amp;nbsp;if( @z = @x )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;print 'decrypted PT == original PT'&lt;BR&gt;&amp;nbsp;&amp;nbsp;else&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;print 'Unexpected error. PTs didn''t match'&lt;BR&gt;&amp;nbsp;END&lt;BR&gt;&amp;nbsp;ELSE&lt;BR&gt;&amp;nbsp;&amp;nbsp;print 'Failed to decrypt. Make sure the key is opened'&lt;BR&gt;END&lt;BR&gt;ELSE&lt;BR&gt;&amp;nbsp;print 'Failed to encrypt. Make sure the key is opened'&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&lt;FONT color=#008000&gt;------ Test2&lt;/FONT&gt;&lt;BR&gt;CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'D8|\/||&amp;lt; p455\/\/oRx!'&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;CREATE CERTIFICATE certTest2 WITH SUBJECT = 'Demo - LOB encryption DBMK protected'&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT face="Courier New" size=2&gt;declare @x varbinary(max)&lt;BR&gt;declare @y varbinary(max)&lt;BR&gt;declare @z varchar(max)&lt;BR&gt;declare @i int&lt;BR&gt;set @i = 0&lt;BR&gt;SET @x = convert( varbinary(max), '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')&lt;BR&gt;while @i &amp;lt; 4 -- PT will be a little more than 1k&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;SET @i = @i + 1&lt;BR&gt;&amp;nbsp;SET @x = @x + @x&lt;BR&gt;END&lt;BR&gt;SELECT @y = dbo.EncryptLobByCert( cert_id('CertTest2'), @x )&lt;BR&gt;SELECT datalength( @y ) as 'Ciphertext length'&lt;BR&gt;&lt;FONT color=#008000&gt;--select @y as CipherTextLob&lt;/FONT&gt;&lt;BR&gt;if( @y is not null )&lt;BR&gt;BEGIN&lt;BR&gt;&lt;FONT color=#008000&gt;&amp;nbsp;-- Use null for the password parameter &lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;SELECT @z = convert( varchar(max), dbo.DecryptLobByCert( cert_id('CertTest2'), @y, null ))&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;if( @z is not null )&lt;BR&gt;&amp;nbsp;BEGIN&lt;BR&gt;&amp;nbsp;&amp;nbsp;SELECT datalength( @x) as 'original PT len', datalength(@z) as 'decrypted PT len', substring( @z, datalength(@z) - 16, 100) as 'Last 16 chars'&lt;BR&gt;&amp;nbsp;&amp;nbsp;if( @z = @x )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;print 'decrypted PT == original PT'&lt;BR&gt;&amp;nbsp;&amp;nbsp;else&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;print 'Unexpected error. PTs didn''t match'&lt;BR&gt;&amp;nbsp;END&lt;BR&gt;&amp;nbsp;ELSE&lt;BR&gt;&amp;nbsp;&amp;nbsp;print 'Failed to decrypt. Make sure the key is opened'&lt;BR&gt;END&lt;BR&gt;ELSE&lt;BR&gt;&amp;nbsp;print 'Failed to encrypt. Make sure the key is opened'&lt;BR&gt;go&lt;BR&gt;&lt;FONT color=#008000&gt;----------------------- CLEANUP&lt;/FONT&gt;&lt;BR&gt;use master&lt;BR&gt;go&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;DROP DATABASE demo_LobEncryption&lt;BR&gt;go&lt;BR&gt;&lt;FONT color=#008000&gt;----------------------- END OF DEMO -----------------------&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=496521" width="1" height="1"&gt;</description></item><item><title>The beginning - Securing Data</title><link>http://blogs.msdn.com/yukondoit/archive/2005/10/14/480907.aspx</link><pubDate>Fri, 14 Oct 2005 05:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:480907</guid><dc:creator>yukondoit</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/yukondoit/comments/480907.aspx</comments><wfw:commentRss>http://blogs.msdn.com/yukondoit/commentrss.aspx?PostID=480907</wfw:commentRss><description>&lt;P&gt;&lt;FONT face=Verdana size=2&gt;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.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Verdana size=2&gt;Well, not much has changed - I am still lazy as ever, inarticulate as ever - but&amp;nbsp;I have been able to post my first article &lt;a href="http://blogs.msdn.com/yukondoit/articles/480854.aspx" target=_blank&gt;&lt;SPAN lang=en-us&gt;&lt;U&gt;&lt;FONT face=Arial color=#0000ff size=2&gt;http://blogs.msdn.com/yukondoit/articles/480854.aspx&lt;/FONT&gt;&lt;/U&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;/FONT&gt;&lt;FONT face=Verdana size=2&gt;.&amp;nbsp;It is about&amp;nbsp;security considerations while securing data using SQL Server 2005. &lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=480907" width="1" height="1"&gt;</description></item></channel></rss>