1// Copyright 2021 The BoringSSL Authors 2// 3// Permission to use, copy, modify, and/or distribute this software for any 4// purpose with or without fee is hereby granted, provided that the above 5// copyright notice and this permission notice appear in all copies. 6// 7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 15// testmodulewrapper is a modulewrapper binary that works with acvptool and 16// implements the primitives that BoringSSL's modulewrapper doesn't, so that 17// we have something that can exercise all the code in avcptool. 18 19package main 20 21import ( 22 "bytes" 23 "crypto" 24 "crypto/aes" 25 "crypto/cipher" 26 "crypto/ed25519" 27 "crypto/hmac" 28 "crypto/rand" 29 "crypto/sha256" 30 "crypto/sha512" 31 "encoding/binary" 32 "errors" 33 "fmt" 34 "hash" 35 "io" 36 "os" 37 38 "filippo.io/edwards25519" 39 40 "golang.org/x/crypto/hkdf" 41 "golang.org/x/crypto/pbkdf2" 42 "golang.org/x/crypto/sha3" 43 "golang.org/x/crypto/xts" 44) 45 46var ( 47 output io.Writer 48 outputBuffer *bytes.Buffer 49) 50 51var handlers = map[string]func([][]byte) error{ 52 "flush": flush, 53 "getConfig": getConfig, 54 "KDF-counter": kdfCounter, 55 "AES-XTS/encrypt": xtsEncrypt, 56 "AES-XTS/decrypt": xtsDecrypt, 57 "HKDF/SHA2-256": hkdfMAC, 58 "hmacDRBG-reseed/SHA2-256": hmacDRBGReseed, 59 "hmacDRBG-pr/SHA2-256": hmacDRBGPredictionResistance, 60 "AES-CBC-CS3/encrypt": ctsEncrypt, 61 "AES-CBC-CS3/decrypt": ctsDecrypt, 62 "PBKDF": pbkdf, 63 "EDDSA/keyGen": eddsaKeyGen, 64 "EDDSA/keyVer": eddsaKeyVer, 65 "EDDSA/sigGen": eddsaSigGen, 66 "EDDSA/sigVer": eddsaSigVer, 67 "SHAKE-128": shakeAftVot(sha3.NewShake128), 68 "SHAKE-128/VOT": shakeAftVot(sha3.NewShake128), 69 "SHAKE-128/MCT": shakeMct(sha3.NewShake128), 70 "SHAKE-256": shakeAftVot(sha3.NewShake256), 71 "SHAKE-256/VOT": shakeAftVot(sha3.NewShake256), 72 "SHAKE-256/MCT": shakeMct(sha3.NewShake256), 73} 74 75func flush(args [][]byte) error { 76 if outputBuffer == nil { 77 return nil 78 } 79 80 if _, err := os.Stdout.Write(outputBuffer.Bytes()); err != nil { 81 return err 82 } 83 outputBuffer = new(bytes.Buffer) 84 output = outputBuffer 85 return nil 86} 87 88func getConfig(args [][]byte) error { 89 if len(args) != 0 { 90 return fmt.Errorf("getConfig received %d args", len(args)) 91 } 92 93 if err := reply([]byte(`[ 94 { 95 "algorithm": "acvptool", 96 "features": ["batch"] 97 }, { 98 "algorithm": "KDF", 99 "revision": "1.0", 100 "capabilities": [{ 101 "kdfMode": "counter", 102 "macMode": [ 103 "HMAC-SHA2-256" 104 ], 105 "supportedLengths": [{ 106 "min": 8, 107 "max": 4096, 108 "increment": 8 109 }], 110 "fixedDataOrder": [ 111 "before fixed data" 112 ], 113 "counterLength": [ 114 32 115 ] 116 }] 117 }, { 118 "algorithm": "ACVP-AES-XTS", 119 "revision": "1.0", 120 "direction": [ 121 "encrypt", 122 "decrypt" 123 ], 124 "keyLen": [ 125 128, 126 256 127 ], 128 "payloadLen": [ 129 1024 130 ], 131 "tweakMode": [ 132 "number" 133 ] 134 }, { 135 "algorithm": "KDA", 136 "mode": "HKDF", 137 "revision": "Sp800-56Cr1", 138 "fixedInfoPattern": "uPartyInfo||vPartyInfo", 139 "encoding": [ 140 "concatenation" 141 ], 142 "hmacAlg": [ 143 "SHA2-256" 144 ], 145 "macSaltMethods": [ 146 "default", 147 "random" 148 ], 149 "l": 256, 150 "z": [256, 384] 151 }, { 152 "algorithm": "hmacDRBG", 153 "revision": "1.0", 154 "predResistanceEnabled": [false, true], 155 "reseedImplemented": true, 156 "capabilities": [{ 157 "mode": "SHA2-256", 158 "derFuncEnabled": false, 159 "entropyInputLen": [ 160 256 161 ], 162 "nonceLen": [ 163 128 164 ], 165 "persoStringLen": [ 166 256 167 ], 168 "additionalInputLen": [ 169 256 170 ], 171 "returnedBitsLen": 256 172 }] 173 }, { 174 "algorithm": "ACVP-AES-CBC-CS3", 175 "revision": "1.0", 176 "payloadLen": [{ 177 "min": 128, 178 "max": 2048, 179 "increment": 8 180 }], 181 "direction": [ 182 "encrypt", 183 "decrypt" 184 ], 185 "keyLen": [ 186 128, 187 256 188 ] 189 }, { 190 "algorithm": "PBKDF", 191 "revision":"1.0", 192 "capabilities": [{ 193 "iterationCount":[{ 194 "min":1, 195 "max":10000, 196 "increment":1 197 }], 198 "keyLen": [{ 199 "min":112, 200 "max":4096, 201 "increment":8 202 }], 203 "passwordLen":[{ 204 "min":8, 205 "max":64, 206 "increment":1 207 }], 208 "saltLen":[{ 209 "min":128, 210 "max":512, 211 "increment":8 212 }], 213 "hmacAlg":[ 214 "SHA2-224", 215 "SHA2-256", 216 "SHA2-384", 217 "SHA2-512", 218 "SHA2-512/224", 219 "SHA2-512/256", 220 "SHA3-224", 221 "SHA3-256", 222 "SHA3-384", 223 "SHA3-512" 224 ] 225 }] 226 }, { 227 "algorithm": "EDDSA", 228 "mode": "keyVer", 229 "revision": "1.0", 230 "curve": ["ED-25519"] 231 }, { 232 "algorithm": "EDDSA", 233 "mode": "sigVer", 234 "revision": "1.0", 235 "pure": true, 236 "preHash": true, 237 "curve": ["ED-25519"] 238 }, { 239 "algorithm": "SHAKE-128", 240 "inBit": false, 241 "outBit": false, 242 "inEmpty": false, 243 "outputLen": [{ 244 "min": 128, 245 "max": 4096, 246 "increment": 8 247 }], 248 "revision": "1.0" 249 }, { 250 "algorithm": "SHAKE-256", 251 "inBit": false, 252 "outBit": false, 253 "inEmpty": false, 254 "outputLen": [{ 255 "min": 128, 256 "max": 4096, 257 "increment": 8 258 }], 259 "revision": "1.0" 260 } 261]`)); err != nil { 262 return err 263 } 264 265 return flush(nil) 266} 267 268func kdfCounter(args [][]byte) error { 269 if len(args) != 5 { 270 return fmt.Errorf("KDF received %d args", len(args)) 271 } 272 273 outputBytes32, prf, counterLocation, key, counterBits32 := args[0], args[1], args[2], args[3], args[4] 274 outputBytes := binary.LittleEndian.Uint32(outputBytes32) 275 counterBits := binary.LittleEndian.Uint32(counterBits32) 276 277 if !bytes.Equal(prf, []byte("HMAC-SHA2-256")) { 278 return fmt.Errorf("KDF received unsupported PRF %q", string(prf)) 279 } 280 if !bytes.Equal(counterLocation, []byte("before fixed data")) { 281 return fmt.Errorf("KDF received unsupported counter location %q", counterLocation) 282 } 283 if counterBits != 32 { 284 return fmt.Errorf("KDF received unsupported counter length %d", counterBits) 285 } 286 287 if len(key) == 0 { 288 key = make([]byte, 32) 289 rand.Reader.Read(key) 290 } 291 292 // See https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf section 5.1 293 if outputBytes+31 < outputBytes { 294 return fmt.Errorf("KDF received excessive output length %d", outputBytes) 295 } 296 297 n := (outputBytes + 31) / 32 298 result := make([]byte, 0, 32*n) 299 mac := hmac.New(sha256.New, key) 300 var input [4 + 8]byte 301 var digest []byte 302 rand.Reader.Read(input[4:]) 303 for i := uint32(1); i <= n; i++ { 304 mac.Reset() 305 binary.BigEndian.PutUint32(input[:4], i) 306 mac.Write(input[:]) 307 digest = mac.Sum(digest[:0]) 308 result = append(result, digest...) 309 } 310 311 return reply(key, input[4:], result[:outputBytes]) 312} 313 314func reply(responses ...[]byte) error { 315 if len(responses) > maxArgs { 316 return fmt.Errorf("%d responses is too many", len(responses)) 317 } 318 319 var lengths [4 * (1 + maxArgs)]byte 320 binary.LittleEndian.PutUint32(lengths[:4], uint32(len(responses))) 321 for i, response := range responses { 322 binary.LittleEndian.PutUint32(lengths[4*(i+1):4*(i+2)], uint32(len(response))) 323 } 324 325 lengthsLength := (1 + len(responses)) * 4 326 if n, err := output.Write(lengths[:lengthsLength]); n != lengthsLength || err != nil { 327 return fmt.Errorf("write failed: %s", err) 328 } 329 330 for _, response := range responses { 331 if n, err := output.Write(response); n != len(response) || err != nil { 332 return fmt.Errorf("write failed: %s", err) 333 } 334 } 335 336 return nil 337} 338 339func xtsEncrypt(args [][]byte) error { 340 return doXTS(args, false) 341} 342 343func xtsDecrypt(args [][]byte) error { 344 return doXTS(args, true) 345} 346 347func doXTS(args [][]byte, decrypt bool) error { 348 if len(args) != 3 { 349 return fmt.Errorf("XTS received %d args, wanted 3", len(args)) 350 } 351 key := args[0] 352 msg := args[1] 353 tweak := args[2] 354 355 if len(msg)%16 != 0 { 356 return fmt.Errorf("XTS received %d-byte msg, need multiple of 16", len(msg)) 357 } 358 if len(tweak) != 16 { 359 return fmt.Errorf("XTS received %d-byte tweak, wanted 16", len(tweak)) 360 } 361 362 var zeros [8]byte 363 if !bytes.Equal(tweak[8:], zeros[:]) { 364 return errors.New("XTS received tweak with invalid structure. Ensure that configuration specifies a 'number' tweak") 365 } 366 367 sectorNum := binary.LittleEndian.Uint64(tweak[:8]) 368 369 c, err := xts.NewCipher(aes.NewCipher, key) 370 if err != nil { 371 return err 372 } 373 374 if decrypt { 375 c.Decrypt(msg, msg, sectorNum) 376 } else { 377 c.Encrypt(msg, msg, sectorNum) 378 } 379 380 return reply(msg) 381} 382 383func hkdfMAC(args [][]byte) error { 384 if len(args) != 4 { 385 return fmt.Errorf("HKDF received %d args, wanted 4", len(args)) 386 } 387 388 key := args[0] 389 salt := args[1] 390 info := args[2] 391 lengthBytes := args[3] 392 393 if len(lengthBytes) != 4 { 394 return fmt.Errorf("uint32 length was %d bytes long", len(lengthBytes)) 395 } 396 397 length := binary.LittleEndian.Uint32(lengthBytes) 398 399 mac := hkdf.New(sha256.New, key, salt, info) 400 ret := make([]byte, length) 401 mac.Read(ret) 402 403 return reply(ret) 404} 405 406func hmacDRBGReseed(args [][]byte) error { 407 if len(args) != 8 { 408 return fmt.Errorf("hmacDRBG received %d args, wanted 8", len(args)) 409 } 410 411 outLenBytes, entropy, personalisation, reseedAdditionalData, reseedEntropy, additionalData1, additionalData2, nonce := args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7] 412 413 if len(outLenBytes) != 4 { 414 return fmt.Errorf("uint32 length was %d bytes long", len(outLenBytes)) 415 } 416 outLen := binary.LittleEndian.Uint32(outLenBytes) 417 out := make([]byte, outLen) 418 419 drbg := NewHMACDRBG(entropy, nonce, personalisation) 420 drbg.Reseed(reseedEntropy, reseedAdditionalData) 421 drbg.Generate(out, additionalData1) 422 drbg.Generate(out, additionalData2) 423 424 return reply(out) 425} 426 427func hmacDRBGPredictionResistance(args [][]byte) error { 428 if len(args) != 8 { 429 return fmt.Errorf("hmacDRBG received %d args, wanted 8", len(args)) 430 } 431 432 outLenBytes, entropy, personalisation, additionalData1, entropy1, additionalData2, entropy2, nonce := args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7] 433 434 if len(outLenBytes) != 4 { 435 return fmt.Errorf("uint32 length was %d bytes long", len(outLenBytes)) 436 } 437 outLen := binary.LittleEndian.Uint32(outLenBytes) 438 out := make([]byte, outLen) 439 440 drbg := NewHMACDRBG(entropy, nonce, personalisation) 441 drbg.Reseed(entropy1, additionalData1) 442 drbg.Generate(out, nil) 443 drbg.Reseed(entropy2, additionalData2) 444 drbg.Generate(out, nil) 445 446 return reply(out) 447} 448 449func swapFinalTwoAESBlocks(d []byte) { 450 var blockNMinus1 [aes.BlockSize]byte 451 copy(blockNMinus1[:], d[len(d)-2*aes.BlockSize:]) 452 copy(d[len(d)-2*aes.BlockSize:], d[len(d)-aes.BlockSize:]) 453 copy(d[len(d)-aes.BlockSize:], blockNMinus1[:]) 454} 455 456func roundUp(n, m int) int { 457 return n + (m-(n%m))%m 458} 459 460func doCTSEncrypt(key, origPlaintext, iv []byte) []byte { 461 // https://nvlpubs.nist.gov/nistpubs/legacy/sp/nistspecialpublication800-38a-add.pdf 462 if len(origPlaintext) < aes.BlockSize { 463 panic("input too small") 464 } 465 466 plaintext := make([]byte, roundUp(len(origPlaintext), aes.BlockSize)) 467 copy(plaintext, origPlaintext) 468 469 block, err := aes.NewCipher(key) 470 if err != nil { 471 panic(err) 472 } 473 cbcEncryptor := cipher.NewCBCEncrypter(block, iv) 474 cbcEncryptor.CryptBlocks(plaintext, plaintext) 475 ciphertext := plaintext 476 477 if len(origPlaintext) > aes.BlockSize { 478 swapFinalTwoAESBlocks(ciphertext) 479 480 if len(origPlaintext)%16 != 0 { 481 // Truncate the ciphertext 482 ciphertext = ciphertext[:len(ciphertext)-aes.BlockSize+(len(origPlaintext)%aes.BlockSize)] 483 } 484 } 485 486 if len(ciphertext) != len(origPlaintext) { 487 panic("internal error") 488 } 489 490 return ciphertext 491} 492 493func doCTSDecrypt(key, origCiphertext, iv []byte) []byte { 494 if len(origCiphertext) < aes.BlockSize { 495 panic("input too small") 496 } 497 498 ciphertext := make([]byte, roundUp(len(origCiphertext), aes.BlockSize)) 499 copy(ciphertext, origCiphertext) 500 501 if len(ciphertext) > aes.BlockSize { 502 swapFinalTwoAESBlocks(ciphertext) 503 } 504 505 block, err := aes.NewCipher(key) 506 if err != nil { 507 panic(err) 508 } 509 cbcDecrypter := cipher.NewCBCDecrypter(block, iv) 510 511 var plaintext []byte 512 if overhang := len(origCiphertext) % aes.BlockSize; overhang == 0 { 513 cbcDecrypter.CryptBlocks(ciphertext, ciphertext) 514 plaintext = ciphertext 515 } else { 516 ciphertext, finalBlock := ciphertext[:len(ciphertext)-aes.BlockSize], ciphertext[len(ciphertext)-aes.BlockSize:] 517 var plaintextFinalBlock [aes.BlockSize]byte 518 block.Decrypt(plaintextFinalBlock[:], finalBlock) 519 copy(ciphertext[len(ciphertext)-aes.BlockSize+overhang:], plaintextFinalBlock[overhang:]) 520 plaintext = make([]byte, len(origCiphertext)) 521 cbcDecrypter.CryptBlocks(plaintext, ciphertext) 522 for i := 0; i < overhang; i++ { 523 plaintextFinalBlock[i] ^= ciphertext[len(ciphertext)-aes.BlockSize+i] 524 } 525 copy(plaintext[len(ciphertext):], plaintextFinalBlock[:overhang]) 526 } 527 528 return plaintext 529} 530 531func ctsEncrypt(args [][]byte) error { 532 if len(args) != 4 { 533 return fmt.Errorf("ctsEncrypt received %d args, wanted 4", len(args)) 534 } 535 536 key, plaintext, iv, numIterations32 := args[0], args[1], args[2], args[3] 537 if len(numIterations32) != 4 || binary.LittleEndian.Uint32(numIterations32) != 1 { 538 return errors.New("only a single iteration supported for ctsEncrypt") 539 } 540 541 if len(plaintext) < aes.BlockSize { 542 return fmt.Errorf("ctsEncrypt plaintext too short: %d bytes", len(plaintext)) 543 } 544 545 return reply(doCTSEncrypt(key, plaintext, iv)) 546} 547 548func ctsDecrypt(args [][]byte) error { 549 if len(args) != 4 { 550 return fmt.Errorf("ctsDecrypt received %d args, wanted 4", len(args)) 551 } 552 553 key, ciphertext, iv, numIterations32 := args[0], args[1], args[2], args[3] 554 if len(numIterations32) != 4 || binary.LittleEndian.Uint32(numIterations32) != 1 { 555 return errors.New("only a single iteration supported for ctsDecrypt") 556 } 557 558 if len(ciphertext) < aes.BlockSize { 559 return errors.New("ctsDecrypt ciphertext too short") 560 } 561 562 return reply(doCTSDecrypt(key, ciphertext, iv)) 563} 564 565func pbkdf(args [][]byte) error { 566 if len(args) != 5 { 567 return fmt.Errorf("pbkdf received %d args, wanted 5", len(args)) 568 } 569 570 hmacName := args[0] 571 var h func() hash.Hash 572 switch string(hmacName) { 573 case "SHA2-224": 574 h = sha256.New224 575 case "SHA2-256": 576 h = sha256.New 577 case "SHA2-384": 578 h = sha512.New384 579 case "SHA2-512": 580 h = sha512.New 581 case "SHA2-512/224": 582 h = sha512.New512_224 583 case "SHA2-512/256": 584 h = sha512.New512_256 585 case "SHA3-224": 586 h = sha3.New224 587 case "SHA3-256": 588 h = sha3.New256 589 case "SHA3-384": 590 h = sha3.New384 591 case "SHA3-512": 592 h = sha3.New512 593 default: 594 return fmt.Errorf("pbkdf unknown HMAC algorithm: %q", hmacName) 595 } 596 keyLen := binary.LittleEndian.Uint32(args[1]) / 8 597 salt, password := args[2], args[3] 598 iterationCount := binary.LittleEndian.Uint32(args[4]) 599 600 derivedKey := pbkdf2.Key(password, salt, int(iterationCount), int(keyLen), h) 601 602 return reply(derivedKey) 603} 604 605func eddsaKeyGen(args [][]byte) error { 606 if string(args[0]) != "ED-25519" { 607 return fmt.Errorf("unsupported EDDSA curve: %q", args[0]) 608 } 609 610 pk, sk, err := ed25519.GenerateKey(nil) 611 if err != nil { 612 return fmt.Errorf("generating EDDSA keypair: %w", err) 613 } 614 615 // EDDSA/keyGen/AFT responses are d & q, described[0] as: 616 // d The encoded private key point 617 // q The encoded public key point 618 // 619 // Contrary to the description of a "point", d is the private key 620 // seed bytes per FIPS.186-5[1] A.2.3. 621 // 622 // [0]: https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-9.1 623 // [1]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf 624 return reply(sk.Seed(), pk) 625} 626 627func eddsaKeyVer(args [][]byte) error { 628 if string(args[0]) != "ED-25519" { 629 return fmt.Errorf("unsupported EDDSA curve: %q", args[0]) 630 } 631 632 if len(args[1]) != ed25519.PublicKeySize { 633 return reply([]byte{0}) 634 } 635 636 // Verify the point is on the curve. The higher-level ed25519 API does 637 // this at signature verification time so we have to use the lower-level 638 // edwards25519 package to do it here in absence of a signature to verify. 639 if _, err := new(edwards25519.Point).SetBytes(args[1]); err != nil { 640 return reply([]byte{0}) 641 } 642 643 return reply([]byte{1}) 644} 645 646func eddsaSigGen(args [][]byte) error { 647 if string(args[0]) != "ED-25519" { 648 return fmt.Errorf("unsupported EDDSA curve: %q", args[0]) 649 } 650 651 sk := ed25519.NewKeyFromSeed(args[1]) 652 msg := args[2] 653 prehash := args[3] 654 context := string(args[4]) 655 656 var opts ed25519.Options 657 if prehash[0] == 1 { 658 opts.Hash = crypto.SHA512 659 h := sha512.New() 660 h.Write(msg) 661 msg = h.Sum(nil) 662 // With ed25519 the context is only specified for sigGen tests when using prehashing. 663 // See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6 664 opts.Context = context 665 } 666 667 sig, err := sk.Sign(nil, msg, &opts) 668 if err != nil { 669 return fmt.Errorf("error signing message: %w", err) 670 } 671 672 return reply(sig) 673} 674 675func eddsaSigVer(args [][]byte) error { 676 if string(args[0]) != "ED-25519" { 677 return fmt.Errorf("unsupported EDDSA curve: %q", args[0]) 678 } 679 680 msg := args[1] 681 pk := ed25519.PublicKey(args[2]) 682 sig := args[3] 683 prehash := args[4] 684 685 var opts ed25519.Options 686 if prehash[0] == 1 { 687 opts.Hash = crypto.SHA512 688 h := sha512.New() 689 h.Write(msg) 690 msg = h.Sum(nil) 691 // Context is only specified for sigGen, not sigVer. 692 // See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6 693 } 694 695 if err := ed25519.VerifyWithOptions(pk, msg, sig, &opts); err != nil { 696 return reply([]byte{0}) 697 } 698 699 return reply([]byte{1}) 700} 701 702func shakeAftVot(digestFn func() sha3.ShakeHash) func([][]byte) error { 703 return func(args [][]byte) error { 704 if len(args) != 2 { 705 return fmt.Errorf("shakeAftVot received %d args, wanted 2", len(args)) 706 } 707 708 msg := args[0] 709 outLenBytes := binary.LittleEndian.Uint32(args[1]) 710 711 h := digestFn() 712 h.Write(msg) 713 digest := make([]byte, outLenBytes) 714 h.Read(digest) 715 716 return reply(digest) 717 } 718} 719 720func shakeMct(digestFn func() sha3.ShakeHash) func([][]byte) error { 721 return func(args [][]byte) error { 722 if len(args) != 4 { 723 return fmt.Errorf("shakeMct received %d args, wanted 4", len(args)) 724 } 725 726 md := args[0] 727 minOutBytes := binary.LittleEndian.Uint32(args[1]) 728 maxOutBytes := binary.LittleEndian.Uint32(args[2]) 729 730 outputLenBytes := binary.LittleEndian.Uint32(args[3]) 731 if outputLenBytes < 2 { 732 return fmt.Errorf("invalid output length: %d", outputLenBytes) 733 } 734 735 if maxOutBytes < minOutBytes { 736 return fmt.Errorf("invalid maxOutBytes and minOutBytes: %d, %d", maxOutBytes, minOutBytes) 737 } 738 739 rangeBytes := maxOutBytes - minOutBytes + 1 740 741 for i := 0; i < 1000; i++ { 742 // "The MSG[i] input to SHAKE MUST always contain at least 128 bits. If this is not the case 743 // as the previous digest was too short, append empty bits to the rightmost side of the digest." 744 boundary := min(len(md), 16) 745 msg := make([]byte, 16) 746 copy(msg, md[:boundary]) 747 748 // MD[i] = SHAKE(MSG[i], OutputLen * 8) 749 h := digestFn() 750 h.Write(msg) 751 digest := make([]byte, outputLenBytes) 752 h.Read(digest) 753 md = digest 754 755 // RightmostOutputBits = 16 rightmost bits of MD[i] as an integer 756 // OutputLen = minOutBytes + (RightmostOutputBits % Range) 757 rightmostOutput := uint32(md[outputLenBytes-2])<<8 | uint32(md[outputLenBytes-1]) 758 outputLenBytes = minOutBytes + (rightmostOutput % rangeBytes) 759 } 760 761 encodedOutputLenBytes := make([]byte, 4) 762 binary.LittleEndian.PutUint32(encodedOutputLenBytes, outputLenBytes) 763 764 return reply(md, encodedOutputLenBytes) 765 } 766} 767 768const ( 769 maxArgs = 9 770 maxArgLength = 1 << 20 771 maxNameLength = 30 772) 773 774func main() { 775 if err := do(); err != nil { 776 fmt.Fprintf(os.Stderr, "%s.\n", err) 777 os.Exit(1) 778 } 779} 780 781func do() error { 782 // In order to exercise pipelining, all output is buffered until a "flush". 783 outputBuffer = new(bytes.Buffer) 784 output = outputBuffer 785 786 var nums [4 * (1 + maxArgs)]byte 787 var argLengths [maxArgs]uint32 788 var args [maxArgs][]byte 789 var argsData []byte 790 791 for { 792 if _, err := io.ReadFull(os.Stdin, nums[:8]); err != nil { 793 return err 794 } 795 796 numArgs := binary.LittleEndian.Uint32(nums[:4]) 797 if numArgs == 0 { 798 return errors.New("Invalid, zero-argument operation requested") 799 } else if numArgs > maxArgs { 800 return fmt.Errorf("Operation requested with %d args, but %d is the limit", numArgs, maxArgs) 801 } 802 803 if numArgs > 1 { 804 if _, err := io.ReadFull(os.Stdin, nums[8:4+4*numArgs]); err != nil { 805 return err 806 } 807 } 808 809 input := nums[4:] 810 var need uint64 811 for i := uint32(0); i < numArgs; i++ { 812 argLength := binary.LittleEndian.Uint32(input[:4]) 813 if i == 0 && argLength > maxNameLength { 814 return fmt.Errorf("Operation with name of length %d exceeded limit of %d", argLength, maxNameLength) 815 } else if argLength > maxArgLength { 816 return fmt.Errorf("Operation with argument of length %d exceeded limit of %d", argLength, maxArgLength) 817 } 818 need += uint64(argLength) 819 argLengths[i] = argLength 820 input = input[4:] 821 } 822 823 if need > uint64(cap(argsData)) { 824 argsData = make([]byte, need) 825 } else { 826 argsData = argsData[:need] 827 } 828 829 if _, err := io.ReadFull(os.Stdin, argsData); err != nil { 830 return err 831 } 832 833 input = argsData 834 for i := uint32(0); i < numArgs; i++ { 835 args[i] = input[:argLengths[i]] 836 input = input[argLengths[i]:] 837 } 838 839 name := string(args[0]) 840 if handler, ok := handlers[name]; !ok { 841 return fmt.Errorf("unknown operation %q", name) 842 } else { 843 if err := handler(args[1:numArgs]); err != nil { 844 return err 845 } 846 } 847 } 848} 849