An implementation of the OATH Challenge-Response Algorithm (OCRA) as specified in RFC 6287.
This implementation fully complies with RFC 6287 and passes all official test vectors:
- All hash algorithms (SHA1, SHA256, SHA512)
- All data input formats (C, Q, P, S, T)
- All question formats (N, A, H)
- Developped to works only in browsers
- Chrome 49+
- Firefox 45+
- Safari 10.1+
- Opera 36+
- Edge 13+
- Work with : CryptoJS; jsSHA and Browser Web Crypto API
Running RFC conformance Test Vectors her
<!-- Include a crypto library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>
<!-- Include OCRA -->
<script src="ocra.js"></script>
<script>
async function generateCode() {
const code = await OCRA.generate(
"OCRA-1:HOTP-SHA1-6:QN08", // Suite
"12345678901234567890", // Secret key
"12345678" // Challenge
);
console.log("OCRA Code:", code);
}
</script>Generates an OCRA code according to the specified suite.
| Parameter | Type | Required | Description |
|---|---|---|---|
suite |
string |
âś… | OCRA suite specification (e.g., "OCRA-1:HOTP-SHA1-6:QN08") |
key |
Hex Encoded string |
âś… | Secret key (HEX encoded) |
challenge |
Hex Encoded string |
âś… | Challenge/question string (HEX encoded, type to encode depend on suite QNxx/QAxx/QHxx, QN = BigInt hexx String encoded, QA = String Hex Encoded, QH = Raw Hex String, max 128 bytes) |
counter |
Big Int Hex Encoded String |
❌ | Counter value (for suites with 'C') (BigInt HEX encoded, max 16 bytes) |
password |
Hex Encoded string |
❌ | Password (for suites with 'P') (HEX encoded, max 20 bytes) |
sessionInfo |
Hex Encoded string |
❌ | Session information (for suites with 'S') (HEX encoded, max bytes depend on the Ocra Suite : 64, 128, 512) |
timestamp |
Big Int Hex Encoded |
❌ | Timestamp (for suites with 'T') (BigInt Hex Encoded, the signification of the depend on the Time Step Granularity of the Ocra Suite) |
Promise<string>- The generated OCRA code
An OCRASuite value follows this general format:
<Algorithm>:<CryptoFunction>:<DataInput>
The OCRASuite is composed of three main components separated by colons (:):
- Algorithm - Specifies the OCRA version
- CryptoFunction - Defines the cryptographic function used
- DataInput - Describes the input parameters for computation
Format: OCRA-v
- Description: Indicates the version of OCRA being used
- Values:
OCRA-1(RFC 6287 specifies version 1) - Example:
OCRA-1
Format: HOTP-H-t
- Description: Specifies the HMAC-based function and truncation parameters
- Components:
HOTP- Fixed prefix indicating HOTP-based computationH- Hash function (SHA1, SHA256, SHA512)t- Truncation length in decimal digits (0, 4-10)
Supported Values:
| Function Name | HMAC Function | Truncation Size |
|---|---|---|
| HOTP-SHA1-t | HMAC-SHA1 | 0, 4-10 |
| HOTP-SHA256-t | HMAC-SHA256 | 0, 4-10 |
| HOTP-SHA512-t | HMAC-SHA512 | 0, 4-10 |
Common Examples:
HOTP-SHA1-6(default) - SHA1 with 6-digit truncationHOTP-SHA256-8- SHA256 with 8-digit truncationHOTP-SHA512-4- SHA512 with 4-digit truncationHOTP-SHA1-0- SHA1 with no truncation (full HMAC)
Format: [C][|QFxx][|PH][|Snnn][|TG]
The DataInput component specifies which input parameters are used in the computation. Components are separated by hyphens (-) and include:
- Symbol:
C - Description: 8-byte counter value synchronized between parties
- Usage: Incremented on each computation request
- Example:
C
- Format:
QFxx - Description: Challenge question with specified format and maximum length
- Components:
Q- Fixed prefix for challengeF- Format specifierxx- Maximum length (04-64)
Format Specifiers:
| Format (F) | Type | Length Range |
|---|---|---|
| A | Alphanumeric | 04-64 |
| N | Numeric | 04-64 |
| H | Hexadecimal | 04-64 |
Default: QN08 (Numeric, up to 8 digits)
Examples:
QN08- Numeric challenge, max 8 digitsQA10- Alphanumeric challenge, max 10 charactersQH16- Hexadecimal challenge, max 16 nibbles
- Format:
PH - Description: Hashed version of PIN/password
- Components:
P- Fixed prefix for passwordH- Hash function (SHA1, SHA256, SHA512)
Supported Hash Functions:
PSHA1- SHA1 hash of PIN/password (default)PSHA256- SHA256 hash of PIN/passwordPSHA512- SHA512 hash of PIN/password
- Format:
Snnn - Description: UTF-8 encoded session data
- Components:
S- Fixed prefix for sessionnnn- Length in bytes
Common Lengths:
S064- 64 bytes (default)S128- 128 bytesS256- 256 bytesS512- 512 bytes
- Format:
TG - Description: Time-based parameter
- Components:
T- Fixed prefix for timestampG- Time-step granularity
Time-Step Granularity:
| Granularity (G) | Description | Examples |
|---|---|---|
| [1-59]S | Seconds | 20S |
| [1-59]M | Minutes | 5M |
| [0-48]H | Hours | 24H |
Default: T1M (1-minute time steps)
Format: [C]|QFxx|[PH|Snnn|TG]
Examples:
QN08- Simple numeric challengeC-QN08-PSHA1- Counter + numeric challenge + PINQA10-T1M- Alphanumeric challenge + timestamp
Format: [C]|QFxx|[PH|TG]
Examples:
QA08- Alphanumeric signature challengeQH8-S512- Hex challenge + session info
OCRA-1:HOTP-SHA1-6:QN08
- Version 1 OCRA
- SHA1 with 6-digit truncation
- Numeric challenge up to 8 digits
OCRA-1:HOTP-SHA512-8:C-QN08-PSHA1
- Version 1 OCRA
- SHA512 with 8-digit truncation
- Counter + numeric challenge + SHA1-hashed PIN
OCRA-1:HOTP-SHA256-6:QA10-T1M
- Version 1 OCRA
- SHA256 with 6-digit truncation
- Alphanumeric challenge + 1-minute timestamps
OCRA-1:HOTP-SHA1-4:QH8-S512
- Version 1 OCRA
- SHA1 with 4-digit truncation
- Hex challenge + 512-byte session data
- Key Agreement: Client and server must agree on OCRASuite values during provisioning or negotiation
- Mutual Authentication: Requires two OCRASuite values (one for server, one for client computation)
- Default Values: When optional parameters are omitted, defaults apply (QN08, PSHA1, S064, T1M)
- Padding: Challenge/questions less than 128 bytes are padded with zeros to the right
- Encoding: Session information uses UTF-8 encoding
- Epoch Time: Timestamps based on Unix epoch (January 1, 1970, midnight UTC)
const suite = "OCRA-1:HOTP-SHA1-6:QN08";
const key = "12345678901234567890";
const challenge = "12345678";
const code = await OCRA.generate(suite, key, challenge);
console.log(code); // e.g., "123456"const key = "3132333435363738393031323334353637383930"; // hex encoded seed key
const code = await OCRA.generate(
"OCRA-1:HOTP-SHA1-6:QN08",
key,
ORCA.bigIntToHex("00000000") // QN = numeric challenge
);const code = await OCRA.generate(
"OCRA-1:HOTP-SHA1-6:C-QN08",
key,
ORCA.bigIntToHex("12345678"), // QN = numeric challenge
ORCA.bigIntToHex("123") // counter
);const code = await OCRA.generate(
"OCRA-1:HOTP-SHA256-8:QN08-PSHA1",
key,
ORCA.bigIntToHex("12345678"), // QN = numeric challenge
undefined, // no counter
OCRA.stringToHex("1234") // PSHA1 = SHA1 password
);const timestampMinutes = Math.floor(Date.now() / 60000); // Actual nulber of minute from epoch because set T1M in ocra suite
const code = await OCRA.generate(
"OCRA-1:HOTP-SHA512-8:QN08-T1M",
key,
ORCA.bigIntToHex("12345678"), // QN = numeric challenge
undefined, // no counter
undefined, // no password
undefined, // no session
ORCA.bigIntToHex(timestampMinutes)
);The implementation automatically detects and uses available crypto libraries in this order:
- WebCrypto API (default)
- CryptoJS (alternative)
- jsSHA (alternative)
Automatique detection :
const cryptoInfo = OCRA.getCryptoInfo();
console.log('Libraries available:', cryptoInfo.available);
console.log('Primary library:', cryptoInfo.primary);<!-- Browser -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script><!-- Browser -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsSHA/3.3.1/sha.js"></script>try {
const code = await OCRA.generate(suite, key, challenge);
console.log("Success:", code);
} catch (error) {
console.error("OCRA Error:", error.message);
}Invalid OCRA suite format- Malformed suite stringInvalid crypto function- Unsupported hash algorithmCrypto library not supported- No compatible crypto library foundAlgorithm X not supported with Y- Library doesn't support the algorithm
GNU Lesser General Public License v3.0 or later (LGPL-3.0-or-later)
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.