-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbake.go
More file actions
605 lines (554 loc) · 19.3 KB
/
Copy pathbake.go
File metadata and controls
605 lines (554 loc) · 19.3 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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
package bee2go
/*
#cgo CFLAGS: -I${SRCDIR}/bee2/include
#cgo LDFLAGS: -L${SRCDIR}/bee2/build/src -lbee2_static
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bee2/core/err.h"
#include "bee2/core/prng.h"
#include "bee2/crypto/bake.h"
#include "bee2/crypto/bign.h"
// CGO cannot cast unsafe.Pointer to a C function-pointer type directly.
// These thin wrappers accept void* and perform the cast in C, where it is valid.
static void bake_settings_set_rng(bake_settings* s, void* rng_fn, void* rng_state) {
s->rng = (gen_i)rng_fn;
s->rng_state = rng_state;
}
static bake_cert* make_bake_cert(octet* data, size_t len, void* val_fn) {
bake_cert* c = (bake_cert*)malloc(sizeof(bake_cert));
if (c) {
c->data = data;
c->len = len;
c->val = (bake_certval_i)val_fn;
}
return c;
}
static err_t bsts_step4_wrap(
octet* out, const octet* in, size_t in_len, void* vala, void* state)
{
return bakeBSTSStep4(out, in, in_len, (bake_certval_i)vala, state);
}
static err_t bsts_step5_wrap(
const octet* in, size_t in_len, void* valb, void* state)
{
return bakeBSTSStep5(in, in_len, (bake_certval_i)valb, state);
}
// bake_urandom is a gen_i that reads random bytes from /dev/urandom.
static void bake_urandom(void* buf, size_t count, void* state) {
FILE* f = fopen("/dev/urandom", "rb");
if (f) {
size_t got = fread(buf, 1, count, f);
fclose(f);
// /dev/urandom does not short-read in practice; zero any shortfall so
// the gen_i contract (all count octets produced) still holds.
if (got < count)
memset((octet*)buf + got, 0, count - got);
}
}
// accept_all_certval is a bake_certval_i that accepts any certificate whose
// last l/2 bytes are treated as the public key. Convention: cert data is
// <identity_bytes> || <pubkey_bytes>, so pubkey = data[len - l/2 : len].
static err_t accept_all_certval(
octet* pubkey, const bign_params* params,
const octet* data, size_t len)
{
if (!params || (params->l != 128 && params->l != 192 && params->l != 256))
return ERR_BAD_INPUT;
if (!data || len < params->l / 2)
return ERR_BAD_CERT;
if (pubkey)
memcpy(pubkey, data + (len - params->l / 2), params->l / 2);
return ERR_OK;
}
// Getter helpers return void* so CGO can map them to unsafe.Pointer.
static void* get_bake_urandom(void) { return (void*)bake_urandom; }
static void* get_accept_all_certval(void) { return (void*)accept_all_certval; }
static void* get_prng_echo_step_r(void) { return (void*)prngEchoStepR; }
static void* make_prng_echo_state(const octet* seed, size_t seed_len) {
void* state = malloc(prngEcho_keep());
if (state)
prngEchoStart(state, seed, seed_len);
return state;
}
*/
import "C"
import (
"errors"
"unsafe"
)
// ────────────────────────────────────────────────────────────────────────────
// Built-in C helpers exposed to Go callers
// ────────────────────────────────────────────────────────────────────────────
// BakeDefaultRNG returns the /dev/urandom gen_i function pointer as
// unsafe.Pointer, suitable for passing to NewBakeSettings.
func BakeDefaultRNG() unsafe.Pointer { return C.get_bake_urandom() }
// BakeAcceptAllCertVal returns a bake_certval_i function pointer as
// unsafe.Pointer that accepts any certificate and extracts the public key from
// its last l/2 bytes (convention: cert = <identity> || <pubkey>).
// Suitable for passing to NewBakeCert, Step4, and Step5.
func BakeAcceptAllCertVal() unsafe.Pointer { return C.get_accept_all_certval() }
// BakeEchoRNG wraps bee2's deterministic prngEcho generator.
//
// It is intended for reproducible known-answer tests and protocol fixtures.
type BakeEchoRNG struct {
state unsafe.Pointer
}
// NewBakeEchoRNG creates a deterministic RNG that repeats seed.
func NewBakeEchoRNG(seed []byte) (*BakeEchoRNG, error) {
if len(seed) == 0 {
return nil, errors.New("bee2: prngEcho seed must not be empty")
}
state := C.make_prng_echo_state((*C.octet)(unsafe.Pointer(&seed[0])), C.size_t(len(seed)))
if state == nil {
return nil, errors.New("bee2: malloc prngEcho state")
}
return &BakeEchoRNG{state: state}, nil
}
// Func returns the C gen_i function pointer for NewBakeSettings.
func (r *BakeEchoRNG) Func() unsafe.Pointer { return C.get_prng_echo_step_r() }
// State returns the C RNG state pointer for NewBakeSettings.
func (r *BakeEchoRNG) State() unsafe.Pointer {
if r == nil {
return nil
}
return r.state
}
// Free releases the underlying C RNG state.
func (r *BakeEchoRNG) Free() {
if r.state != nil {
freeWiped(r.state, uintptr(C.prngEcho_keep()))
r.state = nil
}
}
// BakeKDF derives a 32-byte key from secret, iv, and key number num.
func BakeKDF(secret, iv []byte, num int) ([]byte, error) {
if len(secret) == 0 {
return nil, errors.New("bee2: bakeKDF secret must not be empty")
}
if len(iv) == 0 {
return nil, errors.New("bee2: bakeKDF iv must not be empty")
}
if num < 0 {
return nil, errors.New("bee2: bakeKDF num must be non-negative")
}
key := make([]byte, 32)
rc := C.bakeKDF(
(*C.octet)(unsafe.Pointer(&key[0])),
(*C.octet)(unsafe.Pointer(&secret[0])),
C.size_t(len(secret)),
(*C.octet)(unsafe.Pointer(&iv[0])),
C.size_t(len(iv)),
C.size_t(num),
)
if rc != 0 {
MemWipe(key)
return nil, errors.New("bee2: bakeKDF failed")
}
return key, nil
}
// BakeSWU maps msg to a point on the bign curve described by params.
func BakeSWU(params *BignParams, msg []byte) ([]byte, error) {
if params == nil {
return nil, errors.New("bee2: params is nil")
}
if len(msg) != params.PrivKeyLen() {
return nil, errors.New("bee2: bakeSWU message has invalid length")
}
pt := make([]byte, params.PubKeyLen())
rc := C.bakeSWU(
(*C.octet)(unsafe.Pointer(&pt[0])),
params.params,
(*C.octet)(unsafe.Pointer(&msg[0])),
)
if rc != 0 {
MemWipe(pt)
return nil, errors.New("bee2: bakeSWU failed")
}
return pt, nil
}
// BakeDH is the bake name for the base bign Diffie-Hellman operation.
func BakeDH(params *BignParams, privKey, peerPubKey []byte, keyLen int) ([]byte, error) {
return BignDH(params, privKey, peerPubKey, keyLen)
}
// ────────────────────────────────────────────────────────────────────────────
// BakeSettings
// ────────────────────────────────────────────────────────────────────────────
// BakeSettings wraps bake_settings.
// rng must be a C gen_i function pointer cast to unsafe.Pointer (CGo cannot
// convert a Go func to a C function pointer directly).
// rngState is the opaque state pointer passed back to rng on each call.
type BakeSettings struct {
settings *C.bake_settings
helloa unsafe.Pointer
hellob unsafe.Pointer
helloaLen uintptr
hellobLen uintptr
}
// NewBakeSettings allocates and populates a bake_settings struct.
// helloa / hellob are optional greeting messages; pass nil to omit.
func NewBakeSettings(kca, kcb bool, helloa, hellob []byte, rng, rngState unsafe.Pointer) (*BakeSettings, error) {
s := (*C.bake_settings)(C.calloc(1, C.size_t(C.sizeof_bake_settings)))
if s == nil {
return nil, errors.New("bee2: failed to allocate bake_settings")
}
bs := &BakeSettings{settings: s}
if kca {
s.kca = 1
}
if kcb {
s.kcb = 1
}
if len(helloa) > 0 {
bs.helloa = C.CBytes(helloa)
bs.helloaLen = uintptr(len(helloa))
s.helloa = bs.helloa
s.helloa_len = C.size_t(len(helloa))
}
if len(hellob) > 0 {
bs.hellob = C.CBytes(hellob)
bs.hellobLen = uintptr(len(hellob))
s.hellob = bs.hellob
s.hellob_len = C.size_t(len(hellob))
}
if rng != nil {
C.bake_settings_set_rng(s, rng, rngState)
}
return bs, nil
}
// Free releases C memory owned by BakeSettings.
func (s *BakeSettings) Free() {
if s.helloa != nil {
freeWiped(s.helloa, s.helloaLen)
s.helloa = nil
s.helloaLen = 0
}
if s.hellob != nil {
freeWiped(s.hellob, s.hellobLen)
s.hellob = nil
s.hellobLen = 0
}
if s.settings != nil {
freeWiped(unsafe.Pointer(s.settings), uintptr(C.sizeof_bake_settings))
s.settings = nil
}
}
// ────────────────────────────────────────────────────────────────────────────
// BakeCert
// ────────────────────────────────────────────────────────────────────────────
// BakeCert wraps bake_cert.
type BakeCert struct {
cert *C.bake_cert
data unsafe.Pointer
dataLen uintptr
owned bool
}
// NewBakeCert creates a BakeCert from raw certificate data and a C-side
// validation function pointer (bake_certval_i cast to unsafe.Pointer).
// Pass nil for valFn to skip validation.
func NewBakeCert(data []byte, valFn unsafe.Pointer) (*BakeCert, error) {
cData := C.CBytes(data)
cert := C.make_bake_cert((*C.octet)(cData), C.size_t(len(data)), valFn)
if cert == nil {
freeWiped(cData, uintptr(len(data)))
return nil, errors.New("bee2: failed to allocate bake_cert")
}
return &BakeCert{cert: cert, data: cData, dataLen: uintptr(len(data)), owned: true}, nil
}
// NewBakeCertFromC wraps a bake_cert already configured on the C side.
// The caller is responsible for the lifetime of the underlying memory.
func NewBakeCertFromC(certPtr unsafe.Pointer) *BakeCert {
return &BakeCert{cert: (*C.bake_cert)(certPtr), owned: false}
}
// Free releases C memory owned by this BakeCert.
func (c *BakeCert) Free() {
if !c.owned {
return
}
if c.data != nil {
freeWiped(c.data, c.dataLen)
c.data = nil
c.dataLen = 0
}
if c.cert != nil {
freeWiped(unsafe.Pointer(c.cert), uintptr(C.sizeof_bake_cert))
c.cert = nil
}
}
// ────────────────────────────────────────────────────────────────────────────
// BakeBSTS
// ────────────────────────────────────────────────────────────────────────────
// BakeBSTS wraps the BSTS authenticated key-establishment protocol state
// (СТБ 34.101.66, algorithm BSTS).
//
// Protocol flow (A initiates, B responds):
//
// B: stB = NewBakeBSTS(...) A: stA = NewBakeBSTS(...)
// B: m1, _ = stB.Step2() → send m1 →
// A: m2, _ = stA.Step3(m1)
// ← send m2 ←
// B: m3, _ = stB.Step4(m2, valA) → send m3 →
// A: stA.Step5(m3, valB)
// B: key, _ = stB.StepG() A: key, _ = stA.StepG()
type BakeBSTS struct {
state unsafe.Pointer
l int
certLen int
}
// NewBakeBSTS initialises the BSTS state for one party.
// l is the security level in bits (128, 192, or 256).
// privKey must be l/4 bytes.
func NewBakeBSTS(l int, params *BignParams, settings *BakeSettings, privKey []byte, cert *BakeCert) (*BakeBSTS, error) {
if params == nil || settings == nil || cert == nil {
return nil, errors.New("bee2: params, settings, and cert must not be nil")
}
state := C.malloc(C.size_t(C.bakeBSTS_keep(C.size_t(l))))
if state == nil {
return nil, errors.New("bee2: failed to allocate bakeBSTS state")
}
var privKeyPtr *C.octet
if len(privKey) > 0 {
privKeyPtr = (*C.octet)(unsafe.Pointer(&privKey[0]))
}
rc := C.bakeBSTSStart(state, params.params, settings.settings, privKeyPtr, cert.cert)
if rc != 0 {
freeWiped(state, uintptr(C.bakeBSTS_keep(C.size_t(l))))
return nil, errors.New("bee2: bakeBSTSStart failed")
}
return &BakeBSTS{state: state, l: l, certLen: int(cert.cert.len)}, nil
}
// Free releases the underlying C state.
func (b *BakeBSTS) Free() {
if b.state != nil {
freeWiped(b.state, uintptr(C.bakeBSTS_keep(C.size_t(b.l))))
b.state = nil
}
}
// Step2 is called by party B to produce message M1 (l/2 bytes).
func (b *BakeBSTS) Step2() ([]byte, error) {
out := make([]byte, b.l/2)
if rc := C.bakeBSTSStep2((*C.octet)(unsafe.Pointer(&out[0])), b.state); rc != 0 {
MemWipe(out)
return nil, errors.New("bee2: bakeBSTSStep2 failed")
}
return out, nil
}
// Step3 is called by party A: processes M1 and produces M2.
// Output size: 3*l/4 + certLen + 8 bytes.
func (b *BakeBSTS) Step3(in []byte) ([]byte, error) {
out := make([]byte, 3*b.l/4+b.certLen+8)
var inPtr *C.octet
if len(in) > 0 {
inPtr = (*C.octet)(unsafe.Pointer(&in[0]))
}
if rc := C.bakeBSTSStep3((*C.octet)(unsafe.Pointer(&out[0])), inPtr, b.state); rc != 0 {
MemWipe(out)
return nil, errors.New("bee2: bakeBSTSStep3 failed")
}
return out, nil
}
// Step4 is called by party B: processes M2 and produces M3.
// Output size: l/4 + certLen + 8 bytes.
// vala is a C bake_certval_i pointer used to validate A's certificate in M2.
func (b *BakeBSTS) Step4(in []byte, vala unsafe.Pointer) ([]byte, error) {
out := make([]byte, b.l/4+b.certLen+8)
var inPtr *C.octet
if len(in) > 0 {
inPtr = (*C.octet)(unsafe.Pointer(&in[0]))
}
rc := C.bsts_step4_wrap(
(*C.octet)(unsafe.Pointer(&out[0])),
inPtr, C.size_t(len(in)),
vala, b.state,
)
if rc != 0 {
MemWipe(out)
return nil, errors.New("bee2: bakeBSTSStep4 failed")
}
return out, nil
}
// Step5 is called by party A: processes M3 and finalises the handshake.
// valb is a C bake_certval_i pointer used to validate B's certificate in M3.
func (b *BakeBSTS) Step5(in []byte, valb unsafe.Pointer) error {
var inPtr *C.octet
if len(in) > 0 {
inPtr = (*C.octet)(unsafe.Pointer(&in[0]))
}
if rc := C.bsts_step5_wrap(inPtr, C.size_t(len(in)), valb, b.state); rc != 0 {
return errors.New("bee2: bakeBSTSStep5 failed")
}
return nil
}
// StepG extracts the 32-byte shared session key after the protocol completes.
// Call after Step4 (party B) or Step5 (party A).
func (b *BakeBSTS) StepG() ([]byte, error) {
key := make([]byte, 32)
if rc := C.bakeBSTSStepG((*C.octet)(unsafe.Pointer(&key[0])), b.state); rc != 0 {
MemWipe(key)
return nil, errors.New("bee2: bakeBSTSStepG failed")
}
return key, nil
}
// ────────────────────────────────────────────────────────────────────────────
// BakeBPACE
// ────────────────────────────────────────────────────────────────────────────
// BakeBPACE wraps the BPACE password-authenticated key-establishment protocol
// state (СТБ 34.101.66, algorithm BPACE).
//
// Protocol flow:
//
// B: m1 = Step2() → send M1 →
// A: m2 = Step3(m1)
// ← send M2 ←
// B: m3 = Step4(m2) → send M3 →
// A: m4 = Step5(m3)
// ← send M4 ←
// B: Step6(m4)
// A/B: key = StepG()
type BakeBPACE struct {
state unsafe.Pointer
l int
kca bool
kcb bool
}
// NewBakeBPACE initialises one BPACE party.
// l is the security level in bits (128, 192, or 256).
func NewBakeBPACE(l int, params *BignParams, settings *BakeSettings, password []byte) (*BakeBPACE, error) {
if params == nil || settings == nil {
return nil, errors.New("bee2: params and settings must not be nil")
}
if l != 128 && l != 192 && l != 256 {
return nil, errors.New("bee2: unsupported BPACE security level")
}
if len(password) == 0 {
return nil, errors.New("bee2: BPACE password is empty")
}
state := C.malloc(C.size_t(C.bakeBPACE_keep(C.size_t(l))))
if state == nil {
return nil, errors.New("bee2: failed to allocate bakeBPACE state")
}
rc := C.bakeBPACEStart(
state,
params.params,
settings.settings,
(*C.octet)(unsafe.Pointer(&password[0])),
C.size_t(len(password)),
)
if rc != 0 {
freeWiped(state, uintptr(C.bakeBPACE_keep(C.size_t(l))))
return nil, errors.New("bee2: bakeBPACEStart failed")
}
return &BakeBPACE{
state: state,
l: l,
kca: settings.settings.kca != 0,
kcb: settings.settings.kcb != 0,
}, nil
}
// Free releases the underlying C state.
func (b *BakeBPACE) Free() {
if b.state != nil {
freeWiped(b.state, uintptr(C.bakeBPACE_keep(C.size_t(b.l))))
b.state = nil
}
}
// Step2 is called by party B to produce M1 (l/8 bytes).
func (b *BakeBPACE) Step2() ([]byte, error) {
out := make([]byte, b.l/8)
if rc := C.bakeBPACEStep2((*C.octet)(unsafe.Pointer(&out[0])), b.state); rc != 0 {
MemWipe(out)
return nil, errors.New("bee2: bakeBPACEStep2 failed")
}
return out, nil
}
// Step3 is called by party A: processes M1 and produces M2 (5*l/8 bytes).
func (b *BakeBPACE) Step3(in []byte) ([]byte, error) {
if len(in) != b.l/8 {
return nil, errors.New("bee2: BPACE M1 has invalid length")
}
out := make([]byte, 5*b.l/8)
if rc := C.bakeBPACEStep3(
(*C.octet)(unsafe.Pointer(&out[0])),
(*C.octet)(unsafe.Pointer(&in[0])),
b.state,
); rc != 0 {
MemWipe(out)
return nil, errors.New("bee2: bakeBPACEStep3 failed")
}
return out, nil
}
// Step4 is called by party B: processes M2 and produces M3.
// Output size is l/2 bytes plus 8 bytes when party B confirms the key.
func (b *BakeBPACE) Step4(in []byte) ([]byte, error) {
if len(in) != 5*b.l/8 {
return nil, errors.New("bee2: BPACE M2 has invalid length")
}
outLen := b.l / 2
if b.kcb {
outLen += 8
}
out := make([]byte, outLen)
if rc := C.bakeBPACEStep4(
(*C.octet)(unsafe.Pointer(&out[0])),
(*C.octet)(unsafe.Pointer(&in[0])),
b.state,
); rc != 0 {
MemWipe(out)
return nil, errors.New("bee2: bakeBPACEStep4 failed")
}
return out, nil
}
// Step5 is called by party A: processes M3 and produces M4 when party A
// confirms the key.
func (b *BakeBPACE) Step5(in []byte) ([]byte, error) {
inLen := b.l / 2
if b.kcb {
inLen += 8
}
if len(in) != inLen {
return nil, errors.New("bee2: BPACE M3 has invalid length")
}
outLen := 0
if b.kca {
outLen = 8
}
out := make([]byte, outLen)
var outPtr *C.octet
if len(out) > 0 {
outPtr = (*C.octet)(unsafe.Pointer(&out[0]))
}
if rc := C.bakeBPACEStep5(
outPtr,
(*C.octet)(unsafe.Pointer(&in[0])),
b.state,
); rc != 0 {
MemWipe(out)
return nil, errors.New("bee2: bakeBPACEStep5 failed")
}
return out, nil
}
// Step6 is called by party B to verify M4 when party A confirms the key.
func (b *BakeBPACE) Step6(in []byte) error {
if !b.kca {
if len(in) == 0 {
return nil
}
return errors.New("bee2: BPACE M4 supplied when kca is disabled")
}
if len(in) != 8 {
return errors.New("bee2: BPACE M4 has invalid length")
}
if rc := C.bakeBPACEStep6((*C.octet)(unsafe.Pointer(&in[0])), b.state); rc != 0 {
return errors.New("bee2: bakeBPACEStep6 failed")
}
return nil
}
// StepG extracts the 32-byte shared key after the protocol completes.
func (b *BakeBPACE) StepG() ([]byte, error) {
key := make([]byte, 32)
if rc := C.bakeBPACEStepG((*C.octet)(unsafe.Pointer(&key[0])), b.state); rc != 0 {
MemWipe(key)
return nil, errors.New("bee2: bakeBPACEStepG failed")
}
return key, nil
}