-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbash_hash.go
More file actions
97 lines (85 loc) · 2.39 KB
/
Copy pathbash_hash.go
File metadata and controls
97 lines (85 loc) · 2.39 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
package bee2go
/*
#cgo CFLAGS: -I${SRCDIR}/bee2/include
#cgo LDFLAGS: -L${SRCDIR}/bee2/build/src -lbee2_static
#include <stdlib.h>
#include <string.h>
#include "bee2/crypto/bash.h"
*/
import "C"
import (
"errors"
"hash"
"unsafe"
)
type bashHash struct {
state unsafe.Pointer
l int
}
// NewBashHash returns a hash.Hash computing bash hash at security level l.
// l must be 128, 192, or 256; the digest size is l/4 bytes (e.g. 32 bytes for l=128).
func NewBashHash(l int) (hash.Hash, error) {
if l != 128 && l != 192 && l != 256 {
return nil, errors.New("bee2: security level l must be 128, 192, or 256")
}
state := C.malloc(C.size_t(C.bashHash_keep()))
if state == nil {
return nil, errors.New("bee2: failed to allocate bashHash state")
}
C.bashHashStart(state, C.size_t(l))
return &bashHash{state: state, l: l}, nil
}
func (h *bashHash) Write(p []byte) (int, error) {
if len(p) > 0 {
C.bashHashStepH(unsafe.Pointer(&p[0]), C.size_t(len(p)), h.state)
}
return len(p), nil
}
func (h *bashHash) Sum(b []byte) []byte {
hashLen := h.l / 4
out := make([]byte, hashLen)
// Copy state so Sum can be called multiple times without consuming it.
stateSize := C.size_t(C.bashHash_keep())
tmp := C.malloc(stateSize)
if tmp == nil {
panic("bee2: failed to allocate temporary bashHash state")
}
defer freeWiped(tmp, uintptr(stateSize))
C.memcpy(tmp, h.state, stateSize)
C.bashHashStepG((*C.octet)(unsafe.Pointer(&out[0])), C.size_t(hashLen), tmp)
result := append(b, out...)
MemWipe(out)
return result
}
func (h *bashHash) Reset() {
wipePointer(h.state, uintptr(C.bashHash_keep()))
C.bashHashStart(h.state, C.size_t(h.l))
}
// Size returns the digest size in bytes (l/4).
func (h *bashHash) Size() int {
return h.l / 4
}
// BlockSize returns the sponge rate in bytes ((1536 - 2*l) / 8).
func (h *bashHash) BlockSize() int {
return (1536 - 2*h.l) / 8
}
// Free releases the underlying C state. Must be called when the hash is no longer needed.
func (h *bashHash) Free() {
if h.state != nil {
freeWiped(h.state, uintptr(C.bashHash_keep()))
h.state = nil
}
}
// BashHash computes the bash hash of src at security level l in a single call.
// l must be 128, 192, or 256.
func BashHash(l int, src []byte) ([]byte, error) {
h, err := NewBashHash(l)
if err != nil {
return nil, err
}
defer h.(*bashHash).Free()
if _, err := h.Write(src); err != nil {
return nil, err
}
return h.Sum(nil), nil
}