Mirror of BoringSSL (grpc依赖)
https://boringssl.googlesource.com/boringssl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
6.1 KiB
267 lines
6.1 KiB
// testmodulewrapper is a modulewrapper binary that works with acvptool and |
|
// implements the primitives that BoringSSL's modulewrapper doesn't, so that |
|
// we have something that can exercise all the code in avcptool. |
|
|
|
package main |
|
|
|
import ( |
|
"bytes" |
|
"crypto/aes" |
|
"crypto/hmac" |
|
"crypto/rand" |
|
"crypto/sha256" |
|
"encoding/binary" |
|
"errors" |
|
"fmt" |
|
"io" |
|
"os" |
|
|
|
"golang.org/x/crypto/xts" |
|
) |
|
|
|
var handlers = map[string]func([][]byte) error{ |
|
"getConfig": getConfig, |
|
"KDF-counter": kdfCounter, |
|
"AES-XTS/encrypt": xtsEncrypt, |
|
"AES-XTS/decrypt": xtsDecrypt, |
|
} |
|
|
|
func getConfig(args [][]byte) error { |
|
if len(args) != 0 { |
|
return fmt.Errorf("getConfig received %d args", len(args)) |
|
} |
|
|
|
return reply([]byte(`[ |
|
{ |
|
"algorithm": "KDF", |
|
"revision": "1.0", |
|
"capabilities": [{ |
|
"kdfMode": "counter", |
|
"macMode": [ |
|
"HMAC-SHA2-256" |
|
], |
|
"supportedLengths": [{ |
|
"min": 8, |
|
"max": 4096, |
|
"increment": 8 |
|
}], |
|
"fixedDataOrder": [ |
|
"before fixed data" |
|
], |
|
"counterLength": [ |
|
32 |
|
] |
|
}] |
|
}, { |
|
"algorithm": "ACVP-AES-XTS", |
|
"revision": "1.0", |
|
"direction": [ |
|
"encrypt", |
|
"decrypt" |
|
], |
|
"keyLen": [ |
|
128, |
|
256 |
|
], |
|
"payloadLen": [ |
|
1024 |
|
], |
|
"tweakMode": [ |
|
"number" |
|
] |
|
} |
|
]`)) |
|
} |
|
|
|
func kdfCounter(args [][]byte) error { |
|
if len(args) != 5 { |
|
return fmt.Errorf("KDF received %d args", len(args)) |
|
} |
|
|
|
outputBytes32, prf, counterLocation, key, counterBits32 := args[0], args[1], args[2], args[3], args[4] |
|
outputBytes := binary.LittleEndian.Uint32(outputBytes32) |
|
counterBits := binary.LittleEndian.Uint32(counterBits32) |
|
|
|
if !bytes.Equal(prf, []byte("HMAC-SHA2-256")) { |
|
return fmt.Errorf("KDF received unsupported PRF %q", string(prf)) |
|
} |
|
if !bytes.Equal(counterLocation, []byte("before fixed data")) { |
|
return fmt.Errorf("KDF received unsupported counter location %q", counterLocation) |
|
} |
|
if counterBits != 32 { |
|
return fmt.Errorf("KDF received unsupported counter length %d", counterBits) |
|
} |
|
|
|
if len(key) == 0 { |
|
key = make([]byte, 32) |
|
rand.Reader.Read(key) |
|
} |
|
|
|
// See https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf section 5.1 |
|
if outputBytes+31 < outputBytes { |
|
return fmt.Errorf("KDF received excessive output length %d", outputBytes) |
|
} |
|
|
|
n := (outputBytes + 31) / 32 |
|
result := make([]byte, 0, 32*n) |
|
mac := hmac.New(sha256.New, key) |
|
var input [4 + 8]byte |
|
var digest []byte |
|
rand.Reader.Read(input[4:]) |
|
for i := uint32(1); i <= n; i++ { |
|
mac.Reset() |
|
binary.BigEndian.PutUint32(input[:4], i) |
|
mac.Write(input[:]) |
|
digest = mac.Sum(digest[:0]) |
|
result = append(result, digest...) |
|
} |
|
|
|
return reply(key, input[4:], result[:outputBytes]) |
|
} |
|
|
|
func reply(responses ...[]byte) error { |
|
if len(responses) > maxArgs { |
|
return fmt.Errorf("%d responses is too many", len(responses)) |
|
} |
|
|
|
var lengths [4 * (1 + maxArgs)]byte |
|
binary.LittleEndian.PutUint32(lengths[:4], uint32(len(responses))) |
|
for i, response := range responses { |
|
binary.LittleEndian.PutUint32(lengths[4*(i+1):4*(i+2)], uint32(len(response))) |
|
} |
|
|
|
lengthsLength := (1 + len(responses)) * 4 |
|
if n, err := os.Stdout.Write(lengths[:lengthsLength]); n != lengthsLength || err != nil { |
|
return fmt.Errorf("write failed: %s", err) |
|
} |
|
|
|
for _, response := range responses { |
|
if n, err := os.Stdout.Write(response); n != len(response) || err != nil { |
|
return fmt.Errorf("write failed: %s", err) |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func xtsEncrypt(args [][]byte) error { |
|
return doXTS(args, false) |
|
} |
|
|
|
func xtsDecrypt(args [][]byte) error { |
|
return doXTS(args, true) |
|
} |
|
|
|
func doXTS(args [][]byte, decrypt bool) error { |
|
if len(args) != 3 { |
|
return fmt.Errorf("XTS received %d args, wanted 3", len(args)) |
|
} |
|
key := args[0] |
|
msg := args[1] |
|
tweak := args[2] |
|
|
|
if len(msg)%16 != 0 { |
|
return fmt.Errorf("XTS received %d-byte msg, need multiple of 16", len(msg)) |
|
} |
|
if len(tweak) != 16 { |
|
return fmt.Errorf("XTS received %d-byte tweak, wanted 16", len(tweak)) |
|
} |
|
|
|
var zeros [8]byte |
|
if !bytes.Equal(tweak[8:], zeros[:]) { |
|
return errors.New("XTS received tweak with invalid structure. Ensure that configuration specifies a 'number' tweak") |
|
} |
|
|
|
sectorNum := binary.LittleEndian.Uint64(tweak[:8]) |
|
|
|
c, err := xts.NewCipher(aes.NewCipher, key) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
if decrypt { |
|
c.Decrypt(msg, msg, sectorNum) |
|
} else { |
|
c.Encrypt(msg, msg, sectorNum) |
|
} |
|
|
|
return reply(msg) |
|
} |
|
|
|
const ( |
|
maxArgs = 8 |
|
maxArgLength = 1 << 20 |
|
maxNameLength = 30 |
|
) |
|
|
|
func main() { |
|
if err := do(); err != nil { |
|
fmt.Fprintf(os.Stderr, "%s.\n", err) |
|
os.Exit(1) |
|
} |
|
} |
|
|
|
func do() error { |
|
var nums [4 * (1 + maxArgs)]byte |
|
var argLengths [maxArgs]uint32 |
|
var args [maxArgs][]byte |
|
var argsData []byte |
|
|
|
for { |
|
if _, err := io.ReadFull(os.Stdin, nums[:8]); err != nil { |
|
return err |
|
} |
|
|
|
numArgs := binary.LittleEndian.Uint32(nums[:4]) |
|
if numArgs == 0 { |
|
return errors.New("Invalid, zero-argument operation requested") |
|
} else if numArgs > maxArgs { |
|
return fmt.Errorf("Operation requested with %d args, but %d is the limit", numArgs, maxArgs) |
|
} |
|
|
|
if numArgs > 1 { |
|
if _, err := io.ReadFull(os.Stdin, nums[8:4+4*numArgs]); err != nil { |
|
return err |
|
} |
|
} |
|
|
|
input := nums[4:] |
|
var need uint64 |
|
for i := uint32(0); i < numArgs; i++ { |
|
argLength := binary.LittleEndian.Uint32(input[:4]) |
|
if i == 0 && argLength > maxNameLength { |
|
return fmt.Errorf("Operation with name of length %d exceeded limit of %d", argLength, maxNameLength) |
|
} else if argLength > maxArgLength { |
|
return fmt.Errorf("Operation with argument of length %d exceeded limit of %d", argLength, maxArgLength) |
|
} |
|
need += uint64(argLength) |
|
argLengths[i] = argLength |
|
input = input[4:] |
|
} |
|
|
|
if need > uint64(cap(argsData)) { |
|
argsData = make([]byte, need) |
|
} else { |
|
argsData = argsData[:need] |
|
} |
|
|
|
if _, err := io.ReadFull(os.Stdin, argsData); err != nil { |
|
return err |
|
} |
|
|
|
input = argsData |
|
for i := uint32(0); i < numArgs; i++ { |
|
args[i] = input[:argLengths[i]] |
|
input = input[argLengths[i]:] |
|
} |
|
|
|
name := string(args[0]) |
|
if handler, ok := handlers[name]; !ok { |
|
return fmt.Errorf("unknown operation %q", name) |
|
} else { |
|
if err := handler(args[1:numArgs]); err != nil { |
|
return err |
|
} |
|
} |
|
} |
|
}
|
|
|