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