Tag: T-SQL

  • Decryption and CASTing

    In my last encryption post I showed how to encrypt and decrypt data with a symmetric key. However there was a piece of the explanation I left out. If you look at that post, suppose that you ran this query after you’d encrypted the data:

    -- decrypt the data
    select 
      id
    ,firstname
    ,lastname
    ,title
    ,Salary = DecryptByKey(EnryptedSalary)
    ,EnryptedSalary
     from Employees
    go

    The results wouldn’t be what you’d expect:

    decrypt

    The binary data is returned, which isn’t rendered correctly. The salary column is the decryption, and the EncryptedSalary is the encrypted data. Note they are different.

    This stumped me for awhile when I was playing with encryption and I checked the dercryptbykey page thoroughly before I realized that the return type was varbinary and needed to be CAST.

    If I cast this back to nvarchar, I get the data:

    select 
      id
    , title
    , Salary = cast(DecryptByKey(EnryptedSalary) as nvarchar) 
    , EnryptedSalary
     from Employees

    decrypt2

    In my example, I CAST to nvarchar, and then to numeric, mostly for clean coding. This is numeric data. Can I cast directly?

    select 
      id
    , title
    , Salary = cast(DecryptByKey(EnryptedSalary) as numeric(10,4))
    , EnryptedSalary
     from Employees
    go

    No. I get an error.

    Msg 8115, Level 16, State 6, Line 1

    Arithmetic overflow error converting varbinary to data type numeric.

    This isn’t a valid CAST, so I need to double up the CASTs as shown in the original post.

  • Using a Symmetric Key

    In my Encryption Primer talk, I do demo on symmetric key use, and wanted to document it here. Encryption is a serious subject, and please do your research and education, as well as testing, before you implement it.

    This post will look at some simple encryption and decryption using symmetric keys. I showed how to create a symmetric key before, so I won’t talk about that here, but I’ll just show the code.

    Let’s set up a test table. In this case, I’m showing salary in a table, which isn’t something you want to do, but you might have this in an existing application: data you need to encrypt, but it’s stored unencrypted.

    -- create a table 
    create table Employees ( 
     id int identity(1,1)
     , firstname varchar(200)
     ,lastname varchar(200)
     ,title varchar(200)
     ,salary numeric(10, 4) );
    go
    insert Employees 
    values
      ('Steve','Jones','CEO', 5000)
     , ('Delaney','Jones','Manure Shoveler', 10)
     , ('Kendall','Jones','Window Washer', 5)
    ;
    go 

    Here I have three employees and salaries. Now I want to encrypt the salary. However I cannot just encrypt this value. Encryption creates a binary representation of the data, and that won’t fit in a varchar field. So I need to add a column.

    alter table Employees 
     add EnryptedSalary varbinary(max);
    go 

    Now I have a placeholder, so let’s create a key and then update the new binary column with the encrypted value.

    -- create a symmetric key
    create symmetric key MySalaryProtector
     WITH ALGORITHM=AES_256
     , IDENTITY_VALUE = 'Salary Protection Key'
     , Key_SOURCE = N'Keep this phrase a secr#t' 
     ENCRYPTION BY PASSWORD = 'Us#aStrongP2ssword'
    ;
    go 
    -- open the key 
    open symmetric key MySalaryProtector
     decryption by password='Us#aStrongP2ssword'
    ;
    
    -- encrypt the data 
    update Employees 
     set EnryptedSalary = ENCRYPTBYKEY(key_guid('MySalaryProtector'),cast(salary as nvarchar))
    ; 
    go 
    -- remove the old data 
    update employees
     set salary = 0
    ; 
    go 

    Note that I open the key, which is needed. I can close it at the end, or it will close when my session ends. I don’t close it here as I usually run this demo in the course of one session.

    The encryption takes place with the ENCRYPTBYKEY function, which requires the GUID of the key. Why the GUID and not the name I don’t know, but it seems like a PIA, halfway implementation. In any case, the KEY_GUID function is used as the first parameter.

    The number needs to be cast as a character, so I do that first, and then it’s the next parameter in the function. If I look at the data, it looks like this:

    select id , firstname , lastname , title , salary , EnryptedSalary
     from Employees; go 

    encryptsymm

    If you use the same identity_value and key_source, you should get the same encryption.

    To decrypt it, I do this:

    -- decrypt the data, with the casting  select id  , firstname  , lastname  , title  , Salary = cast(cast(DecryptByKey(EnryptedSalary) as nvarchar) as numeric(10,4))  , EnryptedSalary  from Employees go 

    The encrypted value has a header that tells it what key is used, so as long as it’s open, this works.

  • T-SQL Tuesday #31 – Logging

    TSQL2sDay150x150It’s T-SQL Tuesday time again, and this month Aaron Nelson (blog | @sqlvariant) is hosting. The topic is logging, and if you’re like to participate, read Aaron’s post and learn the rules. We do this on the second Tuesday of every month.

    If you’d like to host, contact Adam Machanic. It’s easy to do. Get on the schedule, pick a topic, and then write a post.

    A list of previous posts is here,

    Logging

    I’ve found documentation of events to be one of the most important things I can do in my career. Finding out what happened, what changed, or what I did has been important many times, and often helped me come through difficult situations.

    Logging is the automated version of documentation. All kinds of applications, including SQL Server, produce logs of the various activity on the system. In SQL Server, we are moving to an eventing system, and if you haven’t looked at Extended Events, you should.

    One of the times when I found logging to be lacking was in a startup I worked at a decade ago. We had a number of developers that were working on various development servers. They had full rights, and they were allowed to build their own objects. That was a little concern to a controlling DBA like me, but I allowed it since they often wanted new objects quickly, and if I allowed them to write their own, they’d use stored procedures.

    A good compromise, if you ask me.

    However in the hectic pace of development, I found that the developers didn’t often keep good notes about what was being built for which features and functions. Since we had to produce a build script fairly quickly every Monday in order to update our QA systems, we would find that developers invariably would forget objects and we would not have a well tested QA script on Monday afternoon.

    I decided that we needed to better log the changes on our development server. I didn’t care about every change, especially intermediate changes to objects, but I did care about the gross changes made each day.

    This was in the SQL Server 2000 days, with limited tracking of changes outside of SQL Trace. Since I had no desire to move through lots of trace files, even in an automated fashion, I decided on a much simpler method.

    In sysobjects (now sys.objects), there was a crdate field, which tells you when the object was created. However that doesn’t change if an ALTER TABLE is run (or any other ALTER). That stumped me briefly, but I decided to search further.

    I found that there was a schema_ver field, which is incremented every time the object is changed. Since the majority of our developer changes were ALTERs, I could track the version number and then compare this each day. I tested this out, and it worked well.

    The outline of the solution is that I grabbed a copy of the sysobjects table every day and stored it in a temporary table. I then used a left join to compare this with the previous values stored in a table I’d created to store the data. When I found differences, I logged them in a table, along with the date, and sent myself an email. I would then overwrite the stored version of the objects with the version from the temp table, giving me a baseline for the next execution.

    At the end of the week, I’d have an aggregate list of all objects changed, which I could then compare against our build script.

    At the time we were in an agile environment, releasing new code every Wednesday, and operating on very short timelines. The logging I did cut down on mistakes and allowed us to have a smooth release process that functioned for over 18 months, with code releases nearly every Wednesday outside of holidays.

  • Creating a Filetable

    How do you create a filetable? I assume you’ve enabled Filestream and created a filegroup for your filestream and filetable data. Then you just do this:

    -- Create a filetable
    CREATE TABLE AuthorDrafts 
      AS FileTable
    GO
    
    

    The only optional part of this statement is the table name. No other options, no columns, no schema needed. The FileTable has a fixed schema, which is mostly metadata about the files that you put in it.

    If I were to select from this table, I’d use this statement. I’m not showing all the columns in the results since there are a lot, but they are in the select.

    -- check the table.
    select 
       stream_id ,
              file_stream ,
              name ,
              path_locator ,
              parent_path_locator ,
              file_type ,
              cached_file_size ,
              creation_time ,
              last_write_time ,
              last_access_time ,
              is_directory ,
              is_offline ,
              is_hidden ,
              is_readonly ,
              is_archive ,
              is_system ,
              is_temporary
     from AuthorDrafts;
    go
    
    

    Most of these are really meta data about the file. If I were to drop a table in the share, I’d see results like this:

    filetable1

    Putting files inside the table is really a drag and drop from Windows. I can get the share name for my filetable from :

    -- check the share
    select  FileTableRootPath('dbo.AuthorDrafts');
    go
    

    If I paste this in Explorer, I see my file:

    filetable2

    I can drag and drop, or use any scripting commands (Powershell, VBScript, etc) to move files in and out of this share, and they will appear in my table.

    It’s that easy to start working with FileTables. How you use them in your application? That’s a whole other series of posts. I’ll work on a few examples you can use over time.