• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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