sm2-crypto 0.1 → 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b51258ccfa3e81ed0173f642cd16e1f96a1ba5944a6646dc68aa5850cd4d9039
4
- data.tar.gz: d9e2bfb6afbd01095baf46c283e906bca986510d5988e4c67e55510cc8fd1c93
3
+ metadata.gz: e11ed586baf19d83dea3bde65ca1c67c793229c1618222c3b0eab7dcaf4aa145
4
+ data.tar.gz: 87b1ef2ecdcb6cf6852a5616e2da6655964f065a62a0418824702936fd5a0a31
5
5
  SHA512:
6
- metadata.gz: b030ea7c612717190baff608b974cdd74781ca7f15288602f0c8465f73be34d55abc28ce850329e09123e3f9c5d4020e8f6c4ecc903308878680ce929719a661
7
- data.tar.gz: f8c0172e0e341570d0e672edebae78e4e552d7aca5441356b266480793b39b91fb428b433dee967a1e64e93dd2af766c56e6de32661330f9f64075b99f43711f
6
+ metadata.gz: 42430a1b69e52b255684bdfaf35ff4f501f908cb78be9516575c2a2e850288e29cb99c705b512b967eaab1d25f960319fc89f8acb6d79883608e199dc8825b61
7
+ data.tar.gz: 3c2142bcb64674f49d147791fe66fb726953e6fd7973969392ed0e892ef17424e9018ee31706164f45f85c3eab56f57b49e9ca456ab11c7ffe2b39bacb331207
data/README.md CHANGED
@@ -30,13 +30,15 @@ $ gem install sm2-crypto
30
30
 
31
31
  ## Usage
32
32
 
33
+ ### Encrypt and Decrypt
34
+
33
35
  ```ruby
34
36
  require 'sm2_crypto'
35
37
 
36
38
  # Generate key pair
37
39
  keypair = OpenSSL::PKey::EC.generate("SM2")
38
40
  private_key = keypair.private_key.to_s(2)
39
- public_key = keypair.public_key.to_bn.to_s(2)
41
+ public_key = keypair.public_key.to_octet_string(:uncompressed)
40
42
 
41
43
  # Encrypt data
42
44
  message = "Hello, SM2 encryption!"
@@ -48,6 +50,28 @@ decrypted_message = SM2Crypto.decrypt(private_key, encrypted_data)
48
50
  puts "Decrypted message: #{decrypted_message}"
49
51
  ```
50
52
 
53
+ ### Sign and Verify
54
+
55
+ ```ruby
56
+ message = "Hello, SM2 signature!"
57
+ # get signatrue
58
+ sign = SM2Crypto.sign(private_key, message)
59
+ # verify signatrue
60
+ SM2Crypto.verify(public_key, message, sign)
61
+
62
+ user_id = "31323334353637383132333435363738" # user_id should be a hex string
63
+ # sign with hash and user_id
64
+ sign = SM2Crypto.sign(private_key, message, sm3_hash: true, user_id: user_id)
65
+ # verify with hash and user_id
66
+ SM2Crypto.verify(public_key, message, sign, sm3_hash: true, user_id: user_id)
67
+ ```
68
+
69
+ ### Get Public Key from Private Key
70
+
71
+ ```ruby
72
+ public_key = SM2Crypto.get_public_key(private_key)
73
+ ```
74
+
51
75
  ## Contributing
52
76
 
53
77
  Contributions to the project are welcome. Please fork the repository, create a feature branch, and submit a pull request. Be sure to add tests and update documentation as needed.
data/lib/sm2_crypto.rb CHANGED
@@ -32,10 +32,10 @@ module SM2Crypto
32
32
  point = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC::Group.new("SM2"), OpenSSL::BN.new(public_key, 2))
33
33
  random_key = OpenSSL::PKey::EC.generate("SM2")
34
34
  k = random_key.private_key
35
- c1 = random_key.public_key.to_bn.to_s(2)
35
+ c1 = random_key.public_key.to_octet_string(:uncompressed)
36
36
 
37
37
  p = point.mul(k)
38
- p_bin_str = p.to_bn.to_s(2)
38
+ p_bin_str = p.to_octet_string(:uncompressed)
39
39
  x2 = p_bin_str[1, 32]
40
40
  y2 = p_bin_str[33, 32]
41
41
 
@@ -71,7 +71,7 @@ module SM2Crypto
71
71
  point = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC::Group.new("SM2"), OpenSSL::BN.new(c1, 2))
72
72
  pkey = OpenSSL::BN.new(private_key, 2)
73
73
  p = point.mul(pkey)
74
- p_bin_str = p.to_bn.to_s(2)
74
+ p_bin_str = p.to_octet_string(:uncompressed)
75
75
  x2 = p_bin_str[1, 32]
76
76
  y2 = p_bin_str[33, 32]
77
77
 
@@ -85,4 +85,100 @@ module SM2Crypto
85
85
 
86
86
  msg
87
87
  end
