1use std::mem::MaybeUninit;
7use gmssl_rs_sys;
8
9use crate::error::{ok_or_library_error, verify_result, GmsslError};
10use crate::pem_helpers;
11
12pub struct Sm9SignMasterKey {
17 key: gmssl_rs_sys::SM9_SIGN_MASTER_KEY,
18}
19
20impl std::fmt::Debug for Sm9SignMasterKey {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 f.debug_struct("Sm9SignMasterKey").finish()
23 }
24}
25
26impl Sm9SignMasterKey {
27 pub fn generate() -> Result<Self, GmsslError> {
29 let mut key = MaybeUninit::uninit();
30 ok_or_library_error(
31 unsafe { gmssl_rs_sys::sm9_sign_master_key_generate(key.as_mut_ptr()) },
32 "sm9_sign_master_key_generate",
33 )?;
34 Ok(Sm9SignMasterKey {
35 key: unsafe { key.assume_init() },
36 })
37 }
38
39 pub fn extract_key(&self, id: &str) -> Result<Sm9SignKey, GmsslError> {
41 let id_c = std::ffi::CString::new(id)
42 .map_err(|_| GmsslError::InvalidInput("ID contains NUL byte"))?;
43 let mut key = MaybeUninit::uninit();
44 ok_or_library_error(
45 unsafe {
46 gmssl_rs_sys::sm9_sign_master_key_extract_key(
47 &self.key,
48 id_c.as_ptr(),
49 id.len(),
50 key.as_mut_ptr(),
51 )
52 },
53 "sm9_sign_master_key_extract_key",
54 )?;
55 Ok(Sm9SignKey {
56 key: unsafe { key.assume_init() },
57 id: id.to_string(),
58 })
59 }
60
61 pub fn from_encrypted_pem(pem_data: &[u8], password: &str) -> Result<Self, GmsslError> {
63 let pass_c = std::ffi::CString::new(password)
64 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
65 let mut key = MaybeUninit::uninit();
66 let fp = unsafe { pem_helpers::file_from_bytes(pem_data)? };
67 let ret = unsafe {
68 gmssl_rs_sys::sm9_sign_master_key_info_decrypt_from_pem(
69 key.as_mut_ptr(),
70 pass_c.as_ptr(),
71 fp,
72 )
73 };
74 unsafe { libc::fclose(fp) };
75 ok_or_library_error(ret, "sm9_sign_master_key_info_decrypt_from_pem")?;
76 Ok(Sm9SignMasterKey {
77 key: unsafe { key.assume_init() },
78 })
79 }
80
81 pub fn to_encrypted_pem(&self, password: &str) -> Result<Vec<u8>, GmsslError> {
83 let pass_c = std::ffi::CString::new(password)
84 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
85 unsafe {
86 pem_helpers::collect_to_bytes(|fp| {
87 gmssl_rs_sys::sm9_sign_master_key_info_encrypt_to_pem(
88 &self.key,
89 pass_c.as_ptr(),
90 fp,
91 )
92 })
93 }
94 }
95}
96
97pub struct Sm9SignKey {
102 key: gmssl_rs_sys::SM9_SIGN_KEY,
103 id: String,
104}
105
106impl std::fmt::Debug for Sm9SignKey {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 f.debug_struct("Sm9SignKey").field("id", &self.id).finish()
109 }
110}
111
112impl Sm9SignKey {
113 pub fn id(&self) -> &str {
115 &self.id
116 }
117
118 pub fn from_encrypted_pem(pem_data: &[u8], password: &str) -> Result<Self, GmsslError> {
120 let pass_c = std::ffi::CString::new(password)
121 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
122 let mut key = MaybeUninit::uninit();
123 let fp = unsafe { pem_helpers::file_from_bytes(pem_data)? };
124 let ret = unsafe {
125 gmssl_rs_sys::sm9_sign_key_info_decrypt_from_pem(
126 key.as_mut_ptr(),
127 pass_c.as_ptr(),
128 fp,
129 )
130 };
131 unsafe { libc::fclose(fp) };
132 ok_or_library_error(ret, "sm9_sign_key_info_decrypt_from_pem")?;
133 Ok(Sm9SignKey {
134 key: unsafe { key.assume_init() },
135 id: String::new(), })
137 }
138
139 pub fn to_encrypted_pem(&self, password: &str) -> Result<Vec<u8>, GmsslError> {
141 let pass_c = std::ffi::CString::new(password)
142 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
143 unsafe {
144 pem_helpers::collect_to_bytes(|fp| {
145 gmssl_rs_sys::sm9_sign_key_info_encrypt_to_pem(
146 &self.key,
147 pass_c.as_ptr(),
148 fp,
149 )
150 })
151 }
152 }
153}
154
155pub fn sm9_sign(key: &Sm9SignKey, data: &[u8]) -> Result<Vec<u8>, GmsslError> {
161 let mut ctx = MaybeUninit::uninit();
162 ok_or_library_error(
163 unsafe { gmssl_rs_sys::sm9_sign_init(ctx.as_mut_ptr()) },
164 "sm9_sign_init",
165 )?;
166 ok_or_library_error(
167 unsafe { gmssl_rs_sys::sm9_sign_update(ctx.as_mut_ptr(), data.as_ptr(), data.len()) },
168 "sm9_sign_update",
169 )?;
170
171 let mut sig = vec![0u8; 256];
172 let mut siglen: usize = sig.len();
173 ok_or_library_error(
174 unsafe {
175 gmssl_rs_sys::sm9_sign_finish(
176 ctx.as_mut_ptr(),
177 &key.key,
178 sig.as_mut_ptr(),
179 &mut siglen,
180 )
181 },
182 "sm9_sign_finish",
183 )?;
184 truncate_der_sequence(&mut sig);
187 Ok(sig)
188}
189
190pub fn sm9_verify(
192 mpk: &Sm9SignMasterKey,
193 id: &str,
194 data: &[u8],
195 sig: &[u8],
196) -> Result<bool, GmsslError> {
197 let id_c = std::ffi::CString::new(id)
198 .map_err(|_| GmsslError::InvalidInput("ID contains NUL byte"))?;
199
200 let mut ctx = MaybeUninit::uninit();
201 ok_or_library_error(
202 unsafe { gmssl_rs_sys::sm9_verify_init(ctx.as_mut_ptr()) },
203 "sm9_verify_init",
204 )?;
205 ok_or_library_error(
206 unsafe { gmssl_rs_sys::sm9_verify_update(ctx.as_mut_ptr(), data.as_ptr(), data.len()) },
207 "sm9_verify_update",
208 )?;
209
210 verify_result(
211 unsafe {
212 gmssl_rs_sys::sm9_verify_finish(
213 ctx.as_mut_ptr(),
214 sig.as_ptr(),
215 sig.len(),
216 &mpk.key,
217 id_c.as_ptr(),
218 id.len(),
219 )
220 },
221 "sm9_verify_finish",
222 )
223}
224
225pub struct Sm9EncMasterKey {
230 key: gmssl_rs_sys::SM9_ENC_MASTER_KEY,
231}
232
233impl std::fmt::Debug for Sm9EncMasterKey {
234 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
235 f.debug_struct("Sm9EncMasterKey").finish()
236 }
237}
238
239impl Sm9EncMasterKey {
240 pub fn generate() -> Result<Self, GmsslError> {
242 let mut key = MaybeUninit::uninit();
243 ok_or_library_error(
244 unsafe { gmssl_rs_sys::sm9_enc_master_key_generate(key.as_mut_ptr()) },
245 "sm9_enc_master_key_generate",
246 )?;
247 Ok(Sm9EncMasterKey {
248 key: unsafe { key.assume_init() },
249 })
250 }
251
252 pub fn extract_key(&self, id: &str) -> Result<Sm9EncKey, GmsslError> {
254 let id_c = std::ffi::CString::new(id)
255 .map_err(|_| GmsslError::InvalidInput("ID contains NUL byte"))?;
256 let mut key = MaybeUninit::uninit();
257 ok_or_library_error(
258 unsafe {
259 gmssl_rs_sys::sm9_enc_master_key_extract_key(
260 &self.key,
261 id_c.as_ptr(),
262 id.len(),
263 key.as_mut_ptr(),
264 )
265 },
266 "sm9_enc_master_key_extract_key",
267 )?;
268 Ok(Sm9EncKey {
269 key: unsafe { key.assume_init() },
270 id: id.to_string(),
271 })
272 }
273
274 pub fn from_encrypted_pem(pem_data: &[u8], password: &str) -> Result<Self, GmsslError> {
276 let pass_c = std::ffi::CString::new(password)
277 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
278 let mut key = MaybeUninit::uninit();
279 let fp = unsafe { pem_helpers::file_from_bytes(pem_data)? };
280 let ret = unsafe {
281 gmssl_rs_sys::sm9_enc_master_key_info_decrypt_from_pem(
282 key.as_mut_ptr(),
283 pass_c.as_ptr(),
284 fp,
285 )
286 };
287 unsafe { libc::fclose(fp) };
288 ok_or_library_error(ret, "sm9_enc_master_key_info_decrypt_from_pem")?;
289 Ok(Sm9EncMasterKey {
290 key: unsafe { key.assume_init() },
291 })
292 }
293
294 pub fn to_encrypted_pem(&self, password: &str) -> Result<Vec<u8>, GmsslError> {
296 let pass_c = std::ffi::CString::new(password)
297 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
298 unsafe {
299 pem_helpers::collect_to_bytes(|fp| {
300 gmssl_rs_sys::sm9_enc_master_key_info_encrypt_to_pem(
301 &self.key,
302 pass_c.as_ptr(),
303 fp,
304 )
305 })
306 }
307 }
308}
309
310pub struct Sm9EncKey {
315 key: gmssl_rs_sys::SM9_ENC_KEY,
316 id: String,
317}
318
319impl std::fmt::Debug for Sm9EncKey {
320 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321 f.debug_struct("Sm9EncKey").field("id", &self.id).finish()
322 }
323}
324
325impl Sm9EncKey {
326 pub fn id(&self) -> &str {
328 &self.id
329 }
330
331 pub fn from_encrypted_pem(pem_data: &[u8], password: &str) -> Result<Self, GmsslError> {
333 let pass_c = std::ffi::CString::new(password)
334 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
335 let mut key = MaybeUninit::uninit();
336 let fp = unsafe { pem_helpers::file_from_bytes(pem_data)? };
337 let ret = unsafe {
338 gmssl_rs_sys::sm9_enc_key_info_decrypt_from_pem(
339 key.as_mut_ptr(),
340 pass_c.as_ptr(),
341 fp,
342 )
343 };
344 unsafe { libc::fclose(fp) };
345 ok_or_library_error(ret, "sm9_enc_key_info_decrypt_from_pem")?;
346 Ok(Sm9EncKey {
347 key: unsafe { key.assume_init() },
348 id: String::new(),
349 })
350 }
351
352 pub fn to_encrypted_pem(&self, password: &str) -> Result<Vec<u8>, GmsslError> {
354 let pass_c = std::ffi::CString::new(password)
355 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
356 unsafe {
357 pem_helpers::collect_to_bytes(|fp| {
358 gmssl_rs_sys::sm9_enc_key_info_encrypt_to_pem(
359 &self.key,
360 pass_c.as_ptr(),
361 fp,
362 )
363 })
364 }
365 }
366}
367
368pub fn sm9_encrypt(
374 mpk: &Sm9EncMasterKey,
375 id: &str,
376 data: &[u8],
377) -> Result<Vec<u8>, GmsslError> {
378 if data.len() > gmssl_rs_sys::SM9_MAX_PLAINTEXT_SIZE {
379 return Err(GmsslError::InvalidInput(
380 "SM9 plaintext exceeds 255 bytes maximum",
381 ));
382 }
383 let id_c = std::ffi::CString::new(id)
384 .map_err(|_| GmsslError::InvalidInput("ID contains NUL byte"))?;
385
386 let mut out = vec![0u8; gmssl_rs_sys::SM9_MAX_CIPHERTEXT_SIZE];
387 let mut outlen: usize = out.len();
388 ok_or_library_error(
389 unsafe {
390 gmssl_rs_sys::sm9_encrypt(
391 &mpk.key,
392 id_c.as_ptr(),
393 id.len(),
394 data.as_ptr(),
395 data.len(),
396 out.as_mut_ptr(),
397 &mut outlen,
398 )
399 },
400 "sm9_encrypt",
401 )?;
402 truncate_der_sequence(&mut out);
405 Ok(out)
406}
407
408pub fn sm9_decrypt(key: &Sm9EncKey, id: &str, ciphertext: &[u8]) -> Result<Vec<u8>, GmsslError> {
410 let id_c = std::ffi::CString::new(id)
411 .map_err(|_| GmsslError::InvalidInput("ID contains NUL byte"))?;
412
413 let mut out = vec![0u8; ciphertext.len()];
414 let mut outlen: usize = out.len();
415 ok_or_library_error(
416 unsafe {
417 gmssl_rs_sys::sm9_decrypt(
418 &key.key,
419 id_c.as_ptr(),
420 id.len(),
421 ciphertext.as_ptr(),
422 ciphertext.len(),
423 out.as_mut_ptr(),
424 &mut outlen,
425 )
426 },
427 "sm9_decrypt",
428 )?;
429 out.truncate(outlen);
430 Ok(out)
431}
432
433fn truncate_der_sequence(data: &mut Vec<u8>) {
435 if data.len() >= 2 && data[0] == 0x30 {
436 let content_len = data[1] as usize;
437 let total = if content_len < 0x80 {
438 2 + content_len
439 } else if content_len == 0x81 && data.len() >= 3 {
440 2 + 1 + data[2] as usize
441 } else if content_len == 0x82 && data.len() >= 4 {
442 let l = u16::from_be_bytes([data[2], data[3]]) as usize;
443 2 + 2 + l
444 } else {
445 return;
446 };
447 if total <= data.len() {
448 data.truncate(total);
449 }
450 }
451}
452
453#[cfg(test)]
454mod tests;