You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by ju...@apache.org on 2021/04/24 09:27:00 UTC
[jspwiki] 07/09: feat: Add support for SHA_256 to password
verification
This is an automated email from the ASF dual-hosted git repository.
juanpablo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git
commit 956225660863eef05bf0dea54ffccbca4a7d8222
Author: samhareem <sa...@museoliitto.fi>
AuthorDate: Sat Mar 27 10:42:21 2021 +0200
feat: Add support for SHA_256 to password verification
---
.../main/java/org/apache/wiki/util/CryptoUtil.java | 50 ++++++++++++----------
1 file changed, 28 insertions(+), 22 deletions(-)
diff --git a/jspwiki-util/src/main/java/org/apache/wiki/util/CryptoUtil.java b/jspwiki-util/src/main/java/org/apache/wiki/util/CryptoUtil.java
index f0d734a..d11961e 100644
--- a/jspwiki-util/src/main/java/org/apache/wiki/util/CryptoUtil.java
+++ b/jspwiki-util/src/main/java/org/apache/wiki/util/CryptoUtil.java
@@ -193,7 +193,7 @@ public final class CryptoUtil
/**
* Compares a password to a given entry and returns true, if it matches.
- *
+ *
* @param password The password in bytes.
* @param entry The password entry, typically starting with {SSHA}.
* @return True, if the password matches.
@@ -201,19 +201,25 @@ public final class CryptoUtil
*/
public static boolean verifySaltedPassword(final byte[] password, final String entry ) throws NoSuchAlgorithmException
{
- // First, extract everything after {SSHA} and decode from Base64
- if( !entry.startsWith( SSHA ) )
+ if( !entry.startsWith( SSHA ) && !entry.startsWith( SHA256 ) )
{
- throw new IllegalArgumentException( "Hash not prefixed by {SSHA}; is it really a salted hash?" );
+ throw new IllegalArgumentException( "Hash not prefixed by expected algorithm; is it really a salted hash?" );
}
- final byte[] challenge = Base64.getDecoder().decode( entry.substring( 6 ).getBytes( StandardCharsets.UTF_8 ) );
+ String algorithm = entry.startsWith( SSHA ) ? SSHA : SHA256;
+
+ final byte[] challenge = Base64.getDecoder().decode( entry.substring( algorithm.length() )
+ .getBytes( StandardCharsets.UTF_8 ) );
// Extract the password hash and salt
- final byte[] passwordHash = extractPasswordHash( challenge );
- final byte[] salt = extractSalt( challenge );
+ final byte[] passwordHash = extractPasswordHash( challenge, algorithm.equals(SSHA) ? 20 : 32 );
+ final byte[] salt = extractSalt( challenge, algorithm.equals(SSHA) ? 20 : 32 );
// Re-create the hash using the password and the extracted salt
- final MessageDigest digest = MessageDigest.getInstance( "SHA" );
+ // The term SSHA is used as a password prefix for backwards compatibility, but we use SHA-1 when fetching an instance
+ // of MessageDigest, as it is the guaranteed option. We also need to remove curly braces surrounding the string for
+ // backwards compatibility.
+ String algorithmToUse = algorithm.equals(SSHA) ? SHA1 : algorithm;
+ final MessageDigest digest = MessageDigest.getInstance( algorithmToUse.substring( 1, algorithmToUse.length() -1 ) );
digest.update( password );
final byte[] hash = digest.digest( salt );
@@ -222,8 +228,8 @@ public final class CryptoUtil
}
/**
- * Helper method that extracts the hashed password fragment from a supplied salted SHA digest
- * by taking all of the characters before position 20.
+ * Helper method that extracts the hashed password fragment from a supplied salted SHA-1 or SHA-256 digest
+ * by taking all of the characters before position 20 or 32 depending on algorithm.
*
* @param digest the salted digest, which is assumed to have been
* previously decoded from Base64.
@@ -231,40 +237,40 @@ public final class CryptoUtil
* @throws IllegalArgumentException if the length of the supplied digest is
* less than or equal to 20 bytes
*/
- protected static byte[] extractPasswordHash(final byte[] digest ) throws IllegalArgumentException
+ protected static byte[] extractPasswordHash(final byte[] digest, final int hashLength ) throws IllegalArgumentException
{
- if( digest.length < 20 )
+ if( digest.length < hashLength )
{
- throw new IllegalArgumentException( "Hash was less than 20 characters; could not extract password hash!" );
+ throw new IllegalArgumentException( "Hash was shorter than expected; could not extract password hash!" );
}
// Extract the password hash
- final byte[] hash = new byte[20];
- System.arraycopy(digest, 0, hash, 0, 20);
+ final byte[] hash = new byte[hashLength];
+ System.arraycopy(digest, 0, hash, 0, hashLength);
return hash;
}
/**
* Helper method that extracts the salt from supplied salted digest by taking all of the
- * characters at position 20 and higher.
+ * characters after a given index.
*
* @param digest the salted digest, which is assumed to have been previously
* decoded from Base64.
* @return the salt
* @throws IllegalArgumentException if the length of the supplied digest is
- * less than or equal to 20 bytes
+ * less than given length.
*/
- protected static byte[] extractSalt(final byte[] digest ) throws IllegalArgumentException
+ protected static byte[] extractSalt(final byte[] digest, final int hashLength ) throws IllegalArgumentException
{
- if( digest.length <= 20 )
+ if( digest.length <= hashLength )
{
- throw new IllegalArgumentException( "Hash was less than 21 characters; we found no salt!" );
+ throw new IllegalArgumentException( "Hash was shorter than expected; we found no salt!" );
}
// Extract the salt
- final byte[] salt = new byte[digest.length - 20];
- System.arraycopy(digest, 20, salt, 0, digest.length - 20);
+ final byte[] salt = new byte[digest.length - hashLength];
+ System.arraycopy(digest, hashLength, salt, 0, digest.length - hashLength);
return salt;
}