In a SQL Server 2012 database, I have a table with a varbinary(128) column that stores data encrypted by a certificate (AppCert) backed key (Secret_Key) and authenticator using a SHA2_512 hash of the primary key:
CREATE TABLE [Lookup].[SecretStuff] (
[Id] tinyint NOT NULL,
[Secret] varbinary(128) NOT NULL
CONSTRAINT [PK_Lookup-SecretStuff_Id] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [UN_Lookup-SecretStuff_Secret] UNIQUE NONCLUSTERED ([Secret])
);
OPEN SYMMETRIC KEY [Secret_Key] DECRYPTION BY CERTIFICATE [AppCert];
INSERT INTO [Lookup].[SecretStuff] ([Id], [Secret]) VALUES (1, ENCRYPTBYKEY(KEY_GUID('Secret_Key'), CONVERT(nvarchar(512), 'I have a secret'), 1, HASHBYTES('SHA2_512', CONVERT(varbinary(128), CONVERT(tinyint, 1)))));
CLOSE SYMMETRIC KEY [Secret_Key];
OPEN SYMMETRIC KEY [Secret_Key] DECRYPTION BY CERTIFICATE [AppCert];
SELECT [Id], CONVERT(nvarchar, DECRYPTBYKEY([Secret], 1, HASHBYTES('SHA2_512', CONVERT(varbinary, [Id])))) AS [Secret] FROM [Lookup].[SecretStuff];
CLOSE SYMMETRIC KEY [Secret_Key];
This all works beautifully. Now, I have a Spring Boot application using JPA/Hibernate that is wired up and tested/verified to work with this database. The SecretStuff class:
@Entity
@Table(name="SecretStuff", schema="Lookup")
public class SecretStuff {
@Id
@Column(name = "Id",
nullable = false)
private Integer id;
@Column(name = "Secret",
nullable = false,
unique = true)
@Size(min = 1, max = 255)
@ColumnTransformer(
read = "CONVERT(nvarchar(89), DECRYPTBYKEY([Secret], 1,
HASHBYTES('SHA2_512', CONVERT(varbinary(128), [Id]))))")
private String secret;
// getters/setter omitted
}
When I test the SecretStuff class, I see the following Hibernate generated SQL:
select
secretstuf0_.Id as Id1_7_0_,
CONVERT(nvarchar(89), DECRYPTBYKEY(secretstuf0_.[Secret],
1,
HASHBYTES('SHA2_512',
CONVERT(varbinary(128),
secretstuf0_.[Id])))) as Secret2_7_0_
from
Lookup.SecretStuff secretstuf0_
where
secretstuf0_.Id=?
Perfectly reasonable query that executes and returns 1 row with Id = 1 Secret = NULL, because the SYMMETRIC KEY is not opened before the query is executed.
My Question: How can I execute the OPEN SYMMETRIC KEY... command in the same transaction before the query and the CLOSE SYMMETRIC KEY... command in the same transaction after the query?
I have used Hibernate.initialize inside service class methods to lazy fetch to-many relations inside of transactions. Would I use a similar approach here? How?
I saw this article as I was typing up this question, but it is a couple of years old and uses the EntityManager approach with NativeQuery. Is there an updated way to manage this with JPA/Hibernate?