Experimental sealing

This commit is contained in:
Tony Garnock-Jones 2024-05-29 11:50:23 +02:00
parent 9c85ac5a85
commit 333f743114
4 changed files with 76 additions and 4 deletions

View File

@ -20,6 +20,7 @@ export * as Skeleton from './runtime/skeleton.js';
export * from './runtime/space.js';
export * from './runtime/supervise.js';
export * as SaltyCrypto from 'salty-crypto';
export * as Cryptography from './transport/cryptography.js';
export * as WireProtocol from './transport/protocol.js';
export * as Relay from './transport/relay.js';

View File

@ -28,8 +28,7 @@
"@preserves/core": "^0.995.200"
},
"dependencies": {
"@syndicate-lang/core": "^0.34.5",
"salty-crypto": "0.3"
"@syndicate-lang/core": "^0.34.5"
},
"devDependencies": {
"@syndicate-lang/ts-plugin": "^0.36.5",

View File

@ -24,14 +24,15 @@ import {
stringify,
underlying,
Embeddable,
SaltyCrypto,
} from "@syndicate-lang/core";
import G = Schemas.gatekeeper;
import S = Schemas.sturdy;
import N = Schemas.noise;
import T = Schemas.transportAddress;
import E = Schemas.stdenv;
import * as SaltyCrypto from 'salty-crypto';
export * as SaltyCrypto from 'salty-crypto';
export * from './seal.js';
type TransportState = {
addr: T.WebSocket,

View File

@ -0,0 +1,71 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Bytes, Value, encode, decode, isEmbedded, isSequence } from "@preserves/core";
import { SaltyCrypto, Ref } from "@syndicate-lang/core";
const aead = SaltyCrypto.ChaCha20Poly1305_RFC8439;
export type Sealed = [Bytes, number, number, number];
export function makeSeal() {
const key = new DataView(SaltyCrypto.randomBytes(aead.KEYBYTES).buffer);
const n = new SaltyCrypto.Nonce();
return {
seal(v: Value<Ref>): Promise<Sealed> {
return new Promise(k => {
at this.sealer {
send message [v, create ({
message(reply) { k(reply as Sealed); }
})];
}
});
},
unseal(sealed: Sealed): Promise<{ ok: true, value: Value } | { ok: false }> {
return new Promise(k => {
at this.unsealer {
send message [sealed, create ({
message(reply) { k(reply as any); }
})];
}
});
},
sealer: create ({
message(req) {
if (isSequence(req) && req.length === 2 && isEmbedded(req[1])) {
try {
const [term, k] = req;
const m = encode(term);
const c = aead.encrypt(m._view, key, n);
at k { send message [Bytes.from(c), n.lo, n.hi, n.extra]; }
n.increment();
} catch (_e) { console.error('Failed sealing: ' + _e); }
}
}
}),
unsealer: create ({
message(req) {
if (
isSequence(req) && req.length === 2 && isEmbedded(req[1]) &&
isSequence(req[0]) && req[0].length === 4 &&
Bytes.isBytes(req[0][0]) &&
typeof req[0][1] === 'number' &&
typeof req[0][2] === 'number' &&
typeof req[0][3] === 'number'
) {
const [[c, lo, hi, extra], k] = req;
try {
const n = new SaltyCrypto.Nonce(lo, hi, extra);
const m = aead.decrypt(c._view, key, n);
at k { send message { ok: true, value: decode(Bytes.from(m)) }; }
} catch (e) {
at k { send message { ok: false }; }
}
}
},
}),
};
}