json-seal 0.9.1 → 0.10.0

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.
Files changed (2) hide show
  1. package/README.md +59 -157
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,77 +1,62 @@
1
1
  # **json‑seal**
2
2
  ![npm version](https://img.shields.io/npm/v/json-seal)
3
- ![license](https://img.shields.io/npm/l/json-seal)
3
+ ![Deterministic JSON](https://img.shields.io/badge/Deterministic%20JSON-RFC%208785%20Compliant-success)
4
+ ![crypto](https://img.shields.io/badge/crypto-RSA--PSS-green)
5
+ ![dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)
4
6
  ![types](https://img.shields.io/badge/types-TypeScript-blue)
5
7
  ![bundle size](https://img.shields.io/bundlephobia/minzip/json-seal)
6
- ![crypto](https://img.shields.io/badge/crypto-RSA--PSS-green)
7
8
  ![npm downloads](https://img.shields.io/npm/dm/json-seal)
8
9
 
9
- Cryptographically signed, tamperproof JSON backups for apps - zero dependencies and a tiny footprint under 5 kB.
10
-
11
- json‑seal lets you:
12
-
13
- - Canonicalize any JSON object
14
- - Sign it with a private key
15
- - Embed the public key
16
- - Verify integrity later
17
- - Detect any tampering - even a single character
18
-
19
- It’s like JWS, but for **arbitrary JSON documents**, without JWT complexity, and designed for **offline‑first apps**, **local backups**, and **portable integrity checks**.
10
+ **A lightweight, zerodependency library for creating cryptographically signed, tamper‑proof JSON backups.**
20
11
 
21
12
  ---
22
13
 
23
- ## **Why json‑seal exists**
14
+ ## **Why json‑seal**
24
15
 
25
- Most security libraries focus on:
16
+ Apps often need to store or transmit JSON in a way that guarantees it hasn’t been tampered with — without relying on servers, tokens, or opaque binary formats. Most security libraries focus on encrypted blobs, authentication tokens, or low‑level crypto primitives, but none solve the simple problem:
26
17
 
27
- - encrypted blobs (ironwebcrypto)
28
- - authentication tokens (JOSE/JWS/JWT)
29
- - low‑level primitives (WebCrypto, libsodium)
18
+ **“I need to store JSON in a way that guarantees integrity — while keeping it readable, portable, and frameworkagnostic.”**
30
19
 
31
- None of these solves the problem of:
20
+ json‑seal fills that gap. It lets you:
32
21
 
33
- **“I need to store or transmit JSON in a way that guarantees it hasn’t been tampered with - while keeping it readable, portable, and framework‑agnostic.”**
34
-
35
- json‑seal fills that gap.
22
+ - Canonicalize any JSON value
23
+ - Sign it with a private key
24
+ - Embed the public key
25
+ - Verify integrity later
26
+ - Detect any tampering — even a single character
36
27
 
37
- It turns any JSON object into a **sealed artifact** that can be verified anywhere, on any device, without servers, shared secrets, or opaque binary formats. The result is a portable, human‑readable, cryptographically signed JSON document that remains trustworthy for years.
28
+ It’s like JWS, but for **arbitrary JSON documents**, without JWT complexity, and designed for **offline‑first apps**, **local backups**, and **portable integrity checks**. It turns any JSON value into a **portable, human‑readable, cryptographically signed artifact** that can be verified anywhere, on any device, with no external dependencies.
38
29
 
39
30
  ---
40
31
 
41
32
  ## **Features**
42
33
 
43
- ### **Deterministic canonicalization**
44
- Stable, cross‑platform byte representation of JSON for reliable signatures.
45
- If the JSON changes - even whitespace - verification fails.
34
+ ### **RFC 8785 Canonical JSON**
35
+ Deterministic, cross‑runtime canonicalization:
46
36
 
47
- ### **RSA‑PSS digital signatures**
48
- Modern, secure, asymmetric signing using the WebCrypto API.
49
- No shared passwords, no symmetric secrets, no server dependency.
37
+ - sorted keys
38
+ - strict number formatting
39
+ - ECMAScript string escaping
40
+ - duplicate‑key rejection
41
+ - stable UTF‑8 output
50
42
 
51
- ### **Pure JSON seal format**
52
- Human‑readable, portable, and easy to store, sync, export, or transmit.
53
- Everything needed for verification is embedded.
43
+ ### **RSA‑PSS Signatures**
44
+ Modern asymmetric signing using WebCrypto.
45
+ No shared secrets. No servers. No dependencies.
54
46
 
55
- ### **Browser + Node support**
56
- Works anywhere `crypto.subtle` is available - modern browsers, PWAs, Node 18+, Bun, Deno, and edge runtimes.
57
-
58
- ### **Framework‑agnostic**
59
- Angular, React, Vue, Svelte, Ionic, Capacitor, PWAs, Node, Bun, Deno - json‑seal fits everywhere.
60
-
61
- ### **Zero dependencies**
62
- Small, auditable, and safe for long‑term use.
63
- No polyfills, no crypto libraries, no runtime baggage.
47
+ ### **Portable JSON Backup Format**
48
+ Everything needed for verification is embedded:
64
49
 
65
- ### **Perfect for offline‑first apps**
66
- Protects:
50
+ - payload
51
+ - timestamp
52
+ - signature
53
+ - public key
67
54
 
68
- - Local storage
69
- - IndexedDB
70
- - Sync engines
71
- - User‑exported backups
72
- - Cross‑device data portability
55
+ ### **Works Everywhere**
56
+ Browsers, PWAs, Node 18+, Bun, Deno, and mobile runtimes.
73
57
 
74
- json‑seal is built for apps that need **trustworthy, tamper‑proof JSON**, not tokens or encrypted blobs.
58
+ ### **Zero Dependencies**
59
+ Small, auditable, and safe for long‑term use.
75
60
 
76
61
  ---
77
62
 
@@ -117,7 +102,7 @@ if (result.valid) {
117
102
 
118
103
  ---
119
104
 
120
- ## **What a signed backup looks like**
105
+ ## **Example Backup**
121
106
 
122
107
  ```json
123
108
  {
@@ -132,13 +117,11 @@ if (result.valid) {
132
117
  }
133
118
  ```
134
119
 
135
- Everything needed to verify the backup is embedded.
136
-
137
120
  ---
138
121
 
139
122
  ## **Tamper Detection**
140
123
 
141
- Any modification - even deep inside nested objects - invalidates the signature.
124
+ Any modification even deep inside nested objects invalidates the signature.
142
125
 
143
126
  ```ts
144
127
  const tampered = { ...backup, payload: { id: 1, data: "hacked" } };
@@ -148,123 +131,44 @@ verifyBackup(tampered).valid; // false
148
131
 
149
132
  ---
150
133
 
151
- ## **Key Management**
152
-
153
- `generateKeyPair()` should be called **once**, not on every backup.
154
- Apps are expected to generate or receive a keypair during onboarding and store it securely.
155
-
156
- ---
157
-
158
- ### **App‑generated keys**
159
-
160
- Most offline‑first apps generate a keypair on first launch:
161
-
162
- ```ts
163
- import { generateKeyPair } from "json-seal";
164
-
165
- const { privateKey, publicKey } = await generateKeyPair();
166
-
167
- secureStore.set("privateKey", privateKey);
168
- secureStore.set("publicKey", publicKey);
169
- ```
170
-
171
- On subsequent runs:
172
-
173
- ```ts
174
- const privateKey = secureStore.get("privateKey");
175
- const publicKey = secureStore.get("publicKey");
176
-
177
- const backup = await signPayload(data, privateKey, publicKey);
178
- ```
179
-
180
- ---
181
-
182
- ### **Where to store keys**
183
-
184
- Storage depends on the platform:
185
-
186
- - iOS → Keychain
187
- - Android → Keystore
188
- - Web → IndexedDB + WebCrypto
189
- - Desktop → OS keyring or encrypted local file
190
- - Node → environment variables or encrypted file
191
-
192
- json‑seal intentionally does **not** handle storage so it can remain environment‑agnostic.
193
-
194
- ---
195
-
196
- ### **Server‑generated keys**
197
-
198
- Some architectures prefer the backend to generate and manage keys:
199
-
200
- 1. Server generates keypair
201
- 2. Server stores private key
202
- 3. Server sends public key to the app
203
- 4. App signs backups using the server’s public key
204
- 5. Server verifies integrity later
205
-
206
- Useful for multi‑device accounts or enterprise systems.
207
-
208
- ---
209
-
210
- ### **Key rotation**
211
-
212
- json‑seal embeds the public key inside each backup, so old backups remain verifiable even after rotation.
213
-
214
- Typical strategy:
215
-
216
- - generate a new keypair yearly
217
- - store the new private key
218
- - keep old public keys for verification
219
- - continue verifying old backups without breaking anything
220
-
221
- ---
134
+ ## **API**
222
135
 
223
- ### **Importing and exporting keys**
136
+ ### **`generateKeyPair()`**
137
+ Generates a 2048‑bit RSA‑PSS keypair.
224
138
 
225
- Keys are standard PEM strings, so they can be:
139
+ ### **`signPayload(payload, privateKey, publicKey)`**
140
+ Canonicalizes the payload, signs it, and returns a sealed backup object.
226
141
 
227
- - backed up
228
- - migrated
229
- - synced
230
- - exported/imported
142
+ ### **`verifyBackup(backup)`**
143
+ Verifies the signature and returns `{ valid, payload? }`.
231
144
 
232
- Perfect for long‑term, portable backup formats.
145
+ ### **`canonicalize(value)`**
146
+ Full RFC 8785 Canonical JSON implementation.
233
147
 
234
148
  ---
235
149
 
236
- ## **API**
237
-
238
- ### **`generateKeyPair()`**
239
- Generates a 2048‑bit RSA‑PSS keypair using WebCrypto.
150
+ ## **Prior Art**
240
151
 
241
- ### **`signPayload(payload, privateKey, publicKey)`**
242
- - Canonicalizes the JSON
243
- - Signs it using RSA‑PSS SHA‑256
244
- - Embeds the public key
245
- - Returns a portable backup object
152
+ json‑seal builds on ideas from:
246
153
 
247
- ### **`verifyBackup(backup)`**
248
- - Re‑canonicalizes the payload
249
- - Verifies the signature
250
- - Returns `{ valid: boolean, payload?: any }`
154
+ - **json-canonicalize** — RFC 8785 canonicalization (no signing or backup format)
155
+ - **rfc8785 (Python)** — pure Python canonicalizer
156
+ - **jcs (Elixir)** — Elixir implementation of JCS
157
+ - **JOSE / JWS / JWT** — signing standards focused on tokens, not arbitrary JSON
251
158
 
252
- ### **`canonicalize(obj)`**
253
- Deterministic JSON serializer with sorted keys.
159
+ json‑seal combines **canonicalization + signing + verification** into a single, zero‑dependency library designed for **offline‑first, portable JSON integrity**.
254
160
 
255
161
  ---
256
162
 
257
163
  ## **Testing**
258
164
 
259
- json‑seal ships with a full Vitest suite covering:
165
+ The test suite covers:
260
166
 
167
+ - RFC 8785 canonicalization
168
+ - Unicode and number edge cases
261
169
  - Valid signatures
262
- - Shallow tampering
263
- - Deep tampering
264
- - Missing signature
265
- - Wrong public key
266
- - Corrupted signature
267
- - Canonicalization stability
170
+ - Shallow and deep tampering
171
+ - Missing / wrong / corrupted signatures
268
172
  - Large payloads
269
173
  - Arrays and primitives
270
174
  - RSA‑PSS non‑determinism
@@ -276,11 +180,9 @@ npm test
276
180
  ```
277
181
 
278
182
  ---
279
-
280
- Pull Requests welcome.
281
-
183
+ Pull Requests are welcome.
282
184
  ## **License**
283
185
 
284
186
  MIT
285
187
 
286
- ---
188
+ ---
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "json-seal",
3
- "version": "0.9.1",
4
- "description": "Cryptographically signed, tamper‑proof JSON backups with deterministic canonicalization and RSA‑PSS signatures.",
3
+ "version": "0.10.0",
4
+ "description": "Create cryptographically signed, tamper‑proof JSON backups with zero dependencies.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",