You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by le...@flowlogix.com on 2025/10/21 18:26:20 UTC

BCrypt algorithm usage in Shiro 2 - Does anyone use it?

Hi,

Just taking a quick survey if anyone is using BCrypt (2y) etc. algorithm.
It’s currently very difficult to use and should be renamed to bcrypt2y, etc.

Thank you.

Re: BCrypt algorithm usage in Shiro 2 - Does anyone use it?

Posted by le...@flowlogix.com.
- Notice the “$2y$” which signifies the BCrypt usage. I am trying to figure out if it’ll break compatibility to use “$bcrypt2y” instead of “2y”
or does this need to be pushed to Shirov3.

> On Oct 21, 2025, at 9:15 PM, lenny@flowlogix.com wrote:
> 
> Thanks for your quick response.
> Just to clarify, your records in the password database look something like this:
> 
> $shiro2$2y$10$EiVaDycDiJG1O24MqXb6F.42YtW.3VDpMAwDkC0N8JZehp52o9q32
> 
> Is that correct?
> 
>> On Oct 21, 2025, at 7:58 PM, Andreas Reichel <an...@manticore-projects.com> wrote:
>> 
>> On Tue, 2025-10-21 at 13:26 -0500, lenny@flowlogix.com wrote:
>>> Hi,
>>> 
>>> Just taking a quick survey if anyone is using BCrypt (2y) etc. algorithm.
>>> It’s currently very difficult to use and should be renamed to bcrypt2y, etc.
>>> 
>>> Thank you.
>> 
>> 
>> Greetings Lenni and Team,
>> 
>> yes we do since our database solution stores in BCrypt format.
>> 
>> Cheers and best
>> Andreas
> 


Re: BCrypt algorithm usage in Shiro 2 - Does anyone use it?

Posted by le...@flowlogix.com.
Thank you Andreas, this doesn’t look like it’s affected.

