At the moment, we store device related server private key as a plain text in the database. This is not a big issue in some scenarios, since back-ends are in a secure infrastructure with very limited access, however we could still improve security of the key by:
- Introducing a new property (in case the property is not set, no encryption is used):
powerauth.server.db.master.encryption.key=MTIzNDU2Nzg5MDEyMzQ1Ng==
- Using conversion mechanism whenever loading a
serverPrivateKey
value for the activation entity.
Note that since there is the good old rule "Same data should result in different encrypted values", we should introduce IV value for the encryption that should be stored with the value, such as (pseudo-code):
public byte[] encrypt(byte[] orig, SecretKey key) {
byte[] iv = Bytes.random(16);
byte[] encrypted = aes.encrypt(orig, iv, key);
byte[] record = iv.append(encrypted)
return record;
}
public byte[] decrypt(byte[] record, SecretKey key) {
byte[] iv = record.byteRange(0, 16); // offset, length
byte[] encrypted = record.byteRange(16, -1); // offset, remaining
byte[] orig = aes.decrypt(encrypted, iv, key);
return orig;
}
Also, in order to achieve consistency between activation record and encrypted server private key (to avoid partial record swap), we should pay attention to how we construct the encryption key. It should be derived from the master DB encryption key using KDF_INTERNAL with user ID and activation ID derivate as a base, like so:
public SecretKey deriveSecretKey(SecretKey masterDbEncryptionKey, String userId, String activationId) {
String base = activationId.getBytes("UTF-8");
String salt = userId.getBytes("UTF-8");
byte[] index = PBKDF2.expand(base, salt, iterations, lengthInBits);
return KDF_INTERNAL.derive(masterDbEncryptionKey, index);
}
Since we need entity context in order to achieve this, we very likely aren't able to use (aspect / annotation based) converter...