-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathutils.ts
More file actions
114 lines (93 loc) · 3.35 KB
/
utils.ts
File metadata and controls
114 lines (93 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { unmarshalPublicKey, unmarshalPrivateKey } from '@libp2p/crypto/keys'
import type { PeerId } from '@libp2p/interface-peer-id'
import { peerIdFromKeys } from '@libp2p/peer-id'
import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import type { bytes } from './@types/basic.js'
import { pb } from './proto/payload.js'
const NoiseHandshakePayloadProto = pb.NoiseHandshakePayload
export async function getPayload (
localPeer: PeerId,
staticPublicKey: bytes,
earlyData?: bytes
): Promise<bytes> {
const signedPayload = await signPayload(localPeer, getHandshakePayload(staticPublicKey))
const earlyDataPayload = earlyData ?? new Uint8Array(0)
if (localPeer.publicKey == null) {
throw new Error('PublicKey was missing from local PeerId')
}
return createHandshakePayload(
localPeer.publicKey,
signedPayload,
earlyDataPayload
)
}
export function createHandshakePayload (
libp2pPublicKey: Uint8Array,
signedPayload: Uint8Array,
earlyData?: Uint8Array
): bytes {
return NoiseHandshakePayloadProto.encode({
identityKey: libp2pPublicKey,
identitySig: signedPayload,
data: earlyData ?? new Uint8Array(0)
}).subarray()
}
export async function signPayload (peerId: PeerId, payload: bytes): Promise<bytes> {
if (peerId.privateKey == null) {
throw new Error('PrivateKey was missing from PeerId')
}
const privateKey = await unmarshalPrivateKey(peerId.privateKey)
return await privateKey.sign(payload)
}
export async function getPeerIdFromPayload (payload: pb.NoiseHandshakePayload): Promise<PeerId> {
return await peerIdFromKeys(payload.identityKey)
}
export function decodePayload (payload: bytes|Uint8Array): pb.NoiseHandshakePayload {
return NoiseHandshakePayloadProto.decode(payload)
}
export function getHandshakePayload (publicKey: bytes): bytes {
const prefix = uint8ArrayFromString('noise-libp2p-static-key:')
return uint8ArrayConcat([prefix, publicKey], prefix.length + publicKey.length)
}
/**
* Verifies signed payload, throws on any irregularities.
*
* @param {bytes} noiseStaticKey - owner's noise static key
* @param {bytes} payload - decoded payload
* @param {PeerId} remotePeer - owner's libp2p peer ID
* @returns {Promise<PeerId>} - peer ID of payload owner
*/
export async function verifySignedPayload (
noiseStaticKey: bytes,
payload: pb.NoiseHandshakePayload,
remotePeer: PeerId
): Promise<PeerId> {
// Unmarshaling from PublicKey protobuf
const payloadPeerId = await peerIdFromKeys(payload.identityKey)
if (!payloadPeerId.equals(remotePeer)) {
throw new Error("Peer ID doesn't match libp2p public key.")
}
const generatedPayload = getHandshakePayload(noiseStaticKey)
if (payloadPeerId.publicKey == null) {
throw new Error('PublicKey was missing from PeerId')
}
if (payload.identitySig == null) {
throw new Error('Signature was missing from message')
}
const publicKey = unmarshalPublicKey(payloadPeerId.publicKey)
const valid = await publicKey.verify(generatedPayload, payload.identitySig)
if (!valid) {
throw new Error("Static key doesn't match to peer that signed payload!")
}
return payloadPeerId
}
export function isValidPublicKey (pk: bytes): boolean {
if (!(pk instanceof Uint8Array)) {
return false
}
if (pk.length !== 32) {
return false
}
return true
}