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
use crate::{Error, Result};
use alloc::{borrow::ToOwned, string::String, vec::Vec};
use core::str;
use subtle_encoding::base64;
use zeroize::Zeroizing;
pub(crate) struct Boundary {
pre: &'static str,
post: &'static str,
}
pub(crate) const PRIVATE_KEY_BOUNDARY: Boundary = Boundary {
pre: "-----BEGIN PRIVATE KEY-----\n",
post: "\n-----END PRIVATE KEY-----",
};
pub(crate) const PUBLIC_KEY_BOUNDARY: Boundary = Boundary {
pre: "-----BEGIN PUBLIC KEY-----\n",
post: "\n-----END PUBLIC KEY-----",
};
pub(crate) fn decode(s: &str, boundary: Boundary) -> Result<Zeroizing<Vec<u8>>> {
let s = s.trim_end();
let s = s.strip_prefix(boundary.pre).ok_or(Error::Decode)?;
let s = s.strip_suffix(boundary.post).ok_or(Error::Decode)?;
let mut s = Zeroizing::new(s.to_owned());
s.retain(|c| !c.is_whitespace());
base64::decode(&*s)
.map_err(|_| Error::Decode)
.map(Zeroizing::new)
}
pub(crate) fn encode(data: &[u8], boundary: Boundary) -> String {
let mut output = String::new();
output.push_str(boundary.pre);
let b64 = Zeroizing::new(base64::encode(data));
let chunks = b64.chunks(64);
let nchunks = chunks.len();
for (i, chunk) in chunks.enumerate() {
let line = str::from_utf8(chunk).expect("malformed base64");
output.push_str(line);
if i < nchunks.checked_sub(1).expect("unexpected chunks") {
output.push('\n');
}
}
output.push_str(boundary.post);
output
}