use of org.apache.derby.iapi.services.crypto.CipherProvider in project derby by apache.
the class JCECipherFactory method changeBootPassword.
public String changeBootPassword(String changeString, Properties properties, CipherProvider verify) throws StandardException {
// the new bootPassword is expected to be of the form
// oldkey , newkey.
int seperator = changeString.indexOf(',');
if (seperator == -1)
throw StandardException.newException(SQLState.WRONG_PASSWORD_CHANGE_FORMAT);
String oldBP = changeString.substring(0, seperator).trim();
byte[] oldBPAscii = StringUtil.getAsciiBytes(oldBP);
if (oldBPAscii == null || oldBPAscii.length < CipherFactory.MIN_BOOTPASS_LENGTH)
throw StandardException.newException(SQLState.WRONG_BOOT_PASSWORD);
;
String newBP = changeString.substring(seperator + 1).trim();
byte[] newBPAscii = StringUtil.getAsciiBytes(newBP);
if (newBPAscii == null || newBPAscii.length < CipherFactory.MIN_BOOTPASS_LENGTH)
throw StandardException.newException(SQLState.ILLEGAL_BP_LENGTH, CipherFactory.MIN_BOOTPASS_LENGTH);
// verify old key
byte[] generatedKey = getDatabaseSecretKey(properties, oldBPAscii, SQLState.WRONG_BOOT_PASSWORD);
// make sure the oldKey is correct
byte[] IV = generateIV(generatedKey);
if (!((JCECipherProvider) verify).verifyIV(IV)) {
throw StandardException.newException(SQLState.WRONG_BOOT_PASSWORD);
}
// DERBY-5622:
// if we survive those two quick checks, verify that the generated key is still correct
// by using it to decrypt something encrypted by the original generated key
CipherProvider newDecrypter = createNewCipher(DECRYPT, generateKey(generatedKey), IV);
vetCipherProviders(newDecrypter, verify, SQLState.WRONG_BOOT_PASSWORD);
// Make the new key. The generated key is unchanged, only the
// encrypted key is changed.
String newkey = saveSecretKey(generatedKey, newBPAscii);
properties.put(Attribute.CRYPTO_KEY_LENGTH, keyLengthBits + "-" + encodedKeyLength);
return saveSecretKey(generatedKey, newBPAscii);
}
use of org.apache.derby.iapi.services.crypto.CipherProvider in project derby by apache.
the class JCECipherFactory method verifyKey.
/**
* The database can be encrypted with an encryption key given in connection url.
* For security reasons, this key is not made persistent in the database.
*
* But it is necessary to verify the encryption key when booting the database if it is similar
* to the one used when creating 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.
*
* This method performs the steps necessary to verify the encryption key if an external
* encryption key is given.
*
* At database creation, 4k of random data is generated using SecureRandom and MD5 is used
* to compute the checksum for the random data thus generated. This 4k page of random data
* is then encrypted using the encryption key. The checksum of unencrypted data and
* encrypted data is made persistent in the database in file by name given by
* Attribute.CRYPTO_EXTERNAL_KEY_VERIFYFILE (verifyKey.dat). This file exists directly under the
* database root directory.
*
* When trying to boot an existing encrypted database, the given encryption key is used to decrypt
* the data in the verifyKey.dat and the checksum is calculated and compared against the original
* stored checksum. If these checksums dont match an exception is thrown.
*
* Please note, this process of verifying the key does not provide any added security but only is
* intended to allow to fail gracefully if a wrong encryption key is used
*
* StandardException is thrown if there are any problems during the process of verification
* of the encryption key or if there is any mismatch of the encryption key.
*/
public void verifyKey(boolean create, StorageFactory sf, Properties properties) throws StandardException {
if (properties.getProperty(Attribute.CRYPTO_EXTERNAL_KEY) == null)
return;
// if firstTime ( ie during creation of database, initial key used )
// In order to allow for verifying the external key for future database boot,
// generate random 4k of data and store the encrypted random data and the checksum
// using MD5 of the unencrypted data. That way, on next database boot a check is performed
// to verify if the key is the same as used when the database was created
InputStream verifyKeyInputStream = null;
StorageRandomAccessFile verifyKeyFile = null;
byte[] data = new byte[VERIFYKEY_DATALEN];
try {
if (create) {
getSecureRandom().nextBytes(data);
// get the checksum
byte[] checksum = getMD5Checksum(data);
CipherProvider tmpCipherProvider = createNewCipher(ENCRYPT, mainSecretKey, mainIV);
tmpCipherProvider.encrypt(data, 0, data.length, data, 0);
// openFileForWrite
verifyKeyFile = privAccessFile(sf, Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE, "rw");
// write the checksum length as int, and then the checksum and then the encrypted data
verifyKeyFile.writeInt(checksum.length);
verifyKeyFile.write(checksum);
verifyKeyFile.write(data);
verifyKeyFile.sync();
} else {
// Read from verifyKey.dat as an InputStream. This allows for
// reading the information from verifyKey.dat successfully even when using the jar
// subprotocol to boot derby. (DERBY-1373)
verifyKeyInputStream = privAccessGetInputStream(sf, Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
DataInputStream dis = new DataInputStream(verifyKeyInputStream);
// then read the checksum length
int checksumLen = dis.readInt();
byte[] originalChecksum = new byte[checksumLen];
dis.readFully(originalChecksum);
dis.readFully(data);
// decrypt data with key
CipherProvider tmpCipherProvider = createNewCipher(DECRYPT, mainSecretKey, mainIV);
tmpCipherProvider.decrypt(data, 0, data.length, data, 0);
byte[] verifyChecksum = getMD5Checksum(data);
if (!MessageDigest.isEqual(originalChecksum, verifyChecksum)) {
throw StandardException.newException(SQLState.ENCRYPTION_BAD_EXTERNAL_KEY);
}
}
} catch (IOException ioe) {
throw StandardException.newException(SQLState.ENCRYPTION_UNABLE_KEY_VERIFICATION, ioe);
} finally {
try {
if (verifyKeyFile != null)
verifyKeyFile.close();
if (verifyKeyInputStream != null)
verifyKeyInputStream.close();
} catch (IOException ioee) {
throw StandardException.newException(SQLState.ENCRYPTION_UNABLE_KEY_VERIFICATION, ioee);
}
}
return;
}
use of org.apache.derby.iapi.services.crypto.CipherProvider in project derby by apache.
the class JCECipherFactory method encryptKey.
/**
* Encrypt the secretKey with the boot password.
* This includes the following steps,
* getting muck from the boot password and then using this to generate a key,
* generating an appropriate IV using the muck
* using the key and IV thus generated to create the appropriate cipher provider
* and encrypting the secretKey
* @return hexadecimal string of the encrypted secretKey
*
* @exception StandardException Standard Derby error policy
*/
private EncryptedKeyResult encryptKey(byte[] secretKey, byte[] bootPassword) throws StandardException {
// In case of AES, care needs to be taken to allow for 16 bytes muck as well
// as to have the secretKey that needs encryption to be a aligned appropriately
// AES supports 16 bytes block size
int muckLength = secretKey.length;
if (cryptoAlgorithmShort.equals(AES))
muckLength = AES_IV_LENGTH;
byte[] muck = getMuckFromBootPassword(bootPassword, muckLength);
SecretKey key = generateKey(muck);
byte[] IV = generateIV(muck);
CipherProvider tmpCipherProvider = createNewCipher(ENCRYPT, key, IV);
// store the actual secretKey.length before any possible padding
encodedKeyLength = secretKey.length;
// for the secretKey to be encrypted, first ensure that it is aligned to the block size of the
// encryption algorithm by padding bytes appropriately if needed
secretKey = padKey(secretKey, tmpCipherProvider.getEncryptionBlockSize());
byte[] result = new byte[secretKey.length];
// encrypt the secretKey using the key generated of muck from boot password and the generated IV
tmpCipherProvider.encrypt(secretKey, 0, secretKey.length, result, 0);
String hexOutput = org.apache.derby.iapi.util.StringUtil.toHexString(result, 0, result.length);
return new EncryptedKeyResult(hexOutput, secretKey);
}
Aggregations