views:

382

answers:

5

I have a database table with a field that I need to read from and write to via Hibernate. It is string field, but the contents are encrypted. And for various reasons (e.g. a need to sort the plain text values), the encrypt/decrypt functions are implemented inside the database, not in Java.

The problem I'm struggling with now is finding a way to invoke the encrypt/decrypt functions in Hibernate-generated SQL everywhere that the field is referenced and in a way that's transparent to my application code. Is this possible? I've looked into Hibernate's support for "derived" properties, but unfortunately, that approach doesn't support read-write fields. Any ideas appreciated.

A: 

Assuming you have access to the encrypt/decrypt algorithm from within Java, I would set up my mapped class something like

public class encryptedTable {
    @Column(name="encrypted_field")
    private String encryptedValue;

    @Transient
    private String value;

    public String getEncryptedValue() {
        return encryptedValue;
    }

    public String getValue() {
        return value;
    }

    public void setEncryptedValue(String encryptedValue) {
        this.encryptedValue = encryptedValue;
        this.value = decrypt(encryptedValue);
    }

    public void setValue(String value) {
        this.value = value;
        this.encryptedValue = encrypt(value);
    }
}

And then use get/set Value as the accessor within your program and leave the get/set EncryptedValue for Hibernates use when accessing the database.

Mike Clark
This doesn't address my desire to have Hibernate automatically invoke the database's decryption function when the field is referenced in a query (e.g. for sorting).
Rob H
+1  A: 

You could have a trigger internal to the database that, on retrieval, decrypts the value and replaces the returned result and on insert encrypts the value and replaces the stored result with the encrypted value. You could also do this with a view wrapper - i.e. have an insert trigger on the view, and have the view automatically decrypt the value.

To better explain: have a view that decrypts the value, and an on insert trigger that encrypts the value that is linked to the view.

aperkins
I'd considered something like this, but dismissed it as too hard to maintain because I have several tables with encrypted fields and I rely on Hibernate for automatic schema generation. But maybe there's a way to dynamically generate the views and triggers. Hmm...
Rob H
We use a similar approach to this, but we have our database generated, and then we reverse engineer it. You could have the schema for the views/triggers as a separate piece if you are installing the database from the objects, and install it afterward as part of the install script/execution.
aperkins
Database triggers are invoked when data is inserted updated or deleted, not selected.
HLGEM
You wouldn't use a trigger, you would use a view to handle the select, and the trigger on the insert into the view - i.e. the view would handle the selection logic, and the trigger would handle the insert logic. Sorry if that wasn't clear.
aperkins
I'm pursuing the combination of a view wrapper with triggers for insert and update. This achieves the transparency I'm looking for. Thanks.
Rob H
+4  A: 

I don't think there's a way to make encryption like you've described it completely transparent to your application. The closest thing you can get is to make it transparent outside of entity. In your entity class:

@Entity
@SQLInsert(sql="INSERT INTO my_table(my_column, id) VALUES(encrypt(?),?)")
@SQLUpdate( sql="UPDATE my_table SET my_column = encrypt(?) WHERE id = ?")
public class MyEntity {

  private String myValue;

  ....

  @Formula("decrypt(my_column)")
  public String getValue() {
    return myValue;
  }

  public void setValue(String value) {
    myValue = value;
  }

  @Column (name="my_column")
  private String getValueCopy() {
    return myValue;
  }

  private void setValueCopy(String value) {
  }

}

value is mapped as derived property, you should be able to use it in queries.
valueCopy is private and is used to get around derived property being read-only.
SQLInsert and SQLUpdate is black voodoo magic to force encryption on insert / update. Note that parameter order IS important, you need to find out what order Hibernate would generate parameters in without using custom insert / update and then replicate it.

ChssPly76
We did a proof of concept like this. I'm not crazy about the "fake" property, but I like the idea of using explicit INSERTs and UPDATEs in conjunction with a view. Thanks.
Rob H
A: 

Why not just use the SQl server encryption that seems to already be in place by calling a stored proc in Hibernate instead of letting Hibernate generate a query?

HLGEM
A stored procedure does not address the problem of decrypting the field automatically when it is referenced in a query.
Rob H
+1  A: 

Actually, in the end, I went a different route and submitted a patch to Hibernate. It was committed to trunk last week and so I think it will be in the next release following 3.5. Now, in property mappings, you can specify SQL "read" and "write" expressions to call SQL functions or perform some other kind of database-side conversion.

Rob H