1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#![doc = include_str!("../README.md")]

use pkcs8::ObjectIdentifier;
use pkcs8::spki::AlgorithmIdentifier;

pub mod error;
pub mod exchange;
pub(crate) mod formulas;
pub mod key;
mod macros;
pub(crate) mod operation;
pub mod p256_ecc;
pub mod p256_field;
pub mod p256_pre_table;
pub mod util;
pub mod pkcs;

/// Fp 的加法,减法,乘法并不是简单的四则运算。其运算结果的值必须在Fp的有限域中,这样保证椭圆曲线变成离散的点
///
/// 这里我们规定一个有限域Fp
///
/// * 取大质数p,则有限域中有p-1个有限元:0,1,2...p-1
/// * Fp上的加法为模p加法`a+b≡c(mod p)`
/// * Fp上的乘法为模p乘法`a×b≡c(mod p)`
/// * Fp上的减法为模p减法`a-b≡c(mod p)`
/// * Fp上的除法就是乘除数的乘法逆元`a÷b≡c(mod p)`,即 `a×b^(-1)≡c (mod p)`
/// * Fp的乘法单位元为1,零元为0
/// * Fp域上满足交换律,结合律,分配律
pub trait FeOperation {
    /// Returns `(self + other) % modulus`.
    ///
    /// Panics if the modulus is zero.
    ///
    fn mod_add(&self, other: &Self, modulus: &Self) -> Self;

    /// Returns `(self - other) % modulus`.
    ///
    /// Panics if the modulus is zero.
    ///
    fn mod_sub(&self, other: &Self, modulus: &Self) -> Self;

    /// Returns `(self * other) % modulus`.
    ///
    /// Panics if the modulus is zero.
    ///
    fn mod_mul(&self, other: &Self, modulus: &Self) -> Self;

    /// Extended Eulidean Algorithm(EEA) to calculate x^(-1) mod p
    fn inv(&self, modulus: &Self) -> Self;

    /// Self >>= carry
    fn right_shift(&self, carry: u32) -> Self;
}

/// oid to pkcs8
pub const OID_SM2_PKCS8: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.156.10197.1.301");
pub const ALGORITHM_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.2.1");

const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> = AlgorithmIdentifier {
    oid: ALGORITHM_OID,
    parameters: Some(OID_SM2_PKCS8),
};

/// oid refer to GM/T 0006
pub const OID_SM2_CMS_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.156.10197.1.301.1");
pub const OID_SM2_CMS_3: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.156.10197.1.301.3");

/// oid refer to GM/T 0010  pkcs#7
pub const OID_SM2_CMS_DATA: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.156.10197.6.1.4.2.1");
pub const OID_SM2_CMS_SIGNED: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.156.10197.6.1.4.2.2");
pub const OID_SM2_CMS_ENVELOPED: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.156.10197.6.1.4.2.3");
pub const OID_SM2_CMS_SIGNED_AND_ENVELOPED: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.156.10197.6.1.4.2.4");
pub const OID_SM2_CMS_ENCRYPTED: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.156.10197.6.1.4.2.5");
pub const OID_SM2_CMS_KEY_AGREEMENT_INFO: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.156.10197.6.1.4.2.6");

#[cfg(test)]
mod test_sm2 {
    use crate::exchange;
    use crate::key::{gen_keypair, Sm2Model, Sm2PrivateKey, Sm2PublicKey};

    #[test]
    fn test_encrypt_decrypt_with_gen_key() {
        let (pk, sk) = gen_keypair().unwrap();
        let msg = "你好 world,asjdkajhdjadahkubbhj12893718927391873891,@@!! world,1231 wo12321321313asdadadahello world,hello world".as_bytes();
        let encrypt = pk.encrypt(msg, false, Sm2Model::C1C2C3).unwrap();
        let plain = sk.decrypt(&encrypt, false, Sm2Model::C1C2C3).unwrap();
        println!("public key {}", pk.to_hex_string(false));
        println!("private key {}", sk.to_hex_string());
        assert_eq!(msg, plain)
    }

    #[test]
    fn test_encrypt_decrypt_with_special_key() {
        let public_key = "048626c62a8582c639cb3c87b59118713a519988c5f6497f91dd672abbdaaed0420ea7bc2cd03a7c938adc42b450549d312bec823b74cf22cf57c63cebd011c595";
        let private_key = "eb20009ffbffc90aeeb288ca7d782c722332d1d16a206cafec7dd6c64e6fc525";
        let pk = Sm2PublicKey::from_hex_string(public_key).unwrap();
        let sk = Sm2PrivateKey::from_hex_string(private_key).unwrap();

        let msg = "你好 world,asjdkajhdjadahkubbhj12893718927391873891,@@!! world,1231 wo12321321313asdadadahello world,hello world".as_bytes();
        let encrypt = pk.encrypt(msg, false, Sm2Model::C1C3C2).unwrap();
        let plain = sk.decrypt(&encrypt, false, Sm2Model::C1C3C2).unwrap();
        assert_eq!(msg, plain);
    }

    #[test]
    fn test_encrypt_decrypt_with_java_bouncycastle_gen_key() {
        let public_key = "046a6ff781355cc1a9e538213f3a2074ceb32eae9e1caa090e74bbac9024cd58969619ec8dd797635773a9e8c3401135687a49381bb088d4f10c8feed899bf69c5";
        let private_key = "ff88f12d6f28a852cc59ace674efb842163f1c5294890be9843fe5c20e26a011";
        let pk = Sm2PublicKey::from_hex_string(public_key).unwrap();
        let sk = Sm2PrivateKey::from_hex_string(private_key).unwrap();

        let msg = "你好 world,asjdkajhdjadahkubbhj12893718927391873891,@@!! world,1231 wo12321321313asdadadahello world,hello world".as_bytes();
        let encrypt = pk.encrypt(msg, false, Sm2Model::C1C3C2).unwrap();
        let plain = sk.decrypt(&encrypt, false, Sm2Model::C1C3C2).unwrap();
        assert_eq!(msg, plain);
    }

    #[test]
    fn test_sign_verify() {
        let msg = b"hello";
        let (pk, sk) = gen_keypair().unwrap();
        let signature = sk.sign(None, msg).unwrap();
        pk.verify(None, msg, &signature).unwrap();
    }

    #[test]
    fn test_sign_verify_with_special_key() {
        let msg = "hello,你好啊".as_bytes();
        let public_key = "048626c62a8582c639cb3c87b59118713a519988c5f6497f91dd672abbdaaed0420ea7bc2cd03a7c938adc42b450549d312bec823b74cf22cf57c63cebd011c595";
        let private_key = "eb20009ffbffc90aeeb288ca7d782c722332d1d16a206cafec7dd6c64e6fc525";
        let pk = Sm2PublicKey::from_hex_string(public_key).unwrap();
        let sk = Sm2PrivateKey::from_hex_string(private_key).unwrap();
        let signature = sk.sign(None, msg).unwrap();
        pk.verify(None, msg, &signature).unwrap();
    }

    #[test]
    fn test_sign_verify_with_java_bouncycastle_gen_key() {
        let msg = "hello,你好".as_bytes();
        let public_key = "046a6ff781355cc1a9e538213f3a2074ceb32eae9e1caa090e74bbac9024cd58969619ec8dd797635773a9e8c3401135687a49381bb088d4f10c8feed899bf69c5";
        let private_key = "ff88f12d6f28a852cc59ace674efb842163f1c5294890be9843fe5c20e26a011";
        let pk = Sm2PublicKey::from_hex_string(public_key).unwrap();
        let sk = Sm2PrivateKey::from_hex_string(private_key).unwrap();
        let signature = sk.sign(None, msg).unwrap();
        pk.verify(None, msg, &signature).unwrap();
    }

    #[test]
    fn test_key_exchange() {
        let id_a = "alice123@qq.com";
        let id_b = "bob456@qq.com";

        let (mut alice, mut bob) = exchange::build_ex_pair(8, id_a, id_b).unwrap();

        let ra_point = alice.exchange_1().unwrap();
        let (rb_point, sb) = bob.exchange_2(&ra_point).unwrap();
        let sa = alice.exchange_3(&rb_point, sb).unwrap();
        let succ = bob.exchange_4(sa, &ra_point).unwrap();
        assert_eq!(succ, true);
        assert_eq!(alice.k, bob.k);
    }


    #[test]
    fn test_encrypt_decrypt_asn1_with_special_key() {
        let public_key = "048626c62a8582c639cb3c87b59118713a519988c5f6497f91dd672abbdaaed0420ea7bc2cd03a7c938adc42b450549d312bec823b74cf22cf57c63cebd011c595";
        let private_key = "eb20009ffbffc90aeeb288ca7d782c722332d1d16a206cafec7dd6c64e6fc525";
        let pk = Sm2PublicKey::from_hex_string(public_key).unwrap();
        let sk = Sm2PrivateKey::from_hex_string(private_key).unwrap();

        let msg = "你好 world,asjdkajhdjadahkubbhj12893718927391873891,@@!! world,1231 wo12321321313asdadadahello world,hello world".as_bytes();
        let encrypt = pk.encrypt_asn1(msg, false, Sm2Model::C1C3C2).unwrap();
        let plain = sk.decrypt_asn1(&encrypt, false, Sm2Model::C1C3C2).unwrap();
        assert_eq!(msg, plain);
    }

}