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 "math/bits" 22) 23 24// aesKeyShuffle is the "AES Monte Carlo Key Shuffle" from the ACVP 25// specification. 26func aesKeyShuffle(key, result, prevResult []byte) { 27 switch len(key) { 28 case 16: 29 for i := range key { 30 key[i] ^= result[i] 31 } 32 case 24: 33 for i := 0; i < 8; i++ { 34 key[i] ^= prevResult[i+8] 35 } 36 for i := range result { 37 key[i+8] ^= result[i] 38 } 39 case 32: 40 for i, b := range prevResult { 41 key[i] ^= b 42 } 43 for i, b := range result { 44 key[i+16] ^= b 45 } 46 default: 47 panic("unhandled key length") 48 } 49} 50 51// iterateAES implements the "AES Monte Carlo Test - ECB mode" from the ACVP 52// specification. 53func iterateAES(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (mctResults []blockCipherMCTResult) { 54 for i := 0; i < 100; i++ { 55 var iteration blockCipherMCTResult 56 iteration.KeyHex = hex.EncodeToString(key) 57 if encrypt { 58 iteration.PlaintextHex = hex.EncodeToString(input) 59 } else { 60 iteration.CiphertextHex = hex.EncodeToString(input) 61 } 62 63 results, err := transact(2, key, input, uint32le(1000)) 64 if err != nil { 65 panic(err) 66 } 67 input = results[0] 68 prevResult := results[1] 69 70 if encrypt { 71 iteration.CiphertextHex = hex.EncodeToString(input) 72 } else { 73 iteration.PlaintextHex = hex.EncodeToString(input) 74 } 75 76 aesKeyShuffle(key, input, prevResult) 77 mctResults = append(mctResults, iteration) 78 } 79 80 return mctResults 81} 82 83// iterateAESCBC implements the "AES Monte Carlo Test - CBC mode" from the ACVP 84// specification. 85func iterateAESCBC(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (mctResults []blockCipherMCTResult) { 86 for i := 0; i < 100; i++ { 87 var iteration blockCipherMCTResult 88 iteration.KeyHex = hex.EncodeToString(key) 89 if encrypt { 90 iteration.PlaintextHex = hex.EncodeToString(input) 91 } else { 92 iteration.CiphertextHex = hex.EncodeToString(input) 93 } 94 95 iteration.IVHex = hex.EncodeToString(iv) 96 97 results, err := transact(2, key, input, iv, uint32le(1000)) 98 if err != nil { 99 panic("block operation failed") 100 } 101 102 result := results[0] 103 prevResult := results[1] 104 105 if encrypt { 106 iteration.CiphertextHex = hex.EncodeToString(result) 107 } else { 108 iteration.PlaintextHex = hex.EncodeToString(result) 109 } 110 111 aesKeyShuffle(key, result, prevResult) 112 113 iv = result 114 input = prevResult 115 116 mctResults = append(mctResults, iteration) 117 } 118 119 return mctResults 120} 121 122// xorKeyWithOddParityLSB XORs value into key while setting the LSB of each bit 123// to establish odd parity. This embedding of a parity check in a DES key is an 124// old tradition and something that NIST's tests require (despite being 125// undocumented). 126func xorKeyWithOddParityLSB(key, value []byte) { 127 for i := range key { 128 v := key[i] ^ value[i] 129 // Use LSB to establish odd parity. 130 v ^= byte((bits.OnesCount8(v) & 1)) ^ 1 131 key[i] = v 132 } 133} 134 135// desKeyShuffle implements the manipulation of the Key arrays in the "TDES 136// Monte Carlo Test - ECB mode" algorithm from the ACVP specification. 137func keyShuffle3DES(key, result, prevResult, prevPrevResult []byte) { 138 xorKeyWithOddParityLSB(key[:8], result) 139 xorKeyWithOddParityLSB(key[8:16], prevResult) 140 xorKeyWithOddParityLSB(key[16:], prevPrevResult) 141} 142 143// iterate3DES implements "TDES Monte Carlo Test - ECB mode" from the ACVP 144// specification. 145func iterate3DES(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (mctResults []blockCipherMCTResult) { 146 for i := 0; i < 400; i++ { 147 var iteration blockCipherMCTResult 148 keyHex := hex.EncodeToString(key) 149 iteration.Key1Hex = keyHex[:16] 150 iteration.Key2Hex = keyHex[16:32] 151 iteration.Key3Hex = keyHex[32:] 152 153 if encrypt { 154 iteration.PlaintextHex = hex.EncodeToString(input) 155 } else { 156 iteration.CiphertextHex = hex.EncodeToString(input) 157 } 158 159 results, err := transact(3, key, input, uint32le(10000)) 160 if err != nil { 161 panic("block operation failed") 162 } 163 result := results[0] 164 prevResult := results[1] 165 prevPrevResult := results[2] 166 167 if encrypt { 168 iteration.CiphertextHex = hex.EncodeToString(result) 169 } else { 170 iteration.PlaintextHex = hex.EncodeToString(result) 171 } 172 173 keyShuffle3DES(key, result, prevResult, prevPrevResult) 174 mctResults = append(mctResults, iteration) 175 input = result 176 } 177 178 return mctResults 179} 180 181// iterate3DESCBC implements "TDES Monte Carlo Test - CBC mode" from the ACVP 182// specification. 183func iterate3DESCBC(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (mctResults []blockCipherMCTResult) { 184 for i := 0; i < 400; i++ { 185 var iteration blockCipherMCTResult 186 keyHex := hex.EncodeToString(key) 187 iteration.Key1Hex = keyHex[:16] 188 iteration.Key2Hex = keyHex[16:32] 189 iteration.Key3Hex = keyHex[32:] 190 191 if encrypt { 192 iteration.PlaintextHex = hex.EncodeToString(input) 193 } else { 194 iteration.CiphertextHex = hex.EncodeToString(input) 195 } 196 iteration.IVHex = hex.EncodeToString(iv) 197 198 results, err := transact(3, key, input, iv, uint32le(10000)) 199 if err != nil { 200 panic("block operation failed") 201 } 202 203 result := results[0] 204 prevResult := results[1] 205 prevPrevResult := results[2] 206 207 if encrypt { 208 iteration.CiphertextHex = hex.EncodeToString(result) 209 } else { 210 iteration.PlaintextHex = hex.EncodeToString(result) 211 } 212 213 keyShuffle3DES(key, result, prevResult, prevPrevResult) 214 215 if encrypt { 216 input = prevResult 217 iv = result 218 } else { 219 iv = prevResult 220 input = result 221 } 222 223 mctResults = append(mctResults, iteration) 224 } 225 226 return mctResults 227} 228 229// blockCipher implements an ACVP algorithm by making requests to the subprocess 230// to encrypt and decrypt with a block cipher. 231type blockCipher struct { 232 algo string 233 blockSize int 234 // numResults is the number of values returned by the wrapper. The one-shot 235 // tests always take the first value as the result, but the mctFunc may use 236 // them all. 237 numResults int 238 inputsAreBlockMultiples bool 239 hasIV bool 240 mctFunc func(transact func(n int, args ...[]byte) ([][]byte, error), encrypt bool, key, input, iv []byte) (result []blockCipherMCTResult) 241} 242 243type blockCipherVectorSet struct { 244 Groups []blockCipherTestGroup `json:"testGroups"` 245} 246 247type blockCipherTestGroup struct { 248 ID uint64 `json:"tgId"` 249 Type string `json:"testType"` 250 Direction string `json:"direction"` 251 KeyBits int `json:"keylen"` 252 Tests []struct { 253 ID uint64 `json:"tcId"` 254 InputBits *uint64 `json:"payloadLen"` 255 PlaintextHex string `json:"pt"` 256 CiphertextHex string `json:"ct"` 257 IVHex string `json:"iv"` 258 KeyHex string `json:"key"` 259 260 // 3DES tests serialise the key differently. 261 Key1Hex string `json:"key1"` 262 Key2Hex string `json:"key2"` 263 Key3Hex string `json:"key3"` 264 } `json:"tests"` 265} 266 267type blockCipherTestGroupResponse struct { 268 ID uint64 `json:"tgId"` 269 Tests []blockCipherTestResponse `json:"tests"` 270} 271 272type blockCipherTestResponse struct { 273 ID uint64 `json:"tcId"` 274 CiphertextHex string `json:"ct,omitempty"` 275 PlaintextHex string `json:"pt,omitempty"` 276 MCTResults []blockCipherMCTResult `json:"resultsArray,omitempty"` 277} 278 279type blockCipherMCTResult struct { 280 KeyHex string `json:"key,omitempty"` 281 PlaintextHex string `json:"pt"` 282 CiphertextHex string `json:"ct"` 283 IVHex string `json:"iv,omitempty"` 284 285 // 3DES tests serialise the key differently. 286 Key1Hex string `json:"key1,omitempty"` 287 Key2Hex string `json:"key2,omitempty"` 288 Key3Hex string `json:"key3,omitempty"` 289} 290 291func (b *blockCipher) Process(vectorSet []byte, m Transactable) (interface{}, error) { 292 var parsed blockCipherVectorSet 293 if err := json.Unmarshal(vectorSet, &parsed); err != nil { 294 return nil, err 295 } 296 297 var ret []blockCipherTestGroupResponse 298 // See 299 // http://usnistgov.github.io/ACVP/artifacts/draft-celi-acvp-block-ciph-00.html#rfc.section.5.2 300 // for details about the tests. 301 for _, group := range parsed.Groups { 302 response := blockCipherTestGroupResponse{ 303 ID: group.ID, 304 } 305 306 var encrypt bool 307 switch group.Direction { 308 case "encrypt": 309 encrypt = true 310 case "decrypt": 311 encrypt = false 312 default: 313 return nil, fmt.Errorf("test group %d has unknown direction %q", group.ID, group.Direction) 314 } 315 316 op := b.algo + "/encrypt" 317 if !encrypt { 318 op = b.algo + "/decrypt" 319 } 320 321 var mct bool 322 switch group.Type { 323 case "AFT", "CTR": 324 mct = false 325 case "MCT": 326 if b.mctFunc == nil { 327 return nil, fmt.Errorf("test group %d has type MCT which is unsupported for %q", group.ID, op) 328 } 329 mct = true 330 default: 331 return nil, fmt.Errorf("test group %d has unknown type %q", group.ID, group.Type) 332 } 333 334 if group.KeyBits == 0 { 335 // 3DES tests fail to set this parameter. 336 group.KeyBits = 192 337 } 338 339 if group.KeyBits%8 != 0 { 340 return nil, fmt.Errorf("test group %d contains non-byte-multiple key length %d", group.ID, group.KeyBits) 341 } 342 keyBytes := group.KeyBits / 8 343 344 transact := func(n int, args ...[]byte) ([][]byte, error) { 345 return m.Transact(op, n, args...) 346 } 347 348 for _, test := range group.Tests { 349 if len(test.KeyHex) == 0 && len(test.Key1Hex) > 0 { 350 // 3DES encodes the key differently. 351 test.KeyHex = test.Key1Hex + test.Key2Hex + test.Key3Hex 352 } 353 354 if len(test.KeyHex) != keyBytes*2 { 355 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) 356 } 357 358 key, err := hex.DecodeString(test.KeyHex) 359 if err != nil { 360 return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) 361 } 362 363 var inputHex string 364 if encrypt { 365 inputHex = test.PlaintextHex 366 } else { 367 inputHex = test.CiphertextHex 368 } 369 370 if test.InputBits != nil { 371 if *test.InputBits%8 != 0 { 372 return nil, fmt.Errorf("input to test case %d/%d is not a whole number of bytes", group.ID, test.ID) 373 } 374 if inputBits := 4 * uint64(len(inputHex)); *test.InputBits != inputBits { 375 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) 376 } 377 } 378 379 input, err := hex.DecodeString(inputHex) 380 if err != nil { 381 return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) 382 } 383 384 if b.inputsAreBlockMultiples && len(input)%b.blockSize != 0 { 385 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) 386 } 387 388 var iv []byte 389 if b.hasIV { 390 if iv, err = hex.DecodeString(test.IVHex); err != nil { 391 return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) 392 } 393 if len(iv) != b.blockSize { 394 return nil, fmt.Errorf("test case %d/%d has IV of length %d, but expected %d", group.ID, test.ID, len(iv), b.blockSize) 395 } 396 } 397 398 testResp := blockCipherTestResponse{ID: test.ID} 399 if !mct { 400 var result [][]byte 401 var err error 402 403 if b.hasIV { 404 result, err = m.Transact(op, b.numResults, key, input, iv, uint32le(1)) 405 } else { 406 result, err = m.Transact(op, b.numResults, key, input, uint32le(1)) 407 } 408 if err != nil { 409 panic("block operation failed: " + err.Error()) 410 } 411 412 if encrypt { 413 testResp.CiphertextHex = hex.EncodeToString(result[0]) 414 } else { 415 testResp.PlaintextHex = hex.EncodeToString(result[0]) 416 } 417 } else { 418 testResp.MCTResults = b.mctFunc(transact, encrypt, key, input, iv) 419 } 420 421 response.Tests = append(response.Tests, testResp) 422 } 423 424 ret = append(ret, response) 425 } 426 427 return ret, nil 428} 429