@lindorm/ec 0.2.0 → 0.2.2
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/CHANGELOG.md +8 -0
- package/README.md +401 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.2.2](https://github.com/lindorm-io/monorepo/compare/@lindorm/ec@0.2.1...@lindorm/ec@0.2.2) (2025-07-10)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @lindorm/ec
|
|
9
|
+
|
|
10
|
+
## [0.2.1](https://github.com/lindorm-io/monorepo/compare/@lindorm/ec@0.2.0...@lindorm/ec@0.2.1) (2025-07-02)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @lindorm/ec
|
|
13
|
+
|
|
6
14
|
# [0.2.0](https://github.com/lindorm-io/monorepo/compare/@lindorm/ec@0.1.8...@lindorm/ec@0.2.0) (2025-06-17)
|
|
7
15
|
|
|
8
16
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -1 +1,402 @@
|
|
|
1
1
|
# @lindorm/ec
|
|
2
|
+
|
|
3
|
+
Elliptic Curve cryptography utilities for digital signatures using ECDSA algorithms.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @lindorm/ec
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **ECDSA Digital Signatures**: Sign and verify data using elliptic curve algorithms
|
|
14
|
+
- **Multiple Algorithms**: Support for ES256, ES384, and ES512
|
|
15
|
+
- **Flexible Encoding**: Multiple encoding options (base64, base64url, hex)
|
|
16
|
+
- **DSA Format Options**: Support for DER and IEEE-P1363 encoding
|
|
17
|
+
- **Raw Signature Format**: Convert between DER and raw signature formats
|
|
18
|
+
- **Type-Safe**: Full TypeScript support with strict typing
|
|
19
|
+
- **Error Handling**: Comprehensive error messages for debugging
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { EcKit } from "@lindorm/ec";
|
|
25
|
+
import { KryptosEc } from "@lindorm/kryptos";
|
|
26
|
+
|
|
27
|
+
// Create an EC key pair
|
|
28
|
+
const kryptos = KryptosEc.fromB64({
|
|
29
|
+
algorithm: "ES256",
|
|
30
|
+
// ... your key data
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Initialize EcKit
|
|
34
|
+
const ecKit = new EcKit({ kryptos });
|
|
35
|
+
|
|
36
|
+
// Sign data
|
|
37
|
+
const data = Buffer.from("Hello World");
|
|
38
|
+
const signature = ecKit.sign(data);
|
|
39
|
+
|
|
40
|
+
// Verify signature
|
|
41
|
+
const isValid = ecKit.verify(data, signature); // true
|
|
42
|
+
|
|
43
|
+
// Assert signature (throws if invalid)
|
|
44
|
+
ecKit.assert(data, signature);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API Reference
|
|
48
|
+
|
|
49
|
+
### EcKit Class
|
|
50
|
+
|
|
51
|
+
The main class for elliptic curve operations.
|
|
52
|
+
|
|
53
|
+
#### Constructor Options
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
interface EcKitOptions {
|
|
57
|
+
kryptos: IKryptosEc; // EC key pair from @lindorm/kryptos
|
|
58
|
+
dsa?: "der" | "ieee-p1363"; // DSA encoding format (default: "der")
|
|
59
|
+
encoding?: BufferEncoding; // Output encoding (default: "base64")
|
|
60
|
+
raw?: boolean; // Use raw signature format (default: false)
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Methods
|
|
65
|
+
|
|
66
|
+
##### `sign(data: KeyData): Buffer`
|
|
67
|
+
Signs the provided data and returns the signature as a Buffer.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const signature = ecKit.sign("data to sign");
|
|
71
|
+
const signature2 = ecKit.sign(Buffer.from("data"));
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
##### `verify(data: KeyData, signature: KeyData): boolean`
|
|
75
|
+
Verifies a signature against the provided data.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
const isValid = ecKit.verify("data", signature);
|
|
79
|
+
console.log(isValid); // true or false
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
##### `assert(data: KeyData, signature: KeyData): void`
|
|
83
|
+
Verifies a signature and throws an error if invalid.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
try {
|
|
87
|
+
ecKit.assert("data", signature);
|
|
88
|
+
// Signature is valid
|
|
89
|
+
} catch (error) {
|
|
90
|
+
// Signature is invalid
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
##### `format(data: Buffer): string`
|
|
95
|
+
Formats a Buffer to string using the configured encoding.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
const formatted = ecKit.format(signature);
|
|
99
|
+
// Returns base64/base64url/hex string based on configuration
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Supported Algorithms
|
|
103
|
+
|
|
104
|
+
| Algorithm | Curve | Hash Function | Key Size |
|
|
105
|
+
|-----------|-------|---------------|----------|
|
|
106
|
+
| ES256 | P-256 | SHA-256 | 256 bits |
|
|
107
|
+
| ES384 | P-384 | SHA-384 | 384 bits |
|
|
108
|
+
| ES512 | P-521 | SHA-512 | 521 bits |
|
|
109
|
+
|
|
110
|
+
## Encoding Options
|
|
111
|
+
|
|
112
|
+
### DSA Encoding Formats
|
|
113
|
+
|
|
114
|
+
- **DER** (Distinguished Encoding Rules): Standard format used in X.509 certificates
|
|
115
|
+
- **IEEE-P1363**: Alternative format used in some cryptographic protocols
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Using DER format (default)
|
|
119
|
+
const ecKit = new EcKit({
|
|
120
|
+
kryptos,
|
|
121
|
+
dsa: "der"
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Using IEEE-P1363 format
|
|
125
|
+
const ecKit2 = new EcKit({
|
|
126
|
+
kryptos,
|
|
127
|
+
dsa: "ieee-p1363"
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Output Encoding
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// Base64 encoding (default)
|
|
135
|
+
const ecKit = new EcKit({
|
|
136
|
+
kryptos,
|
|
137
|
+
encoding: "base64"
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Base64URL encoding (URL-safe)
|
|
141
|
+
const ecKit2 = new EcKit({
|
|
142
|
+
kryptos,
|
|
143
|
+
encoding: "base64url"
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Hexadecimal encoding
|
|
147
|
+
const ecKit3 = new EcKit({
|
|
148
|
+
kryptos,
|
|
149
|
+
encoding: "hex"
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Raw Signature Format
|
|
154
|
+
|
|
155
|
+
The raw format concatenates the r and s values directly, which is useful for JWT/JWS compatibility.
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// Standard DER format
|
|
159
|
+
const ecKit = new EcKit({
|
|
160
|
+
kryptos,
|
|
161
|
+
raw: false // default
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Raw format (r || s concatenation)
|
|
165
|
+
const ecKitRaw = new EcKit({
|
|
166
|
+
kryptos,
|
|
167
|
+
raw: true
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Advanced Usage
|
|
172
|
+
|
|
173
|
+
### Working with Different Data Types
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// String data with encoding
|
|
177
|
+
const signature1 = ecKit.sign("Hello World");
|
|
178
|
+
|
|
179
|
+
// Buffer data
|
|
180
|
+
const buffer = Buffer.from("Hello World", "utf-8");
|
|
181
|
+
const signature2 = ecKit.sign(buffer);
|
|
182
|
+
|
|
183
|
+
// Base64 encoded data
|
|
184
|
+
const base64Data = Buffer.from("Hello World").toString("base64");
|
|
185
|
+
const signature3 = ecKit.sign(base64Data);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### JWT/JWS Integration
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// For JWT/JWS, use raw format with base64url encoding
|
|
192
|
+
const jwtEcKit = new EcKit({
|
|
193
|
+
kryptos,
|
|
194
|
+
encoding: "base64url",
|
|
195
|
+
raw: true
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Sign JWT payload
|
|
199
|
+
const payload = Buffer.from(JSON.stringify({ sub: "1234567890" }));
|
|
200
|
+
const signature = jwtEcKit.sign(payload);
|
|
201
|
+
const signatureString = jwtEcKit.format(signature);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Signature Format Conversion
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
// Convert between DER and raw formats
|
|
208
|
+
const derEcKit = new EcKit({ kryptos, raw: false });
|
|
209
|
+
const rawEcKit = new EcKit({ kryptos, raw: true });
|
|
210
|
+
|
|
211
|
+
// Sign with DER format
|
|
212
|
+
const derSignature = derEcKit.sign("data");
|
|
213
|
+
|
|
214
|
+
// Verify with raw format (automatic conversion)
|
|
215
|
+
const isValid = rawEcKit.verify("data", derSignature);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Error Handling
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { EcError } from "@lindorm/ec";
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
// Missing private key for signing
|
|
225
|
+
const verifyOnlyKryptos = KryptosEc.fromB64({
|
|
226
|
+
publicKey: "...",
|
|
227
|
+
algorithm: "ES256"
|
|
228
|
+
});
|
|
229
|
+
const ecKit = new EcKit({ kryptos: verifyOnlyKryptos });
|
|
230
|
+
ecKit.sign("data"); // Throws EcError
|
|
231
|
+
} catch (error) {
|
|
232
|
+
if (error instanceof EcError) {
|
|
233
|
+
console.error("EC operation failed:", error.message);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Examples
|
|
239
|
+
|
|
240
|
+
### Creating a Signing Service
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import { EcKit } from "@lindorm/ec";
|
|
244
|
+
import { KryptosEc } from "@lindorm/kryptos";
|
|
245
|
+
|
|
246
|
+
class SigningService {
|
|
247
|
+
private ecKit: EcKit;
|
|
248
|
+
|
|
249
|
+
constructor(privateKey: string, algorithm: "ES256" | "ES384" | "ES512") {
|
|
250
|
+
const kryptos = KryptosEc.fromB64({
|
|
251
|
+
privateKey,
|
|
252
|
+
algorithm
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
this.ecKit = new EcKit({
|
|
256
|
+
kryptos,
|
|
257
|
+
encoding: "base64url",
|
|
258
|
+
raw: true // For JWT compatibility
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
signPayload(payload: object): string {
|
|
263
|
+
const data = Buffer.from(JSON.stringify(payload));
|
|
264
|
+
const signature = this.ecKit.sign(data);
|
|
265
|
+
return this.ecKit.format(signature);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
verifyPayload(payload: object, signature: string): boolean {
|
|
269
|
+
const data = Buffer.from(JSON.stringify(payload));
|
|
270
|
+
return this.ecKit.verify(data, signature);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Verification Service with Public Key
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
class VerificationService {
|
|
279
|
+
private ecKit: EcKit;
|
|
280
|
+
|
|
281
|
+
constructor(publicKey: string, algorithm: "ES256" | "ES384" | "ES512") {
|
|
282
|
+
const kryptos = KryptosEc.fromB64({
|
|
283
|
+
publicKey,
|
|
284
|
+
algorithm
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
this.ecKit = new EcKit({
|
|
288
|
+
kryptos,
|
|
289
|
+
encoding: "base64url",
|
|
290
|
+
raw: true
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
verifySignature(data: string, signature: string): boolean {
|
|
295
|
+
try {
|
|
296
|
+
this.ecKit.assert(data, signature);
|
|
297
|
+
return true;
|
|
298
|
+
} catch {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Document Signing System
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
interface SignedDocument {
|
|
309
|
+
content: string;
|
|
310
|
+
signature: string;
|
|
311
|
+
algorithm: string;
|
|
312
|
+
timestamp: number;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
class DocumentSigner {
|
|
316
|
+
private ecKit: EcKit;
|
|
317
|
+
private algorithm: string;
|
|
318
|
+
|
|
319
|
+
constructor(kryptos: IKryptosEc) {
|
|
320
|
+
this.ecKit = new EcKit({
|
|
321
|
+
kryptos,
|
|
322
|
+
encoding: "base64"
|
|
323
|
+
});
|
|
324
|
+
this.algorithm = kryptos.algorithm;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
signDocument(content: string): SignedDocument {
|
|
328
|
+
const timestamp = Date.now();
|
|
329
|
+
const dataToSign = `${content}|${timestamp}`;
|
|
330
|
+
const signature = this.ecKit.sign(dataToSign);
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
content,
|
|
334
|
+
signature: this.ecKit.format(signature),
|
|
335
|
+
algorithm: this.algorithm,
|
|
336
|
+
timestamp
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
verifyDocument(doc: SignedDocument): boolean {
|
|
341
|
+
const dataToVerify = `${doc.content}|${doc.timestamp}`;
|
|
342
|
+
return this.ecKit.verify(dataToVerify, doc.signature);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Type Definitions
|
|
348
|
+
|
|
349
|
+
### KeyData Type
|
|
350
|
+
|
|
351
|
+
Input data can be provided in multiple formats:
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
type KeyData = Buffer | string;
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### IKryptosEc Interface
|
|
358
|
+
|
|
359
|
+
The EC key pair interface from `@lindorm/kryptos`:
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
interface IKryptosEc {
|
|
363
|
+
algorithm: "ES256" | "ES384" | "ES512";
|
|
364
|
+
privateKey?: string;
|
|
365
|
+
publicKey?: string;
|
|
366
|
+
// ... other properties
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Error Handling
|
|
371
|
+
|
|
372
|
+
The package throws `EcError` for various error conditions:
|
|
373
|
+
|
|
374
|
+
- Missing private key when attempting to sign
|
|
375
|
+
- Missing public key when attempting to verify
|
|
376
|
+
- Invalid signature during assertion
|
|
377
|
+
- Unsupported EC algorithm
|
|
378
|
+
- Invalid key format
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
import { EcError } from "@lindorm/ec";
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
ecKit.assert(data, invalidSignature);
|
|
385
|
+
} catch (error) {
|
|
386
|
+
if (error instanceof EcError) {
|
|
387
|
+
console.error("Signature verification failed:", error.message);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Security Considerations
|
|
393
|
+
|
|
394
|
+
- Always use secure random number generation for key creation
|
|
395
|
+
- Protect private keys appropriately
|
|
396
|
+
- Use appropriate key sizes (ES256 minimum for most applications)
|
|
397
|
+
- Verify signatures before trusting data
|
|
398
|
+
- Consider using ES384 or ES512 for higher security requirements
|
|
399
|
+
|
|
400
|
+
## License
|
|
401
|
+
|
|
402
|
+
AGPL-3.0-or-later
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lindorm/ec",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"license": "AGPL-3.0-or-later",
|
|
5
5
|
"author": "Jonn Nilsson",
|
|
6
6
|
"repository": {
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"update:auto": "ncu -u"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@lindorm/errors": "^0.1.
|
|
33
|
-
"@lindorm/is": "^0.1.
|
|
34
|
-
"@lindorm/kryptos": "^0.4.
|
|
32
|
+
"@lindorm/errors": "^0.1.10",
|
|
33
|
+
"@lindorm/is": "^0.1.9",
|
|
34
|
+
"@lindorm/kryptos": "^0.4.2"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@lindorm/types": "^0.3.
|
|
37
|
+
"@lindorm/types": "^0.3.1"
|
|
38
38
|
},
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "bb9f6efd6b7dcc5035535d900239a8d93f97cfb7"
|
|
40
40
|
}
|