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:26:53 UTC

[jspwiki] branch master updated (7a7a588 -> c1b0dd4)

This is an automated email from the ASF dual-hosted git repository.

juanpablo pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git.


    from 7a7a588  code format & clean-up as suggested by IntelliJ
     new e17e573  feat: Add SHA-256 prefix and handling to password validation
     new d4b3d7c  feat: getHash method to use SHA-256 by default
     new c7810ea  refactor: Rename getOldHash private method to getShaHash
     new 8812bcd  feat: Add SHA-256 support to getSaltedPassword-method
     new 1a679bc  refactor: Replace SSHA term with SHA-1 when getting MessageDigest instance
     new bd7bdcb  feat: Add algorithm option to CLI
     new 9562256  feat: Add support for SHA_256 to password verification
     new 9140277  test: Update CryptoUtilTest
     new c1b0dd4  test: Update password hashes used with XMLUserDatabaseTest

The 9 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../wiki/auth/user/AbstractUserDatabase.java       |  34 +++----
 .../apache/wiki/auth/user/XMLUserDatabaseTest.java |  10 +-
 jspwiki-main/src/test/resources/userdatabase.xml   |   2 +-
 .../main/java/org/apache/wiki/util/CryptoUtil.java | 102 ++++++++++++---------
 .../java/org/apache/wiki/util/CryptoUtilTest.java  |  24 ++---
 5 files changed, 95 insertions(+), 77 deletions(-)

[jspwiki] 09/09: test: Update password hashes used with XMLUserDatabaseTest

Posted by ju...@apache.org.
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 c1b0dd47baa87dfaf052b9e70c7d3d75aaf1bdc1
Author: samhareem <sa...@museoliitto.fi>
AuthorDate: Sun Mar 28 12:10:42 2021 +0300

    test: Update password hashes used with XMLUserDatabaseTest
---
 .../java/org/apache/wiki/auth/user/XMLUserDatabaseTest.java    | 10 +++++-----
 jspwiki-main/src/test/resources/userdatabase.xml               |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/jspwiki-main/src/test/java/org/apache/wiki/auth/user/XMLUserDatabaseTest.java b/jspwiki-main/src/test/java/org/apache/wiki/auth/user/XMLUserDatabaseTest.java
