@@ -95,6 +95,8 @@ const (
95
95
var (
96
96
// SHA2 algorithm capabilities:
97
97
// https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2
98
+ // SHA3 and SHAKE algorithm capabilities:
99
+ // https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-sha3-and-shake-algorithm-ca
98
100
// HMAC algorithm capabilities:
99
101
// https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7
100
102
// PBKDF2 algorithm capabilities:
@@ -140,6 +142,17 @@ var (
140
142
"SHA3-512" : cmdHashAft (sha3 .New512 ()),
141
143
"SHA3-512/MCT" : cmdSha3Mct (sha3 .New512 ()),
142
144
145
+ // Note: SHAKE AFT and VOT test types can be handled by the same command
146
+ // handler impl, but use distinct acvptool command names, and so are
147
+ // registered twice with the same digest: once under "SHAKE-xxx" for AFT,
148
+ // and once under"SHAKE-xxx/VOT" for VOT.
149
+ "SHAKE-128" : cmdShakeAftVot (sha3 .NewShake128 ()),
150
+ "SHAKE-128/VOT" : cmdShakeAftVot (sha3 .NewShake128 ()),
151
+ "SHAKE-128/MCT" : cmdShakeMct (sha3 .NewShake128 ()),
152
+ "SHAKE-256" : cmdShakeAftVot (sha3 .NewShake256 ()),
153
+ "SHAKE-256/VOT" : cmdShakeAftVot (sha3 .NewShake256 ()),
154
+ "SHAKE-256/MCT" : cmdShakeMct (sha3 .NewShake256 ()),
155
+
143
156
"HMAC-SHA2-224" : cmdHmacAft (func () fips140.Hash { return sha256 .New224 () }),
144
157
"HMAC-SHA2-256" : cmdHmacAft (func () fips140.Hash { return sha256 .New () }),
145
158
"HMAC-SHA2-384" : cmdHmacAft (func () fips140.Hash { return sha512 .New384 () }),
@@ -410,6 +423,70 @@ func cmdSha3Mct(h fips140.Hash) command {
410
423
}
411
424
}
412
425
426
+ func cmdShakeAftVot (h * sha3.SHAKE ) command {
427
+ return command {
428
+ requiredArgs : 2 , // Message, output length (bytes)
429
+ handler : func (args [][]byte ) ([][]byte , error ) {
430
+ msg := args [0 ]
431
+
432
+ outLenBytes := binary .LittleEndian .Uint32 (args [1 ])
433
+ digest := make ([]byte , outLenBytes )
434
+
435
+ h .Reset ()
436
+ h .Write (msg )
437
+ h .Read (digest )
438
+
439
+ return [][]byte {digest }, nil
440
+ },
441
+ }
442
+ }
443
+
444
+ func cmdShakeMct (h * sha3.SHAKE ) command {
445
+ return command {
446
+ requiredArgs : 4 , // Seed message, min output length (bytes), max output length (bytes), output length (bytes)
447
+ handler : func (args [][]byte ) ([][]byte , error ) {
448
+ md := args [0 ]
449
+ minOutBytes := binary .LittleEndian .Uint32 (args [1 ])
450
+ maxOutBytes := binary .LittleEndian .Uint32 (args [2 ])
451
+
452
+ outputLenBytes := binary .LittleEndian .Uint32 (args [3 ])
453
+ if outputLenBytes < 2 {
454
+ return nil , fmt .Errorf ("invalid output length: %d" , outputLenBytes )
455
+ }
456
+
457
+ rangeBytes := maxOutBytes - minOutBytes + 1
458
+ if rangeBytes == 0 {
459
+ return nil , fmt .Errorf ("invalid maxOutBytes and minOutBytes: %d, %d" , maxOutBytes , minOutBytes )
460
+ }
461
+
462
+ for i := 0 ; i < 1000 ; i ++ {
463
+ // "The MSG[i] input to SHAKE MUST always contain at least 128 bits. If this is not the case
464
+ // as the previous digest was too short, append empty bits to the rightmost side of the digest."
465
+ boundary := min (len (md ), 16 )
466
+ msg := make ([]byte , 16 )
467
+ copy (msg , md [:boundary ])
468
+
469
+ // MD[i] = SHAKE(MSG[i], OutputLen * 8)
470
+ h .Reset ()
471
+ h .Write (msg )
472
+ digest := make ([]byte , outputLenBytes )
473
+ h .Read (digest )
474
+ md = digest
475
+
476
+ // RightmostOutputBits = 16 rightmost bits of MD[i] as an integer
477
+ // OutputLen = minOutBytes + (RightmostOutputBits % Range)
478
+ rightmostOutput := uint32 (md [outputLenBytes - 2 ])<< 8 | uint32 (md [outputLenBytes - 1 ])
479
+ outputLenBytes = minOutBytes + (rightmostOutput % rangeBytes )
480
+ }
481
+
482
+ encodedOutputLenBytes := make ([]byte , 4 )
483
+ binary .LittleEndian .PutUint32 (encodedOutputLenBytes , outputLenBytes )
484
+
485
+ return [][]byte {md , encodedOutputLenBytes }, nil
486
+ },
487
+ }
488
+ }
489
+
413
490
func cmdHmacAft (h func () fips140.Hash ) command {
414
491
return command {
415
492
requiredArgs : 2 , // Message and key
0 commit comments