> On Oct 21, 2025, at 9:38 PM, Andreas Reichel <an...@manticore-projects.com> wrote:
> 
> Lenny
> 
> I just checked: We implemented our own realm when our patch did not get accepted. That has been a long time ago and I can't remember the details.
> So technically we are using BCrypt but are not affected when Shiro changed anything about it.
> 
> Sorry for any confusion. I don't touch this stuff too often.
> 
> Best and cheers
> Andreas
> 
> protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
>         throws AuthenticationException {
> 
>     UsernamePasswordToken upToken = (UsernamePasswordToken) token;
>     String username = upToken.getUsername();
> 
>     // Null username is invalid
>     if (username == null) {
>         throw new AccountException("Null usernames are not allowed by this realm.");
>     }
> 
>     Connection conn = null;
>     SimpleAuthenticationInfo info = null;
>     try {
>         conn = dataSource.getConnection();
> 
>         String password = null;
>         String salt = null;
>         switch (saltStyle) {
>             case NO_SALT:
>                 password = getPasswordForUser(conn, username)[0];
>                 break;
>             case CRYPT:
>                 /*
>                  * http://www.slashroot.in/how-are-passwords-stored-linux-understanding-hashing-
>                  * shadow-utils
>                  * 
>                  * Example: $1$Etg2ExUZ$F9NTP7omafhKIlqaBMqng1
>                  * 
>                  * The above shown encoded hash value can be further classified into three
>                  * different fields as below. 1. The first field is a numerical number that
>                  * tell's you the hashing algorithm that's being used.
>                  * 
>                  * $1 = MD5 hashing algorithm. $2 =Blowfish Algorithm is in use. $2a=eksblowfish
>                  * Algorithm $5 =SHA-256 Algorithm $6 =SHA-512 Algorithm
>                  * 
>                  * 2. The second field is the salt value Salt value is nothing but a random data
>                  * that's generated to combine with the original password, inorder to increase
>                  * the strength of the hash..
>                  * 
>                  * 3.The last field is the hash value of salt+user password (we will be
>                  * discussing this shortly).
>                  * 
>                  */
> 
>                 String[] crypt = getPasswordForUser(conn, username)[0].split("\\$");
>                 CredentialsMatcher credentialsMatcher = getCredentialsMatcher();
>                 if (credentialsMatcher instanceof HashedCredentialsMatcher) {
>                     HashedCredentialsMatcher hashedCredentialsMatcher =
>                             (HashedCredentialsMatcher) credentialsMatcher;
> 
>                     switch (crypt.length) {
>                         // hash algorithm is not set
>                         case 3:
> 
>                             // Hex decoding is ugly and should not be used really
>                             salt = hashedCredentialsMatcher.isStoredCredentialsHexEncoded()
>                                     ? new String(Hex.decode(crypt[1]))
>                                     : Base64.decodeToString(crypt[1]);
>                             password = crypt[2];
>                             break;
> 
>                         // hash algorithm is set
>                         case 4:
>                             String hashAlgorithm = crypt[1];
>                             if (hashAlgorithm.equals("6"))
>                                 hashedCredentialsMatcher
>                                         .setHashAlgorithmName(Sha512Hash.ALGORITHM_NAME);
>                             else if (hashAlgorithm.equals("5"))
>                                 hashedCredentialsMatcher
>                                         .setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
>                             else if (hashAlgorithm.equals("1"))
>                                 hashedCredentialsMatcher
>                                         .setHashAlgorithmName(Md5Hash.ALGORITHM_NAME);
>                             else if (hashAlgorithm.equals("2"))
>                                 throw new AuthenticationException(
>                                         "Requested 'Blowfish' algorithm is not supported. Can not validate the token.");
>                             else if (hashAlgorithm.equals("2a"))
>                                 throw new AuthenticationException(
>                                         "Requested 'eksblowfish' algorithm is not supported. Can not validate the token.");
> 
>                             setCredentialsMatcher(credentialsMatcher);
> 
>                             // Hex decoding is ugly and should not be used really
>                             salt = hashedCredentialsMatcher.isStoredCredentialsHexEncoded()
>                                     ? new String(Hex.decode(crypt[2]))
>                                     : Base64.decodeToString(crypt[2]);
> 
>                             password = crypt[3];
>                             break;
>                         default:
>                             throw new AuthenticationException(
>                                     "Unable to parse 'crypt' from password. Can not validate the token.");
>                     }
>                 }
> 
>                 break;
>             case COLUMN:
>                 String[] queryResults = getPasswordForUser(conn, username);
>                 password = queryResults[0];
>                 salt = queryResults[1];
>                 break;
>             case EXTERNAL:
>                 password = getPasswordForUser(conn, username)[0];
>                 salt = getSaltForUser(username);
>         }
> 
>         if (password == null) {
>             throw new UnknownAccountException("No account found for user [" + username + "]");
>         }
> 
>         info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());
> 
>         if (salt != null) {
>             info.setCredentialsSalt(ByteSource.Util.bytes(salt));
>         }
> 
>     } catch (SQLException e) {
>         final String message =
>                 "There was a SQL error while authenticating user [" + username + "]";
>         LOGGER.log(Level.SEVERE, message, e);
> 
>         // Rethrow any SQL errors as an authentication exception
>         throw new AuthenticationException(message, e);
>     } finally {
>         JdbcUtils.closeConnection(conn);
>     }
> 
>     return info;
> }
> 
> On Tue, 2025-10-21 at 21:15 -0500, lenny@flowlogix.com wrote:
>> Thanks for your quick response.
>> Just to clarify, your records in the password database look something like this:
>> 
>> $shiro2$2y$10$EiVaDycDiJG1O24MqXb6F.42YtW.3VDpMAwDkC0N8JZehp52o9q32
>> 
>> Is that correct?
>> 
>>> On Oct 21, 2025, at 7:58 PM, Andreas Reichel <an...@manticore-projects.com> wrote:
>>> 
>>> On Tue, 2025-10-21 at 13:26 -0500, lenny@flowlogix.com wrote:
>>>> Hi,
>>>> 
>>>> Just taking a quick survey if anyone is using BCrypt (2y) etc. algorithm.
>>>> It’s currently very difficult to use and should be renamed to bcrypt2y, etc.
>>>> 
>>>> Thank you.
>>> 
>>> 
>>> Greetings Lenni and Team,
>>> 
>>> yes we do since our database solution stores in BCrypt format.
>>> 
>>> Cheers and best
>>> Andreas


