Search in sources :

Example 1 with CipherProvider

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);
}
Also used : CipherProvider(org.apache.derby.iapi.services.crypto.CipherProvider)

Example 2 with CipherProvider

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;
}
Also used : StorageRandomAccessFile(org.apache.derby.io.StorageRandomAccessFile) DataInputStream(java.io.DataInputStream) InputStream(java.io.InputStream) CipherProvider(org.apache.derby.iapi.services.crypto.CipherProvider) IOException(java.io.IOException) DataInputStream(java.io.DataInputStream)

Example 3 with CipherProvider

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);
}
Also used : SecretKey(javax.crypto.SecretKey) CipherProvider(org.apache.derby.iapi.services.crypto.CipherProvider)

Aggregations

CipherProvider (org.apache.derby.iapi.services.crypto.CipherProvider)3 DataInputStream (java.io.DataInputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 SecretKey (javax.crypto.SecretKey)1 StorageRandomAccessFile (org.apache.derby.io.StorageRandomAccessFile)1