diff --git a/java/client/org/apache/derby/client/am/EncryptionManager.java b/java/client/org/apache/derby/client/am/EncryptionManager.java index e62c02dd2f..054f2944a6 100644 --- a/java/client/org/apache/derby/client/am/EncryptionManager.java +++ b/java/client/org/apache/derby/client/am/EncryptionManager.java @@ -525,7 +525,7 @@ public byte[] generateSeed() { /** * Strong Password Substitution (USRSSBPWD). * - * This method generate a password subtitute to send to the target + * This method generates a password substitute to send to the target * server. * * Substitution algorithm works as follow: @@ -587,6 +587,15 @@ public byte[] substitutePassword( // // Encrypt the password as it is done by the derby engine - Note that // this code (logic) is not shared yet - will be in next revision. + // + // Note that this code assumes that the Derby engine has encrypted + // the password using one particular algorithm (based on SHA-1). After + // DERBY-4483, it is possible that the engine uses another algorithm. + // Since the engine has no way to decrypt the encrypted password, it + // has no way to compared the stored password with the hash we send, so + // authentication will fail unless the engine actually uses the SHA-1 + // based scheme. + messageDigest.reset(); messageDigest.update(this.toHexByte(password, 0, password.length())); diff --git a/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java b/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java index 5654d93701..8bcda92e97 100644 --- a/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java +++ b/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java @@ -8464,6 +8464,8 @@ private void finalizeChain() throws DRDAProtocolException { * SECMEC_USRSSBPWD is ONLY supported by the target server if: * - current authentication provider is Derby BUILTIN or * NONE. (database / system level) (Phase I) + * - database-level password must have been encrypted with the + * SHA-1 based authentication scheme * - Application requester is 'DNC' (Derby Network Client) * (Phase I) * diff --git a/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java b/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java index 1ae8aa7013..851738756c 100644 --- a/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java +++ b/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java @@ -594,7 +594,7 @@ private static DataDictionary getDataDictionary() { /** * Strong Password Substitution (USRSSBPWD). * - * This method generate a password subtitute to authenticate a client + * This method generates a password substitute to authenticate a client * which is using a DRDA security mechanism such as SECMEC_USRSSBPWD. * * Depending how the user is defined in Derby and if BUILTIN @@ -605,6 +605,17 @@ private static DataDictionary getDataDictionary() { * generate a substitute password coming from the store to compare with * the one passed-in. * + * The substitution algorithm used is the same as the one used in the + * SHA-1 authentication scheme ({@link #ID_PATTERN_SHA1_SCHEME}), so in + * the case of database passwords stored using that scheme, we can simply + * compare the received hash with the stored hash. If the configurable + * hash authentication scheme {@link #ID_PATTERN_CONFIGURABLE_HASH_SCHEME} + * is used, we have no way to find out if the received hash matches the + * stored password, since we cannot decrypt the hashed passwords and + * re-apply another hash algorithm. Therefore, strong password substitution + * only works if the database-level passwords are stored with the SHA-1 + * scheme. + * * NOTE: A lot of this logic could be shared with the DRDA decryption * and client encryption managers - This will be done _once_ * code sharing along with its rules are defined between the @@ -633,9 +644,6 @@ protected String substitutePassword( MessageDigest messageDigest = null; - // Pattern that is prefixed to the BUILTIN encrypted password - String ID_PATTERN_NEW_SCHEME = "3b60"; - // PWSEQs's 8-byte value constant - See DRDA Vol 3 byte SECMEC_USRSSBPWD_PWDSEQS[] = { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -694,12 +702,21 @@ protected String substitutePassword( bytePasswd = StringUtil.toHexByte(password, 0, password.length()); messageDigest.update(bytePasswd); byte[] encryptVal = messageDigest.digest(); - hexString = ID_PATTERN_NEW_SCHEME + + hexString = ID_PATTERN_SHA1_SCHEME + StringUtil.toHexString(encryptVal, 0, encryptVal.length); } else + { // Already encrypted from the database store + // NOTE: If the password was stored with the configurable hash + // authentication scheme, the stored password will have been hashed + // with a different algorithm than the hashed password sent from + // the client. Since there's no way to decrypt the stored password + // and rehash it with the algorithm that the client uses, we are + // not able to compare the passwords, and the connection attempt + // will fail. hexString = password; + } // Generate the password substitute now