1// Copyright (c) 2019, Google Inc. 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 15package subprocess 16 17import ( 18 "encoding/hex" 19 "encoding/json" 20 "fmt" 21) 22 23// aesKeyShuffle is the "AES Monte Carlo Key Shuffle" from the ACVP 24// specification. 25func aesKeyShuffle(key, result, prevResult []byte) { 26 switch len(key) { 27 case 16: 28 for i := range key { 29 key[i] ^= result[i] 30 } 31 case 24: 32 for i := 0; i < 8; i++ { 33 key[i] ^= prevResult[i+8] 34 } 35 for i := range result { 36 key[i+8] ^= result[i] 37 } 38 case 32: 39 for i, b := range prevResult { 40 key[i] ^= b 41 } 42 for i, b := range result { 43 key[i+16] ^= b 44 } 45 default: 46 panic("unhandled key length") 47 } 48} 49 50// iterateAES implements the "AES Monte Carlo Test - ECB mode" from the ACVP 51// specification. 52func iterateAES(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (mctResults []blockCipherMCTResult) { 53 for i := 0; i < 100; i++ { 54 var iteration blockCipherMCTResult 55 iteration.KeyHex = hex.EncodeToString(key) 56 if encrypt { 57 iteration.PlaintextHex = hex.EncodeToString(input) 58 } else { 59 iteration.CiphertextHex = hex.EncodeToString(input) 60 } 61 62 results, err := transact(2, key, input, uint32le(1000)) 63 if err != nil { 64 panic(err) 65 } 66 input = results[0] 67 prevResult := results[1] 68 69 if encrypt { 70 iteration.CiphertextHex = hex.EncodeToString(input) 71 } else { 72 iteration.PlaintextHex = hex.EncodeToString(input) 73 } 74 75 aesKeyShuffle(key, input, prevResult) 76 mctResults = append(mctResults, iteration) 77 } 78 79 return mctResults 80} 81 82// iterateAESCBC implements the "AES Monte Carlo Test - CBC mode" from the ACVP 83// specification. 84func iterateAESCBC(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (mctResults []blockCipherMCTResult) { 85 for i := 0; i < 100; i++ { 86 var iteration blockCipherMCTResult 87 iteration.KeyHex = hex.EncodeToString(key) 88 if encrypt { 89 iteration.PlaintextHex = hex.EncodeToString(input) 90 } else { 91 iteration.CiphertextHex = hex.EncodeToString(input) 92 } 93 94 iteration.IVHex = hex.EncodeToString(iv) 95 96 results, err := transact(2, key, input, iv, uint32le(1000)) 97 if err != nil { 98 panic("block operation failed") 99 } 100 101 result := results[0] 102 prevResult := results[1] 103 104 if encrypt { 105 iteration.CiphertextHex = hex.EncodeToString(result) 106 } else { 107 iteration.PlaintextHex = hex.EncodeToString(result) 108 } 109 110 aesKeyShuffle(key, result, prevResult) 111 112 iv = result 113 input = prevResult 114 115 mctResults = append(mctResults, iteration) 116 } 117 118 return mctResults 119} 120 121// blockCipher implements an ACVP algorithm by making requests to the subprocess 122// to encrypt and decrypt with a block cipher. 123type blockCipher struct { 124 algo string 125 blockSize int 126 // numResults is the number of values returned by the wrapper. The one-shot 127 // tests always take the first value as the result, but the mctFunc may use 128 // them all. 129 numResults int 130 inputsAreBlockMultiples bool 131 hasIV bool 132 mctFunc func(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (result []blockCipherMCTResult) 133} 134 135type blockCipherVectorSet struct { 136 Groups []blockCipherTestGroup `json:"testGroups"` 137} 138 139type blockCipherTestGroup struct { 140 ID uint64 `json:"tgId"` 141 Type string `json:"testType"` 142 Direction string `json:"direction"` 143 KeyBits int `json:"keylen"` 144 Tests []struct { 145 ID uint64 `json:"tcId"` 146 InputBits *uint64 `json:"payloadLen"` 147 PlaintextHex string `json:"pt"` 148 CiphertextHex string `json:"ct"` 149 IVHex string `json:"iv"` 150 KeyHex string `json:"key"` 151 } `json:"tests"` 152} 153 154type blockCipherTestGroupResponse struct { 155 ID uint64 `json:"tgId"` 156 Tests []blockCipherTestResponse `json:"tests"` 157} 158 159type blockCipherTestResponse struct { 160 ID uint64 `json:"tcId"` 161 CiphertextHex string `json:"ct,omitempty"` 162 PlaintextHex string `json:"pt,omitempty"` 163 MCTResults []blockCipherMCTResult `json:"resultsArray,omitempty"` 164} 165 166type blockCipherMCTResult struct { 167 KeyHex string `json:"key,omitempty"` 168 PlaintextHex string `json:"pt"` 169 CiphertextHex string `json:"ct"` 170 IVHex string `json:"iv,omitempty"` 171} 172 173func (b *blockCipher) Process(vectorSet []byte, m Transactable) (interface{}, error) { 174 var parsed blockCipherVectorSet 175 if err := json.Unmarshal(vectorSet, &parsed); err != nil { 176 return nil, err 177 } 178 179 var ret []blockCipherTestGroupResponse 180 // See 181 // http://usnistgov.github.io/ACVP/artifacts/draft-celi-acvp-block-ciph-00.html#rfc.section.5.2 182 // for details about the tests. 183 for _, group := range parsed.Groups { 184 response := blockCipherTestGroupResponse{ 185 ID: group.ID, 186 } 187 188 var encrypt bool 189 switch group.Direction { 190 case "encrypt": 191 encrypt = true 192 case "decrypt": 193 encrypt = false 194 default: 195 return nil, fmt.Errorf("test group %d has unknown direction %q", group.ID, group.Direction) 196 } 197 198 op := b.algo + "/encrypt" 199 if !encrypt { 200 op = b.algo + "/decrypt" 201 } 202 203 var mct bool 204 switch group.Type { 205 case "AFT", "CTR": 206 mct = false 207 case "MCT": 208 if b.mctFunc == nil { 209 return nil, fmt.Errorf("test group %d has type MCT which is unsupported for %q", group.ID, op) 210 } 211 mct = true 212 default: 213 return nil, fmt.Errorf("test group %d has unknown type %q", group.ID, group.Type) 214 } 215 216 if group.KeyBits%8 != 0 { 217 return nil, fmt.Errorf("test group %d contains non-byte-multiple key length %d", group.ID, group.KeyBits) 218 } 219 keyBytes := group.KeyBits / 8 220 221 transact := func(n int, args ...[]byte) ([][]byte, error) { 222 return m.Transact(op, n, args...) 223 } 224 225 for _, test := range group.Tests { 226 if len(test.KeyHex) != keyBytes*2 { 227 return nil, fmt.Errorf("test case %d/%d contains key %q of length %d, but expected %d-bit key", group.ID, test.ID, test.KeyHex, len(test.KeyHex), group.KeyBits) 228 } 229 230 key, err := hex.DecodeString(test.KeyHex) 231 if err != nil { 232 return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) 233 } 234 235 var inputHex string 236 if encrypt { 237 inputHex = test.PlaintextHex 238 } else { 239 inputHex = test.CiphertextHex 240 } 241 242 if test.InputBits != nil { 243 if *test.InputBits%8 != 0 { 244 return nil, fmt.Errorf("input to test case %d/%d is not a whole number of bytes", group.ID, test.ID) 245 } 246 if inputBits := 4 * uint64(len(inputHex)); *test.InputBits != inputBits { 247 return nil, fmt.Errorf("input to test case %d/%d is %q (%d bits), but %d bits is specified", group.ID, test.ID, inputHex, inputBits, *test.InputBits) 248 } 249 } 250 251 input, err := hex.DecodeString(inputHex) 252 if err != nil { 253 return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) 254 } 255 256 if b.inputsAreBlockMultiples && len(input)%b.blockSize != 0 { 257 return nil, fmt.Errorf("test case %d/%d has input of length %d, but expected multiple of %d", group.ID, test.ID, len(input), b.blockSize) 258 } 259 260 var iv []byte 261 if b.hasIV { 262 if iv, err = hex.DecodeString(test.IVHex); err != nil { 263 return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) 264 } 265 if len(iv) != b.blockSize { 266 return nil, fmt.Errorf("test case %d/%d has IV of length %d, but expected %d", group.ID, test.ID, len(iv), b.blockSize) 267 } 268 } 269 270 testResp := blockCipherTestResponse{ID: test.ID} 271 if !mct { 272 var result [][]byte 273 var err error 274 275 if b.hasIV { 276 result, err = m.Transact(op, b.numResults, key, input, iv, uint32le(1)) 277 } else { 278 result, err = m.Transact(op, b.numResults, key, input, uint32le(1)) 279 } 280 if err != nil { 281 panic("block operation failed: " + err.Error()) 282 } 283 284 if encrypt { 285 testResp.CiphertextHex = hex.EncodeToString(result[0]) 286 } else { 287 testResp.PlaintextHex = hex.EncodeToString(result[0]) 288 } 289 } else { 290 testResp.MCTResults = b.mctFunc(transact, encrypt, key, input, iv) 291 } 292 293 response.Tests = append(response.Tests, testResp) 294 } 295 296 ret = append(ret, response) 297 } 298 299 return ret, nil 300} 301