Skip to main content

omy_core/
util.rs

1//! 内部工具:随机数、小端序读写、常量时间比较。
2
3use crate::error::{Error, Result};
4
5/// 用操作系统 CSPRNG 填充缓冲区。
6///
7/// # Panics
8///
9/// 系统熵源不可用时 panic。这种情况下继续运行会产生可预测的密钥或 nonce,
10/// 属于灾难性安全故障,快速失败比降级更安全。
11pub fn fill_random(buf: &mut [u8]) {
12    use rand_core::{OsRng, RngCore};
13    OsRng.fill_bytes(buf);
14}
15
16/// 生成随机 16 字节,用作 `file_uuid` 或 `vault_salt`。
17#[must_use]
18pub fn random_16() -> [u8; 16] {
19    let mut b = [0u8; 16];
20    fill_random(&mut b);
21    b
22}
23
24/// BLAKE2b-256 摘要。
25///
26/// 用于内容哈希与容器内逐文件校验。公开出来是为了让上层(CLI、GUI)
27/// 与 core 内部使用**同一个实现**——若各写一遍,哈希算法或参数一旦不一致,
28/// 校验会在解密时才失败,且难以定位。
29#[must_use]
30pub fn blake2b_256(data: &[u8]) -> [u8; 32] {
31    use blake2::digest::{Digest, consts::U32};
32    let mut h = blake2::Blake2b::<U32>::new();
33    h.update(data);
34    let out = h.finalize();
35    let mut r = [0u8; 32];
36    r.copy_from_slice(&out);
37    r
38}
39
40/// 流式计算一个 `Read` 的 BLAKE2b-256,与 [`blake2b_256`] 结果相同。
41///
42/// 容器索引的逐文件哈希就是它;校验磁盘上的原件时按段读,不把整个文件读进内存。
43///
44/// # Errors
45///
46/// 读取失败时返回。
47pub fn blake2b_256_reader<R: std::io::Read>(mut r: R) -> std::io::Result<[u8; 32]> {
48    use blake2::digest::{Digest, consts::U32};
49    let mut h = blake2::Blake2b::<U32>::new();
50    let mut buf = vec![0u8; 1 << 20];
51    loop {
52        let n = r.read(&mut buf)?;
53        if n == 0 {
54            break;
55        }
56        h.update(buf.get(..n).unwrap_or(&[]));
57    }
58    Ok(h.finalize().into())
59}
60
61/// 顺序读取小端序整数的游标。
62///
63/// 每个方法都做边界检查并返回结构化错误,避免 panic —— 解析不可信输入时这点很重要。
64pub struct Cursor<'a> {
65    data: &'a [u8],
66    pos: usize,
67    /// 当前解析的结构名,用于错误信息定位。
68    context: &'static str,
69}
70
71impl<'a> Cursor<'a> {
72    /// 新建游标。
73    #[must_use]
74    pub const fn new(data: &'a [u8], context: &'static str) -> Self {
75        Self { data, pos: 0, context }
76    }
77
78    /// 当前偏移量。
79    #[must_use]
80    pub const fn position(&self) -> usize {
81        self.pos
82    }
83
84    /// 剩余字节数。
85    #[must_use]
86    pub const fn remaining(&self) -> usize {
87        self.data.len().saturating_sub(self.pos)
88    }
89
90    /// 跳过 `n` 字节。
91    ///
92    /// # Errors
93    ///
94    /// 剩余不足时返回 [`Error::Truncated`]。
95    pub fn skip(&mut self, n: usize) -> Result<()> {
96        self.take(n).map(|_| ())
97    }
98
99    /// 取出 `n` 字节切片。
100    ///
101    /// # Errors
102    ///
103    /// 剩余不足时返回 [`Error::Truncated`]。
104    pub fn take(&mut self, n: usize) -> Result<&'a [u8]> {
105        let end = self.pos.checked_add(n).ok_or(Error::Truncated {
106            context: self.context,
107            need: n,
108            got: self.remaining(),
109        })?;
110        let s = self.data.get(self.pos..end).ok_or(Error::Truncated {
111            context: self.context,
112            need: n,
113            got: self.remaining(),
114        })?;
115        self.pos = end;
116        Ok(s)
117    }
118
119    /// 取出固定长度数组。
120    ///
121    /// # Errors
122    ///
123    /// 剩余不足时返回 [`Error::Truncated`]。
124    pub fn take_array<const N: usize>(&mut self) -> Result<[u8; N]> {
125        let s = self.take(N)?;
126        let mut a = [0u8; N];
127        a.copy_from_slice(s);
128        Ok(a)
129    }
130
131    /// 读 `u8`。
132    ///
133    /// # Errors
134    ///
135    /// 剩余不足时返回 [`Error::Truncated`]。
136    pub fn u8(&mut self) -> Result<u8> {
137        Ok(self.take_array::<1>()?[0])
138    }
139
140    /// 读小端序 `u16`。
141    ///
142    /// # Errors
143    ///
144    /// 剩余不足时返回 [`Error::Truncated`]。
145    pub fn u16le(&mut self) -> Result<u16> {
146        Ok(u16::from_le_bytes(self.take_array::<2>()?))
147    }
148
149    /// 读小端序 `u32`。
150    ///
151    /// # Errors
152    ///
153    /// 剩余不足时返回 [`Error::Truncated`]。
154    pub fn u32le(&mut self) -> Result<u32> {
155        Ok(u32::from_le_bytes(self.take_array::<4>()?))
156    }
157
158    /// 读小端序 `u64`。
159    ///
160    /// # Errors
161    ///
162    /// 剩余不足时返回 [`Error::Truncated`]。
163    pub fn u64le(&mut self) -> Result<u64> {
164        Ok(u64::from_le_bytes(self.take_array::<8>()?))
165    }
166}
167
168/// 小端序写入缓冲区。
169#[derive(Debug, Default)]
170pub struct Writer {
171    buf: Vec<u8>,
172}
173
174impl Writer {
175    /// 新建。
176    #[must_use]
177    pub const fn new() -> Self {
178        Self { buf: Vec::new() }
179    }
180
181    /// 预分配容量。
182    #[must_use]
183    pub fn with_capacity(n: usize) -> Self {
184        Self { buf: Vec::with_capacity(n) }
185    }
186
187    /// 当前长度。
188    #[must_use]
189    pub fn len(&self) -> usize {
190        self.buf.len()
191    }
192
193    /// 是否为空。
194    #[must_use]
195    pub fn is_empty(&self) -> bool {
196        self.buf.is_empty()
197    }
198
199    /// 追加原始字节。
200    pub fn bytes(&mut self, b: &[u8]) -> &mut Self {
201        self.buf.extend_from_slice(b);
202        self
203    }
204
205    /// 追加 `u8`。
206    pub fn u8(&mut self, v: u8) -> &mut Self {
207        self.buf.push(v);
208        self
209    }
210
211    /// 追加小端序 `u16`。
212    pub fn u16le(&mut self, v: u16) -> &mut Self {
213        self.buf.extend_from_slice(&v.to_le_bytes());
214        self
215    }
216
217    /// 追加小端序 `u32`。
218    pub fn u32le(&mut self, v: u32) -> &mut Self {
219        self.buf.extend_from_slice(&v.to_le_bytes());
220        self
221    }
222
223    /// 追加小端序 `u64`。
224    pub fn u64le(&mut self, v: u64) -> &mut Self {
225        self.buf.extend_from_slice(&v.to_le_bytes());
226        self
227    }
228
229    /// 追加 `n` 个零字节。
230    pub fn zeros(&mut self, n: usize) -> &mut Self {
231        self.buf.resize(self.buf.len().saturating_add(n), 0);
232        self
233    }
234
235    /// 追加 `n` 个随机字节。
236    ///
237    /// 用于填充未使用的 key slot 与文件名 padding —— 必须是随机而非零,
238    /// 否则「哪些 slot 在用」和「文件名多长」会直接暴露。
239    pub fn random(&mut self, n: usize) -> &mut Self {
240        let start = self.buf.len();
241        self.buf.resize(start.saturating_add(n), 0);
242        if let Some(tail) = self.buf.get_mut(start..) {
243            fill_random(tail);
244        }
245        self
246    }
247
248    /// 零填充到指定总长度。
249    ///
250    /// # Errors
251    ///
252    /// 当前长度已超过目标时返回 [`Error::MalformedHeader`]。
253    pub fn pad_to(&mut self, total: usize) -> Result<&mut Self> {
254        if self.buf.len() > total {
255            return Err(Error::MalformedHeader { reason: "field overflow while padding" });
256        }
257        self.buf.resize(total, 0);
258        Ok(self)
259    }
260
261    /// 取出内部缓冲区。
262    #[must_use]
263    pub fn into_vec(self) -> Vec<u8> {
264        self.buf
265    }
266
267    /// 借出内部缓冲区。
268    #[must_use]
269    pub fn as_slice(&self) -> &[u8] {
270        &self.buf
271    }
272}