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