Raw Credentials Hash API
The Raw Credentials Hash API allows you to simplify checks for compromised credentials against the Enzoic API by returning all of the raw credentials hashes for a given user. The credentials hashes can then be checked locally without additional API calls and without ever passing your user’s credentials to Enzoic. This API is more sensitive and restricted to organizations by approval. Please contact sales if you believe you have an appropriate use case for this API.
Available Calls
- GET Retrieve Credentials Hashes for Account
Query for all credentials hashes for a given user. - Using the Raw Credentials Hash API
GET Retrieve Credentials Hashes for Account
https://api.enzoic.com/accounts
Returns a list of Argon2 credentials hashes in the Enzoic database for a given user. The username can be specified in either plaintext or via a SHA256 hash of the username.
See Using Enzoic for general instructions on using the API.
Request
Parameter | Type | Description |
---|---|---|
username | string | Either the plaintext username (e.g. test@enzoic.com) or a SHA-256 hash of the lower-cased username. |
includeHashes | int | Set to 1 to include the credentials hashes in the response. |
Response
Response | Description |
---|---|
200 | Credentials Hashes for the user were found in the Enzoic database and are included in the response |
404 | Enzoic has no credentials stored for the requested user. |
Response Body
Member | Type | Description |
---|---|---|
credentialsHashes | credentialsHashSpecification[] | An array of credentials hashes and password hash specifications. |
salt | string | The user specific salt value to use when calculating Argon2 credentials hashes. |
lastBreachDate | datetime | A string containing the date/time of the last credentials exposure found for this account. This can be used to more intelligently check credentials for a user, i.e. if the lastBreachDate is less than the last time you performed a credentials check, you can skip the remaining steps. |
CredentialsHashSpecification:
Member | Type | Description |
---|---|---|
credentialsHash | string | The Argon2 credentials hash for this set of credentials. |
hashType | PasswordHashType | The hash algorithm to use (see PasswordHashType enum). The password should be in UTF-8 encoding prior to hashing. Hash type 0 is a cleartext password. |
salt | string | The salt value to use with the algorithm, if applicable. If an empty string, password is cleartext or no salt value is necessary. |
exposures | string[] | An array of Exposure IDs, indicating which exposures this password was revealed in for this user. These can be used with the Exposure Details call to retrieve additional info about the exposure. |
PasswordHashType:
Value | Description | Output |
---|---|---|
0 | Cleartext | Password in cleartext (not hashed) |
1 | MD5 hash algorithm without salt | Hex string |
2 | SHA1 hash algorithm without salt | Hex string |
3 | SHA256 hash algorithm without salt | Hex string |
5 | Composite Algorithm: md5(md5(salt) + md5(password)) | Hex string |
6 | Composite Algorithm: md5(md5(password) + salt) | Hex string |
7 | Composite Algorithm: md5(md5(password) + salt) | Hex string |
8 | BCrypt algorithm using provided salt | Bcrypt string |
9 | CRC32 hash algorithm without salt | Hex string |
10 | PHPBB3 (PHPass) | PHPass string |
11 | Composite Algorithm: xor(sha512(password + salt), whirlpool(salt + password)) | Hex string |
13 | Composite Algorithm: md5(password + salt) | Hex string |
14 | SHA512 hash algorithm without salt | Hex string |
15 | Composite Algorithm with fixed salt: md5(“kikugalanet” + password) | Hex string |
16 | MD5Crypt algorithm using provided salt | MD5Crypt string |
17 | Composite Algorithm: bcrypt(md5(password)) using provided salt for BCrypt | BCrypt string |
18 | Composite Algorithm: sha256(md5(password + salt)) | Hex string |
19 | Composite Algorithm: md5(salt + password) | Hex string |
20 | DESCrypt algorithm using provided salt | DESCrypt string |
21 | MySQL (pre 4.1) algorithm | Hex string |
22 | Composite Algorithm: “*” + sha1(sha1(password)) | Hex string prefixed with “*” |
23 | Composite Algorithm: base64(sha1(UTF16Bytes(password))) | Hex string |
24 | Composite Algorithm: sha1(salt + sha1(password)) | Hex string |
25 | Composite Algorithm: sha1(password + salt) | Hex string |
26 | Partial MD5 – first 20 bytes of MD5 hash of password | Hex string |
27 | Composite Algorithm: md5(md5(password)) | Hex string |
28 | Composite Algorithm: “md5$” + salt + “$” + md5(salt + password) | Hex string |
29 | Composite Algorithm: “sha1$” + salt + “$” + sha1(salt + password) | Formatted hex string |
30 | Partial MD5 – first 29 bytes of MD5 hash of password | Hex string |
31 | Composite Algorithm: salt + sha1(salt + password) | Formatted hex string |
32 | Composite Algorithm: sha1(username + password) | Hex string |
33 | NTLM | Hex string |
34 | Composite Algorithm: sha1(“–” + salt + “–” + password + “–“) | Hex string |
35 | SHA384 | Hex string |
36 | Composite Algorithm: hmac-sha256(sha1(salt) + password) HMAC key: “d2e1a4c569e7018cc142e9cce755a964bd9b193d2d31f02d80bb589c959afd7e” |
Hex string |
37 | Composite Algorithm: sha256(salt + password) | Hex string |
38 | Composite Algorithm: sha512<11 times>(sha512(password + salt)) | Hex string |
39 | SHA512Crypt | SHA512Crypt string |
40 | Composite Algorithm: sha512(password + “:” + salt) | Hex string |
Example
Request
curl --header "authorization: basic {your auth string}" "https://api.enzoic.com/accounts?username=eicar@enzoic.com&includePasswords=1"
Response
{ "lastBreachDate": "2020-01-24T23:45:48.000Z", "passwords": [ { "hashType": 0, "password": "password123", "passwordSalt": "" }, { "hashType": 2, "password": "cbfdac6008f9cab4083784cbd1874f76618d2a97", "passwordSalt": "" } ] }
Using the Raw Credentials Hashes API
Enzoic Credentials Hashes are Argon2 hashes of a username/password combination that was found to be compromised. For security reasons, Enzoic does not return plaintext passwords. To determine if a given username and password are known to be compromised using this API call, you must calculate the corresponding credentials hashes that are requested in the response payload and then compare locally to the hashes that were returned in the payload to see if there is a match.
This process is outlined below:
- Retrieve the Account Salt and Hashes
Make the GET call documented above with the desired username or a SHA256 hash of the username. This returns a salt value, as well as an array of CredentialsHashSpecifications containing hash types (algorithms and potentially salts). If this call returns a 404, it indicates that we have no compromised credentials for this username and you can skip the remaining steps. - Calculate Requested Password Hashes
For each entry in the returned hashes array, construct a hash of the user’s password using the specified hashing algorithm and salt value. See the table of hash algorithms here for reference:hash types - Calculate Credentials Hashes
For each resultant password hash from step 2, construct a credentials hash by concatenating the username and password together, and then calculating an Argon2 hash of the result using the Account salt returned in step 1. - Make Credentials API Call
Make a GET call to the /credentials API endpoint with the array of Argon2 hashes from step 3. The result will indicate whether the credentials have been compromised.
More detail for each step follows below.
Step 1 – Retrieve the Account Salt and Hashes
The first step is to make a GET call to the /accounts API endpoint to retrieve the account-specific salt value and a list of required hashes. The /accounts call is documented above.
Step 2 – Calculate the Requested Password Hashes
Next, iterate over the credentialsHashesRequired array returned in step 1, calculating a password hash as specified by the hashType of each PasswordHashSpecification entry.
HashTypes
Some of the hashTypes are standard hashing algorithms, such as SHA-1 and BCrypt, while others are composite algorithms, combining the password, salt, and potentially multiple standard hashes together to calculate a final hash value. For example, hashType 5 is a composite with the following algorithm: md5(md5(salt) + md5(password)). Thus, it would be necessary to calculate an MD5 of the provided salt and concatenate this with an MD5 of the password. Finally, an MD5 of the resultant string is calculated and this is the final hash. Unless otherwise specified, the standard hash steps in a composite algorithm should all be outputting lowercase hex string representations of the value.
Salts
Note that some of the hashTypes require salt values and some do not, depending on the hash algorithm. When the salt value is not required for the specified algorithm, it will be an empty string.
Hash Libraries
Calculating these hashes will involve language-specific libraries to provide standard hashing functions (MD5, SHA-1, SHA-256, etc). Typically these functions are either built-in or available as open-source libraries for practically any widely-used programming language.
Step 3 – Calculate the Credential Hashes
For each item in the password hashes array produced in step 2, concatenate the username and password hash and then hash the result with the Argon2 algorithm and the account salt returned in step 1. Lastly, extract just the hash value from the Argon2 hash (the string will also contain the algorithm hash parameters and salt value used). This should result in an array of Credential Hashes, which will be the arguments passed to the Credentials API in the final step.
Example:
for (var i = 0; i < passwordHashes.length; i++) { // concatenate the username, "$", and password hash value from step 2 into a single string var toHash = username + "$" + passwordHashes[i]; // calculate the Argon2 hash (Argon2 library for your programming language required) var argon2Hash = Argon2(toHash, accountSalt); // extract just the hash value from the resultant Argon2 string (should be everything after the last "$" credentialHashes[i] = argon2Hash.substr(argon2Hash.lastIndexOf("$") + 1); }
When calculating the Credentials Hash, the Argon2 algorithm should be called with the following settings:
Setting | Value |
---|---|
Type | Argon2d |
Iterations/TimeCost | 3 |
Memory | 1024 |
Parallelism | 2 |
HashLength | 20 |
Step 4 – Compare the calculated Credentials Hashes to Those Returned in the Response Payload
The final step is to compare each calculated Credentials Hash to the ones in the returned in the credentialsHashSpecifications array in the response payload. If any match, the credentials are compromised.