@peerbit/crypto 1.0.9 → 2.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/lib/esm/bytes.js.map +1 -1
- package/lib/esm/ed25519-sign-browser.js.map +1 -1
- package/lib/esm/ed25519-sign.js.map +1 -1
- package/lib/esm/ed25519.js.map +1 -1
- package/lib/esm/encryption.d.ts +45 -9
- package/lib/esm/encryption.js +195 -99
- package/lib/esm/encryption.js.map +1 -1
- package/lib/esm/index.d.ts +0 -2
- package/lib/esm/index.js +1 -3
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/key.d.ts +8 -0
- package/lib/esm/key.js +30 -1
- package/lib/esm/key.js.map +1 -1
- package/lib/esm/libp2p.js.map +1 -1
- package/lib/esm/prehash.js.map +1 -1
- package/lib/esm/sepc256k1.d.ts +3 -1
- package/lib/esm/sepc256k1.js.map +1 -1
- package/lib/esm/signature.js.map +1 -1
- package/lib/esm/x25519.js.map +1 -1
- package/package.json +8 -7
- package/src/encryption.ts +327 -119
- package/src/index.ts +1 -3
- package/src/key.ts +24 -1
- package/src/sepc256k1.ts +5 -2
- package/lib/esm/keychain.d.ts +0 -30
- package/lib/esm/keychain.js +0 -142
- package/lib/esm/keychain.js.map +0 -1
- package/src/keychain.ts +0 -197
package/src/encryption.ts
CHANGED
|
@@ -1,19 +1,222 @@
|
|
|
1
1
|
export * from "./errors.js";
|
|
2
|
+
|
|
2
3
|
import {
|
|
3
4
|
AbstractType,
|
|
4
5
|
deserialize,
|
|
5
6
|
field,
|
|
6
7
|
serialize,
|
|
7
8
|
variant,
|
|
8
|
-
vec
|
|
9
|
+
vec,
|
|
10
|
+
fixedArray
|
|
9
11
|
} from "@dao-xyz/borsh";
|
|
10
12
|
import { equals } from "@peerbit/uint8arrays";
|
|
11
13
|
import { AccessError } from "./errors.js";
|
|
12
14
|
import sodium from "libsodium-wrappers";
|
|
13
15
|
import { X25519Keypair, X25519PublicKey, X25519SecretKey } from "./x25519.js";
|
|
14
|
-
import {
|
|
16
|
+
import { Ed25519PublicKey } from "./ed25519.js";
|
|
15
17
|
import { randomBytes } from "./random.js";
|
|
16
|
-
import {
|
|
18
|
+
import { sha256 } from "./hash.js";
|
|
19
|
+
export type MaybePromise<T> = Promise<T> | T;
|
|
20
|
+
|
|
21
|
+
export type PublicKeyEncryptionParameters = {
|
|
22
|
+
type?: "publicKey";
|
|
23
|
+
receiverPublicKeys: (X25519PublicKey | Ed25519PublicKey)[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type SymmetricKeyEncryptionParameters = {
|
|
27
|
+
type?: "hash";
|
|
28
|
+
};
|
|
29
|
+
/*
|
|
30
|
+
export type NoExchange = {
|
|
31
|
+
type: 'none'
|
|
32
|
+
};
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
export type KeyExchangeOptions =
|
|
36
|
+
| PublicKeyEncryptionParameters
|
|
37
|
+
| SymmetricKeyEncryptionParameters;
|
|
38
|
+
|
|
39
|
+
type EncryptReturnValue<
|
|
40
|
+
T,
|
|
41
|
+
Parameters extends KeyExchangeOptions
|
|
42
|
+
> = EncryptedThing<T, EnvelopeFromParameter<Parameters>>;
|
|
43
|
+
|
|
44
|
+
type CipherWithEnvelope<E = PublicKeyEnvelope | HashedKeyEnvelope> = {
|
|
45
|
+
cipher: Uint8Array;
|
|
46
|
+
nonce: Uint8Array;
|
|
47
|
+
envelope: E;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type SymmetricKeys = Uint8Array;
|
|
51
|
+
type PublicKeyEncryptionKeys = X25519Keypair;
|
|
52
|
+
|
|
53
|
+
function isAsymmetriEncryptionParameters(
|
|
54
|
+
parameters: KeyExchangeOptions
|
|
55
|
+
): parameters is PublicKeyEncryptionParameters {
|
|
56
|
+
return (
|
|
57
|
+
(parameters as PublicKeyEncryptionParameters).receiverPublicKeys != null
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
function isAsymmetricEncryptionKeys(
|
|
61
|
+
parameters: PublicKeyEncryptionKeys | SymmetricKeys
|
|
62
|
+
): parameters is PublicKeyEncryptionKeys {
|
|
63
|
+
return (parameters as PublicKeyEncryptionKeys) instanceof X25519Keypair;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type EnvelopeFromParameter<Parameters extends KeyExchangeOptions> =
|
|
67
|
+
Parameters extends PublicKeyEncryptionParameters
|
|
68
|
+
? PublicKeyEnvelope
|
|
69
|
+
: HashedKeyEnvelope;
|
|
70
|
+
|
|
71
|
+
type EncryptProvide<Parameters extends KeyExchangeOptions> = (
|
|
72
|
+
bytes: Uint8Array,
|
|
73
|
+
parameters: Parameters
|
|
74
|
+
) => Promise<CipherWithEnvelope<EnvelopeFromParameter<Parameters>>>;
|
|
75
|
+
|
|
76
|
+
interface KeyProvider {
|
|
77
|
+
exportByKey(publicKey: X25519PublicKey): Promise<X25519Keypair | undefined>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const createLocalEncryptProvider = <
|
|
81
|
+
K extends PublicKeyEncryptionKeys | SymmetricKeys,
|
|
82
|
+
Parameters extends KeyExchangeOptions = K extends PublicKeyEncryptionKeys
|
|
83
|
+
? PublicKeyEncryptionParameters
|
|
84
|
+
: SymmetricKeyEncryptionParameters
|
|
85
|
+
>(
|
|
86
|
+
keys: K
|
|
87
|
+
) => {
|
|
88
|
+
return async (
|
|
89
|
+
bytes: Uint8Array,
|
|
90
|
+
parameters: Parameters
|
|
91
|
+
): Promise<CipherWithEnvelope<EnvelopeFromParameter<Parameters>>> => {
|
|
92
|
+
const nonce = randomBytes(NONCE_LENGTH); // crypto random is faster than sodim random
|
|
93
|
+
if (
|
|
94
|
+
isAsymmetriEncryptionParameters(parameters) &&
|
|
95
|
+
isAsymmetricEncryptionKeys(keys)
|
|
96
|
+
) {
|
|
97
|
+
const epheremalKey = sodium.crypto_secretbox_keygen();
|
|
98
|
+
const cipher = sodium.crypto_secretbox_easy(bytes, nonce, epheremalKey);
|
|
99
|
+
const { receiverPublicKeys } = parameters;
|
|
100
|
+
const receiverX25519PublicKeys = await Promise.all(
|
|
101
|
+
receiverPublicKeys.map((key) => {
|
|
102
|
+
if (key instanceof Ed25519PublicKey) {
|
|
103
|
+
return X25519PublicKey.from(key);
|
|
104
|
+
}
|
|
105
|
+
return key;
|
|
106
|
+
})
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const ks = receiverX25519PublicKeys.map((receiverPublicKey) => {
|
|
110
|
+
const kNonce = randomBytes(NONCE_LENGTH); // crypto random is faster than sodium random
|
|
111
|
+
return new K({
|
|
112
|
+
encryptedKey: new CipherWithNonce({
|
|
113
|
+
cipher: sodium.crypto_box_easy(
|
|
114
|
+
epheremalKey,
|
|
115
|
+
kNonce,
|
|
116
|
+
receiverPublicKey.publicKey,
|
|
117
|
+
keys.secretKey.secretKey
|
|
118
|
+
),
|
|
119
|
+
nonce: kNonce
|
|
120
|
+
}),
|
|
121
|
+
receiverPublicKey
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
cipher: new Uint8Array(cipher), // TODO do we need this clone?
|
|
127
|
+
nonce,
|
|
128
|
+
envelope: new PublicKeyEnvelope({
|
|
129
|
+
senderPublicKey: keys.publicKey,
|
|
130
|
+
ks
|
|
131
|
+
}) as EnvelopeFromParameter<Parameters>
|
|
132
|
+
};
|
|
133
|
+
} else if (
|
|
134
|
+
!isAsymmetriEncryptionParameters(parameters) &&
|
|
135
|
+
!isAsymmetricEncryptionKeys(keys)
|
|
136
|
+
) {
|
|
137
|
+
const cipher = sodium.crypto_secretbox_easy(bytes, nonce, keys);
|
|
138
|
+
return {
|
|
139
|
+
cipher: new Uint8Array(cipher), // TODO do we need this clone?
|
|
140
|
+
nonce,
|
|
141
|
+
envelope: new HashedKeyEnvelope({
|
|
142
|
+
hash: await sha256(keys)
|
|
143
|
+
}) as EnvelopeFromParameter<Parameters>
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
throw new Error("Unexpected encryption parameters");
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export type DecryptProvider = (
|
|
152
|
+
encrypted: Uint8Array,
|
|
153
|
+
nonce: Uint8Array,
|
|
154
|
+
exchange: Envelope
|
|
155
|
+
) => Promise<Uint8Array>;
|
|
156
|
+
|
|
157
|
+
type KeyResolver = <T extends X25519PublicKey | Uint8Array>(
|
|
158
|
+
key: T
|
|
159
|
+
) => Promise<
|
|
160
|
+
(T extends X25519PublicKey ? X25519Keypair : Uint8Array) | undefined
|
|
161
|
+
>;
|
|
162
|
+
|
|
163
|
+
export const createDecrypterFromKeyResolver = (
|
|
164
|
+
keyResolver: KeyResolver
|
|
165
|
+
): DecryptProvider => {
|
|
166
|
+
return async (
|
|
167
|
+
encrypted: Uint8Array,
|
|
168
|
+
nonce: Uint8Array,
|
|
169
|
+
exchange: Envelope
|
|
170
|
+
): Promise<Uint8Array> => {
|
|
171
|
+
// We only need to open with one of the keys
|
|
172
|
+
|
|
173
|
+
let epheremalKey: Uint8Array | undefined;
|
|
174
|
+
|
|
175
|
+
if (exchange instanceof PublicKeyEnvelope) {
|
|
176
|
+
let key: { index: number; keypair: X25519Keypair } | undefined;
|
|
177
|
+
for (const [i, k] of exchange._ks.entries()) {
|
|
178
|
+
const exported = await keyResolver(k._receiverPublicKey);
|
|
179
|
+
if (exported) {
|
|
180
|
+
key = {
|
|
181
|
+
index: i,
|
|
182
|
+
keypair: exported
|
|
183
|
+
};
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (key) {
|
|
189
|
+
const k = exchange._ks[key.index];
|
|
190
|
+
let secretKey: X25519SecretKey = undefined as any;
|
|
191
|
+
if (key.keypair instanceof X25519Keypair) {
|
|
192
|
+
secretKey = key.keypair.secretKey;
|
|
193
|
+
} else {
|
|
194
|
+
secretKey = await X25519SecretKey.from(key.keypair);
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
epheremalKey = sodium.crypto_box_open_easy(
|
|
198
|
+
k._encryptedKey.cipher,
|
|
199
|
+
k._encryptedKey.nonce,
|
|
200
|
+
exchange._senderPublicKey.publicKey,
|
|
201
|
+
secretKey.secretKey
|
|
202
|
+
);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
throw new AccessError("Failed to decrypt");
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
throw new AccessError("Failed to resolve decryption key");
|
|
208
|
+
}
|
|
209
|
+
} else if (exchange instanceof HashedKeyEnvelope) {
|
|
210
|
+
epheremalKey = await keyResolver(exchange.hash);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!epheremalKey) {
|
|
214
|
+
throw new Error("Failed to resolve ephemeral key");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return sodium.crypto_secretbox_open_easy(encrypted, nonce, epheremalKey);
|
|
218
|
+
};
|
|
219
|
+
};
|
|
17
220
|
|
|
18
221
|
const NONCE_LENGTH = 24;
|
|
19
222
|
|
|
@@ -27,8 +230,13 @@ export abstract class MaybeEncrypted<T> {
|
|
|
27
230
|
}
|
|
28
231
|
|
|
29
232
|
decrypt(
|
|
30
|
-
|
|
31
|
-
):
|
|
233
|
+
keyResolver?: X25519Keypair | KeyProvider
|
|
234
|
+
): MaybePromise<DecryptedThing<T>>;
|
|
235
|
+
decrypt(provider?: DecryptProvider): MaybePromise<DecryptedThing<T>>;
|
|
236
|
+
|
|
237
|
+
decrypt(
|
|
238
|
+
provider?: X25519Keypair | DecryptProvider | KeyProvider
|
|
239
|
+
): MaybePromise<DecryptedThing<T>> | DecryptedThing<T> {
|
|
32
240
|
throw new Error("Not implemented");
|
|
33
241
|
}
|
|
34
242
|
equals(other: MaybeEncrypted<T>): boolean {
|
|
@@ -69,47 +277,42 @@ export class DecryptedThing<T> extends MaybeEncrypted<T> {
|
|
|
69
277
|
return deserialize(this._data, clazz);
|
|
70
278
|
}
|
|
71
279
|
|
|
280
|
+
async encrypt<Parameters extends KeyExchangeOptions>(
|
|
281
|
+
provider: EncryptProvide<Parameters>,
|
|
282
|
+
parameters: Parameters
|
|
283
|
+
): Promise<EncryptReturnValue<T, Parameters>>;
|
|
284
|
+
|
|
72
285
|
async encrypt(
|
|
73
286
|
x25519Keypair: X25519Keypair,
|
|
74
|
-
|
|
75
|
-
): Promise<
|
|
76
|
-
const bytes = serialize(this);
|
|
77
|
-
const epheremalKey = sodium.crypto_secretbox_keygen();
|
|
78
|
-
const nonce = randomBytes(NONCE_LENGTH); // crypto random is faster than sodim random
|
|
79
|
-
const cipher = sodium.crypto_secretbox_easy(bytes, nonce, epheremalKey);
|
|
80
|
-
|
|
81
|
-
const receiverX25519PublicKeys = await Promise.all(
|
|
82
|
-
receiverPublicKeys.map((key) => {
|
|
83
|
-
if (key instanceof Ed25519PublicKey) {
|
|
84
|
-
return X25519PublicKey.from(key);
|
|
85
|
-
}
|
|
86
|
-
return key;
|
|
87
|
-
})
|
|
88
|
-
);
|
|
287
|
+
receiverPublicKeys: (X25519PublicKey | Ed25519PublicKey)[]
|
|
288
|
+
): Promise<EncryptReturnValue<T, PublicKeyEncryptionParameters>>;
|
|
89
289
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
290
|
+
async encrypt(
|
|
291
|
+
keypair: EncryptProvide<any> | X25519Keypair,
|
|
292
|
+
parameters: KeyExchangeOptions | (X25519PublicKey | Ed25519PublicKey)[]
|
|
293
|
+
): Promise<EncryptReturnValue<T, any>> {
|
|
294
|
+
let provider: EncryptProvide<any>;
|
|
295
|
+
let options: KeyExchangeOptions;
|
|
296
|
+
if (keypair instanceof X25519Keypair) {
|
|
297
|
+
provider = createLocalEncryptProvider(keypair);
|
|
298
|
+
options = {
|
|
299
|
+
receiverPublicKeys: parameters as (
|
|
300
|
+
| X25519PublicKey
|
|
301
|
+
| Ed25519PublicKey
|
|
302
|
+
)[],
|
|
303
|
+
type: "publicKey"
|
|
304
|
+
};
|
|
305
|
+
} else {
|
|
306
|
+
provider = keypair;
|
|
307
|
+
options = parameters as KeyExchangeOptions;
|
|
308
|
+
}
|
|
105
309
|
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
})
|
|
310
|
+
const bytes = serialize(this);
|
|
311
|
+
const { cipher, envelope, nonce } = await provider(bytes, options);
|
|
312
|
+
const enc = new EncryptedThing<T, EnvelopeFromParameter<any>>({
|
|
313
|
+
encrypted: cipher,
|
|
314
|
+
envelope,
|
|
315
|
+
nonce
|
|
113
316
|
});
|
|
114
317
|
enc._decrypted = this;
|
|
115
318
|
return enc;
|
|
@@ -196,8 +399,12 @@ export class K {
|
|
|
196
399
|
}
|
|
197
400
|
}
|
|
198
401
|
|
|
402
|
+
abstract class Envelope {
|
|
403
|
+
abstract equals(other: Envelope): boolean;
|
|
404
|
+
}
|
|
405
|
+
|
|
199
406
|
@variant(0)
|
|
200
|
-
|
|
407
|
+
class PublicKeyEnvelope extends Envelope {
|
|
201
408
|
@field({ type: X25519PublicKey })
|
|
202
409
|
_senderPublicKey: X25519PublicKey;
|
|
203
410
|
|
|
@@ -205,14 +412,16 @@ export class Envelope {
|
|
|
205
412
|
_ks: K[];
|
|
206
413
|
|
|
207
414
|
constructor(props?: { senderPublicKey: X25519PublicKey; ks: K[] }) {
|
|
415
|
+
super();
|
|
208
416
|
if (props) {
|
|
209
417
|
this._senderPublicKey = props.senderPublicKey;
|
|
210
418
|
this._ks = props.ks;
|
|
211
419
|
}
|
|
212
420
|
}
|
|
213
421
|
|
|
214
|
-
|
|
215
|
-
|
|
422
|
+
// TODO: should this be comparable to AbstractEnvelope?
|
|
423
|
+
equals(other: PublicKeyEnvelope): boolean {
|
|
424
|
+
if (other instanceof PublicKeyEnvelope) {
|
|
216
425
|
if (!this._senderPublicKey.equals(other._senderPublicKey)) {
|
|
217
426
|
return false;
|
|
218
427
|
}
|
|
@@ -233,7 +442,35 @@ export class Envelope {
|
|
|
233
442
|
}
|
|
234
443
|
|
|
235
444
|
@variant(1)
|
|
236
|
-
|
|
445
|
+
class HashedKeyEnvelope extends Envelope {
|
|
446
|
+
@field({ type: fixedArray("u8", 32) })
|
|
447
|
+
hash: Uint8Array;
|
|
448
|
+
// TODO: Do we need a salt here?
|
|
449
|
+
constructor(props?: { hash: Uint8Array }) {
|
|
450
|
+
super();
|
|
451
|
+
if (props) {
|
|
452
|
+
this.hash = props.hash;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// TODO: should this be comparable to AbstractEnvelope?
|
|
457
|
+
equals(other: HashedKeyEnvelope): boolean {
|
|
458
|
+
if (other instanceof HashedKeyEnvelope) {
|
|
459
|
+
if (!equals(this.hash, other.hash)) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
return true;
|
|
463
|
+
} else {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
@variant(1)
|
|
470
|
+
export class EncryptedThing<
|
|
471
|
+
T,
|
|
472
|
+
E extends Envelope = PublicKeyEnvelope | HashedKeyEnvelope
|
|
473
|
+
> extends MaybeEncrypted<T> {
|
|
237
474
|
@field({ type: Uint8Array })
|
|
238
475
|
_encrypted: Uint8Array;
|
|
239
476
|
|
|
@@ -241,18 +478,18 @@ export class EncryptedThing<T> extends MaybeEncrypted<T> {
|
|
|
241
478
|
_nonce: Uint8Array;
|
|
242
479
|
|
|
243
480
|
@field({ type: Envelope })
|
|
244
|
-
|
|
481
|
+
_keyexchange: E;
|
|
245
482
|
|
|
246
483
|
constructor(props?: {
|
|
247
484
|
encrypted: Uint8Array;
|
|
248
485
|
nonce: Uint8Array;
|
|
249
|
-
envelope:
|
|
486
|
+
envelope: E;
|
|
250
487
|
}) {
|
|
251
488
|
super();
|
|
252
489
|
if (props) {
|
|
253
490
|
this._encrypted = props.encrypted;
|
|
254
491
|
this._nonce = props.nonce;
|
|
255
|
-
this.
|
|
492
|
+
this._keyexchange = props.envelope;
|
|
256
493
|
}
|
|
257
494
|
}
|
|
258
495
|
|
|
@@ -267,85 +504,56 @@ export class EncryptedThing<T> extends MaybeEncrypted<T> {
|
|
|
267
504
|
}
|
|
268
505
|
|
|
269
506
|
async decrypt(
|
|
270
|
-
keyResolver?:
|
|
507
|
+
keyResolver?: X25519Keypair | KeyProvider
|
|
508
|
+
): Promise<DecryptedThing<T>>;
|
|
509
|
+
async decrypt(provider?: DecryptProvider): Promise<DecryptedThing<T>>;
|
|
510
|
+
|
|
511
|
+
async decrypt(
|
|
512
|
+
providerOrResolver?: X25519Keypair | DecryptProvider | KeyProvider
|
|
271
513
|
): Promise<DecryptedThing<T>> {
|
|
272
|
-
|
|
273
|
-
|
|
514
|
+
let provider: DecryptProvider | undefined;
|
|
515
|
+
if (typeof providerOrResolver === "function") {
|
|
516
|
+
provider = providerOrResolver;
|
|
517
|
+
} else if (providerOrResolver instanceof X25519Keypair) {
|
|
518
|
+
const resolver: KeyResolver = (key): any => {
|
|
519
|
+
if (key instanceof X25519PublicKey) {
|
|
520
|
+
if (key.equals(providerOrResolver.publicKey)) {
|
|
521
|
+
return providerOrResolver;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
throw new Error("Missing keypair");
|
|
525
|
+
};
|
|
526
|
+
provider = createDecrypterFromKeyResolver(resolver);
|
|
527
|
+
} else if (providerOrResolver) {
|
|
528
|
+
provider = createDecrypterFromKeyResolver(async (key) => {
|
|
529
|
+
if (key instanceof X25519PublicKey) {
|
|
530
|
+
const keypair = await providerOrResolver.exportByKey(key);
|
|
531
|
+
return keypair as any;
|
|
532
|
+
}
|
|
533
|
+
});
|
|
274
534
|
}
|
|
275
535
|
|
|
276
|
-
if (
|
|
277
|
-
|
|
536
|
+
if (this._decrypted) {
|
|
537
|
+
return this._decrypted;
|
|
278
538
|
}
|
|
279
539
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (keyResolver instanceof X25519Keypair) {
|
|
283
|
-
for (const [i, k] of this._envelope._ks.entries()) {
|
|
284
|
-
if (k._receiverPublicKey.equals(keyResolver.publicKey)) {
|
|
285
|
-
key = {
|
|
286
|
-
index: i,
|
|
287
|
-
keypair: keyResolver
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
} else {
|
|
292
|
-
for (const [i, k] of this._envelope._ks.entries()) {
|
|
293
|
-
const exported = await keyResolver.exportByKey(k._receiverPublicKey);
|
|
294
|
-
if (exported) {
|
|
295
|
-
key = {
|
|
296
|
-
index: i,
|
|
297
|
-
keypair: exported
|
|
298
|
-
};
|
|
299
|
-
break;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
540
|
+
if (!provider) {
|
|
541
|
+
throw new AccessError("Expecting decryption provider");
|
|
302
542
|
}
|
|
303
543
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
let epheremalKey: Uint8Array;
|
|
313
|
-
try {
|
|
314
|
-
epheremalKey = sodium.crypto_box_open_easy(
|
|
315
|
-
k._encryptedKey.cipher,
|
|
316
|
-
k._encryptedKey.nonce,
|
|
317
|
-
this._envelope._senderPublicKey.publicKey,
|
|
318
|
-
secretKey.secretKey
|
|
319
|
-
);
|
|
320
|
-
} catch (error) {
|
|
321
|
-
throw new AccessError("Failed to decrypt");
|
|
322
|
-
}
|
|
544
|
+
const decrypted = await provider(
|
|
545
|
+
this._encrypted,
|
|
546
|
+
this._nonce,
|
|
547
|
+
this._keyexchange
|
|
548
|
+
);
|
|
549
|
+
if (decrypted) {
|
|
550
|
+
const der = deserialize(decrypted, DecryptedThing);
|
|
323
551
|
|
|
324
|
-
// TODO: is nested decryption necessary?
|
|
325
|
-
/* let der: any = this;
|
|
326
|
-
let counter = 0;
|
|
327
|
-
while (der instanceof EncryptedThing) {
|
|
328
|
-
const decrypted = await sodium.crypto_secretbox_open_easy(this._encrypted, this._nonce, epheremalKey);
|
|
329
|
-
der = deserialize(decrypted, DecryptedThing)
|
|
330
|
-
counter += 1;
|
|
331
|
-
if (counter >= 10) {
|
|
332
|
-
throw new Error("Unexpected decryption behaviour, data seems to always be in encrypted state")
|
|
333
|
-
}
|
|
334
|
-
} */
|
|
335
|
-
|
|
336
|
-
const der = deserialize(
|
|
337
|
-
sodium.crypto_secretbox_open_easy(
|
|
338
|
-
this._encrypted,
|
|
339
|
-
this._nonce,
|
|
340
|
-
epheremalKey
|
|
341
|
-
),
|
|
342
|
-
DecryptedThing
|
|
343
|
-
);
|
|
344
552
|
this._decrypted = der as DecryptedThing<T>;
|
|
345
|
-
|
|
346
|
-
throw new AccessError("Failed to resolve decryption key");
|
|
553
|
+
return this._decrypted;
|
|
347
554
|
}
|
|
348
|
-
|
|
555
|
+
|
|
556
|
+
throw new AccessError("Failed to resolve decryption key");
|
|
349
557
|
}
|
|
350
558
|
|
|
351
559
|
equals(other: MaybeEncrypted<T>): boolean {
|
|
@@ -357,7 +565,7 @@ export class EncryptedThing<T> extends MaybeEncrypted<T> {
|
|
|
357
565
|
return false;
|
|
358
566
|
}
|
|
359
567
|
|
|
360
|
-
if (!this.
|
|
568
|
+
if (!this._keyexchange.equals(other._keyexchange)) {
|
|
361
569
|
return false;
|
|
362
570
|
}
|
|
363
571
|
return true;
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export * from "./key.js";
|
|
2
2
|
export * from "./ed25519.js";
|
|
3
3
|
export * from "./signature.js";
|
|
4
|
-
export * from "./key.js";
|
|
5
4
|
export * from "./sepc256k1.js";
|
|
6
5
|
export * from "./x25519.js";
|
|
7
6
|
export * from "./encryption.js";
|
|
@@ -11,7 +10,6 @@ export * from "./hash.js";
|
|
|
11
10
|
export * from "./random.js";
|
|
12
11
|
export * from "./prehash.js";
|
|
13
12
|
export * from "./signer.js";
|
|
14
|
-
export * from "./keychain.js";
|
|
15
13
|
import libsodium from "libsodium-wrappers";
|
|
16
|
-
const ready = libsodium.ready;
|
|
14
|
+
const ready = libsodium.ready;
|
|
17
15
|
export { ready };
|
package/src/key.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { serialize } from "@dao-xyz/borsh";
|
|
1
|
+
import { field, serialize } from "@dao-xyz/borsh";
|
|
2
2
|
import { sha256Base64Sync } from "./hash.js";
|
|
3
3
|
import { PeerId } from "@libp2p/interface/peer-id";
|
|
4
|
+
import { compare } from "@peerbit/uint8arrays";
|
|
5
|
+
import { toHexString } from "./utils.js";
|
|
4
6
|
|
|
5
7
|
interface Key {
|
|
6
8
|
equals(other: Key): boolean;
|
|
@@ -20,6 +22,8 @@ export abstract class Keypair {
|
|
|
20
22
|
toPeerId(): Promise<PeerId> {
|
|
21
23
|
throw new Error("Not implemented");
|
|
22
24
|
}
|
|
25
|
+
|
|
26
|
+
// TODO: Should we add not implemented errors for .create and and .from as well?
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
// ---- SIGNATURE KEYS -----
|
|
@@ -78,3 +82,22 @@ export abstract class PlainKey implements Key {
|
|
|
78
82
|
return this._hashcode || (this._hashcode = sha256Base64Sync(this.bytes));
|
|
79
83
|
}
|
|
80
84
|
}
|
|
85
|
+
|
|
86
|
+
export class ByteKey extends PlainKey {
|
|
87
|
+
@field({ type: Uint8Array })
|
|
88
|
+
key: Uint8Array;
|
|
89
|
+
|
|
90
|
+
constructor(properties: { key: Uint8Array }) {
|
|
91
|
+
super();
|
|
92
|
+
this.key = properties.key;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
equals(other: ByteKey) {
|
|
96
|
+
return compare(this.key, other.key) === 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// TODO: What should be preprended to this string here?
|
|
100
|
+
toString(): string {
|
|
101
|
+
return "bytekey/" + toHexString(this.key);
|
|
102
|
+
}
|
|
103
|
+
}
|
package/src/sepc256k1.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { field, fixedArray, variant, vec } from "@dao-xyz/borsh";
|
|
2
2
|
import { Keypair, PrivateSignKey, PublicSignKey } from "./key.js";
|
|
3
|
+
|
|
3
4
|
import { Wallet } from "@ethersproject/wallet";
|
|
4
5
|
import { arrayify } from "@ethersproject/bytes";
|
|
5
6
|
import { joinSignature } from "@ethersproject/bytes";
|
|
@@ -11,7 +12,7 @@ let _curve: EC;
|
|
|
11
12
|
import { equals } from "@peerbit/uint8arrays";
|
|
12
13
|
import { toHexString } from "./utils.js";
|
|
13
14
|
import { PeerId } from "@libp2p/interface/peer-id";
|
|
14
|
-
import { Identity
|
|
15
|
+
import { Identity } from "./signer.js";
|
|
15
16
|
import { coerce } from "./bytes.js";
|
|
16
17
|
import { generateKeyPair, supportedKeys } from "@libp2p/crypto/keys";
|
|
17
18
|
import utf8 from "@protobufjs/utf8";
|
|
@@ -32,7 +33,9 @@ export class Secp256k1PublicKey extends PublicSignKey {
|
|
|
32
33
|
this.publicKey = properties.publicKey;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
static async recover(wallet:
|
|
36
|
+
static async recover(wallet: {
|
|
37
|
+
signMessage(message: string | Uint8Array): Promise<string> | string;
|
|
38
|
+
}) {
|
|
36
39
|
// Signa message
|
|
37
40
|
const toSign = new Uint8Array([0]);
|
|
38
41
|
const signature = await wallet.signMessage(toSign);
|
package/lib/esm/keychain.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { KeyChain as InternalKeychain } from "@libp2p/interface/keychain";
|
|
2
|
-
import { Cache } from "@peerbit/cache";
|
|
3
|
-
import { Ed25519Keypair, Ed25519PublicKey } from "./ed25519.js";
|
|
4
|
-
import { X25519Keypair, X25519PublicKey } from "./x25519.js";
|
|
5
|
-
export type KeypairFromPublicKey<T> = T extends X25519PublicKey ? X25519PublicKey extends T ? X25519Keypair : Ed25519Keypair : Ed25519Keypair;
|
|
6
|
-
export interface Keychain {
|
|
7
|
-
import(keypair: Ed25519Keypair, id: Uint8Array): Promise<void>;
|
|
8
|
-
exportByKey<T extends Ed25519PublicKey | X25519PublicKey, Q = KeypairFromPublicKey<T>>(publicKey: T): Promise<Q | undefined>;
|
|
9
|
-
exportById<T = "ed25519" | "x25519", Q = T extends "ed25519" ? Ed25519Keypair : X25519Keypair>(id: Uint8Array, type: T): Promise<Q | undefined>;
|
|
10
|
-
}
|
|
11
|
-
export declare class Libp2pKeychain implements Keychain {
|
|
12
|
-
readonly keychain: InternalKeychain;
|
|
13
|
-
readonly options?: {
|
|
14
|
-
cache?: Cache<Ed25519Keypair | X25519Keypair | null> | undefined;
|
|
15
|
-
} | undefined;
|
|
16
|
-
constructor(keychain: InternalKeychain, options?: {
|
|
17
|
-
cache?: Cache<Ed25519Keypair | X25519Keypair | null> | undefined;
|
|
18
|
-
} | undefined);
|
|
19
|
-
keychainKeyIdFromPublicKey(publicKey: X25519PublicKey): string;
|
|
20
|
-
private cacheKey;
|
|
21
|
-
private getCachedById;
|
|
22
|
-
private getCachedByKey;
|
|
23
|
-
exportByKey: <T extends Ed25519PublicKey | X25519PublicKey, Q = KeypairFromPublicKey<T>>(publicKey: T) => Promise<Q | undefined>;
|
|
24
|
-
exportById<T = "ed25519" | "x25519", Q = T extends "ed25519" ? Ed25519Keypair : X25519Keypair>(id: Uint8Array, type: T): Promise<Q | undefined>;
|
|
25
|
-
import: (keypair: Ed25519Keypair, id: Uint8Array) => Promise<void>;
|
|
26
|
-
getAnyKeypair: (publicKeys: any) => Promise<{
|
|
27
|
-
index: number;
|
|
28
|
-
keypair: X25519Keypair;
|
|
29
|
-
}>;
|
|
30
|
-
}
|