use sec1::{
consts::U32,
der::{
self, Decode, DecodeValue, Document, Encode, EncodeValue, Error, Header, Length, Reader,
Result, Sequence, Writer,
asn1::OctetStringRef,
pem::{LineEnding, PemLabel},
},
};
use sm9_core::{G1, G2, Group, fast_pairing};
use std::path::Path;
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::*;
pub type EncodedPoint = sec1::EncodedPoint<U32>;
macro_rules! key_impl {
($name:ident) => {
#[derive(Clone, Debug, Default, Eq, PartialEq, ZeroizeOnDrop)]
pub struct $name(Vec<u8>);
impl $name {
pub(crate) fn new(private_key: &[u8]) -> Self {
let mut v: Vec<u8> = Vec::<u8>::new();
v.extend_from_slice(private_key);
Self(v)
}
pub(crate) fn as_slice(&self) -> &[u8] {
self.0.as_slice()
}
}
impl EncodeKey for $name {
fn to_key_der(&self) -> Result<Document> {
let a = PrivateKey::try_from(self.as_slice())?;
Document::try_from(&a)
}
fn read_pem_file(path: impl AsRef<Path>) -> Result<Self> {
let (label, doc) = Document::read_pem_file(path)?;
Self::validate_pem_label(&label)?;
let key: PrivateKey = doc.decode_msg()?;
Ok(Self::new(key.private_key))
}
fn from_pem(pem: &str) -> Result<Self> {
let (label, doc) =
Document::from_pem(pem).map(|(label, doc)| (label.to_owned(), doc))?;
Self::validate_pem_label(&label)?;
let key: PrivateKey = doc.decode_msg()?;
Ok(Self::new(key.private_key))
}
}
impl Zeroize for $name {
fn zeroize(&mut self) {
self.0.zeroize()
}
}
};
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct PrivateKey<'a> {
private_key: &'a [u8],
}
const VERSION: u8 = 1;
impl<'a> DecodeValue<'a> for PrivateKey<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
if u8::decode(reader)? != VERSION {
return Err(der::Tag::Integer.value_error());
}
let private_key = OctetStringRef::decode(reader)?.as_bytes();
Ok(PrivateKey { private_key })
})
}
}
impl EncodeValue for PrivateKey<'_> {
fn value_len(&self) -> der::Result<Length> {
VERSION.encoded_len()? + OctetStringRef::new(self.private_key)?.encoded_len()?
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
VERSION.encode(writer)?;
OctetStringRef::new(self.private_key)?.encode(writer)
}
}
impl<'a> Sequence<'a> for PrivateKey<'a> {}
impl<'a> TryFrom<&'a [u8]> for PrivateKey<'a> {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<PrivateKey<'a>> {
Ok(Self { private_key: bytes })
}
}
impl TryFrom<PrivateKey<'_>> for Document {
type Error = Error;
fn try_from(private_key: PrivateKey<'_>) -> Result<Self> {
Document::try_from(&private_key)
}
}
impl TryFrom<&PrivateKey<'_>> for Document {
type Error = Error;
fn try_from(private_key: &PrivateKey<'_>) -> Result<Self> {
Self::encode_msg(private_key)
}
}
pub trait EncodeKey: Sized {
fn write_pem_file(
&self,
path: impl AsRef<Path>,
label: &'static str,
line_ending: LineEnding,
) -> Result<()> {
let doc = self.to_key_der()?;
doc.write_pem_file(path, label, line_ending)
}
fn to_key_der(&self) -> Result<Document>;
fn read_pem_file(path: impl AsRef<Path>) -> Result<Self>;
fn from_pem(pem: &str) -> Result<Self>;
}
key_impl!(MasterPrivateKey);
impl PemLabel for MasterPrivateKey {
const PEM_LABEL: &'static str = "SM9 MASTER PRIVATE KEY";
}
impl MasterPrivateKey {
pub(crate) fn generate_master_public_key_to_pem(&self, path: impl AsRef<Path>) {
let ke = Fn::from_slice(self.as_slice()).unwrap();
let pub_e = G1::one() * ke;
let a = pub_e.to_compressed();
let user_key = MasterPublicKey::new(a.as_ref());
assert!(
user_key
.write_pem_file(path, MasterPublicKey::PEM_LABEL, LineEnding::CRLF)
.is_ok()
);
}
pub(crate) fn generate_user_private_key_to_pem(&self, user_id: &[u8], path: impl AsRef<Path>) {
let ke = Fn::from_slice(self.as_slice()).unwrap();
let mut z = Vec::<u8>::new();
z.extend_from_slice(user_id);
z.push(SM9_HID_ENC);
let a = Sm9::hash_1(z.as_slice()).unwrap();
let t1 = a + ke;
let t2 = ke * t1.inverse().unwrap();
let de = G2::one() * t2;
let a = de.to_compressed();
let user_key = UserPrivateKey::new(a.as_ref());
assert!(
user_key
.write_pem_file(path, UserPrivateKey::PEM_LABEL, LineEnding::CRLF)
.is_ok()
);
}
pub(crate) fn generate_master_signature_public_key_to_pem(&self, path: impl AsRef<Path>) {
let ks = Fn::from_slice(self.as_slice()).unwrap();
let pub_s = G2::one() * ks;
let a = pub_s.to_compressed();
let key = MasterSignaturePublicKey::new(a.as_ref());
assert!(
key.write_pem_file(path, MasterSignaturePublicKey::PEM_LABEL, LineEnding::CRLF)
.is_ok()
);
}
pub(crate) fn generate_user_signature_private_key_to_pem(
&self,
user_id: &[u8],
path: impl AsRef<Path>,
) {
let ks = Fn::from_slice(self.as_slice()).unwrap();
let mut z = Vec::<u8>::new();
z.extend_from_slice(user_id);
z.push(SM9_HID_SIGN);
let a = Sm9::hash_1(z.as_slice()).unwrap();
let t1 = a + ks;
let t2 = ks * t1.inverse().unwrap();
let ds = G1::one() * t2;
let a = ds.to_compressed();
let user_key = UserSignaturePrivateKey::new(a.as_ref());
assert!(
user_key
.write_pem_file(path, UserSignaturePrivateKey::PEM_LABEL, LineEnding::CRLF)
.is_ok()
);
}
}
key_impl!(MasterPublicKey);
impl PemLabel for MasterPublicKey {
const PEM_LABEL: &'static str = "SM9 MASTER PUBLIC KEY";
}
impl MasterPublicKey {
pub(crate) fn is_ok(&self) -> bool {
self.to_g1().is_some()
}
pub(crate) fn to_g1(&self) -> Option<G1> {
let b = self.as_slice();
match b.len() {
33 => G1::from_compressed(b).ok(),
64 => G1::from_slice(b).ok(),
65 => G1::from_uncompressed(b).ok(),
_ => None,
}
}
pub(crate) fn key_encapsulation(&self, usr_id: &[u8], klen: usize) -> (Vec<u8>, G1) {
let mut z = Vec::<u8>::new();
z.extend_from_slice(usr_id);
z.push(SM9_HID_ENC);
let h1 = Sm9::hash_1(z.as_slice()).unwrap();
let g1 = G1::one() * h1;
let pube = self.to_g1().expect("MasterPublicKey error");
let q = g1 + pube;
let g = fast_pairing(pube, G2::one());
let mut c;
let mut k;
let rng = &mut rng();
loop {
let r = Fn::random(rng);
c = r * q;
let w = g.pow(r);
let mut z = Vec::<u8>::new();
z.extend_from_slice(c.to_slice().as_ref());
z.extend_from_slice(w.to_slice().as_ref());
z.extend_from_slice(usr_id);
k = Sm9::kdf(z.as_ref(), klen).expect("klen maybe error");
if !k.iter().all(|&e| e == 0) {
break; }
}
(k, c)
}
pub(crate) fn encrypt(&self, usr_id: &[u8], m: &[u8]) -> Vec<u8> {
let klen = m.len() + 32;
let (k, c1) = self.key_encapsulation(usr_id, klen);
let mut c2 = Vec::<u8>::new();
for (b, x) in m.iter().zip(k.iter()) {
c2.push(*b ^ *x);
}
let k2 = &k[m.len()..];
let mut mac = HmacSm3::new_from_slice(k2).expect("HMAC can take key of any size");
mac.update(c2.as_slice());
let c3 = mac.finalize().into_bytes();
let mut c = Vec::<u8>::new();
c.extend_from_slice(c1.to_slice().as_ref());
c.extend_from_slice(c3.as_slice());
c.extend_from_slice(c2.as_slice());
c
}
}
key_impl!(UserPrivateKey);
impl PemLabel for UserPrivateKey {
const PEM_LABEL: &'static str = "SM9 USER PRIVATE KEY";
}
impl UserPrivateKey {
pub(crate) fn is_ok(&self) -> bool {
self.to_g2().is_some()
}
pub(crate) fn to_g2(&self) -> Option<G2> {
let b = self.as_slice();
match b.len() {
65 => G2::from_compressed(b).ok(),
128 => G2::from_slice(b).ok(),
129 => G2::from_uncompressed(b).ok(),
_ => None,
}
}
pub(crate) fn key_decapsulation(&self, usr_id: &[u8], klen: usize, c: &G1) -> Vec<u8> {
let de = self.to_g2().expect("UserPrivateKey error");
let w = fast_pairing(*c, de);
let mut z = Vec::<u8>::new();
z.extend_from_slice(c.to_slice().as_ref());
z.extend_from_slice(w.to_slice().as_ref());
z.extend_from_slice(usr_id);
let k = Sm9::kdf(z.as_slice(), klen).expect("klen maybe error");
k
}
pub(crate) fn decrypt(&self, usr_id: &[u8], ciphertext: Vec<u8>) -> Option<Vec<u8>> {
if ciphertext.len() <= 64 + 32 {
return None;
}
let c1 = &ciphertext[..64];
let c3 = &ciphertext[64..96];
let c2 = &ciphertext[96..];
let c = G1::from_slice(c1).expect("C1 error,not a point on curve");
let klen = c2.len() + 32;
let k = self.key_decapsulation(usr_id, klen, &c);
let k2 = &k[c2.len()..];
let mut mac = HmacSm3::new_from_slice(k2).expect("HMAC can take key of any size");
mac.update(c2);
let binding = mac.finalize().into_bytes();
let u = binding.as_slice();
if u != c3 {
return None;
}
let mut m = Vec::<u8>::new();
for (b, x) in c2.iter().zip(k.iter()) {
m.push(*b ^ *x);
}
Some(m)
}
}
key_impl!(MasterSignaturePublicKey);
impl PemLabel for MasterSignaturePublicKey {
const PEM_LABEL: &'static str = "SM9 MASTER SIGNATURE PUBLIC KEY";
}
impl MasterSignaturePublicKey {
pub(crate) fn is_ok(&self) -> bool {
self.to_g2().is_some()
}
pub(crate) fn to_g2(&self) -> Option<G2> {
let b = self.as_slice();
match b.len() {
65 => G2::from_compressed(b).ok(),
128 => G2::from_slice(b).ok(),
129 => G2::from_uncompressed(b).ok(),
_ => None,
}
}
pub(crate) fn verify(&self, usr_id: &[u8], m: &[u8], (oh, os): (Vec<u8>, Vec<u8>)) -> bool {
let h = Fn::from_slice(oh.as_slice()).expect("signature h error");
let ep = EncodedPoint::from_bytes(os.as_slice()).expect("signature s error");
let ep_compressed = ep.compress();
let s = G1::from_compressed(ep_compressed.as_bytes()).expect("signature s error");
let pub_s = self.to_g2().expect("MasterSignaturePublicKey error");
let g = fast_pairing(G1::one(), pub_s);
let t = g.pow(h);
let mut z = Vec::<u8>::new();
z.extend_from_slice(usr_id);
z.push(SM9_HID_SIGN);
let h1 = Sm9::hash_1(z.as_slice()).unwrap();
let p = G2::one() * h1 + pub_s;
let u = fast_pairing(s, p);
let w = u * t;
let mut z = Vec::<u8>::new();
z.extend_from_slice(m);
z.extend_from_slice(w.to_slice().as_ref());
let h2 = Sm9::hash_2(z.as_slice()).unwrap();
h2 == h
}
}
key_impl!(UserSignaturePrivateKey);
impl PemLabel for UserSignaturePrivateKey {
const PEM_LABEL: &'static str = "SM9 USER SIGNATURE PRIVATE KEY";
}
impl UserSignaturePrivateKey {
pub(crate) fn is_ok(&self) -> bool {
self.to_g1().is_some()
}
pub(crate) fn to_g1(&self) -> Option<G1> {
let b = self.as_slice();
match b.len() {
33 => G1::from_compressed(b).ok(),
64 => G1::from_slice(b).ok(),
65 => G1::from_uncompressed(b).ok(),
_ => None,
}
}
pub(crate) fn sign(&self, msp: &MasterSignaturePublicKey, m: &[u8]) -> (Vec<u8>, Vec<u8>) {
let pub_s = msp.to_g2().expect("MasterSignaturePublicKey error");
let g = fast_pairing(G1::one(), pub_s);
let rng = &mut rng();
let mut h;
let mut l;
loop {
let r = Fn::random(rng);
let w = g.pow(r);
let mut z = Vec::<u8>::new();
z.extend_from_slice(m);
z.extend_from_slice(w.to_slice().as_ref());
h = Sm9::hash_2(z.as_slice()).unwrap();
l = r - h;
if !l.is_zero() {
break;
}
}
let ds = self.to_g1().expect("UserSignaturePrivateKey error");
let s = ds * l;
let mut oh = Vec::<u8>::new();
let mut os = Vec::<u8>::new();
oh.extend_from_slice(h.to_slice().as_ref());
os.extend_from_slice(s.to_uncompressed().as_ref());
(oh, os)
}
}