On the WildFly Elytron PasswordFactory API

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

On the WildFly Elytron PasswordFactory API

David Lloyd-2
The JDK's cryptography/security architecture includes facilities for
handling many kinds of cryptographic key materials, but it does not
include one to handle text passwords.

Text passwords are handled in a very wide variety of formats and used in
a variety of ways, especially when you add challenge/response algorithms
and legacy systems into the mix.  Pursuant to that, there is a new API
inside of WildFly Elytron for the purpose of handling passwords and
translating them between various useful formats.

At present this API is designed to be similar to and consistent with the
JDK key handling APIs.

So I'll dive right in to examples of usage, based on the use cases that
have been identified so far:

Example: Importing an verifying a passwd file password
------------------------------------------------------

    PasswordFactory pf = PasswordFactory.getInstance("crypt");
    // Get a Password for a crypt string
    PasswordSpec spec = new CryptStringPasswordSpec(passwdChars);
    Password password = pf.generatePassword(spec);
    // Now we can verify it
    if (! pf.verify(password, "mygu3ss".toCharArray())) {
        throw new AuthenticationException("Wrong password");
    }

Example: Importing and exporting a clear password
-------------------------------------------------

    PasswordFactory pf = PasswordFactory.getInstance("clear");
    // Import
    PasswordSpec spec = new ClearPasswordSpec("p4ssw0rd".toCharArray());
    Password password = pf.generatePassword(spec);
    // Verify
    boolean ok = pf.verify(password, "p4ssw0rd".toCharArray());
    // Is it clear?
    boolean isClear = pf.convertibleToKeySpec(password,
ClearPasswordSpec.class);
    assert password instanceof TwoWayPassword;
    assert ! (password instanceof OneWayPassword);
    // Export again
    ClearPasswordSpec clearSpec = pf.getKeySpec(password,
ClearPasswordSpec.class);
    System.out.printf("The password is: %s%n", new
String(clearSpec.getEncodedPassword()));

Example: Encrypting a new password
----------------------------------

    PasswordFactory pf = PasswordFactory.getInstance("sha1crypt");
    // API not yet established but will be similar to this possibly:
    ???? parameters = new
???SHA1CryptPasswordParameterSpec("p4ssw0rd".toCharArray());
    Password encrypted = pf.generatePassword(parameters);
    assert encrypted instanceof SHA1CryptPassword;

If anyone has other use cases they feel need to be covered, or questions
or comments about the API, speak up.

--
- DML
_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: On the WildFly Elytron PasswordFactory API

David Lloyd-2
On 06/04/2014 11:07 AM, David M. Lloyd wrote:
[...]
> Example: Encrypting a new password
> ----------------------------------
>
>     PasswordFactory pf = PasswordFactory.getInstance("sha1crypt");
>     // API not yet established but will be similar to this possibly:
>     ???? parameters = new
> ???SHA1CryptPasswordParameterSpec("p4ssw0rd".toCharArray());
>     Password encrypted = pf.generatePassword(parameters);
>     assert encrypted instanceof SHA1CryptPassword;

I have a concrete specification for this example now:

     PasswordFactory pf = PasswordFactory.getInstance("sha-256-crypt");
     // use a 64-byte random salt; most algorithms support flexible sizes
     byte[] salt = new byte[64];
     ThreadLocalRandom.current().getBytes(salt);
     // iteration count is 4096, can generally be more (or less)
     AlgorithmParameterSpec aps =
             new HashedPasswordAlgorithmSpec(4096, salt);
     char[] chars = "p4ssw0rd".toCharArray();
     PasswordSpec spec = new EncryptablePasswordSpec(chars, aps);
     Password pw = pf.generatePassword(spec);
     assert pw.getAlgorithm().equals("sha-256-crypt");
     assert pw instanceof UnixSHACryptPassword;
     assert pf.verifyPassword(pw, chars);

--
- DML
_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: On the WildFly Elytron PasswordFactory API

Anil Saldhana
On 06/11/2014 09:30 AM, David M. Lloyd wrote:

> On 06/04/2014 11:07 AM, David M. Lloyd wrote:
> [...]
>> Example: Encrypting a new password
>> ----------------------------------
>>
>>      PasswordFactory pf = PasswordFactory.getInstance("sha1crypt");
>>      // API not yet established but will be similar to this possibly:
>>      ???? parameters = new
>> ???SHA1CryptPasswordParameterSpec("p4ssw0rd".toCharArray());
>>      Password encrypted = pf.generatePassword(parameters);
>>      assert encrypted instanceof SHA1CryptPassword;
> I have a concrete specification for this example now:
>
>       PasswordFactory pf = PasswordFactory.getInstance("sha-256-crypt");
>       // use a 64-byte random salt; most algorithms support flexible sizes
>       byte[] salt = new byte[64];
>       ThreadLocalRandom.current().getBytes(salt);
>       // iteration count is 4096, can generally be more (or less)
>       AlgorithmParameterSpec aps =
>               new HashedPasswordAlgorithmSpec(4096, salt);
>       char[] chars = "p4ssw0rd".toCharArray();
>       PasswordSpec spec = new EncryptablePasswordSpec(chars, aps);
>       Password pw = pf.generatePassword(spec);
>       assert pw.getAlgorithm().equals("sha-256-crypt");
>       assert pw instanceof UnixSHACryptPassword;
>       assert pf.verifyPassword(pw, chars);
>
- Best is to make the salt and iteration count configurable.
- Opportunities to inject a custom random generator.

The following may be important :
- RW the masked password to a file.

I will think further on the usecases we have seen over the years and
report back.
_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: On the WildFly Elytron PasswordFactory API

Bill Burke


On 6/11/2014 11:33 AM, Anil Saldhana wrote:

> On 06/11/2014 09:30 AM, David M. Lloyd wrote:
>> On 06/04/2014 11:07 AM, David M. Lloyd wrote:
>> [...]
>>> Example: Encrypting a new password
>>> ----------------------------------
>>>
>>>       PasswordFactory pf = PasswordFactory.getInstance("sha1crypt");
>>>       // API not yet established but will be similar to this possibly:
>>>       ???? parameters = new
>>> ???SHA1CryptPasswordParameterSpec("p4ssw0rd".toCharArray());
>>>       Password encrypted = pf.generatePassword(parameters);
>>>       assert encrypted instanceof SHA1CryptPassword;
>> I have a concrete specification for this example now:
>>
>>        PasswordFactory pf = PasswordFactory.getInstance("sha-256-crypt");
>>        // use a 64-byte random salt; most algorithms support flexible sizes
>>        byte[] salt = new byte[64];
>>        ThreadLocalRandom.current().getBytes(salt);
>>        // iteration count is 4096, can generally be more (or less)
>>        AlgorithmParameterSpec aps =
>>                new HashedPasswordAlgorithmSpec(4096, salt);
>>        char[] chars = "p4ssw0rd".toCharArray();
>>        PasswordSpec spec = new EncryptablePasswordSpec(chars, aps);
>>        Password pw = pf.generatePassword(spec);
>>        assert pw.getAlgorithm().equals("sha-256-crypt");
>>        assert pw instanceof UnixSHACryptPassword;
>>        assert pf.verifyPassword(pw, chars);
>>
> - Best is to make the salt and iteration count configurable.

+1

5000 iterations is actually a *huge* performance hit, but unfortunately
way lower than what I've seen recommended.  (I've seen as high as
100,000 based on today's hardware).

In Keycloak we store the iteration count along with the password so that
the admin can change the default iteration count in the future.  We
recalculate the hash on a successful login if the default count and user
count are different.

--
Bill Burke
JBoss, a division of Red Hat
http://bill.burkecentral.com
_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: On the WildFly Elytron PasswordFactory API

David Lloyd-2
On 06/11/2014 10:44 AM, Bill Burke wrote:

>
>
> On 6/11/2014 11:33 AM, Anil Saldhana wrote:
>> On 06/11/2014 09:30 AM, David M. Lloyd wrote:
>>> On 06/04/2014 11:07 AM, David M. Lloyd wrote:
>>> [...]
>>>> Example: Encrypting a new password
>>>> ----------------------------------
>>>>
>>>>        PasswordFactory pf = PasswordFactory.getInstance("sha1crypt");
>>>>        // API not yet established but will be similar to this possibly:
>>>>        ???? parameters = new
>>>> ???SHA1CryptPasswordParameterSpec("p4ssw0rd".toCharArray());
>>>>        Password encrypted = pf.generatePassword(parameters);
>>>>        assert encrypted instanceof SHA1CryptPassword;
>>> I have a concrete specification for this example now:
>>>
>>>         PasswordFactory pf = PasswordFactory.getInstance("sha-256-crypt");
>>>         // use a 64-byte random salt; most algorithms support flexible sizes
>>>         byte[] salt = new byte[64];
>>>         ThreadLocalRandom.current().getBytes(salt);
>>>         // iteration count is 4096, can generally be more (or less)
>>>         AlgorithmParameterSpec aps =
>>>                 new HashedPasswordAlgorithmSpec(4096, salt);
>>>         char[] chars = "p4ssw0rd".toCharArray();
>>>         PasswordSpec spec = new EncryptablePasswordSpec(chars, aps);
>>>         Password pw = pf.generatePassword(spec);
>>>         assert pw.getAlgorithm().equals("sha-256-crypt");
>>>         assert pw instanceof UnixSHACryptPassword;
>>>         assert pf.verifyPassword(pw, chars);
>>>
>> - Best is to make the salt and iteration count configurable.
>
> +1
>
> 5000 iterations is actually a *huge* performance hit, but unfortunately
> way lower than what I've seen recommended.  (I've seen as high as
> 100,000 based on today's hardware).

