@northstartech/cipher 0.0.0-stage → 1.0.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 +541 -2
- package/dist/client.d.ts +237 -0
- package/dist/client.js +555 -0
- package/dist/client.js.map +1 -0
- package/dist/crypto.d.ts +72 -0
- package/dist/crypto.js +244 -0
- package/dist/crypto.js.map +1 -0
- package/dist/encoding.d.ts +17 -0
- package/dist/encoding.js +79 -0
- package/dist/encoding.js.map +1 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.js +22 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/drizzle.d.ts +96 -0
- package/dist/integrations/drizzle.js +285 -0
- package/dist/integrations/drizzle.js.map +1 -0
- package/dist/integrations/mongoose.d.ts +72 -0
- package/dist/integrations/mongoose.js +582 -0
- package/dist/integrations/mongoose.js.map +1 -0
- package/dist/integrations/prisma.d.ts +65 -0
- package/dist/integrations/prisma.js +588 -0
- package/dist/integrations/prisma.js.map +1 -0
- package/dist/integrations/sequelize.d.ts +62 -0
- package/dist/integrations/sequelize.js +677 -0
- package/dist/integrations/sequelize.js.map +1 -0
- package/dist/integrations/shared.d.ts +268 -0
- package/dist/integrations/shared.js +513 -0
- package/dist/integrations/shared.js.map +1 -0
- package/dist/integrations/typeorm.d.ts +109 -0
- package/dist/integrations/typeorm.js +457 -0
- package/dist/integrations/typeorm.js.map +1 -0
- package/dist/object.d.ts +53 -0
- package/dist/object.js +226 -0
- package/dist/object.js.map +1 -0
- package/dist/search.d.ts +250 -0
- package/dist/search.js +258 -0
- package/dist/search.js.map +1 -0
- package/package.json +101 -4
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { randomBytes } from './encoding.js';
|
|
2
|
+
export declare function subtle(): SubtleCrypto;
|
|
3
|
+
export type EnvKind = 'development' | 'production';
|
|
4
|
+
export interface ParsedCredential {
|
|
5
|
+
env: EnvKind;
|
|
6
|
+
id: string;
|
|
7
|
+
key: CryptoKey;
|
|
8
|
+
}
|
|
9
|
+
/** Import an Ed25519 private key from its 32-byte seed. */
|
|
10
|
+
export declare function importEd25519Seed(seed: Uint8Array, extractable?: boolean): Promise<CryptoKey>;
|
|
11
|
+
/** Parse a `nsc_dev_…` / `nsc_live_…` credential secret (protocol §4). */
|
|
12
|
+
export declare function parseCredential(secret: string): Promise<ParsedCredential>;
|
|
13
|
+
/** Build a credential secret from its parts (used by the console when minting credentials). */
|
|
14
|
+
export declare function buildCredentialSecret(env: EnvKind, id: string, seed: Uint8Array): Promise<string>;
|
|
15
|
+
/** Generate a fresh Ed25519 key pair: returns `{ seed, publicKey }` (raw bytes). */
|
|
16
|
+
export declare function generateCredentialKeyPair(): Promise<{
|
|
17
|
+
seed: Uint8Array;
|
|
18
|
+
publicKey: Uint8Array;
|
|
19
|
+
}>;
|
|
20
|
+
export declare function signJws(typ: string, kid: string, claims: unknown, key: CryptoKey): Promise<string>;
|
|
21
|
+
export interface JwsHeader {
|
|
22
|
+
alg: string;
|
|
23
|
+
typ: string;
|
|
24
|
+
kid: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function peekJws(token: string): {
|
|
27
|
+
header: JwsHeader;
|
|
28
|
+
claims: Record<string, unknown>;
|
|
29
|
+
};
|
|
30
|
+
/** Verify an EdDSA compact JWS against a raw Ed25519 public key. */
|
|
31
|
+
export declare function verifyJws(token: string, typ: string, publicKey: Uint8Array): Promise<Record<string, unknown>>;
|
|
32
|
+
/** X-Wing public key: ML-KEM-768 encapsulation key (1184) ‖ X25519 public key (32). */
|
|
33
|
+
export declare const XWING_PUBLIC_KEY_LENGTH = 1216;
|
|
34
|
+
/** X-Wing ciphertext (`enc`): ML-KEM-768 ciphertext (1088) ‖ X25519 ephemeral public key (32). */
|
|
35
|
+
export declare const XWING_ENC_LENGTH = 1120;
|
|
36
|
+
/**
|
|
37
|
+
* Reject anything but a well-formed X-Wing public key: the exact length, and the
|
|
38
|
+
* FIPS 203 §7.2 modulus check (every 12-bit coefficient of ek_M is < q).
|
|
39
|
+
*/
|
|
40
|
+
export declare function assertXWingPublicKey(pk: Uint8Array): void;
|
|
41
|
+
/** X-Wing encapsulation to `pk` (KEM level; tests and diagnostics). `eseed` is for tests only. */
|
|
42
|
+
export declare function xwingEncapsulate(pk: Uint8Array, eseed?: Uint8Array): Promise<{
|
|
43
|
+
enc: Uint8Array;
|
|
44
|
+
sharedSecret: Uint8Array;
|
|
45
|
+
}>;
|
|
46
|
+
export interface SessionKeys {
|
|
47
|
+
c2s: CryptoKey;
|
|
48
|
+
s2c: CryptoKey;
|
|
49
|
+
sid: Uint8Array;
|
|
50
|
+
}
|
|
51
|
+
export declare function sessionInfo(instanceId: string, nonce: Uint8Array): Uint8Array;
|
|
52
|
+
/**
|
|
53
|
+
* HPKE SetupBaseS (X-Wing) to the attested session key; export the session secrets (protocol §6.1).
|
|
54
|
+
* `eseed` (64 bytes) makes the encapsulation deterministic and is for tests only.
|
|
55
|
+
*/
|
|
56
|
+
export declare function establishSession(sessionPk: Uint8Array, instanceId: string, nonce: Uint8Array, eseed?: Uint8Array): Promise<{
|
|
57
|
+
enc: Uint8Array;
|
|
58
|
+
keys: SessionKeys;
|
|
59
|
+
raw?: {
|
|
60
|
+
c2s: Uint8Array;
|
|
61
|
+
s2c: Uint8Array;
|
|
62
|
+
};
|
|
63
|
+
}>;
|
|
64
|
+
export declare function sessionIdFor(instanceId: string, sid: Uint8Array): string;
|
|
65
|
+
export declare function requestAad(sessionId: string, method: string, path: string, timestampMs: number): Uint8Array;
|
|
66
|
+
export declare function responseAad(sessionId: string, requestNonce: Uint8Array, status: number): Uint8Array;
|
|
67
|
+
export declare function seal(key: CryptoKey, aad: Uint8Array, plaintext: Uint8Array, nonce?: Uint8Array<ArrayBufferLike>): Promise<{
|
|
68
|
+
nonce: Uint8Array;
|
|
69
|
+
ciphertext: Uint8Array;
|
|
70
|
+
}>;
|
|
71
|
+
export declare function open(key: CryptoKey, nonce: Uint8Array, aad: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array>;
|
|
72
|
+
export { randomBytes };
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol cryptography on WebCrypto (Node ≥ 20 and modern browsers):
|
|
3
|
+
* Ed25519 credentials and JWS, post-quantum hybrid HPKE session establishment
|
|
4
|
+
* (RFC 9180 via @hpke/core with the X-Wing KEM, MLKEM768-X25519), AES-256-GCM
|
|
5
|
+
* sealing of session messages.
|
|
6
|
+
*/
|
|
7
|
+
import { CipherSuite, ExportOnly, HkdfSha256 } from '@hpke/core';
|
|
8
|
+
import { XWing } from '@hpke/hybridkem-x-wing';
|
|
9
|
+
import { b64u, buf, bytesToUuid, concat, equalBytes, lp, randomBytes, u16, u64, unb64u, utf8, uuidBytes } from './encoding.js';
|
|
10
|
+
import { CipherError } from './errors.js';
|
|
11
|
+
export function subtle() {
|
|
12
|
+
const s = globalThis.crypto?.subtle;
|
|
13
|
+
if (!s)
|
|
14
|
+
throw new CipherError('CONFIGURATION_ERROR', 'WebCrypto is unavailable (Node.js ≥ 20 or a modern browser is required)');
|
|
15
|
+
return s;
|
|
16
|
+
}
|
|
17
|
+
async function sha256(b) {
|
|
18
|
+
return new Uint8Array(await subtle().digest('SHA-256', buf(b)));
|
|
19
|
+
}
|
|
20
|
+
const PKCS8_ED25519 = new Uint8Array([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20]);
|
|
21
|
+
/** Import an Ed25519 private key from its 32-byte seed. */
|
|
22
|
+
export async function importEd25519Seed(seed, extractable = false) {
|
|
23
|
+
const der = concat(PKCS8_ED25519, seed);
|
|
24
|
+
try {
|
|
25
|
+
return await subtle().importKey('pkcs8', buf(der), { name: 'Ed25519' }, extractable, ['sign']);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw new CipherError('CONFIGURATION_ERROR', 'this runtime does not support Ed25519 in WebCrypto (Node.js ≥ 20, Chrome ≥ 137, Safari ≥ 17, Firefox ≥ 129)');
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
der.fill(0);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const MALFORMED = 'credential is malformed (was it copied completely?)';
|
|
35
|
+
/** Parse a `nsc_dev_…` / `nsc_live_…` credential secret (protocol §4). */
|
|
36
|
+
export async function parseCredential(secret) {
|
|
37
|
+
const s = secret.trim();
|
|
38
|
+
const prefix = s.startsWith('nsc_dev_') ? 'nsc_dev_' : s.startsWith('nsc_live_') ? 'nsc_live_' : null;
|
|
39
|
+
if (!prefix)
|
|
40
|
+
throw new CipherError('CONFIGURATION_ERROR', 'credential must start with nsc_dev_ or nsc_live_');
|
|
41
|
+
let body;
|
|
42
|
+
try {
|
|
43
|
+
body = unb64u(s.slice(prefix.length));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new CipherError('CONFIGURATION_ERROR', MALFORMED);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
if (body.length !== 53 || body[0] !== 1)
|
|
50
|
+
throw new CipherError('CONFIGURATION_ERROR', MALFORMED);
|
|
51
|
+
const sum = await sha256(concat(utf8(prefix), body.subarray(0, 49)));
|
|
52
|
+
if (!equalBytes(sum.subarray(0, 4), body.subarray(49, 53)))
|
|
53
|
+
throw new CipherError('CONFIGURATION_ERROR', MALFORMED);
|
|
54
|
+
const id = bytesToUuid(body.subarray(1, 17));
|
|
55
|
+
const key = await importEd25519Seed(body.subarray(17, 49));
|
|
56
|
+
return { env: prefix === 'nsc_dev_' ? 'development' : 'production', id, key };
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
body.fill(0);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** Build a credential secret from its parts (used by the console when minting credentials). */
|
|
63
|
+
export async function buildCredentialSecret(env, id, seed) {
|
|
64
|
+
const prefix = env === 'development' ? 'nsc_dev_' : 'nsc_live_';
|
|
65
|
+
const head = concat(new Uint8Array([1]), uuidBytes(id), seed);
|
|
66
|
+
const sum = await sha256(concat(utf8(prefix), head));
|
|
67
|
+
const body = concat(head, sum.subarray(0, 4));
|
|
68
|
+
const out = prefix + b64u(body);
|
|
69
|
+
head.fill(0);
|
|
70
|
+
body.fill(0);
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
/** Generate a fresh Ed25519 key pair: returns `{ seed, publicKey }` (raw bytes). */
|
|
74
|
+
export async function generateCredentialKeyPair() {
|
|
75
|
+
const seed = randomBytes(32);
|
|
76
|
+
const key = await importEd25519Seed(seed, true);
|
|
77
|
+
const jwk = await subtle().exportKey('jwk', key);
|
|
78
|
+
return { seed, publicKey: unb64u(jwk.x) };
|
|
79
|
+
}
|
|
80
|
+
// ------------------------------------------------------------------------- JWS
|
|
81
|
+
export async function signJws(typ, kid, claims, key) {
|
|
82
|
+
const h = b64u(utf8(JSON.stringify({ alg: 'EdDSA', typ, kid })));
|
|
83
|
+
const p = b64u(utf8(JSON.stringify(claims)));
|
|
84
|
+
const sig = new Uint8Array(await subtle().sign({ name: 'Ed25519' }, key, buf(utf8(`${h}.${p}`))));
|
|
85
|
+
return `${h}.${p}.${b64u(sig)}`;
|
|
86
|
+
}
|
|
87
|
+
export function peekJws(token) {
|
|
88
|
+
const [h, p] = token.split('.');
|
|
89
|
+
if (!h || !p)
|
|
90
|
+
throw new CipherError('PROTOCOL_ERROR', 'malformed token');
|
|
91
|
+
const dec = new TextDecoder();
|
|
92
|
+
return { header: JSON.parse(dec.decode(unb64u(h))), claims: JSON.parse(dec.decode(unb64u(p))) };
|
|
93
|
+
}
|
|
94
|
+
/** Verify an EdDSA compact JWS against a raw Ed25519 public key. */
|
|
95
|
+
export async function verifyJws(token, typ, publicKey) {
|
|
96
|
+
const parts = token.split('.');
|
|
97
|
+
if (parts.length !== 3)
|
|
98
|
+
throw new CipherError('ATTESTATION_FAILED', 'malformed attestation token');
|
|
99
|
+
const { header, claims } = peekJws(token);
|
|
100
|
+
if (header.alg !== 'EdDSA' || header.typ !== typ)
|
|
101
|
+
throw new CipherError('ATTESTATION_FAILED', 'unexpected token type');
|
|
102
|
+
const key = await subtle().importKey('raw', buf(publicKey), { name: 'Ed25519' }, false, ['verify']);
|
|
103
|
+
const ok = await subtle().verify({ name: 'Ed25519' }, key, buf(unb64u(parts[2])), buf(utf8(`${parts[0]}.${parts[1]}`)));
|
|
104
|
+
if (!ok)
|
|
105
|
+
throw new CipherError('ATTESTATION_FAILED', 'attestation token signature is invalid');
|
|
106
|
+
return claims;
|
|
107
|
+
}
|
|
108
|
+
// --------------------------------------------------------------------- session
|
|
109
|
+
//
|
|
110
|
+
// Protocol §6.1: HPKE (RFC 9180) mode_base, KEM X-Wing = MLKEM768-X25519 (0x647a,
|
|
111
|
+
// draft-ietf-hpke-pq), KDF HKDF-SHA256, export-only AEAD. The session secrets stay
|
|
112
|
+
// confidential unless both ML-KEM-768 and X25519 are broken, which protects recorded
|
|
113
|
+
// traffic against harvest-now-decrypt-later attacks. Clients only encapsulate, and there
|
|
114
|
+
// is deliberately no fallback to the classical DHKEM(X25519) suite: a 32-byte session key
|
|
115
|
+
// is rejected.
|
|
116
|
+
/** X-Wing public key: ML-KEM-768 encapsulation key (1184) ‖ X25519 public key (32). */
|
|
117
|
+
export const XWING_PUBLIC_KEY_LENGTH = 1216;
|
|
118
|
+
/** X-Wing ciphertext (`enc`): ML-KEM-768 ciphertext (1088) ‖ X25519 ephemeral public key (32). */
|
|
119
|
+
export const XWING_ENC_LENGTH = 1120;
|
|
120
|
+
/** Length of the encapsulation seed: ML-KEM `m` (32) ‖ X25519 ephemeral secret (32). */
|
|
121
|
+
const ESEED_LENGTH = 64;
|
|
122
|
+
/** ByteEncode12(t̂) part of the ML-KEM-768 encapsulation key (k = 3), followed by the 32-byte ρ. */
|
|
123
|
+
const MLKEM768_T_LENGTH = 1152;
|
|
124
|
+
const MLKEM_Q = 3329;
|
|
125
|
+
/**
|
|
126
|
+
* Reject anything but a well-formed X-Wing public key: the exact length, and the
|
|
127
|
+
* FIPS 203 §7.2 modulus check (every 12-bit coefficient of ek_M is < q).
|
|
128
|
+
*/
|
|
129
|
+
export function assertXWingPublicKey(pk) {
|
|
130
|
+
if (pk.length !== XWING_PUBLIC_KEY_LENGTH) {
|
|
131
|
+
throw new CipherError('ATTESTATION_FAILED', `enclave session key is not an X-Wing (MLKEM768-X25519) public key (${pk.length} bytes, expected ${XWING_PUBLIC_KEY_LENGTH})`);
|
|
132
|
+
}
|
|
133
|
+
for (let i = 0; i < MLKEM768_T_LENGTH; i += 3) {
|
|
134
|
+
const b0 = pk[i];
|
|
135
|
+
const b1 = pk[i + 1];
|
|
136
|
+
const b2 = pk[i + 2];
|
|
137
|
+
if ((b0 | ((b1 & 0x0f) << 8)) >= MLKEM_Q || ((b1 >> 4) | (b2 << 4)) >= MLKEM_Q) {
|
|
138
|
+
throw new CipherError('ATTESTATION_FAILED', 'enclave session key is not a valid ML-KEM-768 encapsulation key');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** X-Wing (via @hpke/hybridkem-x-wing) that keeps the shared secrets it produces so they can be wiped. */
|
|
143
|
+
class WipingXWing extends XWing {
|
|
144
|
+
secrets = [];
|
|
145
|
+
async encap(params) {
|
|
146
|
+
let r;
|
|
147
|
+
try {
|
|
148
|
+
r = await super.encap(params);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// e.g. an ML-KEM key check or a low-order X25519 point
|
|
152
|
+
throw new CipherError('ATTESTATION_FAILED', 'X-Wing encapsulation to the enclave session key failed');
|
|
153
|
+
}
|
|
154
|
+
this.secrets.push(new Uint8Array(r.sharedSecret));
|
|
155
|
+
return r;
|
|
156
|
+
}
|
|
157
|
+
wipe() {
|
|
158
|
+
for (const s of this.secrets)
|
|
159
|
+
s.fill(0);
|
|
160
|
+
this.secrets.length = 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Run `fn` with an X-Wing sender set up for `pk`. `eseed` (64 bytes) is for tests only:
|
|
165
|
+
* production draws 64 bytes from the CSPRNG. The seed and the shared secret are wiped afterwards.
|
|
166
|
+
*/
|
|
167
|
+
async function withEncapsulation(pk, eseed, fn) {
|
|
168
|
+
assertXWingPublicKey(pk);
|
|
169
|
+
if (eseed && eseed.length !== ESEED_LENGTH)
|
|
170
|
+
throw new CipherError('CONFIGURATION_ERROR', `eseed must be ${ESEED_LENGTH} bytes`);
|
|
171
|
+
const seed = eseed ? buf(eseed) : randomBytes(ESEED_LENGTH);
|
|
172
|
+
const kem = new WipingXWing();
|
|
173
|
+
try {
|
|
174
|
+
const recipientPublicKey = await kem.deserializePublicKey(buf(pk).buffer);
|
|
175
|
+
// Passed as the seed's own ArrayBuffer (not copied by the library), so wiping `seed` wipes its view too.
|
|
176
|
+
return await fn(kem, { recipientPublicKey, ekm: seed.buffer });
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
seed.fill(0);
|
|
180
|
+
kem.wipe();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/** X-Wing encapsulation to `pk` (KEM level; tests and diagnostics). `eseed` is for tests only. */
|
|
184
|
+
export async function xwingEncapsulate(pk, eseed) {
|
|
185
|
+
return withEncapsulation(pk, eseed, async (kem, params) => {
|
|
186
|
+
const r = await kem.encap(params);
|
|
187
|
+
// Copy: the original is wiped when this returns.
|
|
188
|
+
return { enc: new Uint8Array(r.enc), sharedSecret: new Uint8Array(r.sharedSecret).slice() };
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
export function sessionInfo(instanceId, nonce) {
|
|
192
|
+
return concat(utf8('northstar-cipher/v1/session'), new Uint8Array([0]), uuidBytes(instanceId), nonce);
|
|
193
|
+
}
|
|
194
|
+
async function aesKey(raw) {
|
|
195
|
+
return subtle().importKey('raw', raw, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* HPKE SetupBaseS (X-Wing) to the attested session key; export the session secrets (protocol §6.1).
|
|
199
|
+
* `eseed` (64 bytes) makes the encapsulation deterministic and is for tests only.
|
|
200
|
+
*/
|
|
201
|
+
export async function establishSession(sessionPk, instanceId, nonce, eseed) {
|
|
202
|
+
return withEncapsulation(sessionPk, eseed, async (kem, params) => {
|
|
203
|
+
const suite = new CipherSuite({ kem, kdf: new HkdfSha256(), aead: new ExportOnly() });
|
|
204
|
+
const ctx = await suite.createSenderContext({ ...params, info: buf(sessionInfo(instanceId, nonce)).buffer });
|
|
205
|
+
const enc = new Uint8Array(ctx.enc);
|
|
206
|
+
if (enc.length !== XWING_ENC_LENGTH)
|
|
207
|
+
throw new CipherError('INTERNAL', 'unexpected X-Wing ciphertext length');
|
|
208
|
+
const c2s = await ctx.export(buf(utf8('nsc c2s')).buffer, 32);
|
|
209
|
+
const s2c = await ctx.export(buf(utf8('nsc s2c')).buffer, 32);
|
|
210
|
+
try {
|
|
211
|
+
const sid = new Uint8Array(await ctx.export(buf(utf8('nsc sid')).buffer, 16));
|
|
212
|
+
const keys = { c2s: await aesKey(c2s), s2c: await aesKey(s2c), sid };
|
|
213
|
+
const raw = eseed ? { c2s: new Uint8Array(c2s.slice(0)), s2c: new Uint8Array(s2c.slice(0)) } : undefined;
|
|
214
|
+
return { enc, keys, raw };
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
new Uint8Array(c2s).fill(0);
|
|
218
|
+
new Uint8Array(s2c).fill(0);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
export function sessionIdFor(instanceId, sid) {
|
|
223
|
+
return `${instanceId}.${b64u(sid)}`;
|
|
224
|
+
}
|
|
225
|
+
export function requestAad(sessionId, method, path, timestampMs) {
|
|
226
|
+
return concat(lp(utf8('northstar-cipher/v1/request')), lp(utf8(sessionId)), lp(utf8(method)), lp(utf8(path)), lp(u64(timestampMs)));
|
|
227
|
+
}
|
|
228
|
+
export function responseAad(sessionId, requestNonce, status) {
|
|
229
|
+
return concat(lp(utf8('northstar-cipher/v1/response')), lp(utf8(sessionId)), lp(requestNonce), lp(u16(status)));
|
|
230
|
+
}
|
|
231
|
+
export async function seal(key, aad, plaintext, nonce = randomBytes(12)) {
|
|
232
|
+
const ct = await subtle().encrypt({ name: 'AES-GCM', iv: buf(nonce), additionalData: buf(aad), tagLength: 128 }, key, buf(plaintext));
|
|
233
|
+
return { nonce, ciphertext: new Uint8Array(ct) };
|
|
234
|
+
}
|
|
235
|
+
export async function open(key, nonce, aad, ciphertext) {
|
|
236
|
+
try {
|
|
237
|
+
return new Uint8Array(await subtle().decrypt({ name: 'AES-GCM', iv: buf(nonce), additionalData: buf(aad), tagLength: 128 }, key, buf(ciphertext)));
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
throw new CipherError('PROTOCOL_ERROR', 'response failed authentication');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
export { randomBytes };
|
|
244
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Strict base64url without padding (protocol §0) and small byte helpers. */
|
|
2
|
+
export declare function utf8(s: string): Uint8Array;
|
|
3
|
+
export declare function fromUtf8(b: Uint8Array): string;
|
|
4
|
+
export declare function b64u(bytes: Uint8Array): string;
|
|
5
|
+
export declare function unb64u(s: string): Uint8Array;
|
|
6
|
+
export declare function concat(...parts: Uint8Array[]): Uint8Array;
|
|
7
|
+
export declare function u16(n: number): Uint8Array;
|
|
8
|
+
export declare function u32(n: number): Uint8Array;
|
|
9
|
+
export declare function u64(n: number): Uint8Array;
|
|
10
|
+
/** `u32(len) ‖ bytes` */
|
|
11
|
+
export declare function lp(b: Uint8Array): Uint8Array;
|
|
12
|
+
export declare function uuidBytes(uuid: string): Uint8Array;
|
|
13
|
+
export declare function bytesToUuid(b: Uint8Array): string;
|
|
14
|
+
export declare function equalBytes(a: Uint8Array, b: Uint8Array): boolean;
|
|
15
|
+
export declare function randomBytes(n: number): Uint8Array;
|
|
16
|
+
/** Copy into a fresh ArrayBuffer-backed view (WebCrypto rejects SharedArrayBuffer views). */
|
|
17
|
+
export declare function buf(b: Uint8Array): Uint8Array<ArrayBuffer>;
|
package/dist/encoding.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** Strict base64url without padding (protocol §0) and small byte helpers. */
|
|
2
|
+
const enc = new TextEncoder();
|
|
3
|
+
const dec = new TextDecoder('utf-8', { fatal: true });
|
|
4
|
+
export function utf8(s) {
|
|
5
|
+
return enc.encode(s);
|
|
6
|
+
}
|
|
7
|
+
export function fromUtf8(b) {
|
|
8
|
+
return dec.decode(b);
|
|
9
|
+
}
|
|
10
|
+
export function b64u(bytes) {
|
|
11
|
+
let bin = '';
|
|
12
|
+
for (let i = 0; i < bytes.length; i++)
|
|
13
|
+
bin += String.fromCharCode(bytes[i]);
|
|
14
|
+
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
15
|
+
}
|
|
16
|
+
export function unb64u(s) {
|
|
17
|
+
if (!/^[A-Za-z0-9_-]*$/.test(s) || s.length % 4 === 1)
|
|
18
|
+
throw new TypeError('invalid base64url');
|
|
19
|
+
const bin = atob(s.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat((4 - (s.length % 4)) % 4));
|
|
20
|
+
const out = new Uint8Array(bin.length);
|
|
21
|
+
for (let i = 0; i < bin.length; i++)
|
|
22
|
+
out[i] = bin.charCodeAt(i);
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
export function concat(...parts) {
|
|
26
|
+
const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
|
|
27
|
+
let o = 0;
|
|
28
|
+
for (const p of parts) {
|
|
29
|
+
out.set(p, o);
|
|
30
|
+
o += p.length;
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
export function u16(n) {
|
|
35
|
+
return new Uint8Array([(n >>> 8) & 0xff, n & 0xff]);
|
|
36
|
+
}
|
|
37
|
+
export function u32(n) {
|
|
38
|
+
return new Uint8Array([(n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff]);
|
|
39
|
+
}
|
|
40
|
+
export function u64(n) {
|
|
41
|
+
const out = new Uint8Array(8);
|
|
42
|
+
new DataView(out.buffer).setBigUint64(0, BigInt(n));
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
/** `u32(len) ‖ bytes` */
|
|
46
|
+
export function lp(b) {
|
|
47
|
+
return concat(u32(b.length), b);
|
|
48
|
+
}
|
|
49
|
+
export function uuidBytes(uuid) {
|
|
50
|
+
const hex = uuid.replace(/-/g, '');
|
|
51
|
+
if (!/^[0-9a-fA-F]{32}$/.test(hex))
|
|
52
|
+
throw new TypeError('invalid UUID');
|
|
53
|
+
const out = new Uint8Array(16);
|
|
54
|
+
for (let i = 0; i < 16; i++)
|
|
55
|
+
out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
export function bytesToUuid(b) {
|
|
59
|
+
const h = Array.from(b, (x) => x.toString(16).padStart(2, '0')).join('');
|
|
60
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
|
|
61
|
+
}
|
|
62
|
+
export function equalBytes(a, b) {
|
|
63
|
+
if (a.length !== b.length)
|
|
64
|
+
return false;
|
|
65
|
+
let d = 0;
|
|
66
|
+
for (let i = 0; i < a.length; i++)
|
|
67
|
+
d |= a[i] ^ b[i];
|
|
68
|
+
return d === 0;
|
|
69
|
+
}
|
|
70
|
+
export function randomBytes(n) {
|
|
71
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(n));
|
|
72
|
+
}
|
|
73
|
+
/** Copy into a fresh ArrayBuffer-backed view (WebCrypto rejects SharedArrayBuffer views). */
|
|
74
|
+
export function buf(b) {
|
|
75
|
+
const out = new Uint8Array(new ArrayBuffer(b.length));
|
|
76
|
+
out.set(b);
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=encoding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Errors raised by the SDK. Messages never contain plaintext or secrets. */
|
|
2
|
+
export type CipherErrorCode = 'AUTHENTICATION_FAILED' | 'SESSION_EXPIRED' | 'PERMISSION_DENIED' | 'TENANT_MISMATCH' | 'KEY_DISABLED' | 'ATTESTATION_FAILED' | 'KEY_NOT_FOUND' | 'INDEX_NOT_ENABLED' | 'NOT_FOUND' | 'CONFLICT' | 'INVALID_REQUEST' | 'INVALID_CONTEXT' | 'INVALID_CIPHERTEXT' | 'RATE_LIMITED' | 'RESOURCE_EXHAUSTED' | 'KEY_AUTHORITY_UNAVAILABLE' | 'SERVICE_UNAVAILABLE' | 'INTERNAL' | 'NETWORK_ERROR' | 'CONFIGURATION_ERROR' | 'PROTOCOL_ERROR' | (string & {});
|
|
3
|
+
export declare class CipherError extends Error {
|
|
4
|
+
readonly code: CipherErrorCode;
|
|
5
|
+
readonly requestId?: string;
|
|
6
|
+
readonly status?: number;
|
|
7
|
+
readonly retryable: boolean;
|
|
8
|
+
constructor(code: CipherErrorCode, message: string, opts?: {
|
|
9
|
+
requestId?: string;
|
|
10
|
+
status?: number;
|
|
11
|
+
retryable?: boolean;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export declare function errorFromBody(status: number, body: unknown): CipherError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Errors raised by the SDK. Messages never contain plaintext or secrets. */
|
|
2
|
+
export class CipherError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
requestId;
|
|
5
|
+
status;
|
|
6
|
+
retryable;
|
|
7
|
+
constructor(code, message, opts = {}) {
|
|
8
|
+
super(`${code}: ${message}`);
|
|
9
|
+
this.name = 'CipherError';
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.requestId = opts.requestId;
|
|
12
|
+
this.status = opts.status;
|
|
13
|
+
this.retryable = opts.retryable ?? false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function errorFromBody(status, body) {
|
|
17
|
+
const e = body?.error;
|
|
18
|
+
if (e?.code)
|
|
19
|
+
return new CipherError(e.code, e.message ?? 'request failed', { requestId: e.request_id, status, retryable: e.retryable });
|
|
20
|
+
return new CipherError('PROTOCOL_ERROR', `unexpected HTTP ${status} from Northstar Cipher`, { status, retryable: status >= 500 });
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,6EAA6E;AA0B7E,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,IAAI,CAAiB;IACrB,SAAS,CAAS;IAClB,MAAM,CAAS;IACf,SAAS,CAAS;IAE3B,YAAY,IAAqB,EAAE,OAAe,EAAE,OAAqE,EAAE;QACzH,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAA;QAC5B,IAAI,CAAC,IAAI,GAAG,aAAa,CAAA;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;QAC/B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QACzB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAA;IAC1C,CAAC;CACF;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,IAAa;IACzD,MAAM,CAAC,GAAI,IAAyG,EAAE,KAAK,CAAA;IAC3H,IAAI,CAAC,EAAE,IAAI;QAAE,OAAO,IAAI,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,IAAI,gBAAgB,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAA;IACvI,OAAO,IAAI,WAAW,CAAC,gBAAgB,EAAE,mBAAmB,MAAM,wBAAwB,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI,GAAG,EAAE,CAAC,CAAA;AACnI,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { NorthstarCipher, wireContext } from './client.js';
|
|
2
|
+
export type { CipherContext, DecryptInput, DecryptObjectInput, DecryptOutput, EncryptInput, EncryptObjectInput, EncryptOutput, Normalization, NorthstarCipherOptions, SessionDetails, Settled, WireEvent, } from './client.js';
|
|
3
|
+
export { CipherError } from './errors.js';
|
|
4
|
+
export { EncryptedObject, canonicalContext, objectContentKey, objectLength, openObject, sealObject } from './object.js';
|
|
5
|
+
export { SearchIndex } from './search.js';
|
|
6
|
+
export type { SearchCiphertext, SearchDocument, SearchField, SearchFieldType, SearchFields, SearchFilter, SearchFilterValue, SearchHit, SearchIndexInfo, SearchIndexVersion, SearchLanguage, SearchQuery, SearchResult, SearchScalar, SearchSchema, SearchSchemaInput, SearchValue, SearchWriteMode, SearchWriteRequest, SearchWriteResult, } from './search.js';
|
|
7
|
+
export type { CipherErrorCode } from './errors.js';
|
|
8
|
+
export { buildCredentialSecret, generateCredentialKeyPair, parseCredential } from './crypto.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { NorthstarCipher, wireContext } from './client.js';
|
|
2
|
+
export { CipherError } from './errors.js';
|
|
3
|
+
export { EncryptedObject, canonicalContext, objectContentKey, objectLength, openObject, sealObject } from './object.js';
|
|
4
|
+
export { SearchIndex } from './search.js';
|
|
5
|
+
export { buildCredentialSecret, generateCredentialKeyPair, parseCredential } from './crypto.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAe1D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACvH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAwBzC,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drizzle ORM helpers. Drizzle has no async lifecycle hooks, so encryption is an
|
|
3
|
+
* explicit, typed step around your queries.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { encrypted, northstarDrizzle, cipherEq } from '@northstartech/cipher/drizzle'
|
|
7
|
+
*
|
|
8
|
+
* export const todos = encrypted(
|
|
9
|
+
* pgTable('todos', { id: serial('id').primaryKey(), title: text('title'), email: text('email'), emailBidx: varchar('email_bidx', { length: 64 }) }),
|
|
10
|
+
* { title: true, email: { searchable: 'email', indexField: 'emailBidx' } },
|
|
11
|
+
* )
|
|
12
|
+
* const nsc = northstarDrizzle(cipher, { db }) // `db` reserves serial ids on PostgreSQL
|
|
13
|
+
*
|
|
14
|
+
* await db.insert(todos).values(await nsc.encryptRows(todos, [{ title: 'Buy milk', email: 'ana@example.com' }]))
|
|
15
|
+
* const rows = await nsc.decryptRows(todos, await db.select().from(todos)) // one decrypt request
|
|
16
|
+
* const tokens = await nsc.searchTokens(todos.email, 'ANA@example.com')
|
|
17
|
+
* const mine = await nsc.decryptRows(todos, await db.select().from(todos).where(cipherEq(todos.email, tokens)))
|
|
18
|
+
*
|
|
19
|
+
* // Northstar Search: index stored rows as they are (the enclave decrypts the ciphertext)
|
|
20
|
+
* await cipher.index('todos').upsert(searchDocuments(todos, await db.select().from(todos), ['title', 'email', 'done']))
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { Column, type SQL, Table } from 'drizzle-orm';
|
|
24
|
+
import type { NorthstarCipher } from '../client.js';
|
|
25
|
+
import { CipherError } from '../errors.js';
|
|
26
|
+
import { type CipherIntegrationOptions, type EncryptedFieldSpec } from './shared.js';
|
|
27
|
+
import type { SearchDocument } from '../search.js';
|
|
28
|
+
export { CIPHERTEXT_PREFIX, PENDING_SENTINEL } from './shared.js';
|
|
29
|
+
export type { EncryptedFieldOptions, EncryptedFieldSpec, CipherIntegrationOptions } from './shared.js';
|
|
30
|
+
type ColumnsOf<T extends Table> = T['_']['columns'];
|
|
31
|
+
type ColumnKey<T extends Table> = keyof ColumnsOf<T> & string;
|
|
32
|
+
/** Encrypted columns of a table, keyed by the table's JS property names. */
|
|
33
|
+
export type DrizzleFieldsConfig<T extends Table> = Partial<Record<ColumnKey<T>, EncryptedFieldSpec>>;
|
|
34
|
+
export interface EncryptedTableOptions<T extends Table> {
|
|
35
|
+
/** JS key of the primary-key column. Default: the column declared `.primaryKey()`. */
|
|
36
|
+
primaryKey?: ColumnKey<T>;
|
|
37
|
+
}
|
|
38
|
+
/** Anything with Drizzle's `execute(sql)`: a database or a transaction. */
|
|
39
|
+
export interface DrizzleExecutor {
|
|
40
|
+
execute(query: SQL): Promise<unknown>;
|
|
41
|
+
}
|
|
42
|
+
export interface NorthstarDrizzleOptions extends CipherIntegrationOptions {
|
|
43
|
+
/** Used to reserve PostgreSQL serial/identity ids before inserts (override per call with `{ db: tx }`). */
|
|
44
|
+
db?: DrizzleExecutor;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Declare the encrypted columns of a Drizzle table (call once, next to the table
|
|
48
|
+
* definition). Returns the table unchanged so it can wrap the definition.
|
|
49
|
+
*/
|
|
50
|
+
export declare function encrypted<T extends Table>(table: T, fields: DrizzleFieldsConfig<T>, options?: EncryptedTableOptions<T>): T;
|
|
51
|
+
/**
|
|
52
|
+
* Exact-match condition: `cipherEq(todos.email, tokens)` → `email_bidx IN (…tokens)`.
|
|
53
|
+
* Accepts the encrypted column (mapped to its blind index) or the blind-index column.
|
|
54
|
+
* Empty token lists match nothing.
|
|
55
|
+
*/
|
|
56
|
+
export declare function cipherEq(column: Column, tokens: readonly string[] | readonly (readonly string[])[]): SQL;
|
|
57
|
+
/**
|
|
58
|
+
* Two-phase write, step 1 (databases where the id is only known after INSERT):
|
|
59
|
+
* the row with every non-null encrypted value replaced by the `nsc:pending:v1`
|
|
60
|
+
* sentinel. Insert it, then `update(...).set(await nsc.encryptRow(table, row, { recordId }))`
|
|
61
|
+
* `.where(and(eq(table.id, id), eq(table.col, PENDING_SENTINEL)))`, ideally in one transaction.
|
|
62
|
+
*/
|
|
63
|
+
export declare function pendingRow<T extends Table, R extends Record<string, unknown>>(table: T, row: R): R;
|
|
64
|
+
/**
|
|
65
|
+
* Northstar Search documents for stored rows (`db.select().from(table)`, not
|
|
66
|
+
* decrypted): encrypted columns are sent as their ciphertext with the context
|
|
67
|
+
* they are bound to and decrypted inside the enclave, so indexing needs no
|
|
68
|
+
* decrypt request. Rows already decrypted with `decryptRows` work too (their
|
|
69
|
+
* plaintext is sent). Document ids are the primary keys; field names are the
|
|
70
|
+
* table's JS keys.
|
|
71
|
+
*/
|
|
72
|
+
export declare function searchDocuments<T extends Table>(table: T, rows: Record<string, unknown>[], fields: ColumnKey<T>[]): SearchDocument[];
|
|
73
|
+
export interface EncryptRowOptions {
|
|
74
|
+
/** Record id to bind to (for updates of partial rows, or step 2 of the two-phase write). */
|
|
75
|
+
recordId?: string | number | bigint;
|
|
76
|
+
/** Database/transaction used to reserve PostgreSQL serial ids. */
|
|
77
|
+
db?: DrizzleExecutor;
|
|
78
|
+
}
|
|
79
|
+
/** The bound helper set returned by {@link northstarDrizzle}. */
|
|
80
|
+
/** A row after encryption: the input plus the columns the helper may fill (primary key, blind indexes). */
|
|
81
|
+
export type EncryptedRow<T extends Table, R> = R & Partial<T['$inferInsert']>;
|
|
82
|
+
export interface NorthstarDrizzle {
|
|
83
|
+
encryptRow<T extends Table, R extends Partial<T['$inferInsert']>>(table: T, row: R, opts?: EncryptRowOptions): Promise<EncryptedRow<T, R>>;
|
|
84
|
+
encryptRows<T extends Table, R extends Partial<T['$inferInsert']>>(table: T, rows: R[], opts?: Omit<EncryptRowOptions, 'recordId'>): Promise<EncryptedRow<T, R>[]>;
|
|
85
|
+
decryptRows<T extends Table, R extends Record<string, unknown>>(table: T, rows: R[], opts?: {
|
|
86
|
+
purpose?: string;
|
|
87
|
+
}): Promise<R[]>;
|
|
88
|
+
decryptRow<T extends Table, R extends Record<string, unknown>>(table: T, row: R | undefined | null, opts?: {
|
|
89
|
+
purpose?: string;
|
|
90
|
+
}): Promise<R | undefined | null>;
|
|
91
|
+
searchTokens(column: Column, value: string | string[]): Promise<string[]>;
|
|
92
|
+
reserveIds<T extends Table>(table: T, count: number, db?: DrizzleExecutor): Promise<(number | bigint)[]>;
|
|
93
|
+
}
|
|
94
|
+
/** Bind the helpers to a Northstar Cipher client. */
|
|
95
|
+
export declare function northstarDrizzle(cipher: NorthstarCipher, options?: NorthstarDrizzleOptions): NorthstarDrizzle;
|
|
96
|
+
export { CipherError };
|