@sphereon/ssi-sdk-ext.key-utils 0.36.1-next.47 → 0.36.1-next.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +133 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +133 -23
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/digest-methods.ts +13 -11
- package/src/functions.ts +133 -9
- package/src/types/key-util-types.ts +3 -0
package/src/functions.ts
CHANGED
|
@@ -31,6 +31,7 @@ import * as u8a from 'uint8arrays'
|
|
|
31
31
|
import { digestMethodParams } from './digest-methods'
|
|
32
32
|
import { validateJwk } from './jwk-jcs'
|
|
33
33
|
import {
|
|
34
|
+
DigestAlgorithm,
|
|
34
35
|
ENC_KEY_ALGS,
|
|
35
36
|
type IImportProvidedOrGeneratedKeyArgs,
|
|
36
37
|
JwkKeyUse,
|
|
@@ -198,8 +199,8 @@ export const toBase64url = (input: string): string => toString(fromString(input)
|
|
|
198
199
|
* Calculate the JWK thumbprint
|
|
199
200
|
* @param args
|
|
200
201
|
*/
|
|
201
|
-
export const calculateJwkThumbprint = (args: { jwk: JWK; digestAlgorithm?:
|
|
202
|
-
const
|
|
202
|
+
export const calculateJwkThumbprint = (args: { jwk: JWK; digestAlgorithm?: DigestAlgorithm }): string => {
|
|
203
|
+
const digestAlgorithm = normalizeHashAlgorithm(args.digestAlgorithm ?? 'SHA-256')
|
|
203
204
|
const jwk = sanitizedJwk(args.jwk)
|
|
204
205
|
let components
|
|
205
206
|
switch (jwk.kty) {
|
|
@@ -227,10 +228,7 @@ export const calculateJwkThumbprint = (args: { jwk: JWK; digestAlgorithm?: 'sha2
|
|
|
227
228
|
throw new Error('"kty" (Key Type) Parameter missing or unsupported')
|
|
228
229
|
}
|
|
229
230
|
const data = JSON.stringify(components)
|
|
230
|
-
|
|
231
|
-
return digestAlgorithm === 'sha512'
|
|
232
|
-
? digestMethodParams('SHA-512').digestMethod(data, 'base64url')
|
|
233
|
-
: digestMethodParams('SHA-256').digestMethod(data, 'base64url')
|
|
231
|
+
return digestMethodParams(digestAlgorithm).digestMethod(data, 'base64url')
|
|
234
232
|
}
|
|
235
233
|
|
|
236
234
|
export const toJwkFromKey = (
|
|
@@ -791,11 +789,49 @@ export const hexStringFromUint8Array = (value: Uint8Array): string => toString(v
|
|
|
791
789
|
|
|
792
790
|
export const signatureAlgorithmFromKey = async (args: SignatureAlgorithmFromKeyArgs): Promise<JoseSignatureAlgorithm> => {
|
|
793
791
|
const { key } = args
|
|
794
|
-
return signatureAlgorithmFromKeyType({ type: key.type })
|
|
792
|
+
return signatureAlgorithmFromKeyType({ type: key.type, algorithms: key.meta?.algorithms })
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
export function signatureAlgorithmToJoseAlgorithm(alg: string): JoseSignatureAlgorithm {
|
|
796
|
+
switch (alg) {
|
|
797
|
+
case 'RSA_SHA256':
|
|
798
|
+
return JoseSignatureAlgorithm.RS256
|
|
799
|
+
case 'RSA_SHA384':
|
|
800
|
+
return JoseSignatureAlgorithm.RS384
|
|
801
|
+
case 'RSA_SHA512':
|
|
802
|
+
return JoseSignatureAlgorithm.RS512
|
|
803
|
+
case 'RSA_SSA_PSS_SHA256_MGF1':
|
|
804
|
+
return JoseSignatureAlgorithm.PS256
|
|
805
|
+
case 'RSA_SSA_PSS_SHA384_MGF1':
|
|
806
|
+
return JoseSignatureAlgorithm.PS384
|
|
807
|
+
case 'RSA_SSA_PSS_SHA512_MGF1':
|
|
808
|
+
return JoseSignatureAlgorithm.PS512
|
|
809
|
+
case 'ECDSA_SHA256':
|
|
810
|
+
return JoseSignatureAlgorithm.ES256
|
|
811
|
+
case 'ECDSA_SHA384':
|
|
812
|
+
return JoseSignatureAlgorithm.ES384
|
|
813
|
+
case 'ECDSA_SHA512':
|
|
814
|
+
return JoseSignatureAlgorithm.ES512
|
|
815
|
+
case 'ES256K':
|
|
816
|
+
return JoseSignatureAlgorithm.ES256K
|
|
817
|
+
case 'ED25519':
|
|
818
|
+
case 'EdDSA':
|
|
819
|
+
return JoseSignatureAlgorithm.EdDSA
|
|
820
|
+
default:
|
|
821
|
+
// If already in JOSE format, return as-is
|
|
822
|
+
return alg as JoseSignatureAlgorithm
|
|
823
|
+
}
|
|
795
824
|
}
|
|
796
825
|
|
|
797
826
|
export const signatureAlgorithmFromKeyType = (args: SignatureAlgorithmFromKeyTypeArgs): JoseSignatureAlgorithm => {
|
|
798
|
-
const { type } = args
|
|
827
|
+
const { type, algorithms } = args
|
|
828
|
+
|
|
829
|
+
// If algorithms metadata is provided, use the first one
|
|
830
|
+
if (algorithms && algorithms.length > 0) {
|
|
831
|
+
return signatureAlgorithmToJoseAlgorithm(algorithms[0])
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// Fallback to type-based defaults
|
|
799
835
|
switch (type) {
|
|
800
836
|
case 'Ed25519':
|
|
801
837
|
case 'X25519':
|
|
@@ -809,7 +845,7 @@ export const signatureAlgorithmFromKeyType = (args: SignatureAlgorithmFromKeyTyp
|
|
|
809
845
|
case 'Secp256k1':
|
|
810
846
|
return JoseSignatureAlgorithm.ES256K
|
|
811
847
|
case 'RSA':
|
|
812
|
-
return JoseSignatureAlgorithm.PS256
|
|
848
|
+
return JoseSignatureAlgorithm.RS256 // Default to RS256 instead of PS256
|
|
813
849
|
default:
|
|
814
850
|
throw new Error(`Key type '${type}' not supported`)
|
|
815
851
|
}
|
|
@@ -1122,3 +1158,91 @@ export function toPkcs1FromHex(publicKeyHex: string) {
|
|
|
1122
1158
|
const pkcs1 = toPkcs1(fromString(publicKeyHex, 'hex'))
|
|
1123
1159
|
return toString(pkcs1, 'hex')
|
|
1124
1160
|
}
|
|
1161
|
+
|
|
1162
|
+
export function joseAlgorithmToDigest(alg: string): DigestAlgorithm {
|
|
1163
|
+
// Normalize the algorithm string by converting to uppercase and removing hyphens
|
|
1164
|
+
const normalized = alg.toUpperCase().replace(/-/g, '')
|
|
1165
|
+
|
|
1166
|
+
switch (normalized) {
|
|
1167
|
+
case 'RS256':
|
|
1168
|
+
case 'ES256':
|
|
1169
|
+
case 'ES256K':
|
|
1170
|
+
case 'PS256':
|
|
1171
|
+
case 'HS256':
|
|
1172
|
+
return 'SHA-256'
|
|
1173
|
+
case 'RS384':
|
|
1174
|
+
case 'ES384':
|
|
1175
|
+
case 'PS384':
|
|
1176
|
+
case 'HS384':
|
|
1177
|
+
return 'SHA-384'
|
|
1178
|
+
case 'RS512':
|
|
1179
|
+
case 'ES512':
|
|
1180
|
+
case 'PS512':
|
|
1181
|
+
case 'HS512':
|
|
1182
|
+
return 'SHA-512'
|
|
1183
|
+
case 'EDDSA':
|
|
1184
|
+
case 'ED25519':
|
|
1185
|
+
return 'SHA-512'
|
|
1186
|
+
default:
|
|
1187
|
+
throw new Error(`Unsupported JOSE algorithm: ${alg}. Cannot determine digest algorithm.`)
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
export function isHash(input: string): boolean {
|
|
1192
|
+
const length = input.length
|
|
1193
|
+
// SHA-256: 64 hex chars, SHA-384: 96 hex chars, SHA-512: 128 hex chars
|
|
1194
|
+
if (length !== 64 && length !== 96 && length !== 128) {
|
|
1195
|
+
return false
|
|
1196
|
+
}
|
|
1197
|
+
return input.match(/^([0-9A-Fa-f])+$/g) !== null
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
export function isHashString(input: Uint8Array): boolean {
|
|
1201
|
+
const length = input.length
|
|
1202
|
+
// SHA-256: 32 bytes, SHA-384: 48 bytes, SHA-512: 64 bytes
|
|
1203
|
+
if (length !== 32 && length !== 48 && length !== 64) {
|
|
1204
|
+
return false
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// A hash digest is raw binary data (any byte values 0x00-0xFF are valid).
|
|
1208
|
+
// We should NOT check if bytes are ASCII hex characters, as that would only detect
|
|
1209
|
+
// hex-encoded strings, not actual binary hash digests.
|
|
1210
|
+
// Instead, we use a heuristic: if the data looks like it has high entropy
|
|
1211
|
+
// and is the right length, we assume it's already a hash.
|
|
1212
|
+
|
|
1213
|
+
// Simple heuristic: Check if data is all printable ASCII (which would indicate it's NOT a hash)
|
|
1214
|
+
// Printable ASCII is roughly 0x20-0x7E
|
|
1215
|
+
let printableCount = 0
|
|
1216
|
+
for (let i = 0; i < length; i++) {
|
|
1217
|
+
const byte = input[i]
|
|
1218
|
+
if (byte === undefined) {
|
|
1219
|
+
return false
|
|
1220
|
+
}
|
|
1221
|
+
// Count printable ASCII characters
|
|
1222
|
+
if (byte >= 0x20 && byte <= 0x7e) {
|
|
1223
|
+
printableCount++
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// If more than 90% of bytes are printable ASCII, it's likely NOT a raw binary hash
|
|
1228
|
+
// Raw binary hashes should have a more uniform distribution across all byte values
|
|
1229
|
+
const printableRatio = printableCount / length
|
|
1230
|
+
return printableRatio < 0.9
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
export type HashAlgorithm = 'SHA-256' | 'sha256' | 'SHA-384' | 'sha384' | 'SHA-512' | 'sha512'
|
|
1234
|
+
|
|
1235
|
+
export function normalizeHashAlgorithm(alg?: HashAlgorithm): 'SHA-256' | 'SHA-384' | 'SHA-512' {
|
|
1236
|
+
if (!alg) {
|
|
1237
|
+
return 'SHA-256'
|
|
1238
|
+
}
|
|
1239
|
+
const upper = alg.toUpperCase()
|
|
1240
|
+
if (upper.includes('256')) return 'SHA-256'
|
|
1241
|
+
if (upper.includes('384')) return 'SHA-384'
|
|
1242
|
+
if (upper.includes('512')) return 'SHA-512'
|
|
1243
|
+
throw new Error(`Invalid hash algorithm: ${alg}`)
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
export function isSameHash(left: HashAlgorithm, right: HashAlgorithm): boolean {
|
|
1247
|
+
return normalizeHashAlgorithm(left) === normalizeHashAlgorithm(right)
|
|
1248
|
+
}
|
|
@@ -21,6 +21,8 @@ export const ENC_KEY_ALGS = ['X25519', 'ECDH_ES_A256KW', 'RSA_OAEP_256']
|
|
|
21
21
|
|
|
22
22
|
export type KeyVisibility = 'public' | 'private'
|
|
23
23
|
|
|
24
|
+
export type DigestAlgorithm = 'SHA-256' | 'sha256' | 'SHA-384' | 'sha384' | 'SHA-512' | 'sha512'
|
|
25
|
+
|
|
24
26
|
export interface X509Opts {
|
|
25
27
|
cn?: string // The certificate Common Name. Will be used as the KID for the private key. Uses alias if not provided.
|
|
26
28
|
privateKeyPEM?: string // Optional as you also need to provide it in hex format, but advisable to use it
|
|
@@ -53,6 +55,7 @@ export type SignatureAlgorithmFromKeyArgs = {
|
|
|
53
55
|
|
|
54
56
|
export type SignatureAlgorithmFromKeyTypeArgs = {
|
|
55
57
|
type: TKeyType
|
|
58
|
+
algorithms?: string[]
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
export type KeyTypeFromCryptographicSuiteArgs = {
|