88
+
89
+ # get public key from private key
90
+ #
91
+ # @param private_key [String] private key, format: binary string
92
+ # @return [String] public key, format: binary string
93
+ def get_public_key(private_key)
94
+ pkey = OpenSSL::BN.new(private_key, 2)
95
+ group = OpenSSL::PKey::EC::Group.new("SM2")
96
+ group.generator.mul(pkey).to_octet_string(:uncompressed)
97
+ end
98
+
99
+ # sign with private key
100
+ #
101
+ # @param private_key [String] private key, format: binary string
102
+ # @param data [String]
103
+ # @param sm3_hash [Boolean], option to sign with sm3 hash, default: false
104
+ # @param user_id [String], format: hex string, default: "31323334353637383132333435363738"
105
+ # @return [String] signature, format: hex string
106
+ def sign(private_key, data, sm3_hash: false, user_id: "31323334353637383132333435363738")
107
+ data = data.unpack1("a*") unless data.ascii_only?
108
+ if sm3_hash
109
+ public_key = get_public_key(private_key)
110
+ data = OpenSSL::Digest.digest("SM3", za(public_key, user_id) + data)
111
+ end
112
+
113
+ n = OpenSSL::BN.new("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
114
+ da = OpenSSL::BN.new(private_key, 2)
115
+ e = OpenSSL::BN.new(data, 2)
116
+ one = OpenSSL::BN.new(1)
117
+
118
+ k = 0
119
+ s = 0
120
+ r = 0
121
+ while s.zero?
122
+ while r.zero? || r + k == n
123
+ random_key = OpenSSL::PKey::EC.generate("SM2")
124
+ k = random_key.private_key
125
+ x1 = OpenSSL::BN.new(random_key.public_key.to_octet_string(:uncompressed)[1, 32], 2)
126
+ # r = (e + x1) mod n
127
+ r = (e + x1) % n
128
+ end
129
+ # s = ((1 + dA)^-1 * (k - r * dA)) mod n
130
+ s = ((one + da).mod_inverse(n) * (k - (r * da))).to_i % n.to_i
131
+ end
132
+
133
+ r.to_s(16).rjust(64, "0") + s.to_s(16).rjust(64, "0")
134
+ end
135
+
136
+ # verify the signature with public_key
137
+ #
138
+ # @param public_key [String] public key, format: binary string
139
+ # @param data [String]
140
+ # @param signature [String], hex string
141
+ # @param sm3_hash [Boolean], option to sign with sm3 hash, default: false
142
+ # @param user_id [String], format: hex string, default: "31323334353637383132333435363738"
143
+ # @return [Boolean] verify result
144
+ def verify(public_key, data, signature, sm3_hash: false, user_id: "31323334353637383132333435363738")
145
+ return false if signature.size != 128
146
+
147
+ public_key = "\x04#{public_key}" if public_key.size == 64 && public_key[0] != "\x04"
148
+ data = data.unpack1("a*") unless data.ascii_only?
149
+ if sm3_hash
150
+ data = OpenSSL::Digest.digest("SM3", za(public_key, user_id) + data)
151
+ end
152
+ r = OpenSSL::BN.new(signature[0, 64], 16)
153
+ s = OpenSSL::BN.new(signature[64, 64], 16)
154
+ n = OpenSSL::BN.new("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
155
+ e = OpenSSL::BN.new(data, 2)
156
+
157
+ # t = (r + s) mod n
158
+ t = (r + s) % n
159
+ return false if t.zero?
160
+
161
+ point = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC::Group.new("SM2"), OpenSSL::BN.new(public_key, 2))
162
+
163
+ # x1y1 = s * G + t * PA
164
+ x1y1 = point.mul(t, s)
165
+ x1 = OpenSSL::BN.new(x1y1.to_octet_string(:uncompressed)[1, 32], 2)
166
+
167
+ # R = (e + x1) mod n
168
+ r1 = (e + x1) % n
169
+
170
+ r == r1
171
+ end
172
+
173
+ # ZA = H256(ENTLA || IDA || a || b || gx || gy || px || py)
174
+ def za(public_key, user_id)
175
+ ida = [user_id].pack("H*")
176
+ entla = [ida.size * 8].pack("n")
177
+ a = ["FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"].pack("H*")
178
+ b = ["28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"].pack("H*")
179
+ gxgy = OpenSSL::PKey::EC::Group.new("SM2").generator.to_octet_string(:uncompressed)[1, 64]
180
+ public_key = public_key[1, 64] if public_key.size == 65
181
+
182
+ OpenSSL::Digest.digest("SM3", entla + ida + a + b + gxgy + public_key)
183
+ end
88
184
  end
data/sm2-crypto.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "sm2-crypto"
5
- spec.version = "0.1"
5
+ spec.version = "0.2"
6
6
  spec.authors = ["Seekr"]
7
7
  spec.email = ["wzhao23@gmail.com"]
8
8
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sm2-crypto
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seekr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-04 00:00:00.000000000 Z
11
+ date: 2023-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest