@sd-jwt/crypto-nodejs 0.3.2-next.72 → 0.3.2-next.74
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.d.mts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +109 -0
- package/dist/index.mjs +109 -0
- package/package.json +2 -2
- package/src/crypto.ts +86 -0
- package/src/test/crypto.spec.ts +26 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
declare const generateSalt: (length: number) => string;
|
|
2
2
|
declare const digest: (data: string, algorithm?: string) => Uint8Array;
|
|
3
|
+
declare const ES256: {
|
|
4
|
+
alg: string;
|
|
5
|
+
generateKeyPair(): Promise<{
|
|
6
|
+
publicKey: JsonWebKey;
|
|
7
|
+
privateKey: JsonWebKey;
|
|
8
|
+
}>;
|
|
9
|
+
getSigner(privateKeyJWK: object): Promise<(data: string) => Promise<string>>;
|
|
10
|
+
getVerifier(publicKeyJWK: object): Promise<(data: string, signatureBase64url: string) => Promise<boolean>>;
|
|
11
|
+
};
|
|
3
12
|
|
|
4
|
-
export { digest, generateSalt };
|
|
13
|
+
export { ES256, digest, generateSalt };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
declare const generateSalt: (length: number) => string;
|
|
2
2
|
declare const digest: (data: string, algorithm?: string) => Uint8Array;
|
|
3
|
+
declare const ES256: {
|
|
4
|
+
alg: string;
|
|
5
|
+
generateKeyPair(): Promise<{
|
|
6
|
+
publicKey: JsonWebKey;
|
|
7
|
+
privateKey: JsonWebKey;
|
|
8
|
+
}>;
|
|
9
|
+
getSigner(privateKeyJWK: object): Promise<(data: string) => Promise<string>>;
|
|
10
|
+
getVerifier(publicKeyJWK: object): Promise<(data: string, signatureBase64url: string) => Promise<boolean>>;
|
|
11
|
+
};
|
|
3
12
|
|
|
4
|
-
export { digest, generateSalt };
|
|
13
|
+
export { ES256, digest, generateSalt };
|
package/dist/index.js
CHANGED
|
@@ -16,10 +16,31 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var __async = (__this, __arguments, generator) => {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
var fulfilled = (value) => {
|
|
22
|
+
try {
|
|
23
|
+
step(generator.next(value));
|
|
24
|
+
} catch (e) {
|
|
25
|
+
reject(e);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var rejected = (value) => {
|
|
29
|
+
try {
|
|
30
|
+
step(generator.throw(value));
|
|
31
|
+
} catch (e) {
|
|
32
|
+
reject(e);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
36
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
37
|
+
});
|
|
38
|
+
};
|
|
19
39
|
|
|
20
40
|
// src/index.ts
|
|
21
41
|
var src_exports = {};
|
|
22
42
|
__export(src_exports, {
|
|
43
|
+
ES256: () => ES256,
|
|
23
44
|
digest: () => digest,
|
|
24
45
|
generateSalt: () => generateSalt
|
|
25
46
|
});
|
|
@@ -43,8 +64,96 @@ var digest = (data, algorithm = "SHA-256") => {
|
|
|
43
64
|
return new Uint8Array(hashBuffer);
|
|
44
65
|
};
|
|
45
66
|
var toNodeCryptoAlg = (hashAlg) => hashAlg.replace("-", "").toLowerCase();
|
|
67
|
+
var ES256 = {
|
|
68
|
+
alg: "ES256",
|
|
69
|
+
generateKeyPair() {
|
|
70
|
+
return __async(this, null, function* () {
|
|
71
|
+
const { subtle } = globalThis.crypto;
|
|
72
|
+
const keyPair = yield subtle.generateKey(
|
|
73
|
+
{
|
|
74
|
+
name: "ECDSA",
|
|
75
|
+
namedCurve: "P-256"
|
|
76
|
+
// ES256
|
|
77
|
+
},
|
|
78
|
+
true,
|
|
79
|
+
// whether the key is extractable (i.e., can be used in exportKey)
|
|
80
|
+
["sign", "verify"]
|
|
81
|
+
// can be used to sign and verify signatures
|
|
82
|
+
);
|
|
83
|
+
const publicKeyJWK = yield subtle.exportKey("jwk", keyPair.publicKey);
|
|
84
|
+
const privateKeyJWK = yield subtle.exportKey("jwk", keyPair.privateKey);
|
|
85
|
+
return { publicKey: publicKeyJWK, privateKey: privateKeyJWK };
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
getSigner(privateKeyJWK) {
|
|
89
|
+
return __async(this, null, function* () {
|
|
90
|
+
const { subtle } = globalThis.crypto;
|
|
91
|
+
const privateKey = yield subtle.importKey(
|
|
92
|
+
"jwk",
|
|
93
|
+
privateKeyJWK,
|
|
94
|
+
{
|
|
95
|
+
name: "ECDSA",
|
|
96
|
+
namedCurve: "P-256"
|
|
97
|
+
// Must match the curve used to generate the key
|
|
98
|
+
},
|
|
99
|
+
true,
|
|
100
|
+
// whether the key is extractable (i.e., can be used in exportKey)
|
|
101
|
+
["sign"]
|
|
102
|
+
);
|
|
103
|
+
return (data) => __async(this, null, function* () {
|
|
104
|
+
const encoder = new TextEncoder();
|
|
105
|
+
const signature = yield subtle.sign(
|
|
106
|
+
{
|
|
107
|
+
name: "ECDSA",
|
|
108
|
+
hash: { name: "SHA-256" }
|
|
109
|
+
// Required for ES256
|
|
110
|
+
},
|
|
111
|
+
privateKey,
|
|
112
|
+
encoder.encode(data)
|
|
113
|
+
);
|
|
114
|
+
return btoa(String.fromCharCode(...new Uint8Array(signature))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
getVerifier(publicKeyJWK) {
|
|
119
|
+
return __async(this, null, function* () {
|
|
120
|
+
const { subtle } = globalThis.crypto;
|
|
121
|
+
const publicKey = yield subtle.importKey(
|
|
122
|
+
"jwk",
|
|
123
|
+
publicKeyJWK,
|
|
124
|
+
{
|
|
125
|
+
name: "ECDSA",
|
|
126
|
+
namedCurve: "P-256"
|
|
127
|
+
// Must match the curve used to generate the key
|
|
128
|
+
},
|
|
129
|
+
true,
|
|
130
|
+
// whether the key is extractable (i.e., can be used in exportKey)
|
|
131
|
+
["verify"]
|
|
132
|
+
);
|
|
133
|
+
return (data, signatureBase64url) => __async(this, null, function* () {
|
|
134
|
+
const encoder = new TextEncoder();
|
|
135
|
+
const signature = Uint8Array.from(
|
|
136
|
+
atob(signatureBase64url.replace(/-/g, "+").replace(/_/g, "/")),
|
|
137
|
+
(c) => c.charCodeAt(0)
|
|
138
|
+
);
|
|
139
|
+
const isValid = yield subtle.verify(
|
|
140
|
+
{
|
|
141
|
+
name: "ECDSA",
|
|
142
|
+
hash: { name: "SHA-256" }
|
|
143
|
+
// Required for ES256
|
|
144
|
+
},
|
|
145
|
+
publicKey,
|
|
146
|
+
signature,
|
|
147
|
+
encoder.encode(data)
|
|
148
|
+
);
|
|
149
|
+
return isValid;
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
};
|
|
46
154
|
// Annotate the CommonJS export names for ESM import in node:
|
|
47
155
|
0 && (module.exports = {
|
|
156
|
+
ES256,
|
|
48
157
|
digest,
|
|
49
158
|
generateSalt
|
|
50
159
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
var __async = (__this, __arguments, generator) => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
var fulfilled = (value) => {
|
|
4
|
+
try {
|
|
5
|
+
step(generator.next(value));
|
|
6
|
+
} catch (e) {
|
|
7
|
+
reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var rejected = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.throw(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
18
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
1
22
|
// src/crypto.ts
|
|
2
23
|
import { createHash, randomBytes } from "crypto";
|
|
3
24
|
var generateSalt = (length) => {
|
|
@@ -16,7 +37,95 @@ var digest = (data, algorithm = "SHA-256") => {
|
|
|
16
37
|
return new Uint8Array(hashBuffer);
|
|
17
38
|
};
|
|
18
39
|
var toNodeCryptoAlg = (hashAlg) => hashAlg.replace("-", "").toLowerCase();
|
|
40
|
+
var ES256 = {
|
|
41
|
+
alg: "ES256",
|
|
42
|
+
generateKeyPair() {
|
|
43
|
+
return __async(this, null, function* () {
|
|
44
|
+
const { subtle } = globalThis.crypto;
|
|
45
|
+
const keyPair = yield subtle.generateKey(
|
|
46
|
+
{
|
|
47
|
+
name: "ECDSA",
|
|
48
|
+
namedCurve: "P-256"
|
|
49
|
+
// ES256
|
|
50
|
+
},
|
|
51
|
+
true,
|
|
52
|
+
// whether the key is extractable (i.e., can be used in exportKey)
|
|
53
|
+
["sign", "verify"]
|
|
54
|
+
// can be used to sign and verify signatures
|
|
55
|
+
);
|
|
56
|
+
const publicKeyJWK = yield subtle.exportKey("jwk", keyPair.publicKey);
|
|
57
|
+
const privateKeyJWK = yield subtle.exportKey("jwk", keyPair.privateKey);
|
|
58
|
+
return { publicKey: publicKeyJWK, privateKey: privateKeyJWK };
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
getSigner(privateKeyJWK) {
|
|
62
|
+
return __async(this, null, function* () {
|
|
63
|
+
const { subtle } = globalThis.crypto;
|
|
64
|
+
const privateKey = yield subtle.importKey(
|
|
65
|
+
"jwk",
|
|
66
|
+
privateKeyJWK,
|
|
67
|
+
{
|
|
68
|
+
name: "ECDSA",
|
|
69
|
+
namedCurve: "P-256"
|
|
70
|
+
// Must match the curve used to generate the key
|
|
71
|
+
},
|
|
72
|
+
true,
|
|
73
|
+
// whether the key is extractable (i.e., can be used in exportKey)
|
|
74
|
+
["sign"]
|
|
75
|
+
);
|
|
76
|
+
return (data) => __async(this, null, function* () {
|
|
77
|
+
const encoder = new TextEncoder();
|
|
78
|
+
const signature = yield subtle.sign(
|
|
79
|
+
{
|
|
80
|
+
name: "ECDSA",
|
|
81
|
+
hash: { name: "SHA-256" }
|
|
82
|
+
// Required for ES256
|
|
83
|
+
},
|
|
84
|
+
privateKey,
|
|
85
|
+
encoder.encode(data)
|
|
86
|
+
);
|
|
87
|
+
return btoa(String.fromCharCode(...new Uint8Array(signature))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
getVerifier(publicKeyJWK) {
|
|
92
|
+
return __async(this, null, function* () {
|
|
93
|
+
const { subtle } = globalThis.crypto;
|
|
94
|
+
const publicKey = yield subtle.importKey(
|
|
95
|
+
"jwk",
|
|
96
|
+
publicKeyJWK,
|
|
97
|
+
{
|
|
98
|
+
name: "ECDSA",
|
|
99
|
+
namedCurve: "P-256"
|
|
100
|
+
// Must match the curve used to generate the key
|
|
101
|
+
},
|
|
102
|
+
true,
|
|
103
|
+
// whether the key is extractable (i.e., can be used in exportKey)
|
|
104
|
+
["verify"]
|
|
105
|
+
);
|
|
106
|
+
return (data, signatureBase64url) => __async(this, null, function* () {
|
|
107
|
+
const encoder = new TextEncoder();
|
|
108
|
+
const signature = Uint8Array.from(
|
|
109
|
+
atob(signatureBase64url.replace(/-/g, "+").replace(/_/g, "/")),
|
|
110
|
+
(c) => c.charCodeAt(0)
|
|
111
|
+
);
|
|
112
|
+
const isValid = yield subtle.verify(
|
|
113
|
+
{
|
|
114
|
+
name: "ECDSA",
|
|
115
|
+
hash: { name: "SHA-256" }
|
|
116
|
+
// Required for ES256
|
|
117
|
+
},
|
|
118
|
+
publicKey,
|
|
119
|
+
signature,
|
|
120
|
+
encoder.encode(data)
|
|
121
|
+
);
|
|
122
|
+
return isValid;
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
};
|
|
19
127
|
export {
|
|
128
|
+
ES256,
|
|
20
129
|
digest,
|
|
21
130
|
generateSalt
|
|
22
131
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sd-jwt/crypto-nodejs",
|
|
3
|
-
"version": "0.3.2-next.
|
|
3
|
+
"version": "0.3.2-next.74+d503996",
|
|
4
4
|
"description": "sd-jwt draft 7 implementation in typescript",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"esm"
|
|
53
53
|
]
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "d5039962a53cb1b55a28dc956d71eab865c05917"
|
|
56
56
|
}
|
package/src/crypto.ts
CHANGED
|
@@ -19,3 +19,89 @@ export const digest = (data: string, algorithm = 'SHA-256'): Uint8Array => {
|
|
|
19
19
|
|
|
20
20
|
const toNodeCryptoAlg = (hashAlg: string): string =>
|
|
21
21
|
hashAlg.replace('-', '').toLowerCase();
|
|
22
|
+
|
|
23
|
+
export const ES256 = {
|
|
24
|
+
alg: 'ES256',
|
|
25
|
+
|
|
26
|
+
async generateKeyPair() {
|
|
27
|
+
const { subtle } = globalThis.crypto;
|
|
28
|
+
const keyPair = await subtle.generateKey(
|
|
29
|
+
{
|
|
30
|
+
name: 'ECDSA',
|
|
31
|
+
namedCurve: 'P-256', // ES256
|
|
32
|
+
},
|
|
33
|
+
true, // whether the key is extractable (i.e., can be used in exportKey)
|
|
34
|
+
['sign', 'verify'], // can be used to sign and verify signatures
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Export the public and private keys in JWK format
|
|
38
|
+
const publicKeyJWK = await subtle.exportKey('jwk', keyPair.publicKey);
|
|
39
|
+
const privateKeyJWK = await subtle.exportKey('jwk', keyPair.privateKey);
|
|
40
|
+
|
|
41
|
+
return { publicKey: publicKeyJWK, privateKey: privateKeyJWK };
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
async getSigner(privateKeyJWK: object) {
|
|
45
|
+
const { subtle } = globalThis.crypto;
|
|
46
|
+
const privateKey = await subtle.importKey(
|
|
47
|
+
'jwk',
|
|
48
|
+
privateKeyJWK,
|
|
49
|
+
{
|
|
50
|
+
name: 'ECDSA',
|
|
51
|
+
namedCurve: 'P-256', // Must match the curve used to generate the key
|
|
52
|
+
},
|
|
53
|
+
true, // whether the key is extractable (i.e., can be used in exportKey)
|
|
54
|
+
['sign'],
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return async (data: string) => {
|
|
58
|
+
const encoder = new TextEncoder();
|
|
59
|
+
const signature = await subtle.sign(
|
|
60
|
+
{
|
|
61
|
+
name: 'ECDSA',
|
|
62
|
+
hash: { name: 'SHA-256' }, // Required for ES256
|
|
63
|
+
},
|
|
64
|
+
privateKey,
|
|
65
|
+
encoder.encode(data),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return btoa(String.fromCharCode(...new Uint8Array(signature)))
|
|
69
|
+
.replace(/\+/g, '-')
|
|
70
|
+
.replace(/\//g, '_')
|
|
71
|
+
.replace(/=+$/, ''); // Convert to base64url format
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
async getVerifier(publicKeyJWK: object) {
|
|
76
|
+
const { subtle } = globalThis.crypto;
|
|
77
|
+
const publicKey = await subtle.importKey(
|
|
78
|
+
'jwk',
|
|
79
|
+
publicKeyJWK,
|
|
80
|
+
{
|
|
81
|
+
name: 'ECDSA',
|
|
82
|
+
namedCurve: 'P-256', // Must match the curve used to generate the key
|
|
83
|
+
},
|
|
84
|
+
true, // whether the key is extractable (i.e., can be used in exportKey)
|
|
85
|
+
['verify'],
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
return async (data: string, signatureBase64url: string) => {
|
|
89
|
+
const encoder = new TextEncoder();
|
|
90
|
+
const signature = Uint8Array.from(
|
|
91
|
+
atob(signatureBase64url.replace(/-/g, '+').replace(/_/g, '/')),
|
|
92
|
+
(c) => c.charCodeAt(0),
|
|
93
|
+
);
|
|
94
|
+
const isValid = await subtle.verify(
|
|
95
|
+
{
|
|
96
|
+
name: 'ECDSA',
|
|
97
|
+
hash: { name: 'SHA-256' }, // Required for ES256
|
|
98
|
+
},
|
|
99
|
+
publicKey,
|
|
100
|
+
signature,
|
|
101
|
+
encoder.encode(data),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
return isValid;
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
};
|
package/src/test/crypto.spec.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { generateSalt, digest } from '../
|
|
2
|
+
import { generateSalt, digest, ES256 } from '../index';
|
|
3
|
+
|
|
4
|
+
// Extract the major version as a number
|
|
5
|
+
const nodeVersionMajor = parseInt(
|
|
6
|
+
process.version.split('.')[0].substring(1),
|
|
7
|
+
10,
|
|
8
|
+
);
|
|
3
9
|
|
|
4
10
|
describe('This file is for utility functions', () => {
|
|
5
11
|
test('generateSalt', async () => {
|
|
@@ -27,4 +33,23 @@ describe('This file is for utility functions', () => {
|
|
|
27
33
|
expect(s1).toBeDefined();
|
|
28
34
|
expect(s1.length).toBe(64);
|
|
29
35
|
});
|
|
36
|
+
|
|
37
|
+
(nodeVersionMajor < 20 ? test.skip : test)('ES256', async () => {
|
|
38
|
+
const { privateKey, publicKey } = await ES256.generateKeyPair();
|
|
39
|
+
expect(privateKey).toBeDefined();
|
|
40
|
+
expect(publicKey).toBeDefined();
|
|
41
|
+
expect(typeof privateKey).toBe('object');
|
|
42
|
+
expect(typeof publicKey).toBe('object');
|
|
43
|
+
|
|
44
|
+
const data =
|
|
45
|
+
'In cryptography, a salt is random data that is used as an additional input to a one-way function that hashes data, a password or passphrase.';
|
|
46
|
+
const signer = await ES256.getSigner(privateKey);
|
|
47
|
+
const signature = await signer(data);
|
|
48
|
+
expect(signature).toBeDefined();
|
|
49
|
+
expect(typeof signature).toBe('string');
|
|
50
|
+
|
|
51
|
+
const verifier = await ES256.getVerifier(publicKey);
|
|
52
|
+
const result = await verifier(data, signature);
|
|
53
|
+
expect(result).toBe(true);
|
|
54
|
+
});
|
|
30
55
|
});
|