1// Copyright 2021 The BoringSSL Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package subprocess 16 17import ( 18 "encoding/binary" 19 "encoding/hex" 20 "encoding/json" 21 "fmt" 22) 23 24// The following structures reflect the JSON of ACVP XTS tests. See 25// https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html 26 27type xtsTestVectorSet struct { 28 Groups []xtsTestGroup `json:"testGroups"` 29} 30 31type xtsTestGroup struct { 32 ID uint64 `json:"tgId"` 33 Type string `json:"testType"` 34 Direction string `json:"direction"` 35 KeyLen int `json:"keyLen"` 36 PayloadLen int `json:"payloadLen"` 37 Tests []struct { 38 ID uint64 `json:"tcId"` 39 KeyHex string `json:"key"` 40 PlaintextHex string `json:"pt"` 41 CiphertextHex string `json:"ct"` 42 SectorNum *uint64 `json:"sequenceNumber"` 43 TweakHex *string `json:"tweakValue"` 44 } `json:"tests"` 45} 46 47type xtsTestGroupResponse struct { 48 ID uint64 `json:"tgId"` 49 Tests []xtsTestResponse `json:"tests"` 50} 51 52type xtsTestResponse struct { 53 ID uint64 `json:"tcId"` 54 PlaintextHex string `json:"pt,omitempty"` 55 CiphertextHex string `json:"ct,omitempty"` 56} 57 58// xts implements an ACVP algorithm by making requests to the subprocess to 59// encrypt/decrypt with AES-XTS. 60type xts struct{} 61 62func (h *xts) Process(vectorSet []byte, m Transactable) (any, error) { 63 var parsed xtsTestVectorSet 64 if err := json.Unmarshal(vectorSet, &parsed); err != nil { 65 return nil, err 66 } 67 68 var ret []xtsTestGroupResponse 69 for _, group := range parsed.Groups { 70 group := group 71 response := xtsTestGroupResponse{ 72 ID: group.ID, 73 } 74 75 if group.Type != "AFT" { 76 return nil, fmt.Errorf("unknown XTS test type %q", group.Type) 77 } 78 79 var decrypt bool 80 switch group.Direction { 81 case "encrypt": 82 decrypt = false 83 case "decrypt": 84 decrypt = true 85 default: 86 return nil, fmt.Errorf("unknown XTS direction %q", group.Direction) 87 } 88 89 funcName := "AES-XTS/" + group.Direction 90 91 for _, test := range group.Tests { 92 test := test 93 if group.KeyLen != len(test.KeyHex)*4/2 { 94 return nil, fmt.Errorf("test case %d/%d contains hex message of length %d but specifies a key length of %d (remember that XTS keys are twice the length of the underlying key size)", group.ID, test.ID, len(test.KeyHex), group.KeyLen) 95 } 96 key, err := hex.DecodeString(test.KeyHex) 97 if err != nil { 98 return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) 99 } 100 101 var tweak [16]byte 102 if test.TweakHex != nil { 103 t, err := hex.DecodeString(*test.TweakHex) 104 if err != nil { 105 return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) 106 } 107 if len(t) != len(tweak) { 108 return nil, fmt.Errorf("wrong tweak length (%d bytes) in test case %d/%d", len(t), group.ID, test.ID) 109 } 110 copy(tweak[:], t) 111 } else if test.SectorNum != nil { 112 // Sector numbers (or "sequence numbers", as NIST calls them) are turned 113 // into tweak values by encoding them in little-endian form. See IEEE 114 // 1619-2007, section 5.1. 115 binary.LittleEndian.PutUint64(tweak[:8], *test.SectorNum) 116 } else { 117 return nil, fmt.Errorf("neither sector number nor explicit tweak in test case %d/%d", group.ID, test.ID) 118 } 119 120 var msg []byte 121 if decrypt { 122 msg, err = hex.DecodeString(test.CiphertextHex) 123 } else { 124 msg, err = hex.DecodeString(test.PlaintextHex) 125 } 126 127 if err != nil { 128 return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) 129 } 130 131 m.TransactAsync(funcName, 1, [][]byte{key, msg, tweak[:]}, func(result [][]byte) error { 132 testResponse := xtsTestResponse{ID: test.ID} 133 if decrypt { 134 testResponse.PlaintextHex = hex.EncodeToString(result[0]) 135 } else { 136 testResponse.CiphertextHex = hex.EncodeToString(result[0]) 137 } 138 139 response.Tests = append(response.Tests, testResponse) 140 return nil 141 }) 142 } 143 144 m.Barrier(func() { 145 ret = append(ret, response) 146 }) 147 } 148 149 if err := m.Flush(); err != nil { 150 return nil, err 151 } 152 153 return ret, nil 154} 155