@shhhum/xftp-web 0.1.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 +47 -0
- package/dist/agent.d.ts +46 -0
- package/dist/agent.js +273 -0
- package/dist/agent.js.map +1 -0
- package/dist/client.d.ts +63 -0
- package/dist/client.js +353 -0
- package/dist/client.js.map +1 -0
- package/dist/crypto/digest.d.ts +3 -0
- package/dist/crypto/digest.js +23 -0
- package/dist/crypto/digest.js.map +1 -0
- package/dist/crypto/file.d.ts +14 -0
- package/dist/crypto/file.js +68 -0
- package/dist/crypto/file.js.map +1 -0
- package/dist/crypto/identity.d.ts +10 -0
- package/dist/crypto/identity.js +98 -0
- package/dist/crypto/identity.js.map +1 -0
- package/dist/crypto/keys.d.ts +27 -0
- package/dist/crypto/keys.js +138 -0
- package/dist/crypto/keys.js.map +1 -0
- package/dist/crypto/padding.d.ts +8 -0
- package/dist/crypto/padding.js +60 -0
- package/dist/crypto/padding.js.map +1 -0
- package/dist/crypto/secretbox.d.ts +22 -0
- package/dist/crypto/secretbox.js +195 -0
- package/dist/crypto/secretbox.js.map +1 -0
- package/dist/download.d.ts +9 -0
- package/dist/download.js +60 -0
- package/dist/download.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/address.d.ts +7 -0
- package/dist/protocol/address.js +50 -0
- package/dist/protocol/address.js.map +1 -0
- package/dist/protocol/chunks.d.ts +15 -0
- package/dist/protocol/chunks.js +75 -0
- package/dist/protocol/chunks.js.map +1 -0
- package/dist/protocol/client.d.ts +9 -0
- package/dist/protocol/client.js +69 -0
- package/dist/protocol/client.js.map +1 -0
- package/dist/protocol/commands.d.ts +68 -0
- package/dist/protocol/commands.js +115 -0
- package/dist/protocol/commands.js.map +1 -0
- package/dist/protocol/description.d.ts +37 -0
- package/dist/protocol/description.js +317 -0
- package/dist/protocol/description.js.map +1 -0
- package/dist/protocol/encoding.d.ts +34 -0
- package/dist/protocol/encoding.js +197 -0
- package/dist/protocol/encoding.js.map +1 -0
- package/dist/protocol/handshake.d.ts +47 -0
- package/dist/protocol/handshake.js +158 -0
- package/dist/protocol/handshake.js.map +1 -0
- package/dist/protocol/transmission.d.ts +15 -0
- package/dist/protocol/transmission.js +84 -0
- package/dist/protocol/transmission.js.map +1 -0
- package/package.json +40 -0
- package/src/agent.ts +372 -0
- package/src/client.ts +448 -0
- package/src/crypto/digest.ts +26 -0
- package/src/crypto/file.ts +94 -0
- package/src/crypto/identity.ts +112 -0
- package/src/crypto/keys.ts +172 -0
- package/src/crypto/padding.ts +61 -0
- package/src/crypto/secretbox.ts +219 -0
- package/src/download.ts +76 -0
- package/src/index.ts +4 -0
- package/src/protocol/address.ts +54 -0
- package/src/protocol/chunks.ts +86 -0
- package/src/protocol/client.ts +95 -0
- package/src/protocol/commands.ts +157 -0
- package/src/protocol/description.ts +363 -0
- package/src/protocol/encoding.ts +224 -0
- package/src/protocol/handshake.ts +220 -0
- package/src/protocol/transmission.ts +113 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface Ed25519KeyPair {
|
|
2
|
+
publicKey: Uint8Array;
|
|
3
|
+
privateKey: Uint8Array;
|
|
4
|
+
}
|
|
5
|
+
export declare function generateEd25519KeyPair(): Ed25519KeyPair;
|
|
6
|
+
export declare function ed25519KeyPairFromSeed(seed: Uint8Array): Ed25519KeyPair;
|
|
7
|
+
export interface X25519KeyPair {
|
|
8
|
+
publicKey: Uint8Array;
|
|
9
|
+
privateKey: Uint8Array;
|
|
10
|
+
}
|
|
11
|
+
export declare function generateX25519KeyPair(): X25519KeyPair;
|
|
12
|
+
export declare function x25519KeyPairFromPrivate(privateKey: Uint8Array): X25519KeyPair;
|
|
13
|
+
export declare function sign(privateKey: Uint8Array, msg: Uint8Array): Uint8Array;
|
|
14
|
+
export declare function verify(publicKey: Uint8Array, sig: Uint8Array, msg: Uint8Array): boolean;
|
|
15
|
+
export declare function dh(publicKey: Uint8Array, privateKey: Uint8Array): Uint8Array;
|
|
16
|
+
export declare function encodePubKeyEd25519(rawPubKey: Uint8Array): Uint8Array;
|
|
17
|
+
export declare function decodePubKeyEd25519(der: Uint8Array): Uint8Array;
|
|
18
|
+
export declare function encodePubKeyX25519(rawPubKey: Uint8Array): Uint8Array;
|
|
19
|
+
export declare function decodePubKeyX25519(der: Uint8Array): Uint8Array;
|
|
20
|
+
export declare function encodePubKeyEd448(rawPubKey: Uint8Array): Uint8Array;
|
|
21
|
+
export declare function decodePubKeyEd448(der: Uint8Array): Uint8Array;
|
|
22
|
+
export declare function verifyEd448(publicKey: Uint8Array, sig: Uint8Array, msg: Uint8Array): boolean;
|
|
23
|
+
export declare function encodePrivKeyEd25519(privateKey: Uint8Array): Uint8Array;
|
|
24
|
+
export declare function decodePrivKeyEd25519(der: Uint8Array): Uint8Array;
|
|
25
|
+
export declare function encodePrivKeyX25519(privateKey: Uint8Array): Uint8Array;
|
|
26
|
+
export declare function decodePrivKeyX25519(der: Uint8Array): Uint8Array;
|
|
27
|
+
export declare function keyHash(derPubKey: Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Key generation, signing, DH -- Simplex.Messaging.Crypto (Ed25519/X25519/Ed448 functions).
|
|
2
|
+
import sodium from "libsodium-wrappers-sumo";
|
|
3
|
+
import { ed448 } from "@noble/curves/ed448";
|
|
4
|
+
import { sha256 } from "./digest.js";
|
|
5
|
+
import { concatBytes } from "../protocol/encoding.js";
|
|
6
|
+
export function generateEd25519KeyPair() {
|
|
7
|
+
const kp = sodium.crypto_sign_keypair();
|
|
8
|
+
return { publicKey: kp.publicKey, privateKey: kp.privateKey };
|
|
9
|
+
}
|
|
10
|
+
// Generate from known 32-byte seed (deterministic, for testing/interop).
|
|
11
|
+
export function ed25519KeyPairFromSeed(seed) {
|
|
12
|
+
const kp = sodium.crypto_sign_seed_keypair(seed);
|
|
13
|
+
return { publicKey: kp.publicKey, privateKey: kp.privateKey };
|
|
14
|
+
}
|
|
15
|
+
export function generateX25519KeyPair() {
|
|
16
|
+
const kp = sodium.crypto_box_keypair();
|
|
17
|
+
return { publicKey: kp.publicKey, privateKey: kp.privateKey };
|
|
18
|
+
}
|
|
19
|
+
// Derive X25519 keypair from raw 32-byte private key.
|
|
20
|
+
export function x25519KeyPairFromPrivate(privateKey) {
|
|
21
|
+
const publicKey = sodium.crypto_scalarmult_base(privateKey);
|
|
22
|
+
return { publicKey, privateKey };
|
|
23
|
+
}
|
|
24
|
+
// -- Ed25519 signing (Crypto.hs:1175 sign')
|
|
25
|
+
export function sign(privateKey, msg) {
|
|
26
|
+
return sodium.crypto_sign_detached(msg, privateKey);
|
|
27
|
+
}
|
|
28
|
+
// -- Ed25519 verification (Crypto.hs:1270 verify')
|
|
29
|
+
export function verify(publicKey, sig, msg) {
|
|
30
|
+
try {
|
|
31
|
+
return sodium.crypto_sign_verify_detached(sig, msg, publicKey);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// -- X25519 Diffie-Hellman (Crypto.hs:1280 dh')
|
|
38
|
+
export function dh(publicKey, privateKey) {
|
|
39
|
+
return sodium.crypto_scalarmult(privateKey, publicKey);
|
|
40
|
+
}
|
|
41
|
+
// -- DER encoding for Ed25519 public keys (RFC 8410, SubjectPublicKeyInfo)
|
|
42
|
+
// SEQUENCE { SEQUENCE { OID 1.3.101.112 } BIT STRING { 0x00 <32 bytes> } }
|
|
43
|
+
const ED25519_PUBKEY_DER_PREFIX = new Uint8Array([
|
|
44
|
+
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
|
|
45
|
+
]);
|
|
46
|
+
const X25519_PUBKEY_DER_PREFIX = new Uint8Array([
|
|
47
|
+
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
|
|
48
|
+
]);
|
|
49
|
+
export function encodePubKeyEd25519(rawPubKey) {
|
|
50
|
+
return concatBytes(ED25519_PUBKEY_DER_PREFIX, rawPubKey);
|
|
51
|
+
}
|
|
52
|
+
export function decodePubKeyEd25519(der) {
|
|
53
|
+
if (der.length !== 44)
|
|
54
|
+
throw new Error("decodePubKeyEd25519: invalid length");
|
|
55
|
+
for (let i = 0; i < ED25519_PUBKEY_DER_PREFIX.length; i++) {
|
|
56
|
+
if (der[i] !== ED25519_PUBKEY_DER_PREFIX[i])
|
|
57
|
+
throw new Error("decodePubKeyEd25519: invalid DER prefix");
|
|
58
|
+
}
|
|
59
|
+
return der.subarray(12);
|
|
60
|
+
}
|
|
61
|
+
export function encodePubKeyX25519(rawPubKey) {
|
|
62
|
+
return concatBytes(X25519_PUBKEY_DER_PREFIX, rawPubKey);
|
|
63
|
+
}
|
|
64
|
+
export function decodePubKeyX25519(der) {
|
|
65
|
+
if (der.length !== 44)
|
|
66
|
+
throw new Error("decodePubKeyX25519: invalid length");
|
|
67
|
+
for (let i = 0; i < X25519_PUBKEY_DER_PREFIX.length; i++) {
|
|
68
|
+
if (der[i] !== X25519_PUBKEY_DER_PREFIX[i])
|
|
69
|
+
throw new Error("decodePubKeyX25519: invalid DER prefix");
|
|
70
|
+
}
|
|
71
|
+
return der.subarray(12);
|
|
72
|
+
}
|
|
73
|
+
// -- DER encoding for Ed448 public keys (RFC 8410, SubjectPublicKeyInfo)
|
|
74
|
+
// SEQUENCE { SEQUENCE { OID 1.3.101.113 } BIT STRING { 0x00 <57 bytes> } }
|
|
75
|
+
const ED448_PUBKEY_DER_PREFIX = new Uint8Array([
|
|
76
|
+
0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x71, 0x03, 0x3a, 0x00,
|
|
77
|
+
]);
|
|
78
|
+
export function encodePubKeyEd448(rawPubKey) {
|
|
79
|
+
return concatBytes(ED448_PUBKEY_DER_PREFIX, rawPubKey);
|
|
80
|
+
}
|
|
81
|
+
export function decodePubKeyEd448(der) {
|
|
82
|
+
if (der.length !== 69)
|
|
83
|
+
throw new Error("decodePubKeyEd448: invalid length");
|
|
84
|
+
for (let i = 0; i < ED448_PUBKEY_DER_PREFIX.length; i++) {
|
|
85
|
+
if (der[i] !== ED448_PUBKEY_DER_PREFIX[i])
|
|
86
|
+
throw new Error("decodePubKeyEd448: invalid DER prefix");
|
|
87
|
+
}
|
|
88
|
+
return der.subarray(12);
|
|
89
|
+
}
|
|
90
|
+
// -- Ed448 verification via @noble/curves (Crypto.hs:1270 verify')
|
|
91
|
+
export function verifyEd448(publicKey, sig, msg) {
|
|
92
|
+
try {
|
|
93
|
+
return ed448.verify(sig, msg, publicKey);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// -- DER encoding for private keys (PKCS8 OneAsymmetricKey, RFC 8410)
|
|
100
|
+
// SEQUENCE { INTEGER 0, SEQUENCE { OID }, OCTET STRING { OCTET STRING { <32 bytes> } } }
|
|
101
|
+
const ED25519_PRIVKEY_DER_PREFIX = new Uint8Array([
|
|
102
|
+
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20,
|
|
103
|
+
]);
|
|
104
|
+
const X25519_PRIVKEY_DER_PREFIX = new Uint8Array([
|
|
105
|
+
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20,
|
|
106
|
+
]);
|
|
107
|
+
export function encodePrivKeyEd25519(privateKey) {
|
|
108
|
+
// privateKey is 64 bytes (libsodium: seed || pubkey), seed is first 32 bytes
|
|
109
|
+
const seed = privateKey.subarray(0, 32);
|
|
110
|
+
return concatBytes(ED25519_PRIVKEY_DER_PREFIX, seed);
|
|
111
|
+
}
|
|
112
|
+
export function decodePrivKeyEd25519(der) {
|
|
113
|
+
if (der.length !== 48)
|
|
114
|
+
throw new Error("decodePrivKeyEd25519: invalid length");
|
|
115
|
+
for (let i = 0; i < ED25519_PRIVKEY_DER_PREFIX.length; i++) {
|
|
116
|
+
if (der[i] !== ED25519_PRIVKEY_DER_PREFIX[i])
|
|
117
|
+
throw new Error("decodePrivKeyEd25519: invalid DER prefix");
|
|
118
|
+
}
|
|
119
|
+
// Returns 32-byte seed; call ed25519KeyPairFromSeed to get full keypair.
|
|
120
|
+
return der.subarray(16);
|
|
121
|
+
}
|
|
122
|
+
export function encodePrivKeyX25519(privateKey) {
|
|
123
|
+
return concatBytes(X25519_PRIVKEY_DER_PREFIX, privateKey);
|
|
124
|
+
}
|
|
125
|
+
export function decodePrivKeyX25519(der) {
|
|
126
|
+
if (der.length !== 48)
|
|
127
|
+
throw new Error("decodePrivKeyX25519: invalid length");
|
|
128
|
+
for (let i = 0; i < X25519_PRIVKEY_DER_PREFIX.length; i++) {
|
|
129
|
+
if (der[i] !== X25519_PRIVKEY_DER_PREFIX[i])
|
|
130
|
+
throw new Error("decodePrivKeyX25519: invalid DER prefix");
|
|
131
|
+
}
|
|
132
|
+
return der.subarray(16);
|
|
133
|
+
}
|
|
134
|
+
// -- KeyHash: SHA-256 of DER-encoded public key (Crypto.hs:981)
|
|
135
|
+
export function keyHash(derPubKey) {
|
|
136
|
+
return sha256(derPubKey);
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/crypto/keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function pad(msg: Uint8Array, paddedLen: number): Uint8Array;
|
|
2
|
+
export declare function unPad(padded: Uint8Array): Uint8Array;
|
|
3
|
+
export declare function padLazy(msg: Uint8Array, msgLen: bigint, padLen: bigint): Uint8Array;
|
|
4
|
+
export declare function unPadLazy(padded: Uint8Array): Uint8Array;
|
|
5
|
+
export declare function splitLen(data: Uint8Array): {
|
|
6
|
+
len: bigint;
|
|
7
|
+
content: Uint8Array;
|
|
8
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Block padding matching Simplex.Messaging.Crypto (strict) and Simplex.Messaging.Crypto.Lazy.
|
|
2
|
+
// Strict: 2-byte BE length prefix + message + '#' fill.
|
|
3
|
+
// Lazy: 8-byte Int64 length prefix + message + '#' fill.
|
|
4
|
+
import { encodeWord16, decodeWord16, encodeInt64, decodeInt64, Decoder } from "../protocol/encoding.js";
|
|
5
|
+
const HASH = 0x23; // '#'
|
|
6
|
+
// -- Strict pad/unPad (protocol messages) -- Crypto.hs:1077
|
|
7
|
+
export function pad(msg, paddedLen) {
|
|
8
|
+
const len = msg.length;
|
|
9
|
+
if (len > 65535)
|
|
10
|
+
throw new Error("pad: message too large for Word16 length");
|
|
11
|
+
const fillLen = paddedLen - len - 2;
|
|
12
|
+
if (fillLen < 0)
|
|
13
|
+
throw new Error("pad: message exceeds padded size");
|
|
14
|
+
const result = new Uint8Array(paddedLen);
|
|
15
|
+
const lenBytes = encodeWord16(len);
|
|
16
|
+
result.set(lenBytes, 0);
|
|
17
|
+
result.set(msg, 2);
|
|
18
|
+
result.fill(HASH, 2 + len);
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
export function unPad(padded) {
|
|
22
|
+
if (padded.length < 2)
|
|
23
|
+
throw new Error("unPad: input too short");
|
|
24
|
+
const d = new Decoder(padded);
|
|
25
|
+
const len = decodeWord16(d);
|
|
26
|
+
if (padded.length - 2 < len)
|
|
27
|
+
throw new Error("unPad: invalid length");
|
|
28
|
+
return padded.subarray(2, 2 + len);
|
|
29
|
+
}
|
|
30
|
+
// -- Lazy pad/unPad (file encryption) -- Crypto/Lazy.hs:70
|
|
31
|
+
export function padLazy(msg, msgLen, padLen) {
|
|
32
|
+
const fillLen = padLen - msgLen - 8n;
|
|
33
|
+
if (fillLen < 0n)
|
|
34
|
+
throw new Error("padLazy: message exceeds padded size");
|
|
35
|
+
const totalLen = Number(padLen);
|
|
36
|
+
const result = new Uint8Array(totalLen);
|
|
37
|
+
const lenBytes = encodeInt64(msgLen);
|
|
38
|
+
result.set(lenBytes, 0);
|
|
39
|
+
result.set(msg.subarray(0, Number(msgLen)), 8);
|
|
40
|
+
result.fill(HASH, 8 + Number(msgLen));
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
export function unPadLazy(padded) {
|
|
44
|
+
return splitLen(padded).content;
|
|
45
|
+
}
|
|
46
|
+
// splitLen: extract 8-byte Int64 length and content -- Crypto/Lazy.hs:96
|
|
47
|
+
// Does not fail if content is shorter than declared length (for chunked decryption).
|
|
48
|
+
export function splitLen(data) {
|
|
49
|
+
if (data.length < 8)
|
|
50
|
+
throw new Error("splitLen: input too short");
|
|
51
|
+
const d = new Decoder(data);
|
|
52
|
+
const len = decodeInt64(d);
|
|
53
|
+
if (len < 0n)
|
|
54
|
+
throw new Error("splitLen: negative length");
|
|
55
|
+
const numLen = Number(len);
|
|
56
|
+
const available = data.length - 8;
|
|
57
|
+
const takeLen = Math.min(numLen, available);
|
|
58
|
+
return { len, content: data.subarray(8, 8 + takeLen) };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=padding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"padding.js","sourceRoot":"","sources":["../../src/crypto/padding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { StateAddress } from "libsodium-wrappers-sumo";
|
|
2
|
+
export interface SbState {
|
|
3
|
+
_subkey: Uint8Array;
|
|
4
|
+
_nonce8: Uint8Array;
|
|
5
|
+
_counter: number;
|
|
6
|
+
_ksBuf: Uint8Array;
|
|
7
|
+
_ksOff: number;
|
|
8
|
+
_authState: StateAddress;
|
|
9
|
+
}
|
|
10
|
+
export declare function sbInit(key: Uint8Array, nonce: Uint8Array): SbState;
|
|
11
|
+
export declare function cbInit(dhSecret: Uint8Array, nonce: Uint8Array): SbState;
|
|
12
|
+
export declare function sbEncryptChunk(state: SbState, chunk: Uint8Array): Uint8Array;
|
|
13
|
+
export declare function sbDecryptChunk(state: SbState, chunk: Uint8Array): Uint8Array;
|
|
14
|
+
export declare function sbAuth(state: SbState): Uint8Array;
|
|
15
|
+
export declare function sbEncryptTailTag(key: Uint8Array, nonce: Uint8Array, data: Uint8Array, len: bigint, padLen: bigint): Uint8Array;
|
|
16
|
+
export declare function sbDecryptTailTag(key: Uint8Array, nonce: Uint8Array, paddedLen: bigint, data: Uint8Array): {
|
|
17
|
+
valid: boolean;
|
|
18
|
+
content: Uint8Array;
|
|
19
|
+
};
|
|
20
|
+
export declare function cryptoBox(key: Uint8Array, nonce: Uint8Array, msg: Uint8Array): Uint8Array;
|
|
21
|
+
export declare function cbEncrypt(dhSecret: Uint8Array, nonce: Uint8Array, msg: Uint8Array, padLen: number): Uint8Array;
|
|
22
|
+
export declare function cbDecrypt(dhSecret: Uint8Array, nonce: Uint8Array, packet: Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// Streaming XSalsa20-Poly1305 -- Simplex.Messaging.Crypto / Crypto.Lazy
|
|
2
|
+
//
|
|
3
|
+
// Libsodium-wrappers-sumo does not expose crypto_stream_xsalsa20_xor_ic,
|
|
4
|
+
// so the Salsa20/20 stream cipher core is implemented here.
|
|
5
|
+
// HSalsa20 uses libsodium's crypto_core_hsalsa20.
|
|
6
|
+
// Poly1305 uses libsodium's streaming crypto_onetimeauth_* API.
|
|
7
|
+
import sodium from "libsodium-wrappers-sumo";
|
|
8
|
+
import { concatBytes } from "../protocol/encoding.js";
|
|
9
|
+
import { pad, unPad, padLazy, unPadLazy } from "./padding.js";
|
|
10
|
+
// crypto_core_hsalsa20 exists at runtime but is missing from @types/libsodium-wrappers-sumo
|
|
11
|
+
const _sodium = sodium;
|
|
12
|
+
// -- Salsa20/20 stream cipher core
|
|
13
|
+
function readU32LE(buf, off) {
|
|
14
|
+
return ((buf[off] | (buf[off + 1] << 8) | (buf[off + 2] << 16) | (buf[off + 3] << 24)) >>> 0);
|
|
15
|
+
}
|
|
16
|
+
function writeU32LE(buf, off, val) {
|
|
17
|
+
buf[off] = val & 0xff;
|
|
18
|
+
buf[off + 1] = (val >>> 8) & 0xff;
|
|
19
|
+
buf[off + 2] = (val >>> 16) & 0xff;
|
|
20
|
+
buf[off + 3] = (val >>> 24) & 0xff;
|
|
21
|
+
}
|
|
22
|
+
function rotl32(v, n) {
|
|
23
|
+
return ((v << n) | (v >>> (32 - n))) >>> 0;
|
|
24
|
+
}
|
|
25
|
+
const SIGMA_0 = 0x61707865;
|
|
26
|
+
const SIGMA_1 = 0x3320646e;
|
|
27
|
+
const SIGMA_2 = 0x79622d32;
|
|
28
|
+
const SIGMA_3 = 0x6b206574;
|
|
29
|
+
function salsa20Block(key, nonce8, counter) {
|
|
30
|
+
const k0 = readU32LE(key, 0), k1 = readU32LE(key, 4);
|
|
31
|
+
const k2 = readU32LE(key, 8), k3 = readU32LE(key, 12);
|
|
32
|
+
const k4 = readU32LE(key, 16), k5 = readU32LE(key, 20);
|
|
33
|
+
const k6 = readU32LE(key, 24), k7 = readU32LE(key, 28);
|
|
34
|
+
const n0 = readU32LE(nonce8, 0), n1 = readU32LE(nonce8, 4);
|
|
35
|
+
const s0 = SIGMA_0, s1 = k0, s2 = k1, s3 = k2;
|
|
36
|
+
const s4 = k3, s5 = SIGMA_1, s6 = n0, s7 = n1;
|
|
37
|
+
const s8 = counter >>> 0, s9 = 0, s10 = SIGMA_2, s11 = k4;
|
|
38
|
+
const s12 = k5, s13 = k6, s14 = k7, s15 = SIGMA_3;
|
|
39
|
+
let x0 = s0, x1 = s1, x2 = s2, x3 = s3;
|
|
40
|
+
let x4 = s4, x5 = s5, x6 = s6, x7 = s7;
|
|
41
|
+
let x8 = s8, x9 = s9, x10 = s10, x11 = s11;
|
|
42
|
+
let x12 = s12, x13 = s13, x14 = s14, x15 = s15;
|
|
43
|
+
for (let i = 0; i < 10; i++) {
|
|
44
|
+
// Column round
|
|
45
|
+
x4 ^= rotl32((x0 + x12) >>> 0, 7);
|
|
46
|
+
x8 ^= rotl32((x4 + x0) >>> 0, 9);
|
|
47
|
+
x12 ^= rotl32((x8 + x4) >>> 0, 13);
|
|
48
|
+
x0 ^= rotl32((x12 + x8) >>> 0, 18);
|
|
49
|
+
x9 ^= rotl32((x5 + x1) >>> 0, 7);
|
|
50
|
+
x13 ^= rotl32((x9 + x5) >>> 0, 9);
|
|
51
|
+
x1 ^= rotl32((x13 + x9) >>> 0, 13);
|
|
52
|
+
x5 ^= rotl32((x1 + x13) >>> 0, 18);
|
|
53
|
+
x14 ^= rotl32((x10 + x6) >>> 0, 7);
|
|
54
|
+
x2 ^= rotl32((x14 + x10) >>> 0, 9);
|
|
55
|
+
x6 ^= rotl32((x2 + x14) >>> 0, 13);
|
|
56
|
+
x10 ^= rotl32((x6 + x2) >>> 0, 18);
|
|
57
|
+
x3 ^= rotl32((x15 + x11) >>> 0, 7);
|
|
58
|
+
x7 ^= rotl32((x3 + x15) >>> 0, 9);
|
|
59
|
+
x11 ^= rotl32((x7 + x3) >>> 0, 13);
|
|
60
|
+
x15 ^= rotl32((x11 + x7) >>> 0, 18);
|
|
61
|
+
// Row round
|
|
62
|
+
x1 ^= rotl32((x0 + x3) >>> 0, 7);
|
|
63
|
+
x2 ^= rotl32((x1 + x0) >>> 0, 9);
|
|
64
|
+
x3 ^= rotl32((x2 + x1) >>> 0, 13);
|
|
65
|
+
x0 ^= rotl32((x3 + x2) >>> 0, 18);
|
|
66
|
+
x6 ^= rotl32((x5 + x4) >>> 0, 7);
|
|
67
|
+
x7 ^= rotl32((x6 + x5) >>> 0, 9);
|
|
68
|
+
x4 ^= rotl32((x7 + x6) >>> 0, 13);
|
|
69
|
+
x5 ^= rotl32((x4 + x7) >>> 0, 18);
|
|
70
|
+
x11 ^= rotl32((x10 + x9) >>> 0, 7);
|
|
71
|
+
x8 ^= rotl32((x11 + x10) >>> 0, 9);
|
|
72
|
+
x9 ^= rotl32((x8 + x11) >>> 0, 13);
|
|
73
|
+
x10 ^= rotl32((x9 + x8) >>> 0, 18);
|
|
74
|
+
x12 ^= rotl32((x15 + x14) >>> 0, 7);
|
|
75
|
+
x13 ^= rotl32((x12 + x15) >>> 0, 9);
|
|
76
|
+
x14 ^= rotl32((x13 + x12) >>> 0, 13);
|
|
77
|
+
x15 ^= rotl32((x14 + x13) >>> 0, 18);
|
|
78
|
+
}
|
|
79
|
+
const out = new Uint8Array(64);
|
|
80
|
+
writeU32LE(out, 0, (x0 + s0) >>> 0);
|
|
81
|
+
writeU32LE(out, 4, (x1 + s1) >>> 0);
|
|
82
|
+
writeU32LE(out, 8, (x2 + s2) >>> 0);
|
|
83
|
+
writeU32LE(out, 12, (x3 + s3) >>> 0);
|
|
84
|
+
writeU32LE(out, 16, (x4 + s4) >>> 0);
|
|
85
|
+
writeU32LE(out, 20, (x5 + s5) >>> 0);
|
|
86
|
+
writeU32LE(out, 24, (x6 + s6) >>> 0);
|
|
87
|
+
writeU32LE(out, 28, (x7 + s7) >>> 0);
|
|
88
|
+
writeU32LE(out, 32, (x8 + s8) >>> 0);
|
|
89
|
+
writeU32LE(out, 36, (x9 + s9) >>> 0);
|
|
90
|
+
writeU32LE(out, 40, (x10 + s10) >>> 0);
|
|
91
|
+
writeU32LE(out, 44, (x11 + s11) >>> 0);
|
|
92
|
+
writeU32LE(out, 48, (x12 + s12) >>> 0);
|
|
93
|
+
writeU32LE(out, 52, (x13 + s13) >>> 0);
|
|
94
|
+
writeU32LE(out, 56, (x14 + s14) >>> 0);
|
|
95
|
+
writeU32LE(out, 60, (x15 + s15) >>> 0);
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
export function sbInit(key, nonce) {
|
|
99
|
+
// Double HSalsa20 cascade matching Haskell cryptonite XSalsa20 (Crypto.hs:xSalsa20):
|
|
100
|
+
// subkey1 = HSalsa20(key, zeros16)
|
|
101
|
+
// subkey2 = HSalsa20(subkey1, nonce[0:16])
|
|
102
|
+
// keystream = Salsa20(subkey2, nonce[16:24])
|
|
103
|
+
const zeros16 = new Uint8Array(16);
|
|
104
|
+
const subkey1 = _sodium.crypto_core_hsalsa20(zeros16, key);
|
|
105
|
+
const subkey = _sodium.crypto_core_hsalsa20(nonce.subarray(0, 16), subkey1);
|
|
106
|
+
const nonce8 = new Uint8Array(nonce.subarray(16, 24));
|
|
107
|
+
const block0 = salsa20Block(subkey, nonce8, 0);
|
|
108
|
+
const poly1305Key = block0.subarray(0, 32);
|
|
109
|
+
const ksBuf = new Uint8Array(block0.subarray(32));
|
|
110
|
+
const authState = sodium.crypto_onetimeauth_init(poly1305Key);
|
|
111
|
+
return { _subkey: subkey, _nonce8: nonce8, _counter: 1, _ksBuf: ksBuf, _ksOff: 0, _authState: authState };
|
|
112
|
+
}
|
|
113
|
+
export function cbInit(dhSecret, nonce) {
|
|
114
|
+
return sbInit(dhSecret, nonce);
|
|
115
|
+
}
|
|
116
|
+
export function sbEncryptChunk(state, chunk) {
|
|
117
|
+
const cipher = xorKeystream(state, chunk);
|
|
118
|
+
sodium.crypto_onetimeauth_update(state._authState, cipher);
|
|
119
|
+
return cipher;
|
|
120
|
+
}
|
|
121
|
+
export function sbDecryptChunk(state, chunk) {
|
|
122
|
+
sodium.crypto_onetimeauth_update(state._authState, chunk);
|
|
123
|
+
return xorKeystream(state, chunk);
|
|
124
|
+
}
|
|
125
|
+
export function sbAuth(state) {
|
|
126
|
+
return sodium.crypto_onetimeauth_final(state._authState);
|
|
127
|
+
}
|
|
128
|
+
// -- High-level: tail tag (tag appended)
|
|
129
|
+
export function sbEncryptTailTag(key, nonce, data, len, padLen) {
|
|
130
|
+
const padded = padLazy(data, len, padLen);
|
|
131
|
+
const state = sbInit(key, nonce);
|
|
132
|
+
const cipher = sbEncryptChunk(state, padded);
|
|
133
|
+
const tag = sbAuth(state);
|
|
134
|
+
return concatBytes(cipher, tag);
|
|
135
|
+
}
|
|
136
|
+
export function sbDecryptTailTag(key, nonce, paddedLen, data) {
|
|
137
|
+
const pLen = Number(paddedLen);
|
|
138
|
+
const cipher = data.subarray(0, pLen);
|
|
139
|
+
const providedTag = data.subarray(pLen);
|
|
140
|
+
const state = sbInit(key, nonce);
|
|
141
|
+
const plaintext = sbDecryptChunk(state, cipher);
|
|
142
|
+
const computedTag = sbAuth(state);
|
|
143
|
+
const valid = providedTag.length === 16 && constantTimeEqual(providedTag, computedTag);
|
|
144
|
+
const content = unPadLazy(plaintext);
|
|
145
|
+
return { valid, content };
|
|
146
|
+
}
|
|
147
|
+
// -- Tag-prepended secretbox (Haskell Crypto.hs:cryptoBox)
|
|
148
|
+
export function cryptoBox(key, nonce, msg) {
|
|
149
|
+
const state = sbInit(key, nonce);
|
|
150
|
+
const cipher = sbEncryptChunk(state, msg);
|
|
151
|
+
const tag = sbAuth(state);
|
|
152
|
+
return concatBytes(tag, cipher);
|
|
153
|
+
}
|
|
154
|
+
export function cbEncrypt(dhSecret, nonce, msg, padLen) {
|
|
155
|
+
return cryptoBox(dhSecret, nonce, pad(msg, padLen));
|
|
156
|
+
}
|
|
157
|
+
export function cbDecrypt(dhSecret, nonce, packet) {
|
|
158
|
+
const tag = packet.subarray(0, 16);
|
|
159
|
+
const cipher = packet.subarray(16);
|
|
160
|
+
const state = sbInit(dhSecret, nonce);
|
|
161
|
+
const plaintext = sbDecryptChunk(state, cipher);
|
|
162
|
+
const computedTag = sbAuth(state);
|
|
163
|
+
if (!constantTimeEqual(tag, computedTag))
|
|
164
|
+
throw new Error("secretbox: authentication failed");
|
|
165
|
+
return unPad(plaintext);
|
|
166
|
+
}
|
|
167
|
+
// -- Internal
|
|
168
|
+
function xorKeystream(state, data) {
|
|
169
|
+
const result = new Uint8Array(data.length);
|
|
170
|
+
let off = 0;
|
|
171
|
+
while (off < data.length) {
|
|
172
|
+
if (state._ksOff >= state._ksBuf.length) {
|
|
173
|
+
state._ksBuf = salsa20Block(state._subkey, state._nonce8, state._counter++);
|
|
174
|
+
state._ksOff = 0;
|
|
175
|
+
}
|
|
176
|
+
const available = state._ksBuf.length - state._ksOff;
|
|
177
|
+
const needed = data.length - off;
|
|
178
|
+
const n = Math.min(available, needed);
|
|
179
|
+
for (let i = 0; i < n; i++) {
|
|
180
|
+
result[off + i] = data[off + i] ^ state._ksBuf[state._ksOff + i];
|
|
181
|
+
}
|
|
182
|
+
state._ksOff += n;
|
|
183
|
+
off += n;
|
|
184
|
+
}
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
function constantTimeEqual(a, b) {
|
|
188
|
+
if (a.length !== b.length)
|
|
189
|
+
return false;
|
|
190
|
+
let diff = 0;
|
|
191
|
+
for (let i = 0; i < a.length; i++)
|
|
192
|
+
diff |= a[i] ^ b[i];
|
|
193
|
+
return diff === 0;
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=secretbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secretbox.js","sourceRoot":"","sources":["../../src/crypto/secretbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type FileHeader } from "./crypto/file.js";
|
|
2
|
+
import type { FileDescription } from "./protocol/description.js";
|
|
3
|
+
export declare function processFileResponse(recipientPrivKey: Uint8Array, // Ephemeral X25519 private key (32 bytes)
|
|
4
|
+
serverDhKey: Uint8Array): Uint8Array;
|
|
5
|
+
export declare function decryptReceivedChunk(dhSecret: Uint8Array, cbNonce: Uint8Array, encData: Uint8Array, expectedDigest: Uint8Array | null): Uint8Array;
|
|
6
|
+
export declare function processDownloadedFile(fd: FileDescription, plaintextChunks: Uint8Array[]): {
|
|
7
|
+
header: FileHeader;
|
|
8
|
+
content: Uint8Array;
|
|
9
|
+
};
|
package/dist/download.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// XFTP download pipeline -- integration of protocol + crypto layers.
|
|
2
|
+
//
|
|
3
|
+
// Ties together: DH key exchange (keys), transport decryption (client),
|
|
4
|
+
// file-level decryption (file), chunk sizing (chunks), digest verification.
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// 1. Parse FileDescription from YAML (description.ts)
|
|
8
|
+
// 2. For each chunk replica:
|
|
9
|
+
// a. generateX25519KeyPair() -> ephemeral DH keypair
|
|
10
|
+
// b. encodeFGET(dhPub) -> FGET command
|
|
11
|
+
// c. encodeAuthTransmission(...) -> padded block (send to server)
|
|
12
|
+
// d. decodeTransmission(responseBlock) -> raw response
|
|
13
|
+
// e. decodeResponse(raw) -> FRFile { rcvDhKey, nonce }
|
|
14
|
+
// f. processFileResponse(rcvPrivKey, rcvDhKey, nonce) -> dhSecret
|
|
15
|
+
// g. decryptReceivedChunk(dhSecret, nonce, encData, digest) -> plaintext
|
|
16
|
+
// 3. processDownloadedFile(fd, plaintextChunks) -> { header, content }
|
|
17
|
+
import { dh } from "./crypto/keys.js";
|
|
18
|
+
import { sha256 } from "./crypto/digest.js";
|
|
19
|
+
import { decryptChunks } from "./crypto/file.js";
|
|
20
|
+
import { decryptTransportChunk } from "./protocol/client.js";
|
|
21
|
+
// -- Process FRFile response
|
|
22
|
+
// Derive transport decryption secret from FRFile response parameters.
|
|
23
|
+
// Uses DH(serverDhKey, recipientPrivKey) to produce shared secret.
|
|
24
|
+
export function processFileResponse(recipientPrivKey, // Ephemeral X25519 private key (32 bytes)
|
|
25
|
+
serverDhKey) {
|
|
26
|
+
return dh(serverDhKey, recipientPrivKey);
|
|
27
|
+
}
|
|
28
|
+
// -- Decrypt a single received chunk
|
|
29
|
+
// Decrypt transport-encrypted chunk data and verify SHA-256 digest.
|
|
30
|
+
// Returns decrypted content or throws on auth tag / digest failure.
|
|
31
|
+
export function decryptReceivedChunk(dhSecret, cbNonce, encData, expectedDigest) {
|
|
32
|
+
const providedTag = encData.slice(encData.length - 16);
|
|
33
|
+
const { valid, content } = decryptTransportChunk(dhSecret, cbNonce, encData);
|
|
34
|
+
if (!valid)
|
|
35
|
+
throw new Error("transport auth tag verification failed");
|
|
36
|
+
if (expectedDigest !== null) {
|
|
37
|
+
const actual = sha256(content);
|
|
38
|
+
if (!digestEqual(actual, expectedDigest)) {
|
|
39
|
+
throw new Error("chunk digest mismatch");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return content;
|
|
43
|
+
}
|
|
44
|
+
// -- Full download pipeline
|
|
45
|
+
// Process downloaded file: concatenate transport-decrypted chunks,
|
|
46
|
+
// then file-level decrypt using key/nonce from file description.
|
|
47
|
+
// Returns parsed FileHeader and file content.
|
|
48
|
+
export function processDownloadedFile(fd, plaintextChunks) {
|
|
49
|
+
return decryptChunks(BigInt(fd.size), plaintextChunks, fd.key, fd.nonce);
|
|
50
|
+
}
|
|
51
|
+
// -- Internal
|
|
52
|
+
function digestEqual(a, b) {
|
|
53
|
+
if (a.length !== b.length)
|
|
54
|
+
return false;
|
|
55
|
+
let diff = 0;
|
|
56
|
+
for (let i = 0; i < a.length; i++)
|
|
57
|
+
diff |= a[i] ^ b[i];
|
|
58
|
+
return diff === 0;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=download.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download.js","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,wEAAwE;AACxE,4EAA4E;AAC5E,EAAE;AACF,SAAS;AACT,wDAAwD;AACxD,+BAA+B;AAC/B,0DAA0D;AAC1D,4CAA4C;AAC5C,uEAAuE;AACvE,4DAA4D;AAC5D,4DAA4D;AAC5D,uEAAuE;AACvE,8EAA8E;AAC9E,yEAAyE;AAEzE,OAAO,EAAC,EAAE,EAAC,MAAM,kBAAkB,CAAA;AACnC,OAAO,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAkB,MAAM,kBAAkB,CAAA;AAC/D,OAAO,EAAC,qBAAqB,EAAC,MAAM,sBAAsB,CAAA;AAG1D,6BAA6B;AAE7B,sEAAsE;AACtE,mEAAmE;AACnE,MAAM,UAAU,mBAAmB,CACjC,gBAA4B,EAAG,0CAA0C;AACzE,WAAuB;IAEvB,OAAO,EAAE,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAA;AAC1C,CAAC;AAED,qCAAqC;AAErC,oEAAoE;AACpE,oEAAoE;AACpE,MAAM,UAAU,oBAAoB,CAClC,QAAoB,EACpB,OAAmB,EACnB,OAAmB,EACnB,cAAiC;IAEjC,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;IACtD,MAAM,EAAC,KAAK,EAAE,OAAO,EAAC,GAAG,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IAC1E,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IACrE,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;QAC9B,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,4BAA4B;AAE5B,mEAAmE;AACnE,iEAAiE;AACjE,8CAA8C;AAC9C,MAAM,UAAU,qBAAqB,CACnC,EAAmB,EACnB,eAA6B;IAE7B,OAAO,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,eAAe,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,CAAA;AAC1E,CAAC;AAED,cAAc;AAEd,SAAS,WAAW,CAAC,CAAa,EAAE,CAAa;IAC/C,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACvC,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IACtD,OAAO,IAAI,KAAK,CAAC,CAAA;AACnB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export * from "./agent.js";
|
|
2
|
+
export { parseXFTPServer, formatXFTPServer, type XFTPServer } from "./protocol/address.js";
|
|
3
|
+
export { decodeFileDescription, encodeFileDescription, validateFileDescription, type FileDescription, type FileChunk, type FileChunkReplica } from "./protocol/description.js";
|
|
4
|
+
export { type FileHeader } from "./crypto/file.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAC,eAAe,EAAE,gBAAgB,EAAkB,MAAM,uBAAuB,CAAA;AACxF,OAAO,EAAC,qBAAqB,EAAE,qBAAqB,EAAE,uBAAuB,EAA8D,MAAM,2BAA2B,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// XFTP server address parsing/formatting -- Simplex.Messaging.Protocol (ProtocolServer)
|
|
2
|
+
//
|
|
3
|
+
// Parses/formats server address strings of the form:
|
|
4
|
+
// xftp://<keyhash>@<host>[,<host2>,...][:<port>]
|
|
5
|
+
//
|
|
6
|
+
// KeyHash is base64url-encoded SHA-256 fingerprint of the identity certificate.
|
|
7
|
+
import { base64urlEncode } from "./description.js";
|
|
8
|
+
// Decode base64url (RFC 4648 section 5) to Uint8Array.
|
|
9
|
+
function base64urlDecode(s) {
|
|
10
|
+
// Convert base64url to standard base64
|
|
11
|
+
let b64 = s.replace(/-/g, '+').replace(/_/g, '/');
|
|
12
|
+
// Add padding if needed
|
|
13
|
+
while (b64.length % 4 !== 0)
|
|
14
|
+
b64 += '=';
|
|
15
|
+
const bin = atob(b64);
|
|
16
|
+
const bytes = new Uint8Array(bin.length);
|
|
17
|
+
for (let i = 0; i < bin.length; i++)
|
|
18
|
+
bytes[i] = bin.charCodeAt(i);
|
|
19
|
+
return bytes;
|
|
20
|
+
}
|
|
21
|
+
// Parse an XFTP server address string.
|
|
22
|
+
// Format: xftp://<base64url-keyhash>@<host>[,<host2>,...][:<port>]
|
|
23
|
+
export function parseXFTPServer(address) {
|
|
24
|
+
const m = address.match(/^xftp:\/\/([A-Za-z0-9_-]+={0,2})@(.+)$/);
|
|
25
|
+
if (!m)
|
|
26
|
+
throw new Error("parseXFTPServer: invalid address format");
|
|
27
|
+
const keyHash = base64urlDecode(m[1]);
|
|
28
|
+
if (keyHash.length !== 32)
|
|
29
|
+
throw new Error("parseXFTPServer: keyHash must be 32 bytes");
|
|
30
|
+
const hostPart = m[2];
|
|
31
|
+
// Take the first host (before any comma), then split port from that
|
|
32
|
+
const firstHost = hostPart.split(',')[0];
|
|
33
|
+
const colonIdx = firstHost.lastIndexOf(':');
|
|
34
|
+
let host;
|
|
35
|
+
let port;
|
|
36
|
+
if (colonIdx > 0) {
|
|
37
|
+
host = firstHost.substring(0, colonIdx);
|
|
38
|
+
port = firstHost.substring(colonIdx + 1);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
host = firstHost;
|
|
42
|
+
port = "443";
|
|
43
|
+
}
|
|
44
|
+
return { keyHash, host, port };
|
|
45
|
+
}
|
|
46
|
+
// Format an XFTPServer back to its URI string representation.
|
|
47
|
+
export function formatXFTPServer(srv) {
|
|
48
|
+
return "xftp://" + base64urlEncode(srv.keyHash) + "@" + srv.host + ":" + srv.port;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=address.js.map
|