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.