acvp_parser/
msgauth.rs

1use json::JsonValue;
2use rand::Rng;
3
4use crate::{
5    parser::{TestCase, TestGroupData, TestResult},
6    util::{Direction, IVMode, TestType},
7    AcvpError, AcvpResult,
8};
9
10#[derive(Debug, Clone, Eq, PartialEq)]
11pub struct MsgAuth {
12    algorithm: String,
13    tcid: u32,
14    test_type: TestType,
15    direction: Direction,
16    res_json: JsonValue,
17    pub key: Vec<u8>,
18    pub key1: Vec<u8>,
19    pub key2: Vec<u8>,
20    pub key3: Vec<u8>,
21    pub iv: Vec<u8>,
22    pub ivmode: IVMode,
23    pub msg: Vec<u8>,
24    pub aad: Vec<u8>,
25    pub tag: Vec<u8>,
26    pub taglen: usize,
27}
28
29impl TestCase for MsgAuth {
30    fn new(testjson: &str, tgdata: &TestGroupData) -> AcvpResult<Self> {
31        let test = match json::parse(testjson) {
32            Ok(test) => test,
33            Err(_e) => {
34                return Err(AcvpError {
35                    code: -libc::EINVAL,
36                    message: "Failed to parse testcase JSON for SHash".to_string(),
37                });
38            }
39        };
40        let tcid = crate::util::get_acvp_u32("tcId", &test)?;
41
42        let mut msg = Vec::new();
43        if test.has_key("msg") {
44            let msghex = crate::util::get_acvp_str("msg", &test)?;
45            msg = crate::util::hex2bin(&msghex)?;
46        } else if test.has_key("message") {
47            let msghex = crate::util::get_acvp_str("message", &test)?;
48            msg = crate::util::hex2bin(&msghex)?;
49        } else if test.has_key("plainText") {
50            let msghex = crate::util::get_acvp_str("plainText", &test)?;
51            msg = crate::util::hex2bin(&msghex)?;
52        } else if test.has_key("cipherText") {
53            let msghex = crate::util::get_acvp_str("cipherText", &test)?;
54            msg = crate::util::hex2bin(&msghex)?;
55        } else if test.has_key("pt") {
56            let msghex = crate::util::get_acvp_str("pt", &test)?;
57            msg = crate::util::hex2bin(&msghex)?;
58        } else if test.has_key("ct") {
59            let msghex = crate::util::get_acvp_str("ct", &test)?;
60            msg = crate::util::hex2bin(&msghex)?;
61        }
62
63        let mut aad = Vec::new();
64        if test.has_key("aad") {
65            let aadhex = crate::util::get_acvp_str("aad", &test)?;
66            aad = crate::util::hex2bin(&aadhex)?;
67        }
68
69        let mut key = Vec::new();
70        if test.has_key("key") {
71            let keyhex = crate::util::get_acvp_str("key", &test)?;
72            key = crate::util::hex2bin(&keyhex)?;
73        }
74
75        let mut key1 = Vec::new();
76        let mut key2 = Vec::new();
77        let mut key3 = Vec::new();
78        if test.has_key("key1") && test.has_key("key2") && test.has_key("key3") {
79            let keyhex = crate::util::get_acvp_str("key1", &test)?;
80            key1 = crate::util::hex2bin(&keyhex)?;
81            let keyhex = crate::util::get_acvp_str("key2", &test)?;
82            key2 = crate::util::hex2bin(&keyhex)?;
83            let keyhex = crate::util::get_acvp_str("key3", &test)?;
84            key3 = crate::util::hex2bin(&keyhex)?;
85        }
86
87        let mut iv = Vec::new();
88        if test.has_key("iv") {
89            let ivhex = crate::util::get_acvp_str("iv", &test)?;
90            iv = crate::util::hex2bin(&ivhex)?;
91        } else if tgdata.ivmode == IVMode::Internal {
92            let mut rng = rand::thread_rng();
93            iv = (0..tgdata.ivlen).map(|_| rng.gen_range(0..255)).collect();
94        }
95
96        let mut tag = Vec::new();
97        if test.has_key("tag") {
98            let taghex = crate::util::get_acvp_str("tag", &test)?;
99            tag = crate::util::hex2bin(&taghex)?;
100        } else if test.has_key("mac") {
101            let taghex = crate::util::get_acvp_str("mac", &test)?;
102            tag = crate::util::hex2bin(&taghex)?;
103        }
104
105        // We need to special case here where the payload may be empty
106        // and the taglength will be set. This issue is seen in ACVP-AES-CCM which
107        // does not specify the tag separately in decryption vectors.
108        if tag.is_empty() && tgdata.direction == Direction::Decrypt {
109            if tgdata.payload_len == 0 {
110                tag = msg.clone();
111                msg = Vec::new();
112            } else {
113                tag = msg[tgdata.payload_len..].to_vec();
114                msg = msg[..tgdata.payload_len].to_vec();
115            }
116        }
117
118        Ok(MsgAuth {
119            algorithm: tgdata.algorithm.to_string(),
120            tcid,
121            test_type: tgdata.test_type,
122            direction: tgdata.direction,
123            res_json: JsonValue::new_object(),
124            key,
125            key1,
126            key2,
127            key3,
128            iv,
129            ivmode: tgdata.ivmode,
130            msg,
131            aad,
132            tag,
133            taglen: tgdata.taglen,
134        })
135    }
136
137    fn get_result(&self) -> AcvpResult<JsonValue> {
138        if self.res_json.is_empty() {
139            return Err(AcvpError {
140                code: -libc::EINVAL,
141                message: "The result is not yet set, call set_*_result APIs".to_string(),
142            });
143        }
144        Ok(self.res_json.clone())
145    }
146
147    fn dump_result(&self) -> AcvpResult<String> {
148        if self.res_json.is_empty() {
149            return Err(AcvpError {
150                code: -libc::EINVAL,
151                message: "The result is not yet set, call set_result API".to_string(),
152            });
153        }
154        Ok(self.res_json.dump())
155    }
156
157    fn pretty_result(&self) -> AcvpResult<String> {
158        if self.res_json.is_empty() {
159            return Err(AcvpError {
160                code: -libc::EINVAL,
161                message: "The result is not yet set, call set_result API".to_string(),
162            });
163        }
164        Ok(self.res_json.pretty(3))
165    }
166}
167
168#[derive(Debug, Clone, Eq, PartialEq)]
169pub struct MsgAuthOutput {
170    pub out: Vec<u8>,
171    pub tag: Vec<u8>,
172}
173
174impl MsgAuthOutput {
175    pub fn new(out: Vec<u8>, tag: Vec<u8>) -> Self {
176        MsgAuthOutput { out, tag }
177    }
178}
179
180impl TestResult<Vec<u8>> for MsgAuth {
181    fn set_result(&mut self, result: Vec<u8>) -> AcvpResult<()> {
182        let mut res = JsonValue::new_object();
183        res["tcId"] = self.tcid.into();
184        if self.algorithm.contains("HMAC")
185            || self.algorithm.contains("TDES")
186            || self.algorithm.contains("CMAC")
187        {
188            res["mac"] = hex::encode(result).to_ascii_uppercase().into();
189        } else if self.algorithm.contains("GMAC") {
190            res["tag"] = hex::encode(result).to_ascii_uppercase().into();
191        } else if self.algorithm.contains("GCM") {
192            res["pt"] = hex::encode(result).to_ascii_uppercase().into();
193        } else {
194            match self.direction {
195                Direction::Decrypt | Direction::Verify => {
196                    res["pt"] = hex::encode(result).to_ascii_uppercase().into();
197                }
198                Direction::Encrypt | Direction::Generate => {
199                    res["ct"] = hex::encode(result).to_ascii_uppercase().into();
200                }
201                Direction::Nil => {
202                    return Err(AcvpError {
203                        code: -libc::EINVAL,
204                        message: "Invalid direction for MsgAuth algorithm".to_string(),
205                    });
206                }
207            };
208        }
209        self.res_json = res;
210        Ok(())
211    }
212}
213
214impl TestResult<MsgAuthOutput> for MsgAuth {
215    fn set_result(&mut self, result: MsgAuthOutput) -> AcvpResult<()> {
216        let mut res = JsonValue::new_array();
217        res["tcId"] = self.tcid.into();
218        if self.ivmode == IVMode::Internal {
219            res["iv"] = hex::encode(&self.iv).to_ascii_uppercase().into();
220        }
221        if self.algorithm.contains("CCM") {
222            let mut ct = result.out;
223            ct.extend(result.tag.iter());
224            res["ct"] = hex::encode(ct).to_ascii_uppercase().into();
225        } else {
226            res["ct"] = hex::encode(result.out).to_ascii_uppercase().into();
227            res["tag"] = hex::encode(result.tag).to_ascii_uppercase().into();
228        }
229        self.res_json = res;
230        Ok(())
231    }
232}
233
234impl TestResult<bool> for MsgAuth {
235    fn set_result(&mut self, result: bool) -> AcvpResult<()> {
236        self.res_json = json::object! {
237            tcId: self.tcid,
238            testPassed: result,
239        };
240        Ok(())
241    }
242}