• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1package subprocess
2
3import (
4	"encoding/hex"
5	"encoding/json"
6	"fmt"
7)
8
9// blockCipher implements an ACVP algorithm by making requests to the subprocess
10// to encrypt and decrypt with a block cipher.
11type blockCipher struct {
12	algo      string
13	blockSize int
14	hasIV     bool
15	m         *Subprocess
16}
17
18type blockCipherVectorSet struct {
19	Groups []blockCipherTestGroup `json:"testGroups"`
20}
21
22type blockCipherTestGroup struct {
23	ID        uint64 `json:"tgId"`
24	Type      string `json:"testType"`
25	Direction string `json:"direction"`
26	KeyBits   int    `json:"keylen"`
27	Tests     []struct {
28		ID            uint64 `json:"tcId"`
29		PlaintextHex  string `json:"pt"`
30		CiphertextHex string `json:"ct"`
31		IVHex         string `json:"iv"`
32		KeyHex        string `json:"key"`
33	} `json:"tests"`
34}
35
36type blockCipherTestGroupResponse struct {
37	ID    uint64                    `json:"tgId"`
38	Tests []blockCipherTestResponse `json:"tests"`
39}
40
41type blockCipherTestResponse struct {
42	ID            uint64                 `json:"tcId"`
43	CiphertextHex string                 `json:"ct,omitempty"`
44	PlaintextHex  string                 `json:"pt,omitempty"`
45	MCTResults    []blockCipherMCTResult `json:"resultsArray,omitempty"`
46}
47
48type blockCipherMCTResult struct {
49	KeyHex        string `json:"key"`
50	PlaintextHex  string `json:"pt"`
51	CiphertextHex string `json:"ct"`
52	IVHex         string `json:"iv,omitempty"`
53}
54
55func (b *blockCipher) Process(vectorSet []byte) (interface{}, error) {
56	var parsed blockCipherVectorSet
57	if err := json.Unmarshal(vectorSet, &parsed); err != nil {
58		return nil, err
59	}
60
61	var ret []blockCipherTestGroupResponse
62	// See
63	// http://usnistgov.github.io/ACVP/artifacts/draft-celi-acvp-block-ciph-00.html#rfc.section.5.2
64	// for details about the tests.
65	for _, group := range parsed.Groups {
66		response := blockCipherTestGroupResponse{
67			ID: group.ID,
68		}
69
70		var encrypt bool
71		switch group.Direction {
72		case "encrypt":
73			encrypt = true
74		case "decrypt":
75			encrypt = false
76		default:
77			return nil, fmt.Errorf("test group %d has unknown direction %q", group.ID, group.Direction)
78		}
79
80		op := b.algo + "/encrypt"
81		if !encrypt {
82			op = b.algo + "/decrypt"
83		}
84
85		var mct bool
86		switch group.Type {
87		case "AFT":
88			mct = false
89		case "MCT":
90			mct = true
91		default:
92			return nil, fmt.Errorf("test group %d has unknown type %q", group.ID, group.Type)
93		}
94
95		if group.KeyBits%8 != 0 {
96			return nil, fmt.Errorf("test group %d contains non-byte-multiple key length %d", group.ID, group.KeyBits)
97		}
98		keyBytes := group.KeyBits / 8
99
100		for _, test := range group.Tests {
101			if len(test.KeyHex) != keyBytes*2 {
102				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)
103			}
104
105			key, err := hex.DecodeString(test.KeyHex)
106			if err != nil {
107				return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err)
108			}
109
110			var inputHex string
111			if encrypt {
112				inputHex = test.PlaintextHex
113			} else {
114				inputHex = test.CiphertextHex
115			}
116
117			input, err := hex.DecodeString(inputHex)
118			if err != nil {
119				return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err)
120			}
121
122			if len(input)%b.blockSize != 0 {
123				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)
124			}
125
126			var iv []byte
127			if b.hasIV {
128				if iv, err = hex.DecodeString(test.IVHex); err != nil {
129					return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err)
130				}
131				if len(iv) != b.blockSize {
132					return nil, fmt.Errorf("test case %d/%d has IV of length %d, but expected %d", group.ID, test.ID, len(iv), b.blockSize)
133				}
134			}
135
136			testResp := blockCipherTestResponse{ID: test.ID}
137			if !mct {
138				var result [][]byte
139				var err error
140
141				if b.hasIV {
142					result, err = b.m.transact(op, 1, key, input, iv)
143				} else {
144					result, err = b.m.transact(op, 1, key, input)
145				}
146				if err != nil {
147					panic("block operation failed: " + err.Error())
148				}
149
150				if encrypt {
151					testResp.CiphertextHex = hex.EncodeToString(result[0])
152				} else {
153					testResp.PlaintextHex = hex.EncodeToString(result[0])
154				}
155			} else {
156				for i := 0; i < 100; i++ {
157					var iteration blockCipherMCTResult
158					iteration.KeyHex = hex.EncodeToString(key)
159					if encrypt {
160						iteration.PlaintextHex = hex.EncodeToString(input)
161					} else {
162						iteration.CiphertextHex = hex.EncodeToString(input)
163					}
164
165					var result, prevResult []byte
166					if !b.hasIV {
167						for j := 0; j < 1000; j++ {
168							prevResult = input
169							result, err := b.m.transact(op, 1, key, input)
170							if err != nil {
171								panic("block operation failed")
172							}
173							input = result[0]
174						}
175						result = input
176					} else {
177						iteration.IVHex = hex.EncodeToString(iv)
178
179						var prevInput []byte
180						for j := 0; j < 1000; j++ {
181							prevResult = result
182							if j > 0 {
183								if encrypt {
184									iv = result
185								} else {
186									iv = prevInput
187								}
188							}
189
190							results, err := b.m.transact(op, 1, key, input, iv)
191							if err != nil {
192								panic("block operation failed")
193							}
194							result = results[0]
195
196							prevInput = input
197							if j == 0 {
198								input = iv
199							} else {
200								input = prevResult
201							}
202						}
203					}
204
205					if encrypt {
206						iteration.CiphertextHex = hex.EncodeToString(result)
207					} else {
208						iteration.PlaintextHex = hex.EncodeToString(result)
209					}
210
211					switch keyBytes {
212					case 16:
213						for i := range key {
214							key[i] ^= result[i]
215						}
216					case 24:
217						for i := 0; i < 8; i++ {
218							key[i] ^= prevResult[i+8]
219						}
220						for i := range result {
221							key[i+8] ^= result[i]
222						}
223					case 32:
224						for i, b := range prevResult {
225							key[i] ^= b
226						}
227						for i, b := range result {
228							key[i+16] ^= b
229						}
230					default:
231						panic("unhandled key length")
232					}
233
234					if !b.hasIV {
235						input = result
236					} else {
237						iv = result
238						input = prevResult
239					}
240
241					testResp.MCTResults = append(testResp.MCTResults, iteration)
242				}
243			}
244
245			response.Tests = append(response.Tests, testResp)
246		}
247
248		ret = append(ret, response)
249	}
250
251	return ret, nil
252}
253