index 7cb5958..7a2a013 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/auth/user/XMLUserDatabaseTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/auth/user/XMLUserDatabaseTest.java
@@ -117,7 +117,7 @@ public class XMLUserDatabaseTest {
             Assertions.assertEquals( "janne", profile.getLoginName() );
             Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
             Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
-            Assertions.assertEquals( "{SSHA}1WFv9OV11pD5IySgVH3sFa2VlCyYjbLrcVT/qw==", profile.getPassword() );
+            Assertions.assertEquals( "{SHA-256}AeJQgAgYDAf2WZiqPJ2l6cGdGC/PgWmkjZmkjrBEV6SW/HlclZGlIg==", profile.getPassword() );
             Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
         } catch( final NoSuchPrincipalException e ) {
             Assertions.assertTrue( false );
@@ -139,7 +139,7 @@ public class XMLUserDatabaseTest {
             Assertions.assertEquals( "janne", profile.getLoginName() );
             Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
             Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
-            Assertions.assertEquals( "{SSHA}1WFv9OV11pD5IySgVH3sFa2VlCyYjbLrcVT/qw==", profile.getPassword() );
+            Assertions.assertEquals( "{SHA-256}AeJQgAgYDAf2WZiqPJ2l6cGdGC/PgWmkjZmkjrBEV6SW/HlclZGlIg==", profile.getPassword() );
             Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
             Assertions.assertNotNull( profile.getCreated() );
             Assertions.assertNotNull( profile.getLastModified() );
@@ -163,7 +163,7 @@ public class XMLUserDatabaseTest {
             Assertions.assertEquals( "janne", profile.getLoginName() );
             Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
             Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
-            Assertions.assertEquals( "{SSHA}1WFv9OV11pD5IySgVH3sFa2VlCyYjbLrcVT/qw==", profile.getPassword() );
+            Assertions.assertEquals( "{SHA-256}AeJQgAgYDAf2WZiqPJ2l6cGdGC/PgWmkjZmkjrBEV6SW/HlclZGlIg==", profile.getPassword() );
             Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
             Assertions.assertNotNull( profile.getCreated() );
             Assertions.assertNotNull( profile.getLastModified() );
@@ -187,7 +187,7 @@ public class XMLUserDatabaseTest {
             Assertions.assertEquals( "janne", profile.getLoginName() );
             Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
             Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
-            Assertions.assertEquals( "{SSHA}1WFv9OV11pD5IySgVH3sFa2VlCyYjbLrcVT/qw==", profile.getPassword() );
+            Assertions.assertEquals( "{SHA-256}AeJQgAgYDAf2WZiqPJ2l6cGdGC/PgWmkjZmkjrBEV6SW/HlclZGlIg==", profile.getPassword() );
             Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
         } catch( final NoSuchPrincipalException e ) {
             Assertions.assertTrue( false );
@@ -209,7 +209,7 @@ public class XMLUserDatabaseTest {
             Assertions.assertEquals( "janne", profile.getLoginName() );
             Assertions.assertEquals( "Janne Jalkanen", profile.getFullname() );
             Assertions.assertEquals( "JanneJalkanen", profile.getWikiName() );
-            Assertions.assertEquals( "{SSHA}1WFv9OV11pD5IySgVH3sFa2VlCyYjbLrcVT/qw==", profile.getPassword() );
+            Assertions.assertEquals( "{SHA-256}AeJQgAgYDAf2WZiqPJ2l6cGdGC/PgWmkjZmkjrBEV6SW/HlclZGlIg==", profile.getPassword() );
             Assertions.assertEquals( "janne@ecyrd.com", profile.getEmail() );
         } catch( final NoSuchPrincipalException e ) {
             Assertions.assertTrue( false );
diff --git a/jspwiki-main/src/test/resources/userdatabase.xml b/jspwiki-main/src/test/resources/userdatabase.xml
index be8a817..5d095f8 100644
--- a/jspwiki-main/src/test/resources/userdatabase.xml
+++ b/jspwiki-main/src/test/resources/userdatabase.xml
@@ -19,7 +19,7 @@
 -->
 
 <users>
-  <user uid="-7739839977499061014" email="janne@ecyrd.com" fullName="Janne Jalkanen" loginName="janne" password="{SSHA}1WFv9OV11pD5IySgVH3sFa2VlCyYjbLrcVT/qw==" wikiName="JanneJalkanen" created="2006.06.25 at 14:50:54:000 EDT" lastModified="2006.01.26 at 14:50:54:000 EST">
+  <user uid="-7739839977499061014" email="janne@ecyrd.com" fullName="Janne Jalkanen" loginName="janne" password="{SHA-256}AeJQgAgYDAf2WZiqPJ2l6cGdGC/PgWmkjZmkjrBEV6SW/HlclZGlIg==" wikiName="JanneJalkanen" created="2006.06.25 at 14:50:54:000 EDT" lastModified="2006.01.26 at 14:50:54:000 EST">
     <attributes>rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAACdAAKYXR0cmlidXRlMXQAEXNvbWUgcmFuZG9tIHZhbHVldAAKYXR0cmlidXRlMnQADWFub3RoZXIgdmFsdWV4</attributes>
   </user>
   <user uid="-8629747547991531672" email="user@example.com" loginName="user" password="{SSHA}iQWmcKE8PyO965jh4+VNLYbxagaDdS0nC9GmuQ==" created="2006.06.25 at 14:50:54:000 EDT" lastModified="2006.01.26 at 14:50:54:000 EST"/>

[jspwiki] 05/09: refactor: Replace SSHA term with SHA-1 when getting MessageDigest instance

Posted by ju...@apache.org.
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 1a679bc4e29522969514a5b808029825f2836a11
Author: samhareem <sa...@museoliitto.fi>
AuthorDate: Wed Mar 24 18:52:02 2021 +0200

    refactor: Replace SSHA term with SHA-1 when getting MessageDigest instance
---
 jspwiki-util/src/main/java/org/apache/wiki/util/CryptoUtil.java | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

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 d99fce3..3fa9303 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
@@ -35,6 +35,8 @@ public final class CryptoUtil
 {
     private static final String SSHA = "{SSHA}";
 
+    private static final String SHA1 = "{SHA-1}";
+
     private static final String SHA256 = "{SHA-256}";
 
     private static final Random RANDOM = new SecureRandom();
@@ -169,7 +171,11 @@ public final class CryptoUtil
      */
     protected static String getSaltedPassword(final byte[] password, final byte[] salt, final String algorithm ) throws NoSuchAlgorithmException
     {
-        final MessageDigest digest = MessageDigest.getInstance( algorithm );
+        //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 );
 

[jspwiki] 03/09: refactor: Rename getOldHash private method to getShaHash

Posted by ju...@apache.org.
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 c7810eabc9c6735f45b0915aeb1f155aab5e70d8
Author: samhareem <sa...@museoliitto.fi>
AuthorDate: Wed Mar 24 17:54:07 2021 +0200

    refactor: Rename getOldHash private method to getShaHash
---
 .../main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java    | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java b/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java
index d1a2194..71982d4 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java
@@ -202,7 +202,7 @@ public abstract class AbstractUserDatabase implements UserDatabase {
             // Use older verification algorithm if password is stored as SHA
             if( storedPassword.startsWith( SHA_PREFIX ) ) {
                 storedPassword = storedPassword.substring( SHA_PREFIX.length() );
-                hashedPassword = getOldHash( password );
+                hashedPassword = getShaHash( password );
                 verified = hashedPassword.equals( storedPassword );
             }
 
@@ -270,7 +270,8 @@ public abstract class AbstractUserDatabase implements UserDatabase {
      * @return the result hash
      * @deprecated this method is retained for backwards compatibility purposes; use {@link #getHash(String, String)} instead
      */
-    String getOldHash( final String text ) {
+    @Deprecated
+    String getShaHash(final String text ) {
         try {
             final MessageDigest md = MessageDigest.getInstance( "SHA" );
             md.update( text.getBytes( StandardCharsets.UTF_8 ) );

[jspwiki] 07/09: feat: Add support for SHA_256 to password verification

Posted by ju...@apache.org.
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;
     }

[jspwiki] 08/09: test: Update CryptoUtilTest

Posted by ju...@apache.org.
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 9140277347cdb9a23f4a8b29f3e19be7e9e558f3
Author: samhareem <sa...@museoliitto.fi>
AuthorDate: Sat Mar 27 10:54:34 2021 +0200

    test: Update CryptoUtilTest
---
 .../java/org/apache/wiki/util/CryptoUtilTest.java  | 24 +++++++++++-----------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/jspwiki-util/src/test/java/org/apache/wiki/util/CryptoUtilTest.java b/jspwiki-util/src/test/java/org/apache/wiki/util/CryptoUtilTest.java
index 3f8ff25..06b43ec 100644
--- a/jspwiki-util/src/test/java/org/apache/wiki/util/CryptoUtilTest.java
+++ b/jspwiki-util/src/test/java/org/apache/wiki/util/CryptoUtilTest.java
@@ -46,7 +46,7 @@ public class CryptoUtilTest
         System.setOut( oldOut );
 
         // Run our tests
-        Assertions.assertTrue( output.startsWith( "{SSHA}" ) );
+        Assertions.assertTrue( output.startsWith( "{SHA-256}" ) );
     }
 
     @Test
@@ -74,7 +74,7 @@ public class CryptoUtilTest
     {
         // Try verifying password without the {SSHA} prefix
         try {
-            CryptoUtil.main( new String[] { "--verify", "password", "yfT8SRT/WoOuNuA6KbJeF10OznZmb28=" } );
+            CryptoUtil.main( new String[] { "--verify", "password", "yfT8SRT/WoOuNuA6KbJeF10OznZmb28=", "{SSHA}" } );
         }
         catch (final IllegalArgumentException e)
         {
@@ -107,13 +107,13 @@ public class CryptoUtilTest
         byte[] digest;
 
         digest = Base64.getDecoder().decode( "yfT8SRT/WoOuNuA6KbJeF10OznZmb28=".getBytes() );
-        Assertions.assertEquals( "foo", new String( CryptoUtil.extractSalt( digest ) ) );
+        Assertions.assertEquals( "foo", new String( CryptoUtil.extractSalt( digest, 20 ) ) );
 
         digest = Base64.getDecoder().decode( "tAVisOOQGAeVyP8UMFQY9qi83lxsb09e".getBytes() );
-        Assertions.assertEquals( "loO^", new String( CryptoUtil.extractSalt( digest ) ) );
+        Assertions.assertEquals( "loO^", new String( CryptoUtil.extractSalt( digest, 20 ) ) );
 
         digest = Base64.getDecoder().decode( "BZaDYvB8czmNW3MjR2j7/mklODV0ZXN0eQ==".getBytes() );
-        Assertions.assertEquals( "testy", new String( CryptoUtil.extractSalt( digest ) ) );
+        Assertions.assertEquals( "testy", new String( CryptoUtil.extractSalt( digest, 20 ) ) );
     }
 
     @Test
@@ -123,20 +123,20 @@ public class CryptoUtilTest
 
         // Generate a hash with a known password and salt
         password = "testing123".getBytes();
-        Assertions.assertEquals( "{SSHA}yfT8SRT/WoOuNuA6KbJeF10OznZmb28=", CryptoUtil.getSaltedPassword( password, "foo".getBytes() ) );
+        Assertions.assertEquals( "{SSHA}yfT8SRT/WoOuNuA6KbJeF10OznZmb28=", CryptoUtil.getSaltedPassword( password, "foo".getBytes(), "{SSHA}" ) );
 
         // Generate two hashes with a known password and 2 different salts
         password = "password".getBytes();
-        Assertions.assertEquals( "{SSHA}tAVisOOQGAeVyP8UMFQY9qi83lxsb09e", CryptoUtil.getSaltedPassword( password, "loO^".getBytes() ) );
-        Assertions.assertEquals( "{SSHA}BZaDYvB8czmNW3MjR2j7/mklODV0ZXN0eQ==", CryptoUtil.getSaltedPassword( password, "testy".getBytes() ) );
+        Assertions.assertEquals( "{SSHA}tAVisOOQGAeVyP8UMFQY9qi83lxsb09e", CryptoUtil.getSaltedPassword( password, "loO^".getBytes(), "{SSHA}" ) );
+        Assertions.assertEquals( "{SSHA}BZaDYvB8czmNW3MjR2j7/mklODV0ZXN0eQ==", CryptoUtil.getSaltedPassword( password, "testy".getBytes(), "{SSHA}" ) );
     }
 
     @Test
     public void testMultipleHashes() throws Exception
     {
-        final String p1 = CryptoUtil.getSaltedPassword( "password".getBytes() );
-        final String p2 = CryptoUtil.getSaltedPassword( "password".getBytes() );
-        final String p3 = CryptoUtil.getSaltedPassword( "password".getBytes() );
+        final String p1 = CryptoUtil.getSaltedPassword( "password".getBytes(), "{SSHA}" );
+        final String p2 = CryptoUtil.getSaltedPassword( "password".getBytes(), "{SSHA}" );
+        final String p3 = CryptoUtil.getSaltedPassword( "password".getBytes(), "{SSHA}" );
         Assertions.assertNotSame( p1, p2 );
         Assertions.assertNotSame( p2, p3 );
         Assertions.assertNotSame( p1, p3 );
@@ -147,7 +147,7 @@ public class CryptoUtilTest
     {
         // Generate a hash with a known password and salt
         final byte[] password = "mySooperRandomPassword".getBytes();
-        final String hash = CryptoUtil.getSaltedPassword( password, "salt".getBytes() );
+        final String hash = CryptoUtil.getSaltedPassword( password, "salt".getBytes(), "{SSHA}" );
 
         // slappasswd says that a 4-byte salt should give us 6 chars for prefix
         // + 20 chars for the hash + 12 for salt (38 total)

[jspwiki] 02/09: feat: getHash method to use SHA-256 by default

Posted by ju...@apache.org.
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 d4b3d7ce490ace39c36df6f4754a189597cf7ee6
Author: samhareem <sa...@museoliitto.fi>
AuthorDate: Wed Mar 24 18:23:10 2021 +0200

    feat: getHash method to use SHA-256 by default
---
 .../java/org/apache/wiki/auth/user/AbstractUserDatabase.java     | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java b/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java
index c738e88..d1a2194 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java
@@ -247,17 +247,18 @@ public abstract class AbstractUserDatabase implements UserDatabase {
     }
     
     /**
-     * Private method that calculates the salted SHA-1 hash of a given <code>String</code>. Note that as of JSPWiki 2.8, this method
+     * Private method that calculates the salted SHA-1 or SHA-256 hash of a given <code>String</code>. Note that as of JSPWiki 2.8, this method
      * calculates a <em>salted</em> hash rather than a plain hash.
      *
      * @param text the text to hash
+     * @param text the algorithm used for the hash
      * @return the result hash
      */
     protected String getHash( final String text ) {
         try {
-            return CryptoUtil.getSaltedPassword( text.getBytes(StandardCharsets.UTF_8 ) );
+            return CryptoUtil.getSaltedPassword( text.getBytes(StandardCharsets.UTF_8), SHA256_PREFIX );
         } catch( final NoSuchAlgorithmException e ) {
-            log.error( "Error creating salted SHA password hash:" + e.getMessage() );
+            log.error( String.format( "Error creating salted password hash: %s", e.getMessage() ) );
             return text;
         }
     }
@@ -267,7 +268,7 @@ public abstract class AbstractUserDatabase implements UserDatabase {
      *
      * @param text the text to hash
      * @return the result hash
-     * @deprecated this method is retained for backwards compatibility purposes; use {@link #getHash(String)} instead
+     * @deprecated this method is retained for backwards compatibility purposes; use {@link #getHash(String, String)} instead
      */
     String getOldHash( final String text ) {
         try {

[jspwiki] 01/09: feat: Add SHA-256 prefix and handling to password validation

Posted by ju...@apache.org.
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 e17e57331f0ae4129104cb3ba9e537d53b8f2060
Author: samhareem <sa...@museoliitto.fi>
AuthorDate: Wed Mar 24 17:52:32 2021 +0200

    feat: Add SHA-256 prefix and handling to password validation
---
 .../wiki/auth/user/AbstractUserDatabase.java       | 22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java b/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java
index 43f382d..c738e88 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/auth/user/AbstractUserDatabase.java
@@ -46,6 +46,7 @@ public abstract class AbstractUserDatabase implements UserDatabase {
     protected static final Logger log = Logger.getLogger( AbstractUserDatabase.class );
     protected static final String SHA_PREFIX = "{SHA}";
     protected static final String SSHA_PREFIX = "{SSHA}";
+    protected static final String SHA256_PREFIX = "{SHA-256}";
 
     /**
      * Looks up and returns the first {@link UserProfile} in the user database that whose login name, full name, or wiki name matches the
@@ -187,29 +188,26 @@ public abstract class AbstractUserDatabase implements UserDatabase {
      */
     @Override
     public boolean validatePassword( final String loginName, final String password ) {
-        final String hashedPassword;
+        String hashedPassword;
         try {
             final UserProfile profile = findByLoginName( loginName );
             String storedPassword = profile.getPassword();
+            boolean verified = false;
 
-            // Is the password stored as a salted hash (the new 2.8 format?)
-            final boolean newPasswordFormat = storedPassword.startsWith( SSHA_PREFIX );
-
-            // If new format, verify the hash
-            if( newPasswordFormat ) {
-                hashedPassword = getHash( password );
-                return CryptoUtil.verifySaltedPassword( password.getBytes( StandardCharsets.UTF_8 ), storedPassword );
+            // If the password is stored as SHA-256 or SSHA, verify the hash
+            if( storedPassword.startsWith( SHA256_PREFIX ) || storedPassword.startsWith( SSHA_PREFIX ) ) {
+                verified = CryptoUtil.verifySaltedPassword( password.getBytes( StandardCharsets.UTF_8 ), storedPassword );
             }
 
-            // If old format, verify using the old SHA verification algorithm
+            // Use older verification algorithm if password is stored as SHA
             if( storedPassword.startsWith( SHA_PREFIX ) ) {
                 storedPassword = storedPassword.substring( SHA_PREFIX.length() );
+                hashedPassword = getOldHash( password );
+                verified = hashedPassword.equals( storedPassword );
             }
-            hashedPassword = getOldHash( password );
-            final boolean verified = hashedPassword.equals( storedPassword );
 
             // If in the old format and password verified, upgrade the hash to SSHA
-            if( verified ) {
+            if( verified && !storedPassword.startsWith( SHA256_PREFIX ) ) {
                 profile.setPassword( password );
                 save( profile );
             }

[jspwiki] 04/09: feat: Add SHA-256 support to getSaltedPassword-method

Posted by ju...@apache.org.
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 8812bcdc7e447ffd2742a56e5fc7420b1ecb948c
Author: samhareem <sa...@museoliitto.fi>
AuthorDate: Wed Mar 24 18:43:00 2021 +0200

    feat: Add SHA-256 support to getSaltedPassword-method
---
 .../main/java/org/apache/wiki/util/CryptoUtil.java | 31 ++++++++++++----------
 1 file changed, 17 insertions(+), 14 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 691a37b..d99fce3 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
@@ -35,6 +35,8 @@ public final class CryptoUtil
 {
     private static final String SSHA = "{SSHA}";
 
+    private static final String SHA256 = "{SHA-256}";
+
     private static final Random RANDOM = new SecureRandom();
 
     private static final int DEFAULT_SALT_SIZE = 8;
@@ -118,8 +120,8 @@ public final class CryptoUtil
 
     /**
      * <p>
-     * Creates an RFC 2307-compliant salted, hashed password with the SHA1
-     * MessageDigest algorithm. After the password is digested, the first 20
+     * Creates an RFC 2307-compliant salted, hashed password with the SHA1 or SHA-256
+     * MessageDigest algorithm. After the password is digested, the first 20 or 32
      * bytes of the digest will be the actual password hash; the remaining bytes
      * will be a randomly generated salt of length {@link #DEFAULT_SALT_SIZE},
      * for example: <blockquote><code>{SSHA}3cGWem65NCEkF5Ew5AEk45ak8LHUWAwPVXAyyw==</code></blockquote>
@@ -136,23 +138,24 @@ public final class CryptoUtil
      * 
      * @param password the password to be digested
      * @return the Base64-encoded password hash, prepended by
-     *         <code>{SSHA}</code>.
-     * @throws NoSuchAlgorithmException If your JVM is completely b0rked and does not have SHA.
+     *         <code>{SSHA}</code> or <code>{SHA256}</code>.
+     * @throws NoSuchAlgorithmException If your JVM does not supply the necessary algorithm. Should not happen.
      */
-    public static String getSaltedPassword(final byte[] password ) throws NoSuchAlgorithmException
+    public static String getSaltedPassword(final byte[] password, final String algorithm ) throws NoSuchAlgorithmException
     {
         final byte[] salt = new byte[DEFAULT_SALT_SIZE];
         RANDOM.nextBytes( salt );
-        return getSaltedPassword( password, salt );
+
+        return getSaltedPassword( password, salt, algorithm );
     }
 
     /**
      * <p>
-     * Helper method that creates an RFC 2307-compliant salted, hashed password with the SHA1
-     * MessageDigest algorithm. After the password is digested, the first 20
+     * Helper method that creates an RFC 2307-compliant salted, hashed password with the SHA1 or SHA256
+     * MessageDigest algorithm. After the password is digested, the first 20 or 32
      * bytes of the digest will be the actual password hash; the remaining bytes
      * will be the salt. Thus, supplying a password <code>testing123</code>
-     * and a random salt <code>foo</code> produces the hash:
+     * and a random salt <code>foo</code> produces the hash when using SHA1:
      * </p>
      * <blockquote><code>{SSHA}yfT8SRT/WoOuNuA6KbJeF10OznZmb28=</code></blockquote>
      * <p>
@@ -161,12 +164,12 @@ public final class CryptoUtil
      * 
      * @param password the password to be digested
      * @param salt the random salt
-     * @return the Base64-encoded password hash, prepended by <code>{SSHA}</code>.
-     * @throws NoSuchAlgorithmException If your JVM is totally b0rked and does not have SHA1.
+     * @return the Base64-encoded password hash, prepended by <code>{SSHA}</code> or <code>{SHA256}</code>.
+     * @throws NoSuchAlgorithmException If your JVM does not supply the necessary algorithm. Should not happen.
      */
-    protected static String getSaltedPassword(final byte[] password, final byte[] salt ) throws NoSuchAlgorithmException
+    protected static String getSaltedPassword(final byte[] password, final byte[] salt, final String algorithm ) throws NoSuchAlgorithmException
     {
-        final MessageDigest digest = MessageDigest.getInstance( "SHA" );
+        final MessageDigest digest = MessageDigest.getInstance( algorithm );
         digest.update( password );
         final byte[] hash = digest.digest( salt );
 
@@ -176,7 +179,7 @@ public final class CryptoUtil
         System.arraycopy(salt, 0, all, hash.length + 0, salt.length);
         final byte[] base64 = Base64.getEncoder().encode( all );
         
-        return SSHA + new String( base64, StandardCharsets.UTF_8 );
+        return algorithm + new String( base64, StandardCharsets.UTF_8 );
     }
 
     /**

[jspwiki] 06/09: feat: Add algorithm option to CLI

Posted by ju...@apache.org.
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 bd7bdcbf83dad20b1fda9fc0a6e073d39e663b0f
Author: samhareem <sa...@museoliitto.fi>
AuthorDate: Wed Mar 24 18:58:13 2021 +0200

    feat: Add algorithm option to CLI
---
 .../src/main/java/org/apache/wiki/util/CryptoUtil.java    | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 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 3fa9303..f0d734a 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
@@ -58,13 +58,13 @@ public final class CryptoUtil
 
     /**
      * <p>
-     * Convenience method for hashing and verifying salted SHA-1 passwords from
+     * Convenience method for hashing and verifying salted SHA-1 or SHA-256 passwords from
      * the command line. This method requires <code>commons-codec-1.3.jar</code>
      * (or a newer version) to be on the classpath. Command line arguments are
      * as follows:
      * </p>
      * <ul>
-     * <li><code>--hash <var>password</var></code> - hashes <var>password</var></code>
+     * <li><code>--hash <var>password</var> SSHA</code> - hashes <var>password</var></code>
      * and prints a password digest that looks like this: <blockquote><code>{SSHA}yfT8SRT/WoOuNuA6KbJeF10OznZmb28=</code></blockquote></li>
      * <li><code>--verify <var>password</var> <var>digest</var></code> -
      * verifies <var>password</var> by extracting the salt from <var>digest</var>
@@ -86,9 +86,9 @@ public final class CryptoUtil
         if( args.length == 0 || (args.length == 1 && HELP.equals( args[0] )) )
         {
             System.out.println( "Usage: CryptoUtil [options] " );
-            System.out.println( "   --hash   password             create hash for password" );
-            System.out.println( "   --verify password digest      verify password for digest" );
-            System.exit( 0 );
+            System.out.println( "   --hash   password algorithm             create hash for password" );
+            System.out.println( "   --verify password digest algorithm      verify password for digest" );
+            System.out.println( "Valid algorithm options are {SSHA} and {SHA-256}. If no algorithm is specified or an unsupported algorithm is specified, SHA-256 is used." );
         }
 
         // User wants to hash the password
@@ -99,7 +99,9 @@ public final class CryptoUtil
                 throw new IllegalArgumentException( "Error: --hash requires a 'password' argument." );
             }
             final String password = args[1].trim();
-            System.out.println( CryptoUtil.getSaltedPassword( password.getBytes( StandardCharsets.UTF_8 ) ) );
+            final String algorithm = args.length > 2 ? args[2].trim() : SHA256;
+
+            System.out.println( CryptoUtil.getSaltedPassword( password.getBytes( StandardCharsets.UTF_8 ), algorithm ) );
         }
 
         // User wants to verify an existing password
@@ -111,6 +113,7 @@ public final class CryptoUtil
             }
             final String password = args[1].trim();
             final String digest = args[2].trim();
+
             System.out.println( CryptoUtil.verifySaltedPassword( password.getBytes( StandardCharsets.UTF_8 ), digest ) );
         }