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