Skip to content

Commit 9264d3a

Browse files
committed
feat(jwt): add support for HS384 algorithm
1 parent 1ccda81 commit 9264d3a

5 files changed

Lines changed: 32 additions & 18 deletions

File tree

Jwt/NAVFoundation.Jwt.axi

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,7 @@ define_function char[HMAC_SHA512_HASH_SIZE] NAVJwtSignData(char data[], char sec
364364
return NAVHmacSha256(secret, data)
365365
}
366366
case NAV_JWT_ALG_TYPE_HS384: {
367-
NAVLibraryFunctionErrorLog(NAV_LOG_LEVEL_ERROR,
368-
__NAV_FOUNDATION_JWT__,
369-
'NAVJwtSignData',
370-
'HS384 algorithm is not supported')
371-
return ''
367+
return NAVHmacSha384(secret, data)
372368
}
373369
case NAV_JWT_ALG_TYPE_HS512: {
374370
return NAVHmacSha512(secret, data)

Jwt/README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This library implements:
1212
Key features:
1313

1414
- Create JWT tokens with custom headers and payloads
15-
- Sign tokens using HMAC algorithms (HS256, HS512; HS384 not yet implemented)
15+
- Sign tokens using HMAC algorithms (HS256, HS384, HS512)
1616
- Verify token signatures
1717
- Decode and extract token components
1818
- Time-based validation (exp, nbf, iat claims)
@@ -272,7 +272,7 @@ define_function char[NAV_JWT_MAX_JSON_LENGTH] NAVJwtCreateHeader(char algorithm[
272272

273273
**Parameters:**
274274

275-
- `algorithm` - Signing algorithm (use `NAV_JWT_ALG_HS256` or `NAV_JWT_ALG_HS512`; HS384 not yet implemented)
275+
- `algorithm` - Signing algorithm (use `NAV_JWT_ALG_HS256`, `NAV_JWT_ALG_HS384`, or `NAV_JWT_ALG_HS512`)
276276
- `tokenType` - Token type (default: `NAV_JWT_TYP_JWT`)
277277

278278
**Returns:** JSON string representing the JWT header
@@ -567,12 +567,12 @@ define_function integer ValidateTokenTiming(char token[], char secret[]) {
567567

568568
### Algorithm Constants
569569

570-
| Constant | Value | Description |
571-
| ------------------- | --------- | ----------------------------------------- |
572-
| `NAV_JWT_ALG_HS256` | `"HS256"` | HMAC using SHA-256 (recommended) |
573-
| `NAV_JWT_ALG_HS384` | `"HS384"` | HMAC using SHA-384 (not yet implemented) |
574-
| `NAV_JWT_ALG_HS512` | `"HS512"` | HMAC using SHA-512 (strongest) |
575-
| `NAV_JWT_ALG_NONE` | `"none"` | No signature (unsafe - use with caution!) |
570+
| Constant | Value | Description |
571+
| ------------------- | --------- | --------------------------- |
572+
| `NAV_JWT_ALG_HS256` | `"HS256"` | HMAC using SHA-256 |
573+
| `NAV_JWT_ALG_HS384` | `"HS384"` | HMAC using SHA-384 |
574+
| `NAV_JWT_ALG_HS512` | `"HS512"` | HMAC using SHA-512 |
575+
| `NAV_JWT_ALG_NONE` | `"none"` | No signature (use caution!) |
576576

577577
### Error Codes
578578

__tests__/include/jwt/NAVJwtCreate.axi

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ constant char JWT_CREATE_TEST_PAYLOADS[][1024] = {
99
'{"sub":"1234567890","name":"John Doe","email":"john.doe@example.com","role":"admin","permissions":["read","write","delete"],"iat":1516239022}', // Complex
1010
'', // Empty (should fail)
1111
'{"exp":0}', // Zero timestamp
12-
'{"sub":"very_long_subject_string_with_lots_of_characters_to_test_boundary_conditions_in_the_jwt_implementation"}' // Long value
12+
'{"sub":"very_long_subject_string_with_lots_of_characters_to_test_boundary_conditions_in_the_jwt_implementation"}', // Long value
13+
'{"sub":"test384","name":"HS384 Test"}' // HS384 test
1314
}
1415

1516
// Expected success/failure for create tests
@@ -19,6 +20,7 @@ constant char JWT_CREATE_TEST_EXPECTED_RESULT[] = {
1920
true,
2021
false,
2122
true,
23+
true,
2224
true
2325
}
2426

@@ -28,7 +30,8 @@ constant char JWT_CREATE_TEST_EXPECTED_HEADER[][255] = {
2830
'{"alg":"HS512","typ":"JWT"}',
2931
'{"alg":"HS256","typ":"JWT"}',
3032
'{"alg":"HS512","typ":"JWT"}',
31-
'{"alg":"HS256","typ":"JWT"}'
33+
'{"alg":"HS256","typ":"JWT"}',
34+
'{"alg":"HS384","typ":"JWT"}'
3235
}
3336

3437
constant char JWT_CREATE_TEST_EXPECTED_TOKEN[][NAV_JWT_MAX_TOKEN_LENGTH] = {
@@ -37,7 +40,8 @@ constant char JWT_CREATE_TEST_EXPECTED_TOKEN[][NAV_JWT_MAX_TOKEN_LENGTH] = {
3740
'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZW1haWwiOiJqb2huLmRvZUBleGFtcGxlLmNvbSIsInJvbGUiOiJhZG1pbiIsInBlcm1pc3Npb25zIjpbInJlYWQiLCJ3cml0ZSIsImRlbGV0ZSJdLCJpYXQiOjE1MTYyMzkwMjJ9.rNdpOMrWSuLXkM-ZpDf5h105WbtNUJK8wDBJu-OtII22JCSUb6KwRlLYHfTIHsNCj1fFvuVsEW03jXz8npo-pA',
3841
'',
3942
'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjB9.S2L6nE_7uhQhro2FiY-nx1o1c1mpdZ8Txy1zzI_KoKm-9O46rmSAmiUJFz8Ur9WFtiSJ88xqYuab_ecoiwEIYA',
40-
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ2ZXJ5X2xvbmdfc3ViamVjdF9zdHJpbmdfd2l0aF9sb3RzX29mX2NoYXJhY3RlcnNfdG9fdGVzdF9ib3VuZGFyeV9jb25kaXRpb25zX2luX3RoZV9qd3RfaW1wbGVtZW50YXRpb24ifQ.qLdhVATRZUtc7X9C9E1u0MFwnIkU5-5rOFBfO3COmes'
43+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ2ZXJ5X2xvbmdfc3ViamVjdF9zdHJpbmdfd2l0aF9sb3RzX29mX2NoYXJhY3RlcnNfdG9fdGVzdF9ib3VuZGFyeV9jb25kaXRpb25zX2luX3RoZV9qd3RfaW1wbGVtZW50YXRpb24ifQ.qLdhVATRZUtc7X9C9E1u0MFwnIkU5-5rOFBfO3COmes',
44+
'eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0Mzg0IiwibmFtZSI6IkhTMzg0IFRlc3QifQ.MrCpeBpIKrmKcj78okchRkWdnV-szd4Iwyb0q5_sGzjCjY1Kpzi2fKdXP5BAeDZG'
4145
}
4246

4347
// Test algorithms for creation
@@ -47,7 +51,8 @@ constant char JWT_CREATE_TEST_ALGORITHMS[][32] = {
4751
'HS512',
4852
'HS256',
4953
'HS512',
50-
'HS256'
54+
'HS256',
55+
'HS384'
5156
}
5257

5358
// Test secrets for creation (RFC 7518 compliant lengths)
@@ -57,7 +62,8 @@ constant char JWT_CREATE_TEST_SECRETS[][128] = {
5762
'your-512-bit-secret-key-with-lots-of-entropy-and-more-padding-1234', // 64 bytes for HS512
5863
'your-256-bit-secret-1234567890ab', // 32 bytes for HS256
5964
'your-512-bit-secret-key-with-lots-of-entropy-and-more-padding-1234', // 64 bytes for HS512
60-
'your-256-bit-secret-1234567890ab' // 32 bytes for HS256
65+
'your-256-bit-secret-1234567890ab', // 32 bytes for HS256
66+
'your-384-bit-secret-key-with-good-entropy-1234567890' // 48+ bytes for HS384
6167
}
6268

6369
define_function TestNAVJwtCreate() {

__tests__/include/jwt/NAVJwtVerify.axi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ constant char JWT_VERIFY_TEST_TOKENS[][NAV_JWT_MAX_TOKEN_LENGTH] = {
77
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wy2x0PggFVbsBBSMKYNE2OwRzvGvZAn0kfzx0VT3VqQ', // Test 1 from Create - HS256
88
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIn0.7w8IDk7KV2rJ_JKsJXrGR5d5ypZBrJp1Z1CL6y-0ViU', // Test 2 from Create - HS256
99
'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZW1haWwiOiJqb2huLmRvZUBleGFtcGxlLmNvbSIsInJvbGUiOiJhZG1pbiIsInBlcm1pc3Npb25zIjpbInJlYWQiLCJ3cml0ZSIsImRlbGV0ZSJdLCJpYXQiOjE1MTYyMzkwMjJ9.rNdpOMrWSuLXkM-ZpDf5h105WbtNUJK8wDBJu-OtII22JCSUb6KwRlLYHfTIHsNCj1fFvuVsEW03jXz8npo-pA', // Test 3 from Create - HS512
10+
'eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0Mzg0IiwibmFtZSI6IkhTMzg0IFRlc3QifQ.MrCpeBpIKrmKcj78okchRkWdnV-szd4Iwyb0q5_sGzjCjY1Kpzi2fKdXP5BAeDZG', // Test 7 from Create - HS384
1011
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wy2x0PggFVbsBBSMKYNE2OwRzvGvZAn0kfzx0VT3VqQ', // Valid token with wrong secret
1112
'', // Empty token (should fail)
1213
'invalid.token', // Only 2 parts (should fail)
@@ -18,6 +19,7 @@ constant char JWT_VERIFY_TEST_SECRETS[][128] = {
1819
'your-256-bit-secret-1234567890ab', // 32 bytes for HS256 - correct
1920
'your-256-bit-secret-1234567890ab', // 32 bytes for HS256 - correct
2021
'your-512-bit-secret-key-with-lots-of-entropy-and-more-padding-1234', // 64 bytes for HS512 - correct
22+
'your-384-bit-secret-key-with-good-entropy-1234567890', // 48+ bytes for HS384 - correct
2123
'wrong-secret-that-should-not-match', // Wrong secret (should fail)
2224
'your-256-bit-secret-1234567890ab', // Secret doesn't matter for empty token
2325
'your-256-bit-secret-1234567890ab', // Secret doesn't matter for malformed token
@@ -29,6 +31,7 @@ constant char JWT_VERIFY_EXPECTED_RESULT[] = {
2931
true, // Valid token with correct secret
3032
true, // Valid token with correct secret
3133
true, // Valid token with correct secret
34+
true, // Valid HS384 token with correct secret
3235
false, // Valid token with wrong secret
3336
false, // Empty token
3437
false, // Malformed token

__tests__/include/jwt/NAVJwtVerifyAndDecode.axi

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ constant char JWT_VERIFY_AND_DECODE_TEST_TOKENS[][NAV_JWT_MAX_TOKEN_LENGTH] = {
77
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wy2x0PggFVbsBBSMKYNE2OwRzvGvZAn0kfzx0VT3VqQ', // Test 1 from Create - HS256
88
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIn0.7w8IDk7KV2rJ_JKsJXrGR5d5ypZBrJp1Z1CL6y-0ViU', // Test 2 from Create - HS256
99
'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZW1haWwiOiJqb2huLmRvZUBleGFtcGxlLmNvbSIsInJvbGUiOiJhZG1pbiIsInBlcm1pc3Npb25zIjpbInJlYWQiLCJ3cml0ZSIsImRlbGV0ZSJdLCJpYXQiOjE1MTYyMzkwMjJ9.rNdpOMrWSuLXkM-ZpDf5h105WbtNUJK8wDBJu-OtII22JCSUb6KwRlLYHfTIHsNCj1fFvuVsEW03jXz8npo-pA', // Test 3 from Create - HS512
10+
'eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0Mzg0IiwibmFtZSI6IkhTMzg0IFRlc3QifQ.MrCpeBpIKrmKcj78okchRkWdnV-szd4Iwyb0q5_sGzjCjY1Kpzi2fKdXP5BAeDZG', // Test 7 from Create - HS384
1011
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wy2x0PggFVbsBBSMKYNE2OwRzvGvZAn0kfzx0VT3VqQ', // Valid token with wrong secret
1112
'', // Empty token
1213
'invalid.token', // Malformed (only 2 parts)
@@ -18,6 +19,7 @@ constant char JWT_VERIFY_AND_DECODE_TEST_SECRETS[][128] = {
1819
'your-256-bit-secret-1234567890ab', // 32 bytes for HS256 - correct
1920
'your-256-bit-secret-1234567890ab', // 32 bytes for HS256 - correct
2021
'your-512-bit-secret-key-with-lots-of-entropy-and-more-padding-1234', // 64 bytes for HS512 - correct
22+
'your-384-bit-secret-key-with-good-entropy-1234567890', // 48+ bytes for HS384 - correct
2123
'wrong-secret-that-should-not-match', // Wrong secret
2224
'your-256-bit-secret-1234567890ab', // Doesn't matter for empty
2325
'your-256-bit-secret-1234567890ab', // Doesn't matter for malformed
@@ -29,6 +31,7 @@ constant char JWT_VERIFY_AND_DECODE_EXPECTED_RESULT[] = {
2931
true, // Valid token with correct secret
3032
true, // Valid token with correct secret
3133
true, // Valid token with correct secret
34+
true, // Valid HS384 token with correct secret
3235
false, // Valid token with wrong secret (decodes but verification fails)
3336
false, // Empty token (decode fails)
3437
false, // Malformed token (decode fails)
@@ -40,6 +43,7 @@ constant char JWT_VERIFY_AND_DECODE_EXPECTED_IS_VALID[] = {
4043
true, // Verified and valid
4144
true, // Verified and valid
4245
true, // Verified and valid
46+
true, // Verified and valid HS384
4347
false, // Wrong secret - signature invalid
4448
false, // Empty token - decode failed
4549
false, // Malformed - decode failed
@@ -51,6 +55,7 @@ constant sinteger JWT_VERIFY_AND_DECODE_EXPECTED_ERRORS[] = {
5155
NAV_JWT_SUCCESS,
5256
NAV_JWT_SUCCESS,
5357
NAV_JWT_SUCCESS,
58+
NAV_JWT_SUCCESS,
5459
NAV_JWT_ERROR_INVALID_SIGNATURE,
5560
NAV_JWT_ERROR_EMPTY_TOKEN,
5661
NAV_JWT_ERROR_INVALID_FORMAT,
@@ -62,6 +67,7 @@ constant char JWT_VERIFY_AND_DECODE_EXPECTED_HEADER[][255] = {
6267
'{"alg":"HS256","typ":"JWT"}',
6368
'{"alg":"HS256","typ":"JWT"}',
6469
'{"alg":"HS512","typ":"JWT"}',
70+
'{"alg":"HS384","typ":"JWT"}',
6571
'{"alg":"HS256","typ":"JWT"}',
6672
'', // Empty token - no header
6773
'', // Malformed - no header
@@ -73,6 +79,7 @@ constant char JWT_VERIFY_AND_DECODE_EXPECTED_PAYLOAD[][1024] = {
7379
'{"sub":"1234567890","name":"John Doe","iat":1516239022}',
7480
'{"sub":"user123"}',
7581
'{"sub":"1234567890","name":"John Doe","email":"john.doe@example.com","role":"admin","permissions":["read","write","delete"],"iat":1516239022}',
82+
'{"sub":"test384","name":"HS384 Test"}',
7683
'{"sub":"1234567890","name":"John Doe","iat":1516239022}',
7784
'', // Empty token - no payload
7885
'', // Malformed - no payload
@@ -84,6 +91,7 @@ constant char JWT_VERIFY_AND_DECODE_EXPECTED_ALG[][32] = {
8491
'HS256',
8592
'HS256',
8693
'HS512',
94+
'HS384',
8795
'HS256',
8896
'', // Empty token
8997
'', // Malformed
@@ -95,6 +103,7 @@ constant sinteger JWT_VERIFY_AND_DECODE_EXPECTED_ALG_TYPE[] = {
95103
NAV_JWT_ALG_TYPE_HS256,
96104
NAV_JWT_ALG_TYPE_HS256,
97105
NAV_JWT_ALG_TYPE_HS512,
106+
NAV_JWT_ALG_TYPE_HS384,
98107
NAV_JWT_ALG_TYPE_HS256,
99108
NAV_JWT_ALG_TYPE_UNKNOWN, // Empty token
100109
NAV_JWT_ALG_TYPE_UNKNOWN, // Malformed

0 commit comments

Comments
 (0)