paysec_keyblock/tr31_2018/
key_block_header.rs1use super::error::KeyBlockHeaderError;
11use super::header_constants::{
12 ALLOWED_ALGORITHMS, ALLOWED_EXPORTABILITIES, ALLOWED_KEY_USAGES, ALLOWED_MODES_OF_USE,
13 ALLOWED_VERSION_IDS,
14};
15use super::opt_block::OptBlock;
16
17#[derive(Debug, PartialEq)]
19pub struct KeyBlockHeader {
20 version_id: String,
21 kb_length: u16,
22 key_usage: String,
23 algorithm: String,
24 mode_of_use: String,
25 key_version_number: String,
26 exportability: String,
27 num_opt_blocks: u8,
28 reserved_field: String,
29 opt_blocks: Option<Box<OptBlock>>,
30}
31
32impl KeyBlockHeader {
33 pub fn new_empty() -> Self {
35 Self {
36 version_id: String::new(),
37 kb_length: 0,
38 key_usage: String::new(),
39 algorithm: String::new(),
40 mode_of_use: String::new(),
41 key_version_number: String::new(),
42 exportability: String::new(),
43 num_opt_blocks: 0,
44 reserved_field: "00".to_string(),
45 opt_blocks: None,
46 }
47 }
48
49 pub fn new_with_values(
51 version_id: &str,
52 key_usage: &str,
53 algorithm: &str,
54 mode_of_use: &str,
55 key_version_number: &str,
56 exportability: &str,
57 ) -> Result<Self, KeyBlockHeaderError> {
58 let mut header = Self::new_empty();
59
60 header.set_version_id(version_id)?;
61
62 header.set_key_usage(key_usage)?;
63
64 header.set_algorithm(algorithm)?;
65
66 header.set_mode_of_use(mode_of_use)?;
67
68 header.set_key_version_number(key_version_number)?;
69
70 header.set_exportability(exportability)?;
71
72 Ok(header)
73 }
74
75 pub fn new_from_str(header_str: &str) -> Result<Self, KeyBlockHeaderError> {
81 const FIXED_HEADER_LENGTH: usize = 16;
82
83 if !header_str.is_ascii() {
84 return Err(KeyBlockHeaderError::NonAsciiHeader);
85 }
86
87 if header_str.len() < FIXED_HEADER_LENGTH {
88 return Err(KeyBlockHeaderError::InvalidDataLength {
89 minimum: FIXED_HEADER_LENGTH,
90 actual: header_str.len(),
91 });
92 }
93
94 let version_id = header_str[0..1].to_string();
95
96 let kb_length = header_str[1..5]
97 .parse::<u16>()
98 .map_err(|_| KeyBlockHeaderError::InvalidKeyBlockLength)?;
99
100 let key_usage = header_str[5..7].to_string();
101
102 let algorithm = header_str[7..8].to_string();
103
104 let mode_of_use = header_str[8..9].to_string();
105
106 let key_version_number = header_str[9..11].to_string();
107
108 let exportability = header_str[11..12].to_string();
109
110 let num_optional_blocks = header_str[12..14]
111 .parse::<u8>()
112 .map_err(|_| KeyBlockHeaderError::InvalidNumberOfOptionalBlocks)?;
113
114 let reserved_field = header_str[14..16].to_string();
115
116 let mut header = Self::new_empty();
117
118 header.set_version_id(&version_id)?;
119
120 header.set_kb_length(kb_length)?;
121
122 header.set_key_usage(&key_usage)?;
123
124 header.set_algorithm(&algorithm)?;
125
126 header.set_mode_of_use(&mode_of_use)?;
127
128 header.set_key_version_number(&key_version_number)?;
129
130 header.set_exportability(&exportability)?;
131
132 header.set_num_optional_blocks(num_optional_blocks)?;
133
134 header.set_reserved_field(&reserved_field)?;
135
136 if num_optional_blocks > 0 && header_str.len() < 20 {
137 return Err(KeyBlockHeaderError::InvalidHeaderLengthWithOptionalBlocks {
138 minimum: 20,
139 actual: header_str.len(),
140 });
141 }
142
143 if num_optional_blocks > 0 {
144 let opt_block_str = &header_str[16..];
145
146 let opt_block = OptBlock::new_from_str(opt_block_str, num_optional_blocks as usize)
147 .map_err(KeyBlockHeaderError::FailedToParseOptionalBlocks)?;
148
149 header.opt_blocks = Some(Box::new(opt_block));
150 }
151
152 Ok(header)
153 }
154
155 pub fn export_str(&self) -> Result<String, KeyBlockHeaderError> {
157 if self.version_id.is_empty()
158 || self.key_usage.is_empty()
159 || self.algorithm.is_empty()
160 || self.mode_of_use.is_empty()
161 || self.key_version_number.is_empty()
162 || self.exportability.is_empty()
163 || self.reserved_field.is_empty()
164 {
165 return Err(KeyBlockHeaderError::ExportFailedEmptyFields);
166 }
167
168 let mut header_str = String::new();
169
170 header_str.push_str(self.version_id());
171
172 header_str.push_str(&format!("{:04}", self.kb_length(),));
173
174 header_str.push_str(self.key_usage());
175
176 header_str.push_str(self.algorithm());
177
178 header_str.push_str(self.mode_of_use());
179
180 header_str.push_str(self.key_version_number());
181
182 header_str.push_str(self.exportability());
183
184 header_str.push_str(&format!("{:02}", self.num_opt_blocks,));
185
186 header_str.push_str(self.reserved_field());
187
188 if let Some(opt_blocks) = &self.opt_blocks {
189 header_str.push_str(&opt_blocks.export_str()?);
190 }
191
192 Ok(header_str)
193 }
194
195 pub fn set_version_id(&mut self, value: &str) -> Result<(), KeyBlockHeaderError> {
197 if ALLOWED_VERSION_IDS.contains(&value) {
198 self.version_id = value.to_string();
199
200 Ok(())
201 } else {
202 Err(KeyBlockHeaderError::InvalidVersionId(value.to_string()))
203 }
204 }
205
206 pub fn version_id(&self) -> &str {
208 &self.version_id
209 }
210
211 pub fn set_kb_length(&mut self, value: u16) -> Result<(), KeyBlockHeaderError> {
213 if value > 9999 {
214 return Err(KeyBlockHeaderError::InvalidKeyBlockLength);
215 }
216
217 self.kb_length = value;
218
219 Ok(())
220 }
221
222 pub fn kb_length(&self) -> u16 {
224 self.kb_length
225 }
226
227 pub fn set_key_usage(&mut self, value: &str) -> Result<(), KeyBlockHeaderError> {
229 if ALLOWED_KEY_USAGES.contains(&value) {
230 self.key_usage = value.to_string();
231
232 Ok(())
233 } else {
234 Err(KeyBlockHeaderError::InvalidKeyUsage(value.to_string()))
235 }
236 }
237
238 pub fn key_usage(&self) -> &str {
240 &self.key_usage
241 }
242
243 pub fn set_algorithm(&mut self, value: &str) -> Result<(), KeyBlockHeaderError> {
245 if ALLOWED_ALGORITHMS.contains(&value) {
246 self.algorithm = value.to_string();
247
248 Ok(())
249 } else {
250 Err(KeyBlockHeaderError::InvalidAlgorithm(value.to_string()))
251 }
252 }
253
254 pub fn algorithm(&self) -> &str {
256 &self.algorithm
257 }
258
259 pub fn set_mode_of_use(&mut self, value: &str) -> Result<(), KeyBlockHeaderError> {
261 if ALLOWED_MODES_OF_USE.contains(&value) {
262 self.mode_of_use = value.to_string();
263
264 Ok(())
265 } else {
266 Err(KeyBlockHeaderError::InvalidModeOfUse(value.to_string()))
267 }
268 }
269
270 pub fn mode_of_use(&self) -> &str {
272 &self.mode_of_use
273 }
274
275 pub fn set_key_version_number(&mut self, value: &str) -> Result<(), KeyBlockHeaderError> {
277 if value.len() != 2 {
278 return Err(KeyBlockHeaderError::InvalidKeyVersionNumberLength(
279 value.to_string(),
280 ));
281 }
282
283 if !value.is_ascii() {
284 return Err(KeyBlockHeaderError::InvalidKeyVersionNumberEncoding(
285 value.to_string(),
286 ));
287 }
288
289 self.key_version_number = value.to_string();
290
291 Ok(())
292 }
293
294 pub fn key_version_number(&self) -> &str {
296 &self.key_version_number
297 }
298
299 pub fn set_exportability(&mut self, value: &str) -> Result<(), KeyBlockHeaderError> {
301 if ALLOWED_EXPORTABILITIES.contains(&value) {
302 self.exportability = value.to_string();
303
304 Ok(())
305 } else {
306 Err(KeyBlockHeaderError::InvalidExportability(value.to_string()))
307 }
308 }
309
310 pub fn exportability(&self) -> &str {
312 &self.exportability
313 }
314
315 pub fn set_num_optional_blocks(&mut self, value: u8) -> Result<(), KeyBlockHeaderError> {
317 const MAX_OPTIONAL_BLOCKS: u8 = 99;
318
319 if value > MAX_OPTIONAL_BLOCKS {
320 return Err(KeyBlockHeaderError::TooManyOptionalBlocks {
321 maximum: MAX_OPTIONAL_BLOCKS,
322 actual: value,
323 });
324 }
325
326 self.num_opt_blocks = value;
327
328 Ok(())
329 }
330
331 pub fn num_optional_blocks(&self) -> u8 {
333 self.num_opt_blocks
334 }
335
336 pub fn set_reserved_field(&mut self, value: &str) -> Result<(), KeyBlockHeaderError> {
338 if value == "00" {
339 self.reserved_field = value.to_string();
340
341 Ok(())
342 } else {
343 Err(KeyBlockHeaderError::InvalidReservedField(value.to_string()))
344 }
345 }
346
347 pub fn reserved_field(&self) -> &str {
349 &self.reserved_field
350 }
351
352 pub fn set_opt_blocks(&mut self, opt_blocks: Option<Box<OptBlock>>) {
354 self.opt_blocks = opt_blocks;
355
356 self.num_opt_blocks = 0;
357
358 if let Some(opt_block) = &self.opt_blocks {
359 let mut current_block = opt_block.as_ref();
360
361 self.num_opt_blocks = 1;
362
363 while let Some(next_block) = current_block.next() {
364 self.num_opt_blocks += 1;
365 current_block = next_block;
366 }
367 }
368 }
369
370 pub fn append_opt_blocks(&mut self, opt_block_to_append: OptBlock) {
373 let mut additional_blocks_count = 1;
374
375 let mut current_block = &opt_block_to_append;
376
377 while let Some(next_block) = current_block.next() {
378 additional_blocks_count += 1;
379
380 current_block = next_block;
381 }
382
383 match &mut self.opt_blocks {
384 Some(existing_opt_block) => {
385 existing_opt_block.append(opt_block_to_append);
386 }
387
388 None => {
389 self.opt_blocks = Some(Box::new(opt_block_to_append));
390 }
391 }
392
393 self.num_opt_blocks += additional_blocks_count;
394 }
395
396 pub fn opt_blocks(&self) -> &Option<Box<OptBlock>> {
398 &self.opt_blocks
399 }
400
401 pub fn len(&self) -> usize {
403 let mut header_length = 16;
404
405 if let Some(opt_blocks) = &self.opt_blocks {
406 header_length += opt_blocks.total_length();
407 }
408
409 header_length
410 }
411
412 pub fn finalize(&mut self) -> Result<(), KeyBlockHeaderError> {
415 let block_size = if self.version_id == "D" { 16 } else { 8 };
416
417 let header_length = self.len();
418
419 if let Some(opt_blocks) = &mut self.opt_blocks {
420 if header_length % block_size != 0 {
421 let mut padding_needed = block_size - (header_length % block_size);
422
423 if padding_needed < 6 {
429 padding_needed += block_size;
430 }
431
432 let padding_data_length = padding_needed - 4;
433
434 let padding_data = "0".repeat(padding_data_length);
435
436 let padding_block = OptBlock::new("PB", &padding_data, None)?;
437
438 opt_blocks.append(padding_block);
439
440 self.num_opt_blocks += 1;
441 }
442 }
443
444 Ok(())
445 }
446}
447
448#[test]
449fn test_header_invalid_version_typed_error() {
450 let result = KeyBlockHeader::new_with_values("X", "P0", "A", "E", "00", "E");
451
452 assert!(matches!(
453 result,
454 Err(KeyBlockHeaderError::InvalidVersionId(_))
455 ));
456}
457
458#[test]
459fn test_header_optional_block_error_is_preserved() {
460 use crate::OptBlockError;
461
462 let result = KeyBlockHeader::new_from_str("D0020P0AE00E0100XX04");
463
464 assert!(matches!(
465 result,
466 Err(KeyBlockHeaderError::FailedToParseOptionalBlocks(
467 OptBlockError::InvalidId(_)
468 ))
469 ));
470}