Yeah the point of having the algorithm parameter spec is to allow these
things to be specified.  Iteration count is recommended to be pretty
high these days, unfortunately, but with this kind of parameter spec, it
is completely configurable so if there's some reason to use a lower
count (or a higher one), you can certainly do it.

> In Keycloak we store the iteration count along with the password so that
> the admin can change the default iteration count in the future.  We
> recalculate the hash on a successful login if the default count and user
> count are different.

Yeah the newer SASL SCRAM mechanisms (and other challenge-response
mechanisms like Digest-MD5 and, I believe, HTTP's digest) also have some
support for caching pre-hashed passwords to help performance.  While on
the one hand, this means that the hash is essentially sufficient to
authenticate, on the other hand the server can always periodically
regenerate the hash with a different salt, which causes the previous
hashed password to essentially become invalid without actually requiring
a password change.

--
- DML
_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: On the WildFly Elytron PasswordFactory API

Anil Saldhana
I also want to highlight the difference between PBE and PBKDF2
(http://en.wikipedia.org/wiki/PBKDF2).
Developers keep pushing for PBKDF2 which is essentially a one way
process. You cannot get the password back.
In the case of an application server, there is a need to get access to
the configured database password to talk to
a database or another EIS system. So it is a two way process.  Not all
databases can do a hashed/digest mechanism.

I hope we can document this in Elytron documentation somewhere.

Similarly, bcrypt (http://en.wikipedia.org/wiki/Bcrypt) is mentioned a
lot. It again is a one way process.

Also below....

On 06/11/2014 11:14 AM, David M. Lloyd wrote:

> On 06/11/2014 10:44 AM, Bill Burke wrote:
>>
>> On 6/11/2014 11:33 AM, Anil Saldhana wrote:
>>> On 06/11/2014 09:30 AM, David M. Lloyd wrote:
>>>> On 06/04/2014 11:07 AM, David M. Lloyd wrote:
>>>> [...]
>>>>> Example: Encrypting a new password
>>>>> ----------------------------------
>>>>>
>>>>>         PasswordFactory pf = PasswordFactory.getInstance("sha1crypt");
>>>>>         // API not yet established but will be similar to this possibly:
>>>>>         ???? parameters = new
>>>>> ???SHA1CryptPasswordParameterSpec("p4ssw0rd".toCharArray());
>>>>>         Password encrypted = pf.generatePassword(parameters);
>>>>>         assert encrypted instanceof SHA1CryptPassword;
>>>> I have a concrete specification for this example now:
>>>>
>>>>          PasswordFactory pf = PasswordFactory.getInstance("sha-256-crypt");
>>>>          // use a 64-byte random salt; most algorithms support flexible sizes
>>>>          byte[] salt = new byte[64];
>>>>          ThreadLocalRandom.current().getBytes(salt);
>>>>          // iteration count is 4096, can generally be more (or less)
>>>>          AlgorithmParameterSpec aps =
>>>>                  new HashedPasswordAlgorithmSpec(4096, salt);
>>>>          char[] chars = "p4ssw0rd".toCharArray();
>>>>          PasswordSpec spec = new EncryptablePasswordSpec(chars, aps);
>>>>          Password pw = pf.generatePassword(spec);
>>>>          assert pw.getAlgorithm().equals("sha-256-crypt");
>>>>          assert pw instanceof UnixSHACryptPassword;
>>>>          assert pf.verifyPassword(pw, chars);
>>>>
>>> - Best is to make the salt and iteration count configurable.
>> +1
>>
>> 5000 iterations is actually a *huge* performance hit, but unfortunately
>> way lower than what I've seen recommended.  (I've seen as high as
>> 100,000 based on today's hardware).
> Yeah the point of having the algorithm parameter spec is to allow these
> things to be specified.  Iteration count is recommended to be pretty
> high these days, unfortunately, but with this kind of parameter spec, it
> is completely configurable so if there's some reason to use a lower
> count (or a higher one), you can certainly do it.
>
>> In Keycloak we store the iteration count along with the password so that
>> the admin can change the default iteration count in the future.  We
>> recalculate the hash on a successful login if the default count and user
>> count are different.
> Yeah the newer SASL SCRAM mechanisms (and other challenge-response
> mechanisms like Digest-MD5 and, I believe, HTTP's digest) also have some
> support for caching pre-hashed passwords to help performance.  While on
> the one hand, this means that the hash is essentially sufficient to
> authenticate, on the other hand the server can always periodically
> regenerate the hash with a different salt, which causes the previous
> hashed password to essentially become invalid without actually requiring
> a password change.
>
Agree. From Elytron perspective, it is important to provide the
configuration to handle
all potential use cases.

_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: On the WildFly Elytron PasswordFactory API

David Lloyd-2
On 06/12/2014 10:55 AM, Anil Saldhana wrote:

> I also want to highlight the difference between PBE and PBKDF2
> (http://en.wikipedia.org/wiki/PBKDF2).
> Developers keep pushing for PBKDF2 which is essentially a one way
> process. You cannot get the password back.
> In the case of an application server, there is a need to get access to
> the configured database password to talk to
> a database or another EIS system. So it is a two way process.  Not all
> databases can do a hashed/digest mechanism.
>
> I hope we can document this in Elytron documentation somewhere.

The Password SPI in fact has OneWayPassword and TwoWayPassword
sub-interfaces.

At present, the only TwoWayPassword implementation we have is "clear",
which, as the name says, is a clear password (and thus is trivially
"reversible").  We recently were discussing that there seem to be very
few (if any) good, reliable two-way password strategies (which do not
involve a keystore, which is *not* the same thing).

I've deliberately been referring to non-clear TwoWayPassword schemes as
"obfuscation" rather than "encryption" since few (if any) two-way
algorithms will actually make the password "secure" in the event of
theft.  More likely this is for the "accidental printout" kind of case.

That said, if anyone knows of any good two-way password obfuscation
algorithms they think should be supported, please comment here and/or
open an issue at https://issues.jboss.org/browse/ELY describing the
algorithm (preferably with a link to a specification if possible).

--
- DML
_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: On the WildFly Elytron PasswordFactory API

Anil Saldhana
On 06/12/2014 11:08 AM, David M. Lloyd wrote:

> On 06/12/2014 10:55 AM, Anil Saldhana wrote:
>> I also want to highlight the difference between PBE and PBKDF2
>> (http://en.wikipedia.org/wiki/PBKDF2).
>> Developers keep pushing for PBKDF2 which is essentially a one way
>> process. You cannot get the password back.
>> In the case of an application server, there is a need to get access to
>> the configured database password to talk to
>> a database or another EIS system. So it is a two way process.  Not all
>> databases can do a hashed/digest mechanism.
>>
>> I hope we can document this in Elytron documentation somewhere.
> The Password SPI in fact has OneWayPassword and TwoWayPassword
> sub-interfaces.
>
> At present, the only TwoWayPassword implementation we have is "clear",
> which, as the name says, is a clear password (and thus is trivially
> "reversible").  We recently were discussing that there seem to be very
> few (if any) good, reliable two-way password strategies (which do not
> involve a keystore, which is *not* the same thing).
>
> I've deliberately been referring to non-clear TwoWayPassword schemes as
> "obfuscation" rather than "encryption" since few (if any) two-way
> algorithms will actually make the password "secure" in the event of
> theft.  More likely this is for the "accidental printout" kind of case.
You are using the right term, David.  I use obfuscation or masking for the
two way password feature. I remember around 2007, Jason and I had this
minor argument
with a JBoss author who kept insisting on using the word "Encryption for
the masking.

Unfortunately PBE is the only available mechanism to do the two way
password without
the low-user-experience usage of a keystore or other certificate mechanism.

>
> That said, if anyone knows of any good two-way password obfuscation
> algorithms they think should be supported, please comment here and/or
> open an issue at https://issues.jboss.org/browse/ELY describing the
> algorithm (preferably with a link to a specification if possible).
>
I have seen a lot of usage and demand for this open source project - jasypt.
http://www.jasypt.org/

I have been planning on using it in PicketLink
(http://www.picketlink.org) to get away from all
the PBE based mechanisms we have to mask passwords in configuration files.

Maybe Elytron can use this library as a dependency.
_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev