spdb_sm2/
signature.rs

1use crate::encrypt;
2use crate::error::Sm2Error;
3use base64::engine::general_purpose::STANDARD;
4use base64::Engine;
5use byteorder::{BigEndian, WriteBytesExt};
6use libsm::sm2::ecc::{EccCtx, Point};
7use libsm::sm2::signature::Signature;
8use libsm::sm3::hash::Sm3Hash;
9use num_bigint::BigUint;
10use num_traits::{One, Zero};
11use sha1::Digest;
12use smcrypto::sm3;
13
14/// rsa公钥验签
15///
16/// - msg: 待验签数据
17/// - pk: 公钥字符串:-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----
18/// - sign: 签名字符串 (Header x-spdb-signature )
19pub fn rsa_verify(msg: &[u8], pk: &[u8], sign: &str) -> Result<bool, Sm2Error> {
20    // base64解密
21    let signature = STANDARD.decode(sign)?;
22
23    // 加载公钥
24    let rsa = openssl::rsa::Rsa::public_key_from_pem(pk)?;
25
26    let pkey = openssl::pkey::PKey::from_rsa(rsa)?;
27
28    // 创建验证器
29    let mut verifier = openssl::sign::Verifier::new(openssl::hash::MessageDigest::sha256(), &pkey)?;
30
31    // 更新验证器的消息
32    verifier.update(msg)?;
33
34    // 验证签名
35    Ok(verifier.verify(&signature)?)
36}
37
38/// # 普通签名
39///
40/// - data: 待签名数据
41/// - secret: 私钥( APP唯一秘钥:X_SPDB_CLIENT_SECRET, 秘钥有过期时间,注意存储方式 )
42pub fn sign_body(data: &str, secret: &str) -> Result<String, Sm2Error> {
43    let data = sha1_base64(data);
44    let data = sm3::sm3_hash(data.as_bytes());
45    encrypt(&data, secret)
46}
47
48/// # 全报文签名
49///
50/// 此处提供公钥与私钥是为了减少私钥推导公钥的时间
51/// - data: 待签名数据
52/// - pk: 客户端公钥( client_sm2_public_key )
53/// - sk: 客户端私钥( client_sm2_private_key )
54pub fn sign(msg: &[u8], pk: &str, sk: &str) -> Result<String, Sm2Error> {
55    let curve = &EccCtx::new();
56    let pk = &hex::decode(pk)?;
57    let pk = load_pubkey(curve, pk)?;
58    let sk = &hex::decode(sk)?;
59    let sk = BigUint::from_bytes_be(sk);
60    // sm3杂凑
61    let digest = sign_hash(curve, &pk, msg)?;
62    let signature = sign_raw(curve, &digest[..], &sk)?;
63    let base64 = STANDARD.encode(signature);
64    Ok(base64)
65}
66
67/// # 签名验签
68///
69/// - msg: 待验签数据, 如:SBmIZpPZUpsdEc+QHJ0xiNY6qAw= (一般在解密Body数据,进过sha1_base64后得到的数据)
70/// - public_key: 公钥字符串( SPDB_PublicKey )
71/// - signature: 签名字符串 (Header x-spdb-signature )
72pub fn verify(msg: &[u8], pk: &str, sign: &str) -> Result<bool, Sm2Error> {
73    let sig = Signature::der_decode(&hex::decode(STANDARD.decode(sign)?)?).map_err(|e| Sm2Error::LibSmError(format!("{}", e)))?;
74    let pk = efficient_sm2::PublicKey::from_slice(&hex::decode(&pk[2..])?);
75    let signature = efficient_sm2::Signature::new(&sig.get_r().to_bytes_be(), &sig.get_s().to_bytes_be()).map_err(|e| Sm2Error::LibSmError(format!("{:?}", e)))?;
76    if signature.verify(&pk, msg).is_ok() {
77        return Ok(true);
78    }
79    Ok(false)
80}
81
82/// # 通过SHA-1生成data的摘要,并转base64
83///
84/// 在通知回调或请求响应中,对解密报文进行签名验证时需要先生成base64。
85pub fn sha1_base64(data: &str) -> String {
86    let mut hasher = sha1::Sha1::new();
87    hasher.update(data);
88    let hash_bytes = hasher.finalize();
89    STANDARD.encode(hash_bytes)
90}
91
92fn load_pubkey(curve: &EccCtx, buf: &[u8]) -> Result<Point, Sm2Error> {
93    curve.bytes_to_point(buf).map_err(|e| Sm2Error::LibSmError(e.to_string()))
94}
95fn sign_hash(curve: &EccCtx, pk: &Point, msg: &[u8]) -> Result<[u8; 32], Sm2Error> {
96    let id = "1234567812345678";
97    let mut prepend: Vec<u8> = Vec::new();
98    prepend.write_u16::<BigEndian>((id.len() * 8) as u16).map_err(|e| Sm2Error::LibSmError(e.to_string()))?;
99    for c in id.bytes() {
100        prepend.push(c);
101    }
102
103    let mut a = curve.get_a().to_bytes();
104    let mut b = curve.get_b().to_bytes();
105
106    prepend.append(&mut a);
107    prepend.append(&mut b);
108
109    let (x_g, y_g) = curve.to_affine(
110        &curve.generator().map_err(|e| Sm2Error::LibSmError(e.to_string()))?
111    ).map_err(|e| Sm2Error::LibSmError(e.to_string()))?;
112    let (mut x_g, mut y_g) = (x_g.to_bytes(), y_g.to_bytes());
113    prepend.append(&mut x_g);
114    prepend.append(&mut y_g);
115
116    let (x_a, y_a) = curve.to_affine(pk).map_err(|e| Sm2Error::LibSmError(e.to_string()))?;
117    let (mut x_a, mut y_a) = (x_a.to_bytes(), y_a.to_bytes());
118    prepend.append(&mut x_a);
119    prepend.append(&mut y_a);
120
121    let mut hasher = Sm3Hash::new(&prepend[..]);
122    let z_a = hasher.get_hash();
123
124    // Z_A = HASH_256(ID_LEN || ID || x_G || y_G || x_A || y_A)
125
126    // e = HASH_256(Z_A || M)
127
128    let mut prepended_msg: Vec<u8> = Vec::new();
129    prepended_msg.extend_from_slice(&z_a[..]);
130    prepended_msg.extend_from_slice(msg);
131
132    let mut hasher = Sm3Hash::new(&prepended_msg[..]);
133    Ok(hasher.get_hash())
134}
135fn sign_raw(curve: &EccCtx, digest: &[u8], sk: &BigUint) -> Result<String, Sm2Error> {
136    // Get the value "e", which is the hash of message and ID, EC parameters and public key
137    let e = BigUint::from_bytes_be(digest);
138    // two while loops
139    loop {
140        // (x_1, y_1) = g^kg
141        let k = BigUint::from_bytes_be(&hex::decode("dc388f4220a38e285ebb3da2bfd48ff2d52358030e13672c76ceceebcb03991f")?);
142        let p_1 = curve.bytes_to_point(&hex::decode("047121548af8b601e2ebec3c7b679429f0d3387b5f3ea7883925c68fdd1161a73fa593a5dd16c9248b93ef9d8d85053715754e050cc199e94ac332cfdde8bdff52")?)
143            .map_err(|e| Sm2Error::LibSmError(e.to_string()))?;
144
145        let (x_1, _) = curve.to_affine(&p_1).map_err(|e| Sm2Error::LibSmError(e.to_string()))?;
146        let x_1 = x_1.to_biguint();
147
148        // r = e + x_1
149        let r = (&e + x_1) % curve.get_n();
150        if r == BigUint::zero() || &r + &k == *curve.get_n() {
151            continue;
152        }
153
154        // s = (1 + sk)^-1 * (k - r * sk)
155        let s1 = curve.inv_n(&(sk + BigUint::one())).map_err(|e| Sm2Error::LibSmError(e.to_string()))?;
156
157        let mut s2_1 = &r * sk;
158        if s2_1 < k {
159            s2_1 += curve.get_n();
160        }
161        let mut s2 = s2_1 - k;
162        s2 %= curve.get_n();
163        let s2 = curve.get_n() - s2;
164
165        let s = (s1 * s2) % curve.get_n();
166
167        if s != BigUint::zero() {
168            // Output the signature (r, s)
169            let signature = yasna::construct_der(|writer| {
170                writer.write_sequence(|writer| {
171                    writer.next().write_biguint(&r);
172                    writer.next().write_biguint(&s);
173                })
174            });
175            // hex
176            let signature = hex::encode(signature);
177            return Ok(signature);
178        }
179        return Err(Sm2Error::LibSmError("Signature failed".to_string()));
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    #[test]
186    fn test_sign() {
187        let msg = r#"hello world"#;
188        let pk = "04ff055e4349345eba0fc69362f483f4f408d876dda2520e8e424e81978129da56b19587538253a2406d035a8d9981efeeac60ec72b3308b9a07a5398b61d3d189";
189        let sk = "6d7964184b735645ef49b3c1ee5a2c2efdbd15d6c9d851c57eef341ed0e1eb1b";
190
191        // 全报文签名
192        let signature = super::sign(msg.as_bytes(), pk, sk).unwrap();
193        assert_eq!(signature, "MzA0NjAyMjEwMDgwMGM3NDg0NTlkZDQ2MTdlMzMzNWM3OGRjNDJlOGFjZWU0OTg5YmYwYjk2NzFmYWYzZjkxN2ZkNmU0NGFhOTkwMjIxMDBjOGM2YjhiZjI5NzRmNzljYWE3Mjc4MzZjZjgwMTc2MzI0YmI1YjkxZDFkYWQzNjIzMWQyODA2MDVhZTNhNDYy");
194
195        // 验签签名
196        let verify = super::verify(msg.as_bytes(), pk, &signature).unwrap();
197        assert_eq!(verify, true);
198
199        // 普通签名
200        let secret = "ZTPkMS00ZNTP5NzPwNjAu";
201        let signature = super::sign_body(msg, secret).unwrap();
202        assert_eq!(signature, "ZTVlOGU0YzZmYjk0N2JiZDQxNDdmZjgyNTgwYTVhMzgxMjVmN2U5M2Q1MzA0NTg2YmJkNjljMmJiYWZlNWMyZWZlY2JiOWI0YmQzNWQ1YWE3OTZlYTkzY2Q0M2RmNmM2ZGEyMzA1NGJiOTEzMTJmMDE5YzI2YzVjOTZhYWVmYmNmMzkwYjMzZTNlY2Q3MzQzMjMwNWM1YzYzNTQ3ZmI0OQ==");
203    }
204
205    #[test]
206    fn test_verify() {
207        let signature = "MzA0NTAyMjEwMGVkOWQ3ZjY3YzhkNmU3NGVmODJjZDJjNDI2N2IwMDQ4ZDliZjc0NDcwNThmNGY4Mzc4NmUyZjI1OGVhNjRhYjQwMjIwMTE1NjM3ZTRmNGY5YWE4Yzg5NmQ3MTE0NjNkN2E3OGEzZGE1NjQ0NDQyOWU2NTlmNTk2NWMwMjJkNmVhNzMxYw==";
208        let body = "M2YyZWFlOTU4MzBkZTUxMGQyOTNjNmUzYzA1ODg2NjM=";
209        let secret = "ZTPkMS00ZNTP5NzPwNjAu";
210        let spdb_pk = "04049bc3c83c5709b1b9d7fce408095809f20ee9cd16fde7944f95fa21392f109bd3c7caed077e41682126f383e547bd48899f9c279cff5f2f06ca0e41013abf11";
211
212        // 先解密报文
213        let msg = crate::decrypt(&body, secret).unwrap();
214        assert_eq!(msg, "hello world");
215        // 验证签名
216        let verify = super::verify(crate::sha1_base64(&msg).as_bytes(), spdb_pk, &signature).unwrap();
217        assert_eq!(verify, true);
218    }
219}