1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::fmt;
use base64;
use byteorder::{BigEndian, ByteOrder};
use crate::PgpError;
use crate::PgpError::InvalidAsciiArmor;
impl From<base64::DecodeError> for PgpError {
fn from(_: base64::DecodeError) -> PgpError {
InvalidAsciiArmor
}
}
pub fn remove_ascii_armor(s: &str, expected_header: &str, expected_footer: &str) -> Result<Vec<u8>, PgpError> {
let lines: Vec<&str> = s.lines().map(|s| s.trim()).collect();
let header = lines.first().ok_or(InvalidAsciiArmor)?;
let footer = lines.last().ok_or(InvalidAsciiArmor)?;
if !header.starts_with("-----")
|| !footer.starts_with("-----")
|| !header.ends_with("-----")
|| !footer.ends_with("-----")
|| header.trim_matches('-').trim() != expected_header
|| footer.trim_matches('-').trim() != expected_footer
{
return Err(InvalidAsciiArmor)
}
let end_of_headers = 1 + lines.iter().take_while(|l| !l.is_empty()).count();
if end_of_headers >= lines.len() - 2 { return Err(InvalidAsciiArmor) }
let ascii_armored: String = lines[end_of_headers..lines.len() - 2].concat();
let data = base64::decode(&ascii_armored)?;
let cksum_line = &lines[lines.len() - 2];
if !cksum_line.starts_with("=") || !cksum_line.len() > 1 {
return Err(InvalidAsciiArmor)
}
let mut cksum = [0; 4];
base64::decode_config_slice(&cksum_line[1..], base64::STANDARD, &mut cksum[..])?;
if BigEndian::read_u32(&cksum[..]) != checksum_crc24(&data) {
return Err(InvalidAsciiArmor)
}
Ok(data)
}
pub fn ascii_armor(
header: &'static str,
footer: &'static str,
data: &[u8],
f: &mut fmt::Formatter
) -> fmt::Result
{
f.write_str("-----")?;
f.write_str(header)?;
f.write_str("-----\n\n")?;
let b64_cfg = base64::Config::new(
base64::CharacterSet::Standard,
true,
false,
base64::LineWrap::Wrap(76, base64::LineEnding::LF),
);
f.write_str(&base64::encode_config(data, b64_cfg))?;
f.write_str("\n=")?;
let cksum = checksum_crc24(data);
let mut cksum_buf = [0; 4];
BigEndian::write_u32(&mut cksum_buf, cksum);
f.write_str(&base64::encode(&cksum_buf[1..4]))?;
f.write_str("\n-----")?;
f.write_str(footer)?;
f.write_str("-----\n")?;
Ok(())
}
fn checksum_crc24(data: &[u8]) -> u32 {
const CRC24_INIT: u32 = 0x_00B7_04CE;
const CRC24_POLY: u32 = 0x_0186_4CFB;
let mut crc = CRC24_INIT;
for &byte in data {
crc ^= (byte as u32) << 16;
for _ in 0..8 {
crc <<= 1;
if (crc & 0x_0100_0000) != 0 {
crc ^= CRC24_POLY;
}
}
}
crc & 0x_00FF_FFFF
}