formdecrypt 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -12,7 +12,7 @@ The private key is read from `./formcrypt.key`, or from the `FORMCRYPT_KEY` envi
12
12
 
13
13
  **Getting the CSV from Netlify:** Site → Forms → your form → Download as CSV.
14
14
 
15
- Every cell that holds a `fc1.` envelope is decrypted in place under its column name. Columns, order and plain cells are untouched, so submissions from before you added encryption come through as they are. A cell that can't be decrypted (wrong key, or moved to another column) is left as it is, and the exit code is 1. Existing files are never overwritten.
15
+ Every cell that holds a `fc1-` envelope is decrypted in place under its column name. Columns, order and plain cells are untouched, so submissions from before you added encryption come through as they are. A cell that can't be decrypted (wrong key, or moved to another column) is left as it is, and the exit code is 1. Existing files are never overwritten.
16
16
 
17
17
  **The output is plaintext.** Store it as carefully as the data deserves. Submissions come from strangers, so a value starting with `=`, `+`, `-` or `@` can run as a formula in a spreadsheet program. Import as text if in doubt.
18
18
 
@@ -20,7 +20,7 @@ Every cell that holds a `fc1.` envelope is decrypted in place under its column n
20
20
 
21
21
  So readers can be written in any language:
22
22
 
23
- - **Envelope:** `fc1.` + base64url (no padding) of `ephemeral P-256 public key (65 B, uncompressed) ‖ IV (12 B) ‖ AES-256-GCM ciphertext + 16 B tag`
23
+ - **Envelope:** `fc1-` + lowercase hex of `ephemeral P-256 public key (65 B, uncompressed) ‖ IV (12 B) ‖ AES-256-GCM ciphertext + 16 B tag`
24
24
  - **AES key:** HKDF-SHA256 over ECDH(ephemeral, recipient), with salt = the 65-byte ephemeral public key and info = `formcrypt/v1`, giving 32 bytes
25
25
  - **Plaintext:** the field's value, UTF-8. **Additional authenticated data:** the field's name, UTF-8
26
26
  - **Keys:** `fc1pk.` + base64url(raw public key) and `fc1sk.` + base64url(PKCS#8 private key)
package/formdecrypt.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- // formdecrypt 0.2.0 · MIT · Keys and CSV decryption for formcrypt (format v1)
2
+ // formdecrypt 0.3.0 · MIT · Keys and CSV decryption for formcrypt (format v1)
3
3
  import { readFileSync, writeFileSync, existsSync } from 'node:fs'
4
4
 
5
5
  const { subtle } = globalThis.crypto
6
6
  const P256 = { name: 'ECDH', namedCurve: 'P-256' }
7
7
  const KEYFILE = 'formcrypt.key'
8
- const ENVELOPE = /^fc1\.[A-Za-z0-9_-]{124,}$/
8
+ const ENVELOPE = /^fc1-[0-9a-f]{186,}$/
9
9
  const fail = (msg) => { console.error(`formdecrypt: ${msg}`); process.exit(1) }
10
10
 
11
11
  async function keygen() {
@@ -26,7 +26,7 @@ async function loadKey() {
26
26
 
27
27
  // Opens one envelope sealed under this field name. Throws if the key or the name is wrong.
28
28
  async function open(envelope, privateKey, name) {
29
- const raw = Buffer.from(envelope.slice(4), 'base64url')
29
+ const raw = Buffer.from(envelope.slice(4), 'hex')
30
30
  const ephRaw = raw.subarray(0, 65)
31
31
  const eph = await subtle.importKey('raw', ephRaw, P256, false, [])
32
32
  const bits = await subtle.deriveBits({ name: 'ECDH', public: eph }, privateKey, 256)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "formdecrypt",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Create formcrypt keys and decrypt the encrypted cells of a CSV export in place, locally.",
5
5
  "type": "module",
6
6
  "bin": {