Password encoding
PingOne supports the following Key Derivation Functions (KDF) and crytographic ciphers as methods for password encoding:
| Method | PingOne Identifier |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
N/A |
The PingOne identifier for the method must be pre-pended to the encoding generated. Refer to the discussion of the specific method for the format.
The common password-encoding use cases for the PingOne Platform APIs are:
Pre-encoded passwords
Pre-encoded passwords must use the LDAP userPassword syntax supported by PingDirectory and other directory servers. For more information about the LDAP userPassword attribute, refer to Hashed attribute values for userPassword. Note that in this specification, the userPassword syntax represented as userpasswordvalue = cleartext-password / prefix b64-hashandsalt should be read as:
userpasswordvalue = cleartext-password
or
userpasswordvalue = prefix b64-hashandsalt
If a pre-encoded password isn’t accepted by PingOne, it doesn’t conform to either of these encoding schemes.
Generating the salt
All of the encoding methods supported by PingOne require a salt to randomize the hashed value generated by the Hash-based Message Authentication Code (HMAC) used. Use only cryptographically strong random number generators (CSPRNG) to generate the salt. You’ll generally find this in the cryptography library for your language and platform. Some of the most common are:
| Language/Platform | Description |
|---|---|
Linux and macOS |
The |
Windows |
The |
C# |
|
Python |
Either |
Java |
The |
JavaScript |
Either |
PBKDF2
PBKDF2 is a Key Derivation Function (KDF) described in RFC 2898. The standard format is:
key = pbkdf2(password, salt, iterations, hash-function, derived-key-length)
PingOne APIs require a slightly modified version of this format, where the PingOne identifier for the encoding method is pre-pended to a Base64 encoding of the parameters:
"{PBKDF2}" + base-64-encode(`version-hex`, `salt-length-hex`, `salt`, `iterations-hex`, `encoded-password`)
Any spaces in the hex values are ignored.
The resulting encoding that can be passed to PingOne APIs will then look similar to this:
{PBKDF2}ARDCg7vxrqqSDV/UzQ5N9j+XJxDv0E64J9X5aHSZk4108X3esUoaKqGJePteFKJxT6qPkQ==
PBKDF2 parameters for PingOne
Spaces are ignored in the hexadecimal values.
| Parameter | Description |
|---|---|
|
The user password. The password is assumed to be encoded. |
|
A hexadecimal encoding of the version identifier for the PKDF2 and the HMAC combination to use. The version identifier can be any one of: * 00 if PBKDF2WithHmacSHA1 * 01 if PBKDF2WithHmacSHA256 * 02 if PBKDF2WithHmacSHA384 * 03 if PBKDF2WithHmacSHA512 |
|
A hexadecimal encoding of the length of the |
|
A securely-generated cryptographically strong random number. |
|
A hexadecimal encoding of the number of iterations to repeat the HMAC identified in |
Argon2
Argon2 is a KDF described in RFC 9106. The standard format is similar to this:
argon2.hash(password, type, iterations, memory, parallelism, hash_len, salt)
PingOne APIs require a slightly modified version of this format:
"{ARGON2}" + type + version, memory, iterations, parallelism
The resulting encoding that can be passed to PingOne APIs will then look similar to this:
$argon2i$v=19$m=64,t=2,p=8$d2pLMjlIUWk2eGU2OFZtVA$dr9M3P+yMs4qv/eFyh5WYw
Argon2 parameters for PingOne
| Parameter | Description |
|---|---|
|
The user password to encode. |
|
One of the supported Argon2 types: Argon2i, Argon2d, Argon2id. |
|
Specified as |
|
Specified as |
|
The number of iterations that’s acceptable for the performance of your application. Typically, start with a 2 - 4 iterations, and modify this based on the desired execution time. The number of iterations must be between 1 and 2{caret}32 − 1. |
|
The degree of parallelism to use is determined by the number of CPU cores on the server. Double the number of CPU cores to get the value here. |
|
A securely-generated cryptographically strong random number used to salt the specified parameters. The salt length must be between 8 and 2{caret}32 − 1 byte. |
|
The desired hashed output length in bytes. Applied to the specified parameters. |
Refer to the Argon2 Hash Generator to generate examples.
Scrypt
Scrypt is described in RFC 7419. Like other KDFs, Scrypt is designed to be expensive, so that attacks against Scrypt-encoded passwords are also expensive. However, Scrypt is different from other KDF algorithms because it is designed to consume a substantial amount of memory during the course of encoding a password, and to require pseudorandom access to portions of that memory. This makes the cost of generating a password dependent upon memory access latency in addition to CPU performance, and reduces the ability to parallelize password cracking attempts.
PingOne uses the "c2NyeXB0" format, where c2NyeXB0 is the base64-encoded representation of "scrypt".
The resulting encoded string is base64-encoded, and the unencoded value always starts with the bytes "scrypt", and is "c2NyeXB0".)
PingOne APIs require a slightly modified version of the c2NyeXB0 format, where the PingOne identifier for the encoding method is pre-pended to the formatting identifier "c2NyeXB0":
"{Scrypt}" + base-64-encode("scrypt", the-zero-byte, logN, r, p, salt, encoded-password)
Encoding details
In the aggregated parameter values "scrypt" + the-zero-byte + logN + r + p + salt:
-
The first 16 bytes is the first half of the SHA-256 encoding.
-
Apply the HMAC-SHA-256 algorithm to the first 64 bytes
-
Append the final 32 bytes to the final encoding.
The initialization key for the HMAC-SHA-256 algorithm is the last 32 bytes of the SCRYPT algorithm output, using the specified values for encoded-password, salt, logN, r, p, and a 64 byte block size.
The string that can be passed to PingOne APIs will then look similar to this:
{Scrypt}c2NyeXB0/UzQ5N9j+XJxDv0E64J9X5aHSZk4108X3esUoaKqGJePteFKJxT6qPkQ==
Scrypt parameters for PingOne
There is a 32 byte salt parameter:
-
logN is one byte
-
r and p are both 4 bytes
-
logN, r, and p use two’s complement representation
| Parameter | Description |
|---|---|
|
The user password to encode. This also is assumed to be encoded by the user. |
|
A 1 byte value (two’s complement) for the exponent to use for the CPU/memory cost factor. The cost factor must be a power of two, so the value of this property represents the power to which two is raised. The CPU/memory cost factor specifies the number of iterations required for encoding the password, and also affects the amount of memory required during processing. A higher cost factor requires more processing and more memory to generate a password, which makes attacks against the password more expensive. The value must be less than |
|
A 4 byte value (two’s complement) for the block size for the digest that will be used in the course of encoding passwords. Increasing the block size while keeping the CPU/memory cost factor constant will increase the amount of memory required to encode a password, but it also increases the ratio of sequential memory access to random memory access (sequential memory access is generally faster than random memory access). The value must be greater than or equal to one. |
|
A 4 byte value (two’s complement) for the number of times that Scrypt is to perform the entire encoding process to produce the final result. The amount of processing required to encode a password increases linearly with the value of this parameter. If an attacker uses an Scrypt implementation that supports the use of multiple threads to perform multiple encodings in parallel, then it also linearly increases the amount of memory required. |
|
A securely-generated cryptographically strong random number used to salt the specified parameters. The salt length is 32 bytes. |
Scrypt RFC-7914
Scrypt RFC-7914 supports a configurable salt, and uses the RFC-compliant encoding scheme described in RFC 7914. It’s designed to prevent GPU, FPGA, and ASIC attacks, and supercedes the older encoding scheme used by Scrypt.
Like the older Scrypt, Scrypt RFC-7914 is designed to be expensive, so that attacks against Scrypt RFC-7914 encoded passwords are also expensive. It’s designed to consume a substantial amount of memory during the course of encoding a password. This makes the cost of generating a password dependent upon memory access latency in addition to CPU performance, and reduces the ability to parallelize password cracking attempts.
The PingOne format is:
"{SCRYPT_RFC7914}" version, N + r + p, base-64-encode(S, P), encoded-password
For each step, the memory is accessed in dependent order, so memory access speed is the bottleneck. The memory required for Scrypt RFC-7914 key derivation is calculated as:
128*r*2^N, and must be <= 128 MiB.
Scrypt RFC-7914 parameters for PingOne
| Parameter | Description |
|---|---|
|
The Scrypt RFC-7914 algorithm version. Currently, this must be "s0". |
|
The hexadecimal string for a 1 byte value (two’s complement) for the exponent to use for the CPU/memory cost factor. This must be from 1-17. The cost factor must be a power of two, so the value of this property represents the power to which two is raised. The CPU/memory cost factor specifies the number of iterations required for encoding the password, and also affects the amount of memory required during processing. A higher cost factor requires more processing and more memory to generate a password, which makes attacks against the password more expensive. The value must be less than |
|
The hexadecimal string for a 4 byte value (two’s complement) for the block size for the digest that will be used in the course of encoding passwords. This must be from 1-8.Increasing the block size while keeping the CPU/memory cost factor constant will increase the amount of memory required to encode a password, but it also increases the ratio of sequential memory access to random memory access (sequential memory access is generally faster than random memory access). The value must be greater than or equal to one. |
|
The hexadecimal string for a 4 byte value (two’s complement) for the number of times that Scrypt RFC-7914 is to perform the entire encoding process to produce the final result. This must be 1. |
|
A securely-generated cryptographically strong random number used to salt the specified parameters. The salt length is 1-64 bytes. |
|
A Base64-encoded passphrase. The length is 1-32 bytes. |
|
The user password, assumed to be encoded. |
An example of the use of the parameters is:
100801 (N = 0x10 = 16, r = 0x08 = 8, p = 0x01 = 1)
The string passed to PingOne APIs might then look similar to this:
{SCRYPT_RFC7914}$s0$100801$a...=$a...=
Bcrypt
BCrypt is a KDF based on the Blowfish cipher, and incorporates the Blowfish HMAC to hash the password. The standard format is:
key = BCRYPT(password, cost, salt)
PingOne APIs require a slightly modified version of this format:
"{BCRYPT}" + "$" + algorithm + "$" + cost + "$" + base-64-encode(salt) + base-64-encode-minus-one(key0)
|
BCrypt doesn’t use the standard base-64 encoding. The encoding algorithm is the same, but the alphabet used is permuted and the plus symbol (+) is replaced by the period symbol (.) |
The resulting encoding that can be passed to PingOne APIs will then look similar to this:
{BCRYPT}$2y$10$xUtlkL33uoLU3jU7M7lkNOb0PbQQ7lKNqKuJLnZa4AzvXRWSq5Vxe
BCrypt parameters for PingOne
Spaces are ignored in the hexadecimal values.
| Parameter | Description |
|---|---|
|
The prefix indicating a parameter. |
|
The version of BCrypt to use. Generally, this should be "$2a". However, this can be any one of the versions: 2a, 2b, 2x, 2y. The versions 2x and 2y are relevant only if you’ve been using |
|
A two digit number between 4 and 31 (inclusive). If the cost is less than 10, then prepend a zero (for example, 6 -> 06). This indicates the number of iterations to repeat the HMAC. In general, use the maximum number of iterations that’s acceptable for the performance of your application. |
|
A securely-generated cryptographically strong random number. |
|
This is the base64 encoding algorithm with the final byte of the base64 encoding removed. The argument |
MSCrypto library
Use the Microsoft method Crypto.hashPassword() to encode passwords, then import those passwords into PingOne using the {MSKCC_PBKDF2} method.
MSCrypto uses PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit key length, and 1000 iterations.
PingOne APIs require this format:
"{MSKCC_PBKDF2}" + base-64-encode(0x00 + salt + digest(password, salt-128, iterations, key-length))
Any spaces in the hex values are ignored.
The resulting encoding that can be passed to PingOne APIs will then look similar to this:
{MSKCC_PBKDF2}ARDCg7vxrqqSDV/UzQ5N9j+XJxDv0E64J9X5aHSZk4108X3esUoaKqGJePteFKJxT6qPkQ==
MSCrypto parameters for PingOne
Spaces are ignored in the hexadecimal values.
| Parameter | Description |
|---|---|
|
A byte of zeros. |
|
A securely-generated cryptographically strong random number. |
|
The PBKDF2 algorithm. |
|
The user password. The password is assumed to be encoded. |
|
A securely-generated cryptographically strong random number of 128 bits. |
|
A hexadecimal encoding of the number of iterations to repeat the HMAC-SHA1 (for example, 10,000). This can be between zero and 2,147,483,647. In general, use the maximum number of iterations that’s acceptable for the performance of your application. |
|
256 bits. |
SSHA methods
The SSHA algorithms incorporate the SHA cryptographic hash functions to hash the password. The PingOne-specific format for all of the SSHA variants is:
"{SSHA-variant}" + base-64-encode(digest(password + salt) + salt )
The plus sign (+) indicates concatenation.
In addition, PingOne supports the following formats for both SHA256 and SHA1. The other variants do not support these formats.
"{SSHA-variant}" + base-64-encode( digest(password + salt) + salt )
"{SSHA-variant}" + base-64-encode( digest(salt + password) + salt )
|
PingOne does not support the following formats for any of the SSHA variants:
|
SSHA parameters for PingOne
| Parameter | Description |
|---|---|
|
The SSHA variant to use. This can be one of the following: SSHA1, SSHA256, SSHA384, SSHA512. |
|
The password encoding using the specified SSHA variant. |
|
The user password to encode. |
|
A securely-generated cryptographically strong random number. |