PingOne Platform APIs

Password encoding

PingOne supports the following Key Derivation Functions (KDF) and crytographic ciphers as methods for password encoding:

Method PingOne Identifier

PBKDF2

{PBKDF2}

ARGON2

{ARGON2}

MSCrypto library

{MSKCC_PBKDF2}

Scrypt

{SCRYPT}

Scrypt RFC-7914

{SCRYPT_RFC7914}

BCrypt

{BCRYPT}

SSHA

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 /dev/random or /dev/urandom sources.

Windows

The BCryptGenRandom function from the Cryptography API: Next Generation (CNG) or higher level cryptography libraries.

C#

System.Security.Cryptography.RandomNumberGenerator.Create() from .NET Framework or .NET Core.

Python

Either os.urandom() or the secrets library.

Java

The java.security.SecureRandom system class.

JavaScript

Either window.crypto.getRandomValues(Uint8Array) for client side (Web browser), or crypto.randomBytes() for server-side (Node.js).

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

encoded-password

The user password. The password is assumed to be encoded.

version-hex

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

salt-length-hex

A hexadecimal encoding of the length of the salt. This must be between 8 and 127 characters in length.

salt

A securely-generated cryptographically strong random number.

iterations-hex

A hexadecimal encoding of the number of iterations to repeat the HMAC identified in version-hex (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.

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

password

The user password to encode.

type

One of the supported Argon2 types: Argon2i, Argon2d, Argon2id.

version

Specified as v=. The current version is decimal 19. Typically, this is unspecified, and defaults to the current version.

memory

Specified as m=. The amount of memory to use in kilobytes. In general, use the maximum amount of memory that’s acceptable for the performance of your application.

iterations

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.

parallelism

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.

salt

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.

hash-len

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

encoded-password

The user password to encode. This also is assumed to be encoded by the user.

logN

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 128*r/8, where r represents the configured block size. The amount of memory that will be consumed in the course of generating the password is 128*2^N*r bytes, where N represents the CPU/memory cost factor exponent and r represents the configured block size.

r

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.

p

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.

salt

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

version

The Scrypt RFC-7914 algorithm version. Currently, this must be "s0".

N

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 128*r/8, where r represents the configured block size. The amount of memory that will be consumed in the course of generating the password is 128*2^N*r bytes, where N represents the CPU/memory cost factor exponent and r represents the configured block size.

r

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.

p

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.

S

A securely-generated cryptographically strong random number used to salt the specified parameters. The salt length is 1-64 bytes.

P

A Base64-encoded passphrase. The length is 1-32 bytes.

encoded-password

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.

algorithm

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 crypt_blowfish, a PHP implementation of BCrypt. The version 2b is relevant only if you’ve been using OpenBSD.

cost

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.

base-64-encode(salt)

A securely-generated cryptographically strong random number.

base-64-encode-minus-one(key0)

This is the base64 encoding algorithm with the final byte of the base64 encoding removed. The argument key0 is the encrypted key (for example, BCrypt(password, cost, salt)), except the last byte is replaced with "0x00".

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

0x00

A byte of zeros.

salt

A securely-generated cryptographically strong random number.

digest

The PBKDF2 algorithm.

password

The user password. The password is assumed to be encoded.

salt-128

A securely-generated cryptographically strong random number of 128 bits.

iterations

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.

key-length

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-variant}" + base-64-encode( salt + digest(password + salt) )
"{SSHA-variant}" + base-64-encode( salt + digest(salt + password) )

SSHA parameters for PingOne

Parameter Description

SSHA-variant

The SSHA variant to use. This can be one of the following: SSHA1, SSHA256, SSHA384, SSHA512.

digest

The password encoding using the specified SSHA variant.

password

The user password to encode.

salt

A securely-generated cryptographically strong random number.