Re: BCrypt algorithm usage in Shiro 2 - Does anyone use it?

Posted by Andreas Reichel <an...@manticore-projects.com>.
Lenny

I just checked: We implemented our own realm when our patch did not get
accepted. That has been a long time ago and I can't remember the
details.
So technically we are using BCrypt but are not affected when Shiro
changed anything about it.

Sorry for any confusion. I don't touch this stuff too often.

Best and cheers
Andreas

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
        throws AuthenticationException {

    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
    String username = upToken.getUsername();

    // Null username is invalid
    if (username == null) {
        throw new AccountException("Null usernames are not allowed by this realm.");
    }

    Connection conn = null;
    SimpleAuthenticationInfo info = null;
    try {
        conn = dataSource.getConnection();

        String password = null;
        String salt = null;
        switch (saltStyle) {
            case NO_SALT:
                password = getPasswordForUser(conn, username)[0];
                break;
            case CRYPT:
                /*
                 * http://www.slashroot.in/how-are-passwords-stored-linux-understanding-hashing-
                 * shadow-utils
                 * 
                 * Example: $1$Etg2ExUZ$F9NTP7omafhKIlqaBMqng1
                 * 
                 * The above shown encoded hash value can be further classified into three
                 * different fields as below. 1. The first field is a numerical number that
                 * tell's you the hashing algorithm that's being used.
                 * 
                 * $1 = MD5 hashing algorithm. $2 =Blowfish Algorithm is in use. $2a=eksblowfish
                 * Algorithm $5 =SHA-256 Algorithm $6 =SHA-512 Algorithm
                 * 
                 * 2. The second field is the salt value Salt value is nothing but a random data
                 * that's generated to combine with the original password, inorder to increase
                 * the strength of the hash..
                 * 
                 * 3.The last field is the hash value of salt+user password (we will be
                 * discussing this shortly).
                 * 
                 */

                String[] crypt = getPasswordForUser(conn, username)[0].split("\\$");
                CredentialsMatcher credentialsMatcher = getCredentialsMatcher();
                if (credentialsMatcher instanceof HashedCredentialsMatcher) {
                    HashedCredentialsMatcher hashedCredentialsMatcher =
                            (HashedCredentialsMatcher) credentialsMatcher;

                    switch (crypt.length) {
                        // hash algorithm is not set
                        case 3:

                            // Hex decoding is ugly and should not be used really
                            salt = hashedCredentialsMatcher.isStoredCredentialsHexEncoded()
                                    ? new String(Hex.decode(crypt[1]))
                                    : Base64.decodeToString(crypt[1]);
                            password = crypt[2];
                            break;

                        // hash algorithm is set
                        case 4:
                            String hashAlgorithm = crypt[1];
                            if (hashAlgorithm.equals("6"))
                                hashedCredentialsMatcher
                                        .setHashAlgorithmName(Sha512Hash.ALGORITHM_NAME);
                            else if (hashAlgorithm.equals("5"))
                                hashedCredentialsMatcher
                                        .setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
                            else if (hashAlgorithm.equals("1"))
                                hashedCredentialsMatcher
                                        .setHashAlgorithmName(Md5Hash.ALGORITHM_NAME);
                            else if (hashAlgorithm.equals("2"))
                                throw new AuthenticationException(
                                        "Requested 'Blowfish' algorithm is not supported. Can not validate the token.");
                            else if (hashAlgorithm.equals("2a"))
                                throw new AuthenticationException(
                                        "Requested 'eksblowfish' algorithm is not supported. Can not validate the token.");

                            setCredentialsMatcher(credentialsMatcher);

                            // Hex decoding is ugly and should not be used really
                            salt = hashedCredentialsMatcher.isStoredCredentialsHexEncoded()
                                    ? new String(Hex.decode(crypt[2]))
                                    : Base64.decodeToString(crypt[2]);

                            password = crypt[3];
                            break;
                        default:
                            throw new AuthenticationException(
                                    "Unable to parse 'crypt' from password. Can not validate the token.");
                    }
                }

                break;
            case COLUMN:
                String[] queryResults = getPasswordForUser(conn, username);
                password = queryResults[0];
                salt = queryResults[1];
                break;
            case EXTERNAL:
                password = getPasswordForUser(conn, username)[0];
                salt = getSaltForUser(username);
        }

        if (password == null) {
            throw new UnknownAccountException("No account found for user [" + username + "]");
        }

        info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());

        if (salt != null) {
            info.setCredentialsSalt(ByteSource.Util.bytes(salt));
        }

    } catch (SQLException e) {
        final String message =
                "There was a SQL error while authenticating user [" + username + "]";
        LOGGER.log(Level.SEVERE, message, e);

        // Rethrow any SQL errors as an authentication exception
        throw new AuthenticationException(message, e);
    } finally {
        JdbcUtils.closeConnection(conn);
    }

    return info;
}

On Tue, 2025-10-21 at 21:15 -0500, lenny@flowlogix.com wrote:
> Thanks for your quick response.
> Just to clarify, your records in the password database look something
> like this:
> 
> $shiro2$2y$10$EiVaDycDiJG1O24MqXb6F.42YtW.3VDpMAwDkC0N8JZehp52o9q32
> 
> Is that correct?
> 
> > On Oct 21, 2025, at 7:58 PM, Andreas Reichel <andreas@manticore-
> > projects.com> wrote:
> > 
> > 
> > On Tue, 2025-10-21 at 13:26 -0500, lenny@flowlogix.com wrote:
> > > Hi,
> > > 
> > > Just taking a quick survey if anyone is using BCrypt (2y) etc.
> > > algorithm.
> > > It’s currently very difficult to use and should be renamed to
> > > bcrypt2y, etc.
> > > 
> > > Thank you.
> > 
> > 
> > 
> > Greetings Lenni and Team,
> > 
> > yes we do since our database solution stores in BCrypt format.
> > 
> > Cheers and best
> > Andreas
> 

Re: BCrypt algorithm usage in Shiro 2 - Does anyone use it?

Posted by le...@flowlogix.com.
Thanks for your quick response.
Just to clarify, your records in the password database look something like this:

$shiro2$2y$10$EiVaDycDiJG1O24MqXb6F.42YtW.3VDpMAwDkC0N8JZehp52o9q32

Is that correct?

> On Oct 21, 2025, at 7:58 PM, Andreas Reichel <an...@manticore-projects.com> wrote:
> 
> On Tue, 2025-10-21 at 13:26 -0500, lenny@flowlogix.com wrote:
>> Hi,
>> 
>> Just taking a quick survey if anyone is using BCrypt (2y) etc. algorithm.
>> It’s currently very difficult to use and should be renamed to bcrypt2y, etc.
>> 
>> Thank you.
> 
> 
> Greetings Lenni and Team,
> 
> yes we do since our database solution stores in BCrypt format.
> 
> Cheers and best
> Andreas


Re: BCrypt algorithm usage in Shiro 2 - Does anyone use it?

Posted by Andreas Reichel <an...@manticore-projects.com>.
On Tue, 2025-10-21 at 13:26 -0500, lenny@flowlogix.com wrote:
> Hi,
> 
> Just taking a quick survey if anyone is using BCrypt (2y) etc.
> algorithm.
> It’s currently very difficult to use and should be renamed to
> bcrypt2y, etc.
> 
> Thank you.


Greetings Lenni and Team,

yes we do since our database solution stores in BCrypt format.

Cheers and best
Andreas