-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathzenroom.go
168 lines (146 loc) · 5.32 KB
/
zenroom.go
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
// Package zenroom is a CGO wrapper for the Zenroom virtual machine, which aims
// to make Zenroom easily usable from Go programs. Currently the C binary we
// wrap is only available for Linux.
package zenroom
// #cgo CFLAGS: -IC:${SRCDIR}
// #cgo LDFLAGS: -L${SRCDIR}/lib -Wl,-rpath=${SRCDIR}/lib -lzenroomgo
// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>
// #include "zenroom.h"
import (
"C"
)
import (
"fmt"
"unsafe"
// dummy import to include binary in dependencies
_ "github.com/DECODEproject/zenroom-go/lib"
)
// maxString is zenroom defined buffer MAX_STRING size
const maxString = 4096
// config is an unexported config struct used to handle the functional variadic
// configuration options defined below.
type config struct {
Keys []byte
Data []byte
Conf string
Verbosity int
}
// Option is a type alias we use to supply optional configuration to the primary
// Exec method this library exposes. Option is a functional configuration type
// alias for a function that takes as a parameter an unexported configuration
// object. Callers can supply keys, data, conf and verbosity via an Option using
// one of the WithXXX helper functions.
type Option func(*config)
// WithKeys is a configuration helper that allows the caller to pass in a value
// for the KEYS parameter that Zenroom supports. The value of KEYS is typically
// a string, often JSON formatted, that contains one or more keys that the
// primary script requires in order to operate. These are passed separately from
// the main script as they will typically have different security requirements
// than the main script contents. Keys must be passed in to the helper in a byte
// slice.
func WithKeys(keys []byte) Option {
return func(c *config) {
c.Keys = keys
}
}
// WithData is a configuration helper that allows the caller to pass in a value
// for the DATA parameter that Zenroom supports. The value of KEYS is a string,
// often but not required to be JSON formatted, containing data over which the
// script should operate. As with the KEYS property, DATA is passed separately
// from either the SCRIPT or the KEYS as these different values will often have
// different security requirements or may come from different sources. DATA must
// be passed as a byte slice.
func WithData(data []byte) Option {
return func(c *config) {
c.Data = data
}
}
// WithConf is a configuration helper that allows the caller to pass in a value
// for the CONF parameter that Zenroom supports. The default for this value if
// not supplied is an empty string.
func WithConf(conf string) Option {
return func(c *config) {
c.Conf = conf
}
}
// WithVerbosity is a configuration helper that allows the caller to specify how
// verbose Zenroom should be with its output. The value of this configuration
// must be an integer from 1 to 3, where 1 is the least verbose, and 3 is the
// most. The default if this value is not supplied is 1.
func WithVerbosity(verbosity int) Option {
return func(c *config) {
c.Verbosity = verbosity
}
}
// Exec is our primary public API method, and it is here that we call Zenroom's
// zenroom_exec_tobuf function. This method attempts to pass a required script,
// and some optional extra parameters to the Zenroom virtual machine, where
// cryptographic operations are performed with the result being returned to the
// caller. The method signature has been tweaked slightly from the original
// function defined by Zenroom; rather than making all parameters required,
// instead we have just included as a required parameter the input SCRIPT, while
// all other properties must be supplied via one of the previously defined
// Option helpers.
//
// Returns the output of the execution of the Zenroom virtual machine, or an
// error.
func Exec(script []byte, options ...Option) ([]byte, error) {
var (
cScript *C.char
optKeys, optData, optConf *C.char
)
// capture the required script parameter
if script == nil {
return nil, fmt.Errorf("missing required script to process")
}
cScript = (*C.char)(unsafe.Pointer(&script[0]))
// set up our default config
conf := &config{
Conf: "",
Verbosity: 1,
}
// and now we iterate through our options, to update our config object
for _, option := range options {
option(conf)
}
if conf.Keys != nil {
optKeys = (*C.char)(unsafe.Pointer(&conf.Keys[0]))
}
if conf.Data != nil {
optData = (*C.char)(unsafe.Pointer(&conf.Data[0]))
}
if conf.Conf != "" {
optConf = C.CString(conf.Conf)
defer C.free(unsafe.Pointer(optConf))
}
// create empty strings to capture zenroom's output
stdout := emptyString(maxString)
stderr := emptyString(maxString)
defer C.free(unsafe.Pointer(stdout))
defer C.free(unsafe.Pointer(stderr))
res := C.zenroom_exec_tobuf(
cScript,
optConf, optKeys, optData, C.int(conf.Verbosity),
stdout, maxString,
stderr, maxString,
)
if res != 0 {
return nil, fmt.Errorf("error calling zenroom: %s ", C.GoString(stderr))
}
return C.GoBytes(unsafe.Pointer(stdout), C.int(C.strlen(stdout))), nil
}
// reimplementation of https://golang.org/src/strings/strings.go?s=13172:13211#L522
func emptyString(size int) *C.char {
p := C.malloc(C.size_t(size + 1))
// largest array size that can be used on all architectures
pp := (*[1 << 30]byte)(p)
bp := copy(pp[:], " ")
for bp < size {
copy(pp[bp:], pp[:bp])
bp *= 2
}
pp[size] = 0
return (*C.char)(p)
}