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
76pub type Error = crate::Error;
88
89const PKCS8_V1: u8 = 0;
93const PKCS8_V2: u8 = 1;
94
95const SM4_KEY_LEN: usize = 16;
97const SM4_IV_LEN: usize = 16;
99
100pub const PBKDF2_MAX_ITERATIONS: u32 = 10_000_000;
107
108#[must_use]
120pub fn encode(key: &Sm2PrivateKey) -> Vec<u8> {
121 let mut scalar_be = key.to_bytes_be();
122 let pub_uncompressed = {
123 let pub_key = crate::sm2::Sm2PublicKey::from_point(key.public_key());
124 pub_key.to_sec1_uncompressed()
125 };
126 let mut inner = sec1::encode(&scalar_be, Some(&pub_uncompressed));
127 scalar_be.zeroize();
128
129 let mut alg_inner = Vec::with_capacity(ID_EC_PUBLIC_KEY.len() + SM2P256V1.len() + 4);
131 writer::write_oid(&mut alg_inner, ID_EC_PUBLIC_KEY);
132 writer::write_oid(&mut alg_inner, SM2P256V1);
133 let mut alg_seq = Vec::with_capacity(alg_inner.len() + 4);
134 writer::write_sequence(&mut alg_seq, &alg_inner);
135
136 let mut body = Vec::with_capacity(inner.len() + alg_seq.len() + 8);
137 writer::write_integer(&mut body, &[PKCS8_V1]);
138 body.extend_from_slice(&alg_seq);
139 writer::write_octet_string(&mut body, &inner);
140
141 let mut out = Vec::with_capacity(body.len() + 4);
142 writer::write_sequence(&mut out, &body);
143
144 inner.zeroize();
149 body.zeroize();
150 out
151}
152
153pub fn decode(input: &[u8]) -> Result<Sm2PrivateKey, Error> {
166 let (body, rest) = reader::read_sequence(input).ok_or(Error::Failed)?;
167 if !rest.is_empty() {
168 return Err(Error::Failed);
169 }
170
171 let (version, body) = reader::read_integer(body).ok_or(Error::Failed)?;
173 if version != [PKCS8_V1] && version != [PKCS8_V2] {
174 return Err(Error::Failed);
175 }
176
177 let (alg_inner, body) = reader::read_sequence(body).ok_or(Error::Failed)?;
179 let (alg_oid, alg_inner) = reader::read_oid(alg_inner).ok_or(Error::Failed)?;
180 if alg_oid != ID_EC_PUBLIC_KEY {
181 return Err(Error::Failed);
182 }
183 let (curve_oid, alg_inner) = reader::read_oid(alg_inner).ok_or(Error::Failed)?;
184 if curve_oid != SM2P256V1 || !alg_inner.is_empty() {
185 return Err(Error::Failed);
186 }
187
188 let (inner_bytes, body) = reader::read_octet_string(body).ok_or(Error::Failed)?;
190 let mut inner = sec1::decode(inner_bytes).ok_or(Error::Failed)?;
191
192 if !body.is_empty() {
197 let mut tail = body;
202 while !tail.is_empty() {
203 if let Some((_, after)) = reader::read_context_tagged_explicit(tail, 0) {
205 tail = after;
206 continue;
207 }
208 if let Some((_, after)) = reader::read_context_tagged_explicit(tail, 1) {
210 tail = after;
211 continue;
212 }
213 inner.scalar_be.zeroize();
215 return Err(Error::Failed);
216 }
217 }
218
219 let d = U256::from_be_slice(&inner.scalar_be);
220 inner.scalar_be.zeroize();
221 let key = Sm2PrivateKey::from_scalar_inner(d);
222 let key: Option<Sm2PrivateKey> = key.into();
223 let key = key.ok_or(Error::Failed)?;
224
225 if let Some(stored_pub) = inner.public {
229 let derived = key.public_key();
230 if !bool::from(stored_pub.ct_eq(&derived)) {
231 return Err(Error::Failed);
232 }
233 }
234
235 Ok(key)
236}
237
238pub fn encrypt(
258 key: &Sm2PrivateKey,
259 password: &[u8],
260 salt: &[u8],
261 iterations: u32,
262 iv: &[u8; SM4_IV_LEN],
263) -> Result<Vec<u8>, Error> {
264 if iterations == 0 {
265 return Err(Error::Failed);
266 }
267
268 let mut inner = encode(key);
270
271 let mut sm4_key = [0u8; SM4_KEY_LEN];
273 pbkdf2_hmac_sm3(password, salt, iterations, &mut sm4_key).ok_or(Error::Failed)?;
274
275 let ciphertext = mode_cbc::encrypt(&sm4_key, iv, &inner);
277
278 inner.zeroize();
280 sm4_key.zeroize();
281
282 let pbes2_params = build_pbes2_params(salt, iterations, iv);
284 let mut alg_inner = Vec::with_capacity(PBES2.len() + pbes2_params.len() + 4);
285 writer::write_oid(&mut alg_inner, PBES2);
286 alg_inner.extend_from_slice(&pbes2_params);
287 let mut alg_seq = Vec::with_capacity(alg_inner.len() + 4);
288 writer::write_sequence(&mut alg_seq, &alg_inner);
289
290 let mut body = Vec::with_capacity(alg_seq.len() + ciphertext.len() + 8);
291 body.extend_from_slice(&alg_seq);
292 writer::write_octet_string(&mut body, &ciphertext);
293
294 let mut out = Vec::with_capacity(body.len() + 4);
295 writer::write_sequence(&mut out, &body);
296 Ok(out)
297}
298
299fn build_pbes2_params(salt: &[u8], iterations: u32, iv: &[u8; SM4_IV_LEN]) -> Vec<u8> {
315 let mut pbkdf2_inner = Vec::with_capacity(salt.len() + 32);
317 writer::write_octet_string(&mut pbkdf2_inner, salt);
318 writer::write_integer(&mut pbkdf2_inner, &iterations.to_be_bytes());
319 let mut prf_inner = Vec::with_capacity(ID_HMAC_WITH_SM3.len() + 4);
321 writer::write_oid(&mut prf_inner, ID_HMAC_WITH_SM3);
322 writer::write_null(&mut prf_inner);
323 let mut prf_seq = Vec::with_capacity(prf_inner.len() + 4);
324 writer::write_sequence(&mut prf_seq, &prf_inner);
325 pbkdf2_inner.extend_from_slice(&prf_seq);
326
327 let mut pbkdf2_seq = Vec::with_capacity(pbkdf2_inner.len() + 4);
328 writer::write_sequence(&mut pbkdf2_seq, &pbkdf2_inner);
329
330 let mut kdf_inner = Vec::with_capacity(ID_PBKDF2.len() + pbkdf2_seq.len() + 4);
332 writer::write_oid(&mut kdf_inner, ID_PBKDF2);
333 kdf_inner.extend_from_slice(&pbkdf2_seq);
334 let mut kdf_seq = Vec::with_capacity(kdf_inner.len() + 4);
335 writer::write_sequence(&mut kdf_seq, &kdf_inner);
336
337 let mut es_inner = Vec::with_capacity(SM4_CBC.len() + iv.len() + 4);
339 writer::write_oid(&mut es_inner, SM4_CBC);
340 writer::write_octet_string(&mut es_inner, iv);
341 let mut es_seq = Vec::with_capacity(es_inner.len() + 4);
342 writer::write_sequence(&mut es_seq, &es_inner);
343
344 let mut params_inner = Vec::with_capacity(kdf_seq.len() + es_seq.len());
345 params_inner.extend_from_slice(&kdf_seq);
346 params_inner.extend_from_slice(&es_seq);
347
348 let mut out = Vec::with_capacity(params_inner.len() + 4);
349 writer::write_sequence(&mut out, ¶ms_inner);
350 out
351}
352
353pub fn decrypt(input: &[u8], password: &[u8]) -> Result<Sm2PrivateKey, Error> {
366 let parsed = parse_encrypted_blob(input).ok_or(Error::Failed)?;
367
368 let mut sm4_key = [0u8; SM4_KEY_LEN];
370 let derive_ok =
371 pbkdf2_hmac_sm3(password, parsed.salt, parsed.iterations, &mut sm4_key).is_some();
372 let _ = derive_ok;
377
378 let plaintext = mode_cbc::decrypt(&sm4_key, &parsed.iv, parsed.ciphertext);
381 sm4_key.zeroize();
382
383 let mut plaintext = plaintext.ok_or(Error::Failed)?;
384
385 let result = decode(&plaintext);
388 plaintext.zeroize();
389 result
390}
391
392struct ParsedEncrypted<'a> {
394 salt: &'a [u8],
395 iterations: u32,
396 iv: [u8; SM4_IV_LEN],
397 ciphertext: &'a [u8],
398}
399
400fn parse_encrypted_blob(input: &[u8]) -> Option<ParsedEncrypted<'_>> {
404 let (body, rest) = reader::read_sequence(input)?;
405 if !rest.is_empty() {
406 return None;
407 }
408 let (alg_inner, body) = reader::read_sequence(body)?;
410 let (alg_oid, alg_inner) = reader::read_oid(alg_inner)?;
411 if alg_oid != PBES2 {
412 return None;
413 }
414 let (params_inner, alg_inner_rest) = reader::read_sequence(alg_inner)?;
415 if !alg_inner_rest.is_empty() {
416 return None;
417 }
418
419 let (kdf_seq, params_rest) = reader::read_sequence(params_inner)?;
421 let (kdf_oid, kdf_after) = reader::read_oid(kdf_seq)?;
422 if kdf_oid != ID_PBKDF2 {
423 return None;
424 }
425 let (pbkdf2_inner, kdf_seq_rest) = reader::read_sequence(kdf_after)?;
426 if !kdf_seq_rest.is_empty() {
427 return None;
428 }
429
430 let (salt, pbkdf2_inner) = reader::read_octet_string(pbkdf2_inner)?;
432 let (iter_bytes, mut pbkdf2_inner) = reader::read_integer(pbkdf2_inner)?;
433 if iter_bytes.len() > 4 {
434 return None;
435 }
436 let mut iter_buf = [0u8; 4];
437 iter_buf[4 - iter_bytes.len()..].copy_from_slice(iter_bytes);
438 let iterations = u32::from_be_bytes(iter_buf);
439 if iterations == 0 || iterations > PBKDF2_MAX_ITERATIONS {
440 return None;
441 }
442 if let Some((kl_bytes, after)) = reader::read_integer(pbkdf2_inner) {
444 if kl_bytes.len() > 4 {
445 return None;
446 }
447 let mut kl_buf = [0u8; 4];
448 kl_buf[4 - kl_bytes.len()..].copy_from_slice(kl_bytes);
449 let key_length = u32::from_be_bytes(kl_buf) as usize;
450 if key_length != SM4_KEY_LEN {
451 return None;
452 }
453 pbkdf2_inner = after;
454 }
455 if pbkdf2_inner.is_empty() {
460 return None;
461 }
462 let (prf_seq, prf_rest) = reader::read_sequence(pbkdf2_inner)?;
463 if !prf_rest.is_empty() {
464 return None;
465 }
466 let (prf_oid, prf_seq_rest) = reader::read_oid(prf_seq)?;
467 if prf_oid != ID_HMAC_WITH_SM3 {
468 return None;
469 }
470 if !prf_seq_rest.is_empty()
472 && (reader::read_null(prf_seq_rest).is_none() || prf_seq_rest.len() != 2)
473 {
474 return None;
475 }
476
477 let (es_seq, params_outer_rest) = reader::read_sequence(params_rest)?;
479 if !params_outer_rest.is_empty() {
480 return None;
481 }
482 let (es_oid, es_after) = reader::read_oid(es_seq)?;
483 if es_oid != SM4_CBC {
484 return None;
485 }
486 let (iv_bytes, es_seq_rest) = reader::read_octet_string(es_after)?;
487 if !es_seq_rest.is_empty() || iv_bytes.len() != SM4_IV_LEN {
488 return None;
489 }
490 let mut iv = [0u8; SM4_IV_LEN];
491 iv.copy_from_slice(iv_bytes);
492
493 let (ciphertext, body_rest) = reader::read_octet_string(body)?;
495 if !body_rest.is_empty() {
496 return None;
497 }
498
499 Some(ParsedEncrypted {
500 salt,
501 iterations,
502 iv,
503 ciphertext,
504 })
505}
506
507#[cfg(test)]
508mod tests {
509 use super::*;
510 use crypto_bigint::U256;
511
512 fn sample_key() -> Sm2PrivateKey {
513 let d =
514 U256::from_be_hex("3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8");
515 Sm2PrivateKey::from_scalar_inner(d).expect("valid d")
516 }
517
518 #[test]
520 fn round_trip_unencrypted() {
521 let key = sample_key();
522 let der = encode(&key);
523 let recovered = decode(&der).expect("decode");
524 assert!(bool::from(recovered.public_key().ct_eq(&key.public_key())));
526 }
527
528 #[test]
530 fn unencrypted_rejects_trailing_bytes() {
531 let key = sample_key();
532 let mut der = encode(&key);
533 der.push(0x00);
534 assert!(matches!(decode(&der), Err(Error::Failed)));
535 }
536
537 #[test]
539 fn unencrypted_rejects_public_key_mismatch() {
540 let d1 =
543 U256::from_be_hex("3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8");
544 let d2 =
545 U256::from_be_hex("1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0");
546 let key1 = Sm2PrivateKey::from_scalar_inner(d1).expect("d1");
547 let key2 = Sm2PrivateKey::from_scalar_inner(d2).expect("d2");
548 let scalar1 = key1.to_bytes_be();
549 let pk2 = crate::sm2::Sm2PublicKey::from_point(key2.public_key()).to_sec1_uncompressed();
550 let inner_bad = sec1::encode(&scalar1, Some(&pk2));
551
552 let mut alg_inner = Vec::new();
554 writer::write_oid(&mut alg_inner, ID_EC_PUBLIC_KEY);
555 writer::write_oid(&mut alg_inner, SM2P256V1);
556 let mut alg_seq = Vec::new();
557 writer::write_sequence(&mut alg_seq, &alg_inner);
558 let mut body = Vec::new();
559 writer::write_integer(&mut body, &[PKCS8_V1]);
560 body.extend_from_slice(&alg_seq);
561 writer::write_octet_string(&mut body, &inner_bad);
562 let mut out = Vec::new();
563 writer::write_sequence(&mut out, &body);
564
565 assert!(matches!(decode(&out), Err(Error::Failed)));
566 }
567
568 #[test]
570 fn round_trip_encrypted() {
571 let key = sample_key();
572 let salt = [0xAB; 16];
573 let iv = [0xCD; SM4_IV_LEN];
574 let blob =
575 encrypt(&key, b"correct horse battery staple", &salt, 1024, &iv).expect("encrypt");
576 let recovered =
577 decrypt(&blob, b"correct horse battery staple").expect("decrypt with right password");
578 assert!(bool::from(recovered.public_key().ct_eq(&key.public_key())));
579 }
580
581 #[test]
583 fn encrypted_wrong_password_fails() {
584 let key = sample_key();
585 let salt = [0xAB; 16];
586 let iv = [0xCD; SM4_IV_LEN];
587 let blob = encrypt(&key, b"right", &salt, 1024, &iv).expect("encrypt");
588 assert!(matches!(decrypt(&blob, b"wrong"), Err(Error::Failed)));
589 }
590
591 #[test]
592 fn encrypted_zero_iterations_rejected() {
593 let key = sample_key();
594 let salt = [0xAB; 16];
595 let iv = [0xCD; SM4_IV_LEN];
596 assert!(matches!(
597 encrypt(&key, b"pw", &salt, 0, &iv),
598 Err(Error::Failed)
599 ));
600 }
601
602 #[test]
603 fn decrypt_rejects_truncated_blob() {
604 assert!(matches!(decrypt(&[], b"pw"), Err(Error::Failed)));
605 assert!(matches!(decrypt(&[0x30, 0x00], b"pw"), Err(Error::Failed)));
606 }
607
608 #[test]
609 fn decrypt_rejects_excessive_iterations() {
610 let key = sample_key();
612 let salt = [0xAB; 16];
613 let iv = [0xCD; SM4_IV_LEN];
614 let blob = encrypt(&key, b"pw", &salt, 1024, &iv).expect("encrypt");
615 let bad_iter: u32 = PBKDF2_MAX_ITERATIONS + 1;
621 let pbes2_params = build_pbes2_params(&salt, bad_iter, &iv);
622 let mut alg_inner = Vec::new();
623 writer::write_oid(&mut alg_inner, PBES2);
624 alg_inner.extend_from_slice(&pbes2_params);
625 let mut alg_seq = Vec::new();
626 writer::write_sequence(&mut alg_seq, &alg_inner);
627 let parsed = parse_encrypted_blob(&blob).expect("baseline parse");
630 let mut body = Vec::new();
631 body.extend_from_slice(&alg_seq);
632 writer::write_octet_string(&mut body, parsed.ciphertext);
633 let mut bad_blob = Vec::new();
634 writer::write_sequence(&mut bad_blob, &body);
635 assert!(matches!(decrypt(&bad_blob, b"pw"), Err(Error::Failed)));
636 }
637}