-
Notifications
You must be signed in to change notification settings - Fork 1
/
api.go
308 lines (281 loc) · 8.46 KB
/
api.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
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
// Package hq implements sphincs-blake3-512 hypertree signatures
package hq
import (
"os"
"runtime"
"strconv"
"time"
"paepcke.de/sphincs"
)
//
// EXPORTED STRUCTS
//
// const
const (
// PublicKeySize
PublicKeySize = sphincs.PublicKeySize
// PrivateKeySize
PrivateKeySize = sphincs.PrivateKeySize
// SignatureSize
SignatureSize = sphincs.SignatureSize
// HashSize
HashSize = 64
)
// HQ ...
type HQ struct {
// ID identiy
ID
// IO exchange
IO
}
// ID identiy
type ID struct {
OWNER [HashSize]byte // OWNER ID
TAG [30]byte // NAME TAG
KEY [PublicKeySize]byte // SPHINCS Public Key
}
// IO exchange
type IO struct {
HashPassONE [HashSize]byte // hashed password token
HashPassTWO [HashSize]byte // hashed password token
MSG [HashSize]byte // message[hash] to [sign|verify]
MSGRAW []byte // pointer to raw message
SCRIPT []byte // compressed and base64 encoded exec
TokenExec string // magic token to determine exec type for execution
ScriptExtL int // lengh of extension name
DirName string // Report DirName
FileName string // Report FileName
FilesTotal uint64 // total number of files
FilesFail uint64 // total number of files with hash|checksum errors
FilesNew uint64 // total number of files with hash|checksum errors
Signify bool // enable optional OpenBSD signify signatures
PlainTextScript bool // Plain Text Posix script interp mode
MapClean bool // true if we need to wipe old maps
Silent bool // silent mode for benchmarking
UnlockedKey bool // true if /.hq/.unlocked key was found
IsExec bool // true if exec mode
ReportID bool // Report Status [summary]
ReportTime bool // Report Status [summary]
ReportValid bool // Report Status [summary]
ColorUI bool // enable CLI ColorUI
SetMe bool // Set Me Key Symbolic Link
PwdEnv bool // true if pass creds from env
CPU int // number of CPU cores
Start time.Time // Time Stamp Start Action
End time.Time // Time Stamp End Action
TSS string // POSIX TS (nanoseconds since 01/01/1970 00:00 UTC)
SIG [SignatureSize]byte // RAW SPHINCS-256 signature
PRIVKEY [PrivateKeySize]byte // RAW SPHINCS-256 private key
SIGNIFYMSG []byte // Encoded OpenBSD Signify Message
SIGNIFYPUB []byte // Encoded OpenBSD Signify PublicKey
SIGNIFYFILE []byte // Encoded OpenBSD Signify Signature
}
// Config ...
type Config struct {
Action string // Requested Action [sign|verify|generate|bench]
Target string // Requested Target [dir|file]
TargetTS string // Requested Target TimeStamp
FileName string // FileName
File *os.File // FileHandle
Signify bool // enable optional OpenBSD signify signatures
CodeReview bool // enable additional code-review hashes for source code files
Silent bool // enable silent mode [eg. for benchmarking]
IsExec bool // true if executeable mode is detected
IsPipe bool // true if exec mode is detected
MapOnly bool // true if exec mode is detected
RunExec bool // true if run mode [not display mode] is requested
PwdComplex bool // true if complex legacy password is requested
PlainTextScript bool // run plaintext sh script interpreter
TokenExec string // magic token to determine exec type for execution
PwdService string // the [legacy] password service name [psn]
ScriptExtL int // lengh of extension name
}
//
// EXPORTED STRUCTS DEFAULTS
//
// NewHQ ...
func NewHQ(c *Config) *HQ {
return &HQ{
ID{},
IO{
Start: time.Now(),
ColorUI: getColorUI(),
ReportID: true,
ReportValid: false,
ReportTime: true,
CPU: runtime.NumCPU(),
Signify: c.Signify,
},
}
}
// NewConfig ...
func NewConfig() *Config {
return &Config{
MapOnly: isMapOnly(),
IsPipe: isPipe(),
FileName: ".",
Target: "file",
PwdComplex: true,
Signify: isEnv(_envHQSignify),
}
}
//
// EXPORTED FUNCTIONS
//
// ParseCmd ...
func (c *Config) ParseCmd() { c.parseCmd() }
// RunAction ...
func (c *Config) RunAction() bool { return c.runAction() }
// DirVerify ...
func (c *Config) DirVerify() bool { return c.dirVerify() }
// DirSign ...
func (c *Config) DirSign() bool { return c.dirSign() }
// CryptoVerify ...
func (c *Config) CryptoVerify() bool { return c.cryptoVerify() }
// RunExecPlain ...
func (c *Config) RunExecPlain() bool { return c.runExecPlain() }
// Bench ...
func (c *Config) Bench() bool { return c.bench() }
// Generate sphincs keypair
func (c *Config) Generate() bool {
id := NewHQ(c)
id.IO.SetMe = true
id.ID.OWNER = getOwner()
id.passEntry("create hq identity")
id.IO.Start = time.Now()
id.genSphincs()
id.writePublicKey()
id.report()
return true
}
// FileSign ...
func (c *Config) FileSign() bool {
id := NewHQ(c)
id.IO.TSS = strconv.FormatInt(id.IO.Start.Unix(), 10)
id.IO.FileName = c.FileName
id.IO.ScriptExtL = c.ScriptExtL
chanHash := make(chan [HashSize]byte, 1)
go func() {
chanHash <- getMSGHash(id.IO.FileName)
close(chanHash)
}()
id.readPublicKey(_me)
id.passEntry("pending " + c.Target + " sign operation [" + id.IO.FileName + "]")
id.IO.MSG = <-chanHash
id.IO.Start = time.Now()
id.unlockHQ()
id.genSig()
id.writeSig()
id.report()
return true
}
// FileSignExecuteable ...
func (c *Config) FileSignExecuteable() bool {
id := NewHQ(c)
id.IO.TSS = strconv.FormatInt(id.IO.Start.Unix(), 10)
id.IO.FileName = c.FileName
id.IO.ScriptExtL = c.ScriptExtL
id.IO.IsExec = true
id.IO.TokenExec = c.TokenExec
id.IO.SCRIPT = compressZstd(readFileErrExit(id.IO.FileName), _compressedScriptLevel)
id.readPublicKey(_me)
id.passEntry("pending " + c.Target + " sign operation [" + id.IO.FileName + "]")
id.IO.Start = time.Now()
id.unlockHQ()
id.genSig()
id.writeSig()
id.report()
return true
}
// FileVerify ...
func (c *Config) FileVerify() bool {
id := NewHQ(c)
id.IO.FileName = c.FileName
id.IO.ReportValid = false
id.parseSig(c)
if id.validateSig() {
id.IO.ReportValid = true
id.report()
return true
}
id.report()
if id.IO.ColorUI {
stat, fail = _Stat, _Fail
}
out(stat + "SIGNATURE VALIDATION: " + fail)
return false
}
// FileVerifyExecuteable verifies and executes an hq singed hqx container
func (c *Config) FileVerifyExecuteable() bool {
id := NewHQ(c)
id.IO.FileName = c.FileName
id.IO.IsExec = c.IsExec
id.IO.ReportValid = false
id.parseSig(c)
if id.validateSig() {
id.IO.ReportValid = true
id.report()
if c.RunExec {
return id.runExec()
}
out(string(decompressZstd(id.IO.SCRIPT)))
return true
}
id.report()
if id.IO.ColorUI {
stat, fail = _Stat, _Fail
}
out(stat + "SIGNATURE VALIDATION: " + fail)
return false
}
// Unlock unlocks the raw sphincs key for subsequent batch operations
func (c *Config) Unlock() bool {
if !_allowUnlockViaEnv {
errExit("store unlocked key operations disabled by security policy")
}
id := NewHQ(c)
id.readPublicKey(_me)
id.passEntry("pending unlock operation")
switch {
case id.validateKey():
id.report()
return true
case !id.wipeUnlockedKey():
errExit("unable to [write|delete] key to ~/hq/.unlocked")
}
id.IO.Start = time.Now()
id.unlockHQ()
id.genSig()
id.writeUnlockedKey()
id.report()
return true
}
// Lock cleans the Unlock() exposed raw key
func (c *Config) Lock() bool {
if !_allowUnlockViaEnv {
errExit("store unlocked key operations disabled by security policy")
}
id := NewHQ(c)
id.readPublicKey(_me)
id.report()
id.IO.Start = time.Now()
return id.wipeUnlockedKey()
}
// LegacyPass is a [k]ey[d]erivation[f]unction for legacy passwords
func (c *Config) LegacyPass() bool {
id := NewHQ(c)
id.pwdTarget(c)
id.readPublicKey(_me)
id.passEntry("legacy password [generation|reproduction]")
id.IO.Start = time.Now()
id.unlockHQ()
id.genSig()
id.report()
id.IO.Start = time.Now()
id.reportPwd(c)
id.IO.End = time.Time{}
id.IO.ReportID = false
id.IO.ReportTime = true
id.report()
return true
}