1use crate::asn1::oid::{ID_EC_PUBLIC_KEY, ID_HMAC_WITH_SM3, ID_PBKDF2, PBES2, SM2P256V1, SM4_CBC};
66use crate::asn1::{reader, writer};
67use crate::kdf::pbkdf2_hmac_sm3;
68use crate::sec1;
69use crate::sm2::Sm2PrivateKey;
70use crate::sm4::mode_cbc;
71use alloc::vec::Vec;
72use crypto_bigint::U256;
73use subtle::ConstantTimeEq;
74use zeroize::Zeroize;
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum Error {
80 Failed,
85}
86
87const PKCS8_V1: u8 = 0;
91const PKCS8_V2: u8 = 1;
92
93const SM4_KEY_LEN: usize = 16;
95const SM4_IV_LEN: usize = 16;
97
98pub const PBKDF2_MAX_ITERATIONS: u32 = 10_000_000;
105
106#[must_use]
118pub fn encode(key: &Sm2PrivateKey) -> Vec<u8> {
119 let mut scalar_be = key.to_sec1_be();
120 let pub_uncompressed = {
121 let pub_key = crate::sm2::Sm2PublicKey::from_point(key.public_key());
122 pub_key.to_sec1_uncompressed()
123 };
124 let mut inner = sec1::encode(&scalar_be, Some(&pub_uncompressed));
125 scalar_be.zeroize();
126
127 let mut alg_inner = Vec::with_capacity(ID_EC_PUBLIC_KEY.len() + SM2P256V1.len() + 4);
129 writer::write_oid(&mut alg_inner, ID_EC_PUBLIC_KEY);
130 writer::write_oid(&mut alg_inner, SM2P256V1);
131 let mut alg_seq = Vec::with_capacity(alg_inner.len() + 4);
132 writer::write_sequence(&mut alg_seq, &alg_inner);
133
134 let mut body = Vec::with_capacity(inner.len() + alg_seq.len() + 8);
135 writer::write_integer(&mut body, &[PKCS8_V1]);
136 body.extend_from_slice(&alg_seq);
137 writer::write_octet_string(&mut body, &inner);
138
139 let mut out = Vec::with_capacity(body.len() + 4);
140 writer::write_sequence(&mut out, &body);
141
142 inner.zeroize();
147 body.zeroize();
148 out
149}
150
151pub fn decode(input: &[u8]) -> Result<Sm2PrivateKey, Error> {
164 let (body, rest) = reader::read_sequence(input).ok_or(Error::Failed)?;
165 if !rest.is_empty() {
166 return Err(Error::Failed);
167 }
168
169 let (version, body) = reader::read_integer(body).ok_or(Error::Failed)?;
171 if version != [PKCS8_V1] && version != [PKCS8_V2] {
172 return Err(Error::Failed);
173 }
174
175 let (alg_inner, body) = reader::read_sequence(body).ok_or(Error::Failed)?;
177 let (alg_oid, alg_inner) = reader::read_oid(alg_inner).ok_or(Error::Failed)?;
178 if alg_oid != ID_EC_PUBLIC_KEY {
179 return Err(Error::Failed);
180 }
181 let (curve_oid, alg_inner) = reader::read_oid(alg_inner).ok_or(Error::Failed)?;
182 if curve_oid != SM2P256V1 || !alg_inner.is_empty() {
183 return Err(Error::Failed);
184 }
185
186 let (inner_bytes, body) = reader::read_octet_string(body).ok_or(Error::Failed)?;
188 let mut inner = sec1::decode(inner_bytes).ok_or(Error::Failed)?;
189
190 if !body.is_empty() {
195 let mut tail = body;
200 while !tail.is_empty() {
201 if let Some((_, after)) = reader::read_context_tagged_explicit(tail, 0) {
203 tail = after;
204 continue;
205 }
206 if let Some((_, after)) = reader::read_context_tagged_explicit(tail, 1) {
208 tail = after;
209 continue;
210 }
211 inner.scalar_be.zeroize();
213 return Err(Error::Failed);
214 }
215 }
216
217 let d = U256::from_be_slice(&inner.scalar_be);
218 inner.scalar_be.zeroize();
219 let key = Sm2PrivateKey::new(d);
220 let key: Option<Sm2PrivateKey> = key.into();
221 let key = key.ok_or(Error::Failed)?;
222
223 if let Some(stored_pub) = inner.public {
227 let derived = key.public_key();
228 if !bool::from(stored_pub.ct_eq(&derived)) {
229 return Err(Error::Failed);
230 }
231 }
232
233 Ok(key)
234}
235
236pub fn encrypt(
256 key: &Sm2PrivateKey,
257 password: &[u8],
258 salt: &[u8],
259 iterations: u32,
260 iv: &[u8; SM4_IV_LEN],
261) -> Result<Vec<u8>, Error> {
262 if iterations == 0 {
263 return Err(Error::Failed);
264 }
265
266 let mut inner = encode(key);
268
269 let mut sm4_key = [0u8; SM4_KEY_LEN];
271 pbkdf2_hmac_sm3(password, salt, iterations, &mut sm4_key).ok_or(Error::Failed)?;
272
273 let ciphertext = mode_cbc::encrypt(&sm4_key, iv, &inner);
275
276 inner.zeroize();
278 sm4_key.zeroize();
279
280 let pbes2_params = build_pbes2_params(salt, iterations, iv);
282 let mut alg_inner = Vec::with_capacity(PBES2.len() + pbes2_params.len() + 4);
283 writer::write_oid(&mut alg_inner, PBES2);
284 alg_inner.extend_from_slice(&pbes2_params);
285 let mut alg_seq = Vec::with_capacity(alg_inner.len() + 4);
286 writer::write_sequence(&mut alg_seq, &alg_inner);
287
288 let mut body = Vec::with_capacity(alg_seq.len() + ciphertext.len() + 8);
289 body.extend_from_slice(&alg_seq);
290 writer::write_octet_string(&mut body, &ciphertext);
291
292 let mut out = Vec::with_capacity(body.len() + 4);
293 writer::write_sequence(&mut out, &body);
294 Ok(out)
295}
296
297fn build_pbes2_params(salt: &[u8], iterations: u32, iv: &[u8; SM4_IV_LEN]) -> Vec<u8> {
313 let mut pbkdf2_inner = Vec::with_capacity(salt.len() + 32);
315 writer::write_octet_string(&mut pbkdf2_inner, salt);
316 writer::write_integer(&mut pbkdf2_inner, &iterations.to_be_bytes());
317 let mut prf_inner = Vec::with_capacity(ID_HMAC_WITH_SM3.len() + 4);
319 writer::write_oid(&mut prf_inner, ID_HMAC_WITH_SM3);
320 writer::write_null(&mut prf_inner);
321 let mut prf_seq = Vec::with_capacity(prf_inner.len() + 4);
322 writer::write_sequence(&mut prf_seq, &prf_inner);
323 pbkdf2_inner.extend_from_slice(&prf_seq);
324
325 let mut pbkdf2_seq = Vec::with_capacity(pbkdf2_inner.len() + 4);
326 writer::write_sequence(&mut pbkdf2_seq, &pbkdf2_inner);
327
328 let mut kdf_inner = Vec::with_capacity(ID_PBKDF2.len() + pbkdf2_seq.len() + 4);
330 writer::write_oid(&mut kdf_inner, ID_PBKDF2);
331 kdf_inner.extend_from_slice(&pbkdf2_seq);
332 let mut kdf_seq = Vec::with_capacity(kdf_inner.len() + 4);
333 writer::write_sequence(&mut kdf_seq, &kdf_inner);
334
335 let mut es_inner = Vec::with_capacity(SM4_CBC.len() + iv.len() + 4);
337 writer::write_oid(&mut es_inner, SM4_CBC);
338 writer::write_octet_string(&mut es_inner, iv);
339 let mut es_seq = Vec::with_capacity(es_inner.len() + 4);
340 writer::write_sequence(&mut es_seq, &es_inner);
341
342 let mut params_inner = Vec::with_capacity(kdf_seq.len() + es_seq.len());
343 params_inner.extend_from_slice(&kdf_seq);
344 params_inner.extend_from_slice(&es_seq);
345
346 let mut out = Vec::with_capacity(params_inner.len() + 4);
347 writer::write_sequence(&mut out, ¶ms_inner);
348 out
349}
350
351pub fn decrypt(input: &[u8], password: &[u8]) -> Result<Sm2PrivateKey, Error> {
364 let parsed = parse_encrypted_blob(input).ok_or(Error::Failed)?;
365
366 let mut sm4_key = [0u8; SM4_KEY_LEN];
368 let derive_ok =
369 pbkdf2_hmac_sm3(password, parsed.salt, parsed.iterations, &mut sm4_key).is_some();
370 let _ = derive_ok;
375
376 let plaintext = mode_cbc::decrypt(&sm4_key, &parsed.iv, parsed.ciphertext);
379 sm4_key.zeroize();
380
381 let mut plaintext = plaintext.ok_or(Error::Failed)?;
382
383 let result = decode(&plaintext);
386 plaintext.zeroize();
387 result
388}
389
390struct ParsedEncrypted<'a> {
392 salt: &'a [u8],
393 iterations: u32,
394 iv: [u8; SM4_IV_LEN],
395 ciphertext: &'a [u8],
396}
397
398fn parse_encrypted_blob(input: &[u8]) -> Option<ParsedEncrypted<'_>> {
402 let (body, rest) = reader::read_sequence(input)?;
403 if !rest.is_empty() {
404 return None;
405 }
406 let (alg_inner, body) = reader::read_sequence(body)?;
408 let (alg_oid, alg_inner) = reader::read_oid(alg_inner)?;
409 if alg_oid != PBES2 {
410 return None;
411 }
412 let (params_inner, alg_inner_rest) = reader::read_sequence(alg_inner)?;
413 if !alg_inner_rest.is_empty() {
414 return None;
415 }
416
417 let (kdf_seq, params_rest) = reader::read_sequence(params_inner)?;
419 let (kdf_oid, kdf_after) = reader::read_oid(kdf_seq)?;
420 if kdf_oid != ID_PBKDF2 {
421 return None;
422 }
423 let (pbkdf2_inner, kdf_seq_rest) = reader::read_sequence(kdf_after)?;
424 if !kdf_seq_rest.is_empty() {
425 return None;
426 }
427
428 let (salt, pbkdf2_inner) = reader::read_octet_string(pbkdf2_inner)?;
430 let (iter_bytes, mut pbkdf2_inner) = reader::read_integer(pbkdf2_inner)?;
431 if iter_bytes.len() > 4 {
432 return None;
433 }
434 let mut iter_buf = [0u8; 4];
435 iter_buf[4 - iter_bytes.len()..].copy_from_slice(iter_bytes);
436 let iterations = u32::from_be_bytes(iter_buf);
437 if iterations == 0 || iterations > PBKDF2_MAX_ITERATIONS {
438 return None;
439 }
440 if let Some((kl_bytes, after)) = reader::read_integer(pbkdf2_inner) {
442 if kl_bytes.len() > 4 {
443 return None;
444 }
445 let mut kl_buf = [0u8; 4];
446 kl_buf[4 - kl_bytes.len()..].copy_from_slice(kl_bytes);
447 let key_length = u32::from_be_bytes(kl_buf) as usize;
448 if key_length != SM4_KEY_LEN {
449 return None;
450 }
451 pbkdf2_inner = after;
452 }
453 if pbkdf2_inner.is_empty() {
458 return None;
459 }
460 let (prf_seq, prf_rest) = reader::read_sequence(pbkdf2_inner)?;
461 if !prf_rest.is_empty() {
462 return None;
463 }
464 let (prf_oid, prf_seq_rest) = reader::read_oid(prf_seq)?;
465 if prf_oid != ID_HMAC_WITH_SM3 {
466 return None;
467 }
468 if !prf_seq_rest.is_empty()
470 && (reader::read_null(prf_seq_rest).is_none() || prf_seq_rest.len() != 2)
471 {
472 return None;
473 }
474
475 let (es_seq, params_outer_rest) = reader::read_sequence(params_rest)?;
477 if !params_outer_rest.is_empty() {
478 return None;
479 }
480 let (es_oid, es_after) = reader::read_oid(es_seq)?;
481 if es_oid != SM4_CBC {
482 return None;
483 }
484 let (iv_bytes, es_seq_rest) = reader::read_octet_string(es_after)?;
485 if !es_seq_rest.is_empty() || iv_bytes.len() != SM4_IV_LEN {
486 return None;
487 }
488 let mut iv = [0u8; SM4_IV_LEN];
489 iv.copy_from_slice(iv_bytes);
490
491 let (ciphertext, body_rest) = reader::read_octet_string(body)?;
493 if !body_rest.is_empty() {
494 return None;
495 }
496
497 Some(ParsedEncrypted {
498 salt,
499 iterations,
500 iv,
501 ciphertext,
502 })
503}
504
505#[cfg(test)]
506mod tests {
507 use super::*;
508 use crypto_bigint::U256;
509
510 fn sample_key() -> Sm2PrivateKey {
511 let d =
512 U256::from_be_hex("3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8");
513 Sm2PrivateKey::new(d).expect("valid d")
514 }
515
516 #[test]
518 fn round_trip_unencrypted() {
519 let key = sample_key();
520 let der = encode(&key);
521 let recovered = decode(&der).expect("decode");
522 assert!(bool::from(recovered.public_key().ct_eq(&key.public_key())));
524 }
525
526 #[test]
528 fn unencrypted_rejects_trailing_bytes() {
529 let key = sample_key();
530 let mut der = encode(&key);
531 der.push(0x00);
532 assert!(matches!(decode(&der), Err(Error::Failed)));
533 }
534
535 #[test]
537 fn unencrypted_rejects_public_key_mismatch() {
538 let d1 =
541 U256::from_be_hex("3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8");
542 let d2 =
543 U256::from_be_hex("1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0");
544 let key1 = Sm2PrivateKey::new(d1).expect("d1");
545 let key2 = Sm2PrivateKey::new(d2).expect("d2");
546 let scalar1 = key1.to_sec1_be();
547 let pk2 = crate::sm2::Sm2PublicKey::from_point(key2.public_key()).to_sec1_uncompressed();
548 let inner_bad = sec1::encode(&scalar1, Some(&pk2));
549
550 let mut alg_inner = Vec::new();
552 writer::write_oid(&mut alg_inner, ID_EC_PUBLIC_KEY);
553 writer::write_oid(&mut alg_inner, SM2P256V1);
554 let mut alg_seq = Vec::new();
555 writer::write_sequence(&mut alg_seq, &alg_inner);
556 let mut body = Vec::new();
557 writer::write_integer(&mut body, &[PKCS8_V1]);
558 body.extend_from_slice(&alg_seq);
559 writer::write_octet_string(&mut body, &inner_bad);
560 let mut out = Vec::new();
561 writer::write_sequence(&mut out, &body);
562
563 assert!(matches!(decode(&out), Err(Error::Failed)));
564 }
565
566 #[test]
568 fn round_trip_encrypted() {
569 let key = sample_key();
570 let salt = [0xAB; 16];
571 let iv = [0xCD; SM4_IV_LEN];
572 let blob =
573 encrypt(&key, b"correct horse battery staple", &salt, 1024, &iv).expect("encrypt");
574 let recovered =
575 decrypt(&blob, b"correct horse battery staple").expect("decrypt with right password");
576 assert!(bool::from(recovered.public_key().ct_eq(&key.public_key())));
577 }
578
579 #[test]
581 fn encrypted_wrong_password_fails() {
582 let key = sample_key();
583 let salt = [0xAB; 16];
584 let iv = [0xCD; SM4_IV_LEN];
585 let blob = encrypt(&key, b"right", &salt, 1024, &iv).expect("encrypt");
586 assert!(matches!(decrypt(&blob, b"wrong"), Err(Error::Failed)));
587 }
588
589 #[test]
590 fn encrypted_zero_iterations_rejected() {
591 let key = sample_key();
592 let salt = [0xAB; 16];
593 let iv = [0xCD; SM4_IV_LEN];
594 assert!(matches!(
595 encrypt(&key, b"pw", &salt, 0, &iv),
596 Err(Error::Failed)
597 ));
598 }
599
600 #[test]
601 fn decrypt_rejects_truncated_blob() {
602 assert!(matches!(decrypt(&[], b"pw"), Err(Error::Failed)));
603 assert!(matches!(decrypt(&[0x30, 0x00], b"pw"), Err(Error::Failed)));
604 }
605
606 #[test]
607 fn decrypt_rejects_excessive_iterations() {
608 let key = sample_key();
610 let salt = [0xAB; 16];
611 let iv = [0xCD; SM4_IV_LEN];
612 let blob = encrypt(&key, b"pw", &salt, 1024, &iv).expect("encrypt");
613 let bad_iter: u32 = PBKDF2_MAX_ITERATIONS + 1;
619 let pbes2_params = build_pbes2_params(&salt, bad_iter, &iv);
620 let mut alg_inner = Vec::new();
621 writer::write_oid(&mut alg_inner, PBES2);
622 alg_inner.extend_from_slice(&pbes2_params);
623 let mut alg_seq = Vec::new();
624 writer::write_sequence(&mut alg_seq, &alg_inner);
625 let parsed = parse_encrypted_blob(&blob).expect("baseline parse");
628 let mut body = Vec::new();
629 body.extend_from_slice(&alg_seq);
630 writer::write_octet_string(&mut body, parsed.ciphertext);
631 let mut bad_blob = Vec::new();
632 writer::write_sequence(&mut bad_blob, &body);
633 assert!(matches!(decrypt(&bad_blob, b"pw"), Err(Error::Failed)));
634 }
635}