use of org.apache.derby.iapi.services.crypto.CipherFactoryBuilder in project derby by apache.
the class RawStore method setupEncryptionEngines.
/*
** data encryption/decryption support
*/
/**
* Setup encryption engines according to the user properties and the
* current database state.
*
* @param create whether a new database is being created, or if this is
* an existing database
* @param properties database properties, including connection attributes
* @return {@code true} if the existing data in the database should be
* transformed by applying a cryptographic operation.
* @throws StandardException if the properties are conflicting, if the
* requested configuration is denied, or if something else goes wrong
*/
private boolean setupEncryptionEngines(boolean create, Properties properties) throws StandardException {
// Check if user has requested to decrypt the database.
boolean decryptDatabase = isTrue(properties, Attribute.DECRYPT_DATABASE);
// Check if user has requested to encrypt the database.
boolean encryptDatabase = isTrue(properties, Attribute.DATA_ENCRYPTION);
boolean reEncrypt = false;
if (!create) {
// Check if database is already encrypted, by directly peeking at
// the database service propertes instead of the properties passed
// to this method. By looking at properties passed to the boot
// method, one can not differentiate between a request to encrypt
// a plaintext database and booting an already encrypted database.
// Attribute.DATA_ENCRYPTION is stored in the service properties
// for encrypted database, and this takes precedence over the
// value specified by the user.
String name = getServiceName(this);
PersistentService ps = getMonitor().getServiceType(this);
String canonicalName = ps.getCanonicalServiceName(name);
Properties serviceprops = ps.getServiceProperties(canonicalName, (Properties) null);
isEncryptedDatabase = isTrue(serviceprops, Attribute.DATA_ENCRYPTION);
if (isEncryptedDatabase) {
// Check if the user has requested to re-encrypt an
// encrypted datbase with a new encryption password/key.
// See also attribute check in EmbedConnection.
reEncrypt = isSet(properties, Attribute.NEW_BOOT_PASSWORD) || isSet(properties, Attribute.NEW_CRYPTO_EXTERNAL_KEY);
encryptDatabase = reEncrypt;
} else if (encryptDatabase && decryptDatabase) {
// We cannot both encrypt and decrypt at the same time.
throw StandardException.newException(SQLState.CONFLICTING_BOOT_ATTRIBUTES, Attribute.DECRYPT_DATABASE + ", " + Attribute.DATA_ENCRYPTION);
}
// Prevent attempts to (re)encrypt or decrypt a read-only database.
if ((encryptDatabase || decryptDatabase) && isReadOnly()) {
throw StandardException.newException(SQLState.CANNOT_ENCRYPT_READONLY_DATABASE);
}
}
// setup encryption engines.
if (isEncryptedDatabase || encryptDatabase) {
// Check if database is or will be encrypted. We save encryption
// properties as service properties, such that
// user does not have to specify them on the URL everytime.
// Incase of re-encryption of an already of encrypted database
// only some information needs to updated; it is not treated
// like the configuring the database for encryption first time.
boolean setupEncryption = create || (encryptDatabase && !reEncrypt);
// start the cipher factory module, that is is used to create
// instances of the cipher factory with specific enctyption
// properties.
CipherFactoryBuilder cb = (CipherFactoryBuilder) startSystemModule(org.apache.derby.shared.common.reference.Module.CipherFactoryBuilder);
// create instance of the cipher factory with the
// specified encryption properties.
currentCipherFactory = cb.createCipherFactory(setupEncryption, properties, false);
// The database can be encrypted using an encryption key that is
// specified in the connection URL. For security reasons this key
// is not persisted in the database, but it is necessary to verify
// the encryption key whenever booting the database. This needs to
// happen before we access the data/logs to avoid the risk of
// corrupting the database because of a wrong encryption key.
// Please note this verification process does not provide any added
// security. Its purpose is to allow us to fail gracefully if an
// incorrect encryption key is used during boot time.
currentCipherFactory.verifyKey(setupEncryption, storageFactory, properties);
// Initializes the encryption and decryption engines.
encryptionEngine = currentCipherFactory.createNewCipher(CipherFactory.ENCRYPT);
if (setupEncryption) {
encryptionBlockSize = encryptionEngine.getEncryptionBlockSize();
// this will be saved after encrypting the exisiting data.
if (create) {
properties.put(RawStoreFactory.ENCRYPTION_BLOCKSIZE, String.valueOf(encryptionBlockSize));
}
} else {
if (isSet(properties, RawStoreFactory.ENCRYPTION_BLOCKSIZE)) {
encryptionBlockSize = Integer.parseInt(properties.getProperty(RawStoreFactory.ENCRYPTION_BLOCKSIZE));
} else {
encryptionBlockSize = encryptionEngine.getEncryptionBlockSize();
}
}
decryptionEngine = currentCipherFactory.createNewCipher(CipherFactory.DECRYPT);
random = currentCipherFactory.getSecureRandom();
if (encryptDatabase) {
if (reEncrypt) {
// Create new cipher factory with the new encryption
// properties specified by the user. This cipher factory
// is used to create the new encryption/decryption
// engines to re-encrypt the database with the new
// encryption keys.
newCipherFactory = cb.createCipherFactory(setupEncryption, properties, true);
newDecryptionEngine = newCipherFactory.createNewCipher(CipherFactory.DECRYPT);
newEncryptionEngine = newCipherFactory.createNewCipher(CipherFactory.ENCRYPT);
} else {
// There is only one engine when configuring an
// un-encrypted database for encryption.
newDecryptionEngine = decryptionEngine;
newEncryptionEngine = encryptionEngine;
}
}
// at database creation time.
if (create) {
currentCipherFactory.saveProperties(properties);
isEncryptedDatabase = true;
}
}
// existing database, or decrypting an already encrypted database.
return (!create && (encryptDatabase || (isEncryptedDatabase && decryptDatabase)));
}
Aggregations