1use std::mem::MaybeUninit;
8use gmssl_rs_sys;
9
10use crate::error::{ok_or_library_error, verify_result, GmsslError};
11use crate::pem_helpers;
12
13#[derive(Debug)]
15pub struct Sm2Key {
16 key: gmssl_rs_sys::SM2_KEY,
17 has_private_key: bool,
18}
19
20impl Sm2Key {
21 pub fn generate() -> Result<Self, GmsslError> {
23 let mut key = MaybeUninit::uninit();
24 ok_or_library_error(
25 unsafe { gmssl_rs_sys::sm2_key_generate(key.as_mut_ptr()) },
26 "sm2_key_generate",
27 )?;
28 Ok(Sm2Key {
29 key: unsafe { key.assume_init() },
30 has_private_key: true,
31 })
32 }
33
34 pub fn from_encrypted_private_key_pem(
36 pem_data: &[u8],
37 password: &str,
38 ) -> Result<Self, GmsslError> {
39 let pass_c = std::ffi::CString::new(password)
40 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
41
42 let mut key = MaybeUninit::uninit();
43 pem_helpers::read_pem_data(pem_data, |fp| unsafe {
44 gmssl_rs_sys::sm2_private_key_info_decrypt_from_pem(
45 key.as_mut_ptr(),
46 pass_c.as_ptr(),
47 fp,
48 )
49 })?;
50 let fp = unsafe { pem_helpers::file_from_bytes(pem_data)? };
52 let ret = unsafe {
53 gmssl_rs_sys::sm2_private_key_info_decrypt_from_pem(
54 key.as_mut_ptr(),
55 pass_c.as_ptr(),
56 fp,
57 )
58 };
59 unsafe { libc::fclose(fp) };
60 ok_or_library_error(ret, "sm2_private_key_info_decrypt_from_pem")?;
61 Ok(Sm2Key {
62 key: unsafe { key.assume_init() },
63 has_private_key: true,
64 })
65 }
66
67 pub fn to_encrypted_private_key_pem(
69 &self,
70 password: &str,
71 ) -> Result<Vec<u8>, GmsslError> {
72 if !self.has_private_key {
73 return Err(GmsslError::InvalidKey("no private key to export"));
74 }
75 let pass_c = std::ffi::CString::new(password)
76 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
77
78 unsafe {
79 pem_helpers::collect_to_bytes(|fp| {
80 gmssl_rs_sys::sm2_private_key_info_encrypt_to_pem(
81 &self.key,
82 pass_c.as_ptr(),
83 fp,
84 )
85 })
86 }
87 }
88
89 pub fn from_public_key_pem(pem_data: &[u8]) -> Result<Self, GmsslError> {
91 let mut key = MaybeUninit::uninit();
92 let fp = unsafe { pem_helpers::file_from_bytes(pem_data)? };
93 let ret = unsafe {
94 gmssl_rs_sys::sm2_public_key_info_from_pem(key.as_mut_ptr(), fp)
95 };
96 unsafe { libc::fclose(fp) };
97 ok_or_library_error(ret, "sm2_public_key_info_from_pem")?;
98 Ok(Sm2Key {
99 key: unsafe { key.assume_init() },
100 has_private_key: false,
101 })
102 }
103
104 pub fn to_public_key_pem(&self) -> Result<Vec<u8>, GmsslError> {
106 unsafe {
107 pem_helpers::collect_to_bytes(|fp| {
108 gmssl_rs_sys::sm2_public_key_info_to_pem(&self.key, fp)
109 })
110 }
111 }
112
113 pub fn from_private_key_pem(pem_data: &[u8]) -> Result<Self, GmsslError> {
115 let mut key = MaybeUninit::uninit();
116 let fp = unsafe { pem_helpers::file_from_bytes(pem_data)? };
117 let ret = unsafe {
118 gmssl_rs_sys::sm2_private_key_info_from_pem(key.as_mut_ptr(), fp)
119 };
120 unsafe { libc::fclose(fp) };
121 ok_or_library_error(ret, "sm2_private_key_info_from_pem")?;
122 Ok(Sm2Key {
123 key: unsafe { key.assume_init() },
124 has_private_key: true,
125 })
126 }
127
128 pub fn to_private_key_pem(&self) -> Result<Vec<u8>, GmsslError> {
130 if !self.has_private_key {
131 return Err(GmsslError::InvalidKey("no private key to export"));
132 }
133 unsafe {
134 pem_helpers::collect_to_bytes(|fp| {
135 gmssl_rs_sys::sm2_private_key_info_to_pem(&self.key, fp)
136 })
137 }
138 }
139
140 pub fn from_public_key_der(der: &[u8]) -> Result<Self, GmsslError> {
142 unsafe {
143 pem_helpers::parse_der(der, |key, pin, pinlen| {
144 gmssl_rs_sys::sm2_public_key_info_from_der(key, pin, pinlen)
145 })
146 }
147 .map(|key| Sm2Key {
148 key,
149 has_private_key: false,
150 })
151 }
152
153 pub fn to_public_key_der(&self) -> Result<Vec<u8>, GmsslError> {
155 unsafe {
156 pem_helpers::collect_der(512, |out, outlen| {
157 gmssl_rs_sys::sm2_public_key_info_to_der(&self.key, out, outlen)
158 })
159 }
160 }
161
162 pub fn from_private_key_der(der: &[u8]) -> Result<Self, GmsslError> {
164 unsafe {
165 let mut attrs: *const u8 = std::ptr::null();
166 let mut attrslen: usize = 0;
167 pem_helpers::parse_der(der, |key, pin, pinlen| {
168 gmssl_rs_sys::sm2_private_key_info_from_der(
169 key,
170 &mut attrs,
171 &mut attrslen,
172 pin,
173 pinlen,
174 )
175 })
176 }
177 .map(|key| Sm2Key {
178 key,
179 has_private_key: true,
180 })
181 }
182
183 pub fn to_private_key_der(&self) -> Result<Vec<u8>, GmsslError> {
185 if !self.has_private_key {
186 return Err(GmsslError::InvalidKey("no private key to export"));
187 }
188 unsafe {
189 pem_helpers::collect_der(512, |out, outlen| {
190 gmssl_rs_sys::sm2_private_key_info_to_der(&self.key, out, outlen)
191 })
192 }
193 }
194
195 pub fn from_public_key_pem_file(path: &str) -> Result<Self, GmsslError> {
197 let mut key = MaybeUninit::uninit();
198 let fp = unsafe { pem_helpers::file_open_read(path)? };
199 let ret = unsafe {
200 gmssl_rs_sys::sm2_public_key_info_from_pem(key.as_mut_ptr(), fp)
201 };
202 unsafe { libc::fclose(fp) };
203 ok_or_library_error(ret, "sm2_public_key_info_from_pem")?;
204 Ok(Sm2Key {
205 key: unsafe { key.assume_init() },
206 has_private_key: false,
207 })
208 }
209
210 pub fn to_public_key_pem_file(&self, path: &str) -> Result<(), GmsslError> {
212 let fp = unsafe { pem_helpers::file_open_write(path)? };
213 let ret = unsafe {
214 gmssl_rs_sys::sm2_public_key_info_to_pem(&self.key, fp)
215 };
216 unsafe { libc::fclose(fp) };
217 ok_or_library_error(ret, "sm2_public_key_info_to_pem")
218 }
219
220 pub fn from_encrypted_private_key_pem_file(
222 path: &str,
223 password: &str,
224 ) -> Result<Self, GmsslError> {
225 let pass_c = std::ffi::CString::new(password)
226 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
227 let mut key = MaybeUninit::uninit();
228 let fp = unsafe { pem_helpers::file_open_read(path)? };
229 let ret = unsafe {
230 gmssl_rs_sys::sm2_private_key_info_decrypt_from_pem(
231 key.as_mut_ptr(),
232 pass_c.as_ptr(),
233 fp,
234 )
235 };
236 unsafe { libc::fclose(fp) };
237 ok_or_library_error(ret, "sm2_private_key_info_decrypt_from_pem")?;
238 Ok(Sm2Key {
239 key: unsafe { key.assume_init() },
240 has_private_key: true,
241 })
242 }
243
244 pub fn to_encrypted_private_key_pem_file(
246 &self,
247 path: &str,
248 password: &str,
249 ) -> Result<(), GmsslError> {
250 if !self.has_private_key {
251 return Err(GmsslError::InvalidKey("no private key to export"));
252 }
253 let pass_c = std::ffi::CString::new(password)
254 .map_err(|_| GmsslError::InvalidInput("password contains NUL byte"))?;
255 let fp = unsafe { pem_helpers::file_open_write(path)? };
256 let ret = unsafe {
257 gmssl_rs_sys::sm2_private_key_info_encrypt_to_pem(
258 &self.key,
259 pass_c.as_ptr(),
260 fp,
261 )
262 };
263 unsafe { libc::fclose(fp) };
264 ok_or_library_error(ret, "sm2_private_key_info_encrypt_to_pem")
265 }
266
267 pub fn compute_z(&self, id: &str) -> Result<[u8; 32], GmsslError> {
269 let id_c = std::ffi::CString::new(id)
270 .map_err(|_| GmsslError::InvalidInput("ID contains NUL byte"))?;
271 let mut z = [0u8; 32];
272 ok_or_library_error(
273 unsafe {
274 gmssl_rs_sys::sm2_compute_z(
275 z.as_mut_ptr(),
276 &self.key.public_key,
277 id_c.as_ptr(),
278 id.len(),
279 )
280 },
281 "sm2_compute_z",
282 )?;
283 Ok(z)
284 }
285
286 pub fn has_private_key(&self) -> bool {
288 self.has_private_key
289 }
290
291 pub(crate) fn as_ptr(&self) -> *const gmssl_rs_sys::SM2_KEY {
293 &self.key
294 }
295}
296
297pub struct Sm2Signer {
303 ctx: Box<MaybeUninit<gmssl_rs_sys::SM2_SIGN_CTX>>,
304}
305
306impl Sm2Signer {
307 pub fn new(key: &Sm2Key, id: Option<&str>) -> Result<Self, GmsslError> {
312 if !key.has_private_key {
313 return Err(GmsslError::InvalidKey("private key required for signing"));
314 }
315 let id = id.unwrap_or("1234567812345678");
316 let id_c = std::ffi::CString::new(id)
317 .map_err(|_| GmsslError::InvalidInput("ID contains NUL byte"))?;
318
319 let mut ctx = Box::new(MaybeUninit::uninit());
320 ok_or_library_error(
321 unsafe {
322 gmssl_rs_sys::sm2_sign_init(
323 ctx.as_mut_ptr(),
324 key.as_ptr(),
325 id_c.as_ptr(),
326 id.len(),
327 )
328 },
329 "sm2_sign_init",
330 )?;
331 Ok(Sm2Signer { ctx })
332 }
333
334 pub fn update(&mut self, data: &[u8]) -> Result<(), GmsslError> {
336 ok_or_library_error(
337 unsafe {
338 gmssl_rs_sys::sm2_sign_update(self.ctx.as_mut_ptr(), data.as_ptr(), data.len())
339 },
340 "sm2_sign_update",
341 )
342 }
343
344 pub fn finish(&mut self) -> Result<Vec<u8>, GmsslError> {
346 let mut sig = vec![0u8; gmssl_rs_sys::SM2_MAX_SIGNATURE_SIZE];
347 let mut siglen: usize = sig.len();
348 ok_or_library_error(
349 unsafe {
350 gmssl_rs_sys::sm2_sign_finish(
351 self.ctx.as_mut_ptr(),
352 sig.as_mut_ptr(),
353 &mut siglen,
354 )
355 },
356 "sm2_sign_finish",
357 )?;
358 truncate_der_sequence(&mut sig);
361 Ok(sig)
362 }
363
364 pub fn sign(key: &Sm2Key, id: Option<&str>, data: &[u8]) -> Result<Vec<u8>, GmsslError> {
366 let mut signer = Sm2Signer::new(key, id)?;
367 signer.update(data)?;
368 signer.finish()
369 }
370}
371
372impl std::fmt::Debug for Sm2Signer {
373 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
374 f.debug_struct("Sm2Signer").finish()
375 }
376}
377
378pub struct Sm2Verifier {
380 ctx: Box<MaybeUninit<gmssl_rs_sys::SM2_VERIFY_CTX>>,
381}
382
383impl Sm2Verifier {
384 pub fn new(key: &Sm2Key, id: Option<&str>) -> Result<Self, GmsslError> {
386 let id = id.unwrap_or("1234567812345678");
387 let id_c = std::ffi::CString::new(id)
388 .map_err(|_| GmsslError::InvalidInput("ID contains NUL byte"))?;
389
390 let mut ctx = Box::new(MaybeUninit::uninit());
391 ok_or_library_error(
392 unsafe {
393 gmssl_rs_sys::sm2_verify_init(
394 ctx.as_mut_ptr(),
395 key.as_ptr(),
396 id_c.as_ptr(),
397 id.len(),
398 )
399 },
400 "sm2_verify_init",
401 )?;
402 Ok(Sm2Verifier { ctx })
403 }
404
405 pub fn update(&mut self, data: &[u8]) -> Result<(), GmsslError> {
407 ok_or_library_error(
408 unsafe {
409 gmssl_rs_sys::sm2_verify_update(self.ctx.as_mut_ptr(), data.as_ptr(), data.len())
410 },
411 "sm2_verify_update",
412 )
413 }
414
415 pub fn finish(&mut self, sig: &[u8]) -> Result<bool, GmsslError> {
419 verify_result(
420 unsafe {
421 gmssl_rs_sys::sm2_verify_finish(
422 self.ctx.as_mut_ptr(),
423 sig.as_ptr(),
424 sig.len(),
425 )
426 },
427 "sm2_verify_finish",
428 )
429 }
430
431 pub fn verify(
433 key: &Sm2Key,
434 id: Option<&str>,
435 data: &[u8],
436 sig: &[u8],
437 ) -> Result<bool, GmsslError> {
438 let mut verifier = Sm2Verifier::new(key, id)?;
439 verifier.update(data)?;
440 verifier.finish(sig)
441 }
442}
443
444impl std::fmt::Debug for Sm2Verifier {
445 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
446 f.debug_struct("Sm2Verifier").finish()
447 }
448}
449
450pub fn sm2_encrypt(key: &Sm2Key, data: &[u8]) -> Result<Vec<u8>, GmsslError> {
455 if data.len() > gmssl_rs_sys::SM2_MAX_PLAINTEXT_SIZE {
456 return Err(GmsslError::InvalidInput(
457 "SM2 plaintext exceeds 255 bytes maximum",
458 ));
459 }
460 let mut out = vec![0u8; gmssl_rs_sys::SM2_MAX_CIPHERTEXT_SIZE];
461 let mut outlen: usize = out.len();
462 ok_or_library_error(
463 unsafe {
464 gmssl_rs_sys::sm2_encrypt(
465 key.as_ptr(),
466 data.as_ptr(),
467 data.len(),
468 out.as_mut_ptr(),
469 &mut outlen,
470 )
471 },
472 "sm2_encrypt",
473 )?;
474 truncate_der_sequence(&mut out);
476 Ok(out)
477}
478
479pub fn sm2_decrypt(key: &Sm2Key, ciphertext: &[u8]) -> Result<Vec<u8>, GmsslError> {
483 if !key.has_private_key {
484 return Err(GmsslError::InvalidKey("private key required for decryption"));
485 }
486 let mut out = vec![0u8; ciphertext.len()];
487 let mut outlen: usize = out.len();
488 ok_or_library_error(
489 unsafe {
490 gmssl_rs_sys::sm2_decrypt(
491 key.as_ptr(),
492 ciphertext.as_ptr(),
493 ciphertext.len(),
494 out.as_mut_ptr(),
495 &mut outlen,
496 )
497 },
498 "sm2_decrypt",
499 )?;
500 out.truncate(outlen);
501 Ok(out)
502}
503
504pub fn sm2_ecdh(key: &Sm2Key, peer_key: &Sm2Key) -> Result<[u8; 32], GmsslError> {
508 if !key.has_private_key {
509 return Err(GmsslError::InvalidKey("private key required for ECDH"));
510 }
511 let mut out = [0u8; 32];
512 ok_or_library_error(
513 unsafe { gmssl_rs_sys::sm2_do_ecdh(key.as_ptr(), peer_key.as_ptr(), out.as_mut_ptr()) },
514 "sm2_do_ecdh",
515 )?;
516 Ok(out)
517}
518
519fn truncate_der_sequence(data: &mut Vec<u8>) {
525 if data.len() >= 2 && data[0] == 0x30 {
526 let content_len = data[1] as usize;
527 let total = if content_len < 0x80 {
528 2 + content_len
530 } else if content_len == 0x81 && data.len() >= 3 {
531 2 + 1 + data[2] as usize
533 } else if content_len == 0x82 && data.len() >= 4 {
534 let l = u16::from_be_bytes([data[2], data[3]]) as usize;
536 2 + 2 + l
537 } else {
538 return; };
540 if total <= data.len() {
541 data.truncate(total);
542 }
543 }
544}
545
546#[cfg(test)]
547mod tests;