-
Notifications
You must be signed in to change notification settings - Fork 0
/
desc-crypto.go
206 lines (178 loc) · 5.97 KB
/
desc-crypto.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
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
package mrnesbits
// file desc-crypto.go holds structs, data structures, and methods used to
// build and read summaries of the measurements of cryptographic algorithms
// available to the mrnesbits model. In particular the data structures
// can be accessed by a GUI used to guide model development
import (
"encoding/json"
"fmt"
"gopkg.in/yaml.v3"
"os"
"path"
"sort"
"strconv"
"strings"
)
// AlgSpec provides representation of crypto algorithm and key lengths
// for which we have timing measurements. Used in the CryptoDesc struct
// below, which can be read by a GUI to align with the crypto algorithms
// and key lengths that are available
type AlgSpec struct {
Name string // e.g., 'aes','des'
KeyLen []int // lengths of keys used in measurements represented in the functional timings
}
// CryptoDesc is a structure used so that the GUI and simulator can
// 'see' the same set of crypto algorithms that might be chosen,
// and have their performance included in the system behavior
type CryptoDesc struct {
Algs []AlgSpec
}
// createCryptoDesc is a constructor
func createCryptoDesc() *CryptoDesc {
cd := new(CryptoDesc)
cd.Algs = []AlgSpec{}
return cd
}
// createAlgSpec is a constructor. When called we assume that all
// the keys known to be associated with the specified algorithm in our
// tables are listed in the keyLen argument
func createAlgSpec(name string, keyLen []int) *AlgSpec {
algSpec := new(AlgSpec)
algSpec.Name = strings.ToLower(name)
algSpec.KeyLen = keyLen
return algSpec
}
// addCryptoAlg is called to include another algorithm
// in the CryptoDesc's list
func (cd *CryptoDesc) addAlgSpec(algSpec AlgSpec) {
for _, as := range cd.Algs {
if as.Name == algSpec.Name {
return
}
}
cd.Algs = append(cd.Algs, algSpec)
}
// WriteToFile stores the CryptoDesc struct to the file whose name is given.
// Serialization to json or to yaml is selected based on the extension of this name.
func (cd *CryptoDesc) WriteToFile(filename string) error {
pathExt := path.Ext(filename)
var bytes []byte
var merr error = nil
if pathExt == ".yaml" || pathExt == ".YAML" || pathExt == ".yml" {
bytes, merr = yaml.Marshal(*cd)
} else if pathExt == ".json" || pathExt == ".JSON" {
bytes, merr = json.MarshalIndent(*cd, "", "\t")
}
if merr != nil {
panic(merr)
}
f, cerr := os.Create(filename)
if cerr != nil {
panic(cerr)
}
_, werr := f.WriteString(string(bytes[:]))
if werr != nil {
panic(werr)
}
f.Close()
return werr
}
// ReadCryptoDesc deserializes a byte slice holding a representation of an CryptoDesc struct.
// If the input argument of dict (those bytes) is empty, the file whose name is given is read
// to acquire them. A deserialized representation is returned, or an error if one is generated
// from a file read or the deserialization.
func ReadCryptoDesc(filename string, useYAML bool, dict []byte) (*CryptoDesc, error) {
var err error
if len(dict) == 0 {
dict, err = os.ReadFile(filename)
if err != nil {
return nil, err
}
}
example := CryptoDesc{}
if useYAML {
err = yaml.Unmarshal(dict, &example)
} else {
err = json.Unmarshal(dict, &example)
}
if err != nil {
return nil, err
}
return &example, nil
}
// BuildCryptoDesc scans a given file of timing descriptions, looking for those
// with a Param == "KeyLength=integer" which are taken to be crypto algortithms and
// the Param a string-encoded integer description of the key length version
func BuildCryptoDesc(filename string) *CryptoDesc {
cd := createCryptoDesc()
var emptyBytes []byte
fdl, _ := ReadFuncExecList(filename, true, emptyBytes)
// create a temporary dictionary to more easily detect
// when an algorithm has already been referenced
algDict := make(map[string]AlgSpec)
// look at each function timing description
for identifier := range fdl.Times {
for _, fd := range fdl.Times[identifier] {
// check whether fd is a description of interest,
// identified as having the param attribute have the format
// keylength="integer"
param := strings.ToLower(fd.Param)
param = strings.Replace(param, " ", "", -1)
if strings.Contains(param, "keylength=") {
ps := strings.Split(param, "=")
_, err := strconv.Atoi(ps[1])
if err != nil {
panic(fmt.Errorf("faulty parameter description for crypto timing"))
}
// crypto timings in the functional timings table are assumed to have the form
// 'op-alg-keylen', and that neither op nor alg have the character '-' embedded,
// so we can split on '-' to get the pieces
lcName := strings.ToLower(fd.Identifier)
cryptoParts := strings.Split(lcName, "-")
if len(cryptoParts) != 3 {
panic(fmt.Errorf("expect identifier in form of 'op-alg-keylen"))
}
// pull out notationally the algorithm and key lengths
alg := cryptoParts[1]
keyLen, _ := strconv.Atoi(cryptoParts[2])
// see whether we've already seen this algorithm
_, present := algDict[alg]
if !present {
// no, so create a representation for it
algDict[alg] = AlgSpec{Name: alg, KeyLen: []int{}}
}
// add keylength, if not present
as := algDict[alg]
foundKey := false
for _, kl := range as.KeyLen {
if kl == keyLen {
foundKey = true
break
}
}
if foundKey {
continue
}
kls := algDict[alg].KeyLen
kls = append(kls, keyLen)
sort.Ints(kls)
algDict[alg] = AlgSpec{Name: alg, KeyLen: kls}
}
}
}
// AlgDict is now a dictionary indexed by representation of
// some crypto algorithm, with a list of key lengths that have been
// observed as being declared in functional timings
// Add these to the CryptoDesc
for algName := range algDict {
algName = strings.Replace(algName, "encrypt-", "", -1)
algName = strings.Replace(algName, "decrypt-", "", -1)
algName = strings.Replace(algName, "hash-", "", -1)
algName = strings.Replace(algName, "sign-", "", -1)
as := createAlgSpec(algName, algDict[algName].KeyLen)
cd.addAlgSpec(*as)
}
// notice that there are no pointers embedded in cd,
// so it can written out to file
return cd
}