0

My problem is that I'm trying to encrypt a column in a SQL Server database because of policies of my work place. I have access only to simple methods for encrypting (TDE seems out of my possibilities) so I've tried using EncryptByCert or EncryptByKey. I was doing fine since the documentation shows the cap at 8000 which is enough for the data we're saving.

It just so happens that when I try to save anything it caps off at around 200 characters generating a 514 byte long varbinary. The 514 byte length varbinary will encrypt and decrypt fine but will not grow or shorten, a single character counts the same as a 200 string making those same 514 bytes binary. After say around 230 characters that I want to encrypt it will just leave the column null.

Does anyone know what's happening with that?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

1 Answers1

0

Encryption performed by these methods is done in chunks, with the maximum chunk size is the key length minus some internal overhead (117 bytes for 1024 bit keys, and 245 bytes for 2048 bit keys first introduced in SQL Server 2016).

If your input is any larger than that, you have to split it into chunks and encrypt one at a time, then concatenate the result.

Decryption, of course, should be performed accordingly. However, an important difference between the two is that encryption chunk size will be smaller than the key, and for decryption it should be exactly the key size. That's because any data, however short, will be encrypted into key long chunk, so that no guesses on the input length can be made by looking at the output.

Here is an excerpt from my encryption function (written for 2012 version, so 1024 bit keys are assumed):

create function [dbo].[security_EncryptByCert]
(
    @ClearText varbinary(max)
)

returns varbinary(max) with schemabinding, returns null on null input as begin

-- Returned value
declare @Ret varbinary(max) = 0x,
    -- Length of the ciphertext
    @Lng int = datalength(@ClearText),
    -- Starting offset of the chunk to encrypt
    @i int = 1,
    -- Chunk size, currently it can't be more than 117 bytes
    @Size int = 100,
    -- Certificate to encrypt data with
    @CertId int;


-- Determine the certificate with which to perform encryption
select @CertId = Id from ...

-- Iterate chunk by chunk til the end of the text
while @i < @Lng begin

    set @Ret += encryptbycert(@CertId, substring(@ClearText, @i, @Size));

    -- Move the pointer to the next block
    set @i += @Size;

end;

return @Ret;
end;

In this case, I used 100 byte chunks, not the largest possible ones. Don't really remember why, but you can use 245 bytes as a limit on 2016.

Graham
  • 7,431
  • 18
  • 59
  • 84
Roger Wolf
  • 7,307
  • 2
  • 24
  • 33