Repository navigation
Expand file tree
/
Copy pathexample_test.go
More file actions
141 lines (126 loc) · 4.25 KB
/
Copy pathexample_test.go
File metadata and controls
141 lines (126 loc) · 4.25 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package session_test
import (
"context"
"crypto/rand"
"fmt"
"github.com/GoCodeAlone/libsignal-go/address"
"github.com/GoCodeAlone/libsignal-go/curve"
"github.com/GoCodeAlone/libsignal-go/kem"
"github.com/GoCodeAlone/libsignal-go/session"
"github.com/GoCodeAlone/libsignal-go/stores/inmem"
)
// Example_sessionRoundTrip shows a PQXDH handshake and the first message.
// Bob publishes a pre-key bundle; Alice processes it and encrypts an initial
// message (a PreKeySignalMessage carrying the inner SignalMessage); Bob
// establishes his side from the same handshake material and decrypts.
//
// Bob's session is established here via InitializeBobSession, the recipient
// seam: it consumes Alice's base key and the Kyber ciphertext (recovered from
// Alice's pending pre-key message) together with Bob's own pre-key private keys.
func Example_sessionRoundTrip() {
ctx := context.Background()
// Small helpers so the example handles every error rather than discarding it,
// while staying readable. In production these errors propagate normally.
genKey := func() curve.KeyPair {
kp, err := curve.GenerateKeyPair(rand.Reader)
if err != nil {
panic(err)
}
return kp
}
sign := func(signer curve.PrivateKey, msg []byte) []byte {
sig, err := signer.CalculateSignature(rand.Reader, msg)
if err != nil {
panic(err)
}
return sig
}
dev, err := address.NewDeviceID(1)
if err != nil {
panic(err)
}
aliceAddr := address.NewProtocolAddress("+15551230001", dev)
bobAddr := address.NewProtocolAddress("+15551230002", dev)
// --- Bob's long-lived + pre-key material ---
bobIdentity := genKey()
bobSignedPre := genKey()
bobOneTime := genKey()
bobKyber, err := kem.GenerateKeyPair(kem.KeyTypeKyber1024, rand.Reader)
if err != nil {
panic(err)
}
// Bob signs his signed-pre-key and Kyber pre-key with his identity key.
signedSig := sign(bobIdentity.PrivateKey, bobSignedPre.PublicKey.Serialize())
kyberSig := sign(bobIdentity.PrivateKey, bobKyber.PublicKey.Serialize())
oneTimeID := uint32(31)
oneTimePub := bobOneTime.PublicKey
bundle, err := session.NewPreKeyBundle(session.PreKeyBundleParams{
RegistrationID: 4242,
DeviceID: 1,
PreKeyID: &oneTimeID,
PreKey: &oneTimePub,
SignedPreKeyID: 55,
SignedPreKey: bobSignedPre.PublicKey,
SignedPreKeySig: signedSig,
KyberPreKeyID: 66,
KyberPreKey: bobKyber.PublicKey,
KyberPreKeySig: kyberSig,
IdentityKey: bobIdentity.PublicKey,
})
if err != nil {
panic(err)
}
// --- Alice establishes a session from Bob's bundle and encrypts ---
aliceIdentity := genKey()
aliceID := inmem.NewIdentityKeyStore(aliceIdentity, 1001)
aliceSess := inmem.NewSessionStore()
if err := session.ProcessPreKeyBundle(ctx, rand.Reader, bobAddr, bundle, aliceSess, aliceID); err != nil {
panic(err)
}
plaintext := []byte("hello, bob")
// On the first (unacknowledged) message Alice wraps the SignalMessage in a
// PreKeySignalMessage; the inner SignalMessage is what Bob's session decrypts.
signalMsg, preKeyMsg, err := session.Encrypt(ctx, plaintext, bobAddr, aliceSess, aliceID, nil, rand.Reader)
if err != nil {
panic(err)
}
if preKeyMsg != nil {
signalMsg = preKeyMsg.Message()
}
// --- Bob establishes his side from the handshake material and decrypts ---
// Recover Alice's base key + Kyber ciphertext from her pending pre-key state.
aliceRec, err := aliceSess.LoadSession(ctx, bobAddr)
if err != nil {
panic(err)
}
pending, ok := aliceRec.CurrentState().PendingPreKeyMessage()
if !ok {
panic("alice has no pending pre-key message")
}
aliceBaseKey, err := curve.DeserializePublicKey(pending.BaseKey)
if err != nil {
panic(err)
}
bobState, err := session.InitializeBobSession(session.BobParams{
OurIdentity: bobIdentity,
OurSignedPre: bobSignedPre,
OurOneTime: &bobOneTime,
OurKyber: bobKyber,
TheirIdentity: aliceIdentity.PublicKey,
TheirBaseKey: aliceBaseKey,
KyberCipher: pending.KyberCiphertext,
})
if err != nil {
panic(err)
}
bobSess := inmem.NewSessionStore()
if err := bobSess.StoreSession(ctx, aliceAddr, session.NewSessionRecord(bobState)); err != nil {
panic(err)
}
got, err := session.Decrypt(ctx, signalMsg, aliceAddr, bobSess, rand.Reader)
if err != nil {
panic(err)
}
fmt.Println(string(got))
// Output: hello, bob
}