12

I have a database column that needs to be encrypted, when passed from a hibernate backed webapp. The webapp is on tomcat 6, Hibernate 4, and Mysql as the backing store.

The problem however is that the password to encrypt/decrypt this field will only be available at runtime of the program. Initially I had hoped to use the AES_ENCRYPT/DECRYPT methods, outlined quite well here:

DataBase encryption in Hibernate

and here:

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#mapping-column-read-and-write

(Though this does refer to version 3.6 of hibernate, I believe it should be the same in 4.0).

However, since this uses the following notation:

@Column(columnDefinition= "LONGBLOB", name="encryptedBody") 
@ColumnTransformer(
  read="AES_DECRYPT(encryptedBody, 'password')", 
  write="AES_ENCRYPT(?, 'password')")
public byte[]  getEncryptedBody() {
    return encryptedBody;
}

public void setEncryptedBody(byte[]  encryptedBody) {
    this.encryptedBody = encryptedBody;
}

This requires that the password be specified in the annotation itself, and cannot be a variable.

Is there a way to use the database methods through hibernate in this manner, but with the password as a variable? Is there a better approach?

Community
  • 1
  • 1
Jordan Robinson
  • 855
  • 11
  • 25

2 Answers2

3

Currently there is not a way to parameterize the pieces of the read/write fragments. They are more meant as general purpose solutions. We have discussed adding support for @Encrypted in Hibernate that would roughly act like you suggest. @Encrypted would give more flexibility, like in-vm crypto versus in-db crypto, parameterization, etc.

JPA 2.1 also has a feature you could use, called attribute converters. They would only be able to apply in-vm crypto however.

Steve Ebersole
  • 9,339
  • 2
  • 48
  • 46
0

You can Use Hibernate @Type attribute,Based on your requirement you can customize the annotation and apply on top of the fied. like :

  public class PhoneNumberType implements UserType {
  @Override
  public int[] sqlTypes() {
return new int[]{Types.INTEGER, Types.INTEGER, Types.INTEGER};
  }

  @Override
  public Class returnedClass() {
      return PhoneNumber.class;
  }

  // other methods
  }   

First, the null SafeGet method:

  @Override
  public Object nullSafeGet(ResultSet rs, String[] names, 
  SharedSessionContractImplementor session, Object owner) throws HibernateException,                   
    SQLException {
  int countryCode = rs.getInt(names[0]);
   if (rs.wasNull())
      return null;
   int cityCode = rs.getInt(names[1]);
  int number = rs.getInt(names[2]);
  PhoneNumber employeeNumber = new PhoneNumber(countryCode, cityCode, number);
   return employeeNumber;
   }

Next, the null SafeSet method:

  @Override
   public void nullSafeSet(PreparedStatement st, Object value, 
    int index, SharedSessionContractImplementor session) 
     throws HibernateException, SQLException {
      if (Objects.isNull(value)) {
      st.setNull(index, Types.INTEGER);
      } else {
      PhoneNumber employeeNumber = (PhoneNumber) value;
      st.setInt(index,employeeNumber.getCountryCode());
      st.setInt(index+1,employeeNumber.getCityCode());
      st.setInt(index+2,employeeNumber.getNumber());
    }
   }

Finally, we can declare our custom PhoneNumberType in our OfficeEmployee entity class:

  @Entity
  @Table(name = "OfficeEmployee")
   public class OfficeEmployee {

    @Columns(columns = { @Column(name = "country_code"), 
    @Column(name = "city_code"), @Column(name = "number") })
    @Type(type = "com.baeldung.hibernate.customtypes.PhoneNumberType")
     private PhoneNumber employeeNumber;

   // other fields and methods
    }

This might solve your problem, This will work for all database. if you want more info refer :: https://www.baeldung.com/hibernate-custom-types
similarly you have to do UTF-8 encoding/Decoding and ISO-8859-1 Decoding/encoding

TryChai
  • 51
  • 3