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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use std::io::{Read, Write, Cursor};
use base64::{decode_config_buf, encode_config_buf, Config};
const B64_CONF: Config = Config::new(base64::CharacterSet::Standard, true);
#[cfg(feature = "encrypt")]
const ASSOCIATED_DATA: &[u8] = b"usdpl-core-data";
#[cfg(feature = "encrypt")]
use aes_gcm_siv::aead::{AeadInPlace, NewAead};
#[derive(Debug)]
pub enum LoadError {
TooSmallBuffer,
InvalidData,
#[cfg(feature = "encrypt")]
DecryptionError,
Io(std::io::Error),
#[cfg(debug_assertions)]
Todo,
}
impl std::fmt::Display for LoadError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::TooSmallBuffer => write!(f, "LoadError: TooSmallBuffer"),
Self::InvalidData => write!(f, "LoadError: InvalidData"),
#[cfg(feature = "encrypt")]
Self::DecryptionError => write!(f, "LoadError: DecryptionError"),
Self::Io(err) => write!(f, "LoadError: Io({})", err),
#[cfg(debug_assertions)]
Self::Todo => write!(f, "LoadError: TODO!"),
}
}
}
pub trait Loadable: Sized {
fn load(buffer: &mut dyn Read) -> Result<(Self, usize), LoadError>;
fn load_base64(buffer: &[u8]) -> Result<(Self, usize), LoadError> {
let mut buffer2 = Vec::with_capacity(crate::socket::PACKET_BUFFER_SIZE);
decode_config_buf(buffer, B64_CONF, &mut buffer2)
.map_err(|_| LoadError::InvalidData)?;
let mut cursor = Cursor::new(buffer2);
Self::load(&mut cursor)
}
#[cfg(feature = "encrypt")]
fn load_encrypted(buffer: &[u8], key: &[u8], nonce: &[u8]) -> Result<(Self, usize), LoadError> {
let key = aes_gcm_siv::Key::from_slice(key);
let cipher = aes_gcm_siv::Aes256GcmSiv::new(key);
let nonce = aes_gcm_siv::Nonce::from_slice(nonce);
let mut decoded_buf = Vec::with_capacity(crate::socket::PACKET_BUFFER_SIZE);
base64::decode_config_buf(buffer, B64_CONF, &mut decoded_buf)
.map_err(|_| LoadError::InvalidData)?;
cipher.decrypt_in_place(nonce, ASSOCIATED_DATA, &mut decoded_buf).map_err(|_| LoadError::DecryptionError)?;
let mut cursor = Cursor::new(decoded_buf);
Self::load(&mut cursor)
}
}
#[derive(Debug)]
pub enum DumpError {
TooSmallBuffer,
Unsupported,
#[cfg(feature = "encrypt")]
EncryptionError,
Io(std::io::Error),
#[cfg(debug_assertions)]
Todo,
}
impl std::fmt::Display for DumpError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::TooSmallBuffer => write!(f, "DumpError: TooSmallBuffer"),
Self::Unsupported => write!(f, "DumpError: Unsupported"),
#[cfg(feature = "encrypt")]
Self::EncryptionError => write!(f, "DumpError: EncryptionError"),
Self::Io(err) => write!(f, "DumpError: Io({})", err),
#[cfg(debug_assertions)]
Self::Todo => write!(f, "DumpError: TODO!"),
}
}
}
pub trait Dumpable {
fn dump(&self, buffer: &mut dyn Write) -> Result<usize, DumpError>;
fn dump_base64(&self, buffer: &mut String) -> Result<usize, DumpError> {
let mut buffer2 = Vec::with_capacity(crate::socket::PACKET_BUFFER_SIZE);
let len = self.dump(&mut buffer2)?;
encode_config_buf(&buffer2[..len], B64_CONF, buffer);
Ok(len)
}
#[cfg(feature = "encrypt")]
fn dump_encrypted(&self, buffer: &mut Vec<u8>, key: &[u8], nonce: &[u8]) -> Result<usize, DumpError> {
let mut buffer2 = Vec::with_capacity(crate::socket::PACKET_BUFFER_SIZE);
let size = self.dump(&mut buffer2)?;
buffer2.truncate(size);
let key = aes_gcm_siv::Key::from_slice(key);
let cipher = aes_gcm_siv::Aes256GcmSiv::new(key);
let nonce = aes_gcm_siv::Nonce::from_slice(nonce);
cipher.encrypt_in_place(nonce, ASSOCIATED_DATA, &mut buffer2).map_err(|_| DumpError::EncryptionError)?;
let mut base64_buf = String::with_capacity(crate::socket::PACKET_BUFFER_SIZE);
encode_config_buf(buffer2.as_slice(), B64_CONF, &mut base64_buf);
buffer.extend_from_slice(base64_buf.as_bytes());
Ok(base64_buf.len())
}
}