sm2-crypto 0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b51258ccfa3e81ed0173f642cd16e1f96a1ba5944a6646dc68aa5850cd4d9039
4
+ data.tar.gz: d9e2bfb6afbd01095baf46c283e906bca986510d5988e4c67e55510cc8fd1c93
5
+ SHA512:
6
+ metadata.gz: b030ea7c612717190baff608b974cdd74781ca7f15288602f0c8465f73be34d55abc28ce850329e09123e3f9c5d4020e8f6c4ecc903308878680ce929719a661
7
+ data.tar.gz: f8c0172e0e341570d0e672edebae78e4e552d7aca5441356b266480793b39b91fb428b433dee967a1e64e93dd2af766c56e6de32661330f9f64075b99f43711f
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2023-03-27
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in sm2-crypto.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+ gem "minitest", "~> 5.0"
data/Gemfile.lock ADDED
@@ -0,0 +1,22 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sm2-crypto (0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ minitest (5.18.0)
10
+ rake (13.0.6)
11
+
12
+ PLATFORMS
13
+ arm64-darwin-22
14
+ x86_64-linux
15
+
16
+ DEPENDENCIES
17
+ minitest (~> 5.0)
18
+ rake (~> 13.0)
19
+ sm2-crypto!
20
+
21
+ BUNDLED WITH
22
+ 2.4.6
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Seekr
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # sm2-crypto
2
+
3
+ sm2-crypto is an implementation of the SM2 encryption and decryption algorithm in pure Ruby based on the OpenSSL SM2 elliptic curve cryptography standard.
4
+
5
+ ## Installation
6
+ OpenSSL has added support for SM2/SM3/SM4 encryption algorithms since version [1.1.1](https://www.openssl.org/news/openssl-1.1.1-notes.html). However, Ruby does not wrap the C interface related to SM2 encryption and decryption in OpenSSL. This library is not a wrapper for the C interface, but an implementation of the SM2 encryption and decryption algorithm in pure Ruby, based on the `OpenSSL::PKey::EC` interface.
7
+
8
+ Before using, please make sure your Ruby's OpenSSL version is `1.1.1` or higher.
9
+
10
+ Check the OpenSSL version in Ruby:
11
+
12
+ ```ruby
13
+ irb(main):001:0> require "openssl"
14
+ => true
15
+ irb(main):002:0> OpenSSL::OPENSSL_VERSION
16
+ => "OpenSSL 1.1.1k 25 Mar 2021"
17
+ ```
18
+
19
+ Add this line to your Gemfile:
20
+
21
+ ```ruby
22
+ gem "sm2-crypto"
23
+ ```
24
+
25
+ Or install it yourself via command line:
26
+
27
+ ```shell
28
+ $ gem install sm2-crypto
29
+ ```
30
+
31
+ ## Usage
32
+
33
+ ```ruby
34
+ require 'sm2_crypto'
35
+
36
+ # Generate key pair
37
+ keypair = OpenSSL::PKey::EC.generate("SM2")
38
+ private_key = keypair.private_key.to_s(2)
39
+ public_key = keypair.public_key.to_bn.to_s(2)
40
+
41
+ # Encrypt data
42
+ message = "Hello, SM2 encryption!"
43
+ encrypted_data = SM2Crypto.encrypt(public_key, message)
44
+ puts "Encrypted message: #{encrypted_data}"
45
+
46
+ # Decrypt data
47
+ decrypted_message = SM2Crypto.decrypt(private_key, encrypted_data)
48
+ puts "Decrypted message: #{decrypted_message}"
49
+ ```
50
+
51
+ ## Contributing
52
+
53
+ 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.
54
+
55
+ For bug reports and feature requests, please open an issue on the [GitHub repository](https://github.com/numbcoder/sm2-crypto/issues).
56
+
57
+ ## License
58
+
59
+ sm2-crypto is released under the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/test_*.rb"]
10
+ end
11
+
12
+ task default: :test
data/lib/sm2_crypto.rb ADDED
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module SM2Crypto
6
+ module_function
7
+
8
+ # Key Derived Function
9
+ #
10
+ # @param key [String] key data
11
+ # @param klen [Integer] export key length
12
+ # @return [Array<Integer>] bytes array
13
+ def kdf(key, klen)
14
+ # hlen = 32 # 哈希函数 SM3 输出长度 32 字节
15
+ n = (klen.to_f / 32).ceil # n = klen/hlen 向上取整
16
+
17
+ (1..n).map do |ct|
18
+ OpenSSL::Digest.digest("SM3", key + [ct].pack("N"))
19
+ end.join.slice(0, klen).bytes
20
+ end
21
+
22
+ # Encrypt
23
+ #
24
+ # @param public_key [String] public key, format: binary string
25
+ # @param data [String] data
26
+ # @param cipher_mode [Integer] 0: C1C2C3, 1: C1C3C2, default: 1
27
+ # @return [String] encrypted data, format: binary string
28
+ def encrypt(public_key, data, cipher_mode: 1)
29
+ data = data.unpack1("a*") unless data.ascii_only?
30
+ public_key = "\x04#{public_key}" if public_key.size == 64 && public_key[0] != "\x04"
31
+
32
+ point = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC::Group.new("SM2"), OpenSSL::BN.new(public_key, 2))
33
+ random_key = OpenSSL::PKey::EC.generate("SM2")
34
+ k = random_key.private_key
35
+ c1 = random_key.public_key.to_bn.to_s(2)
36
+
37
+ p = point.mul(k)
38
+ p_bin_str = p.to_bn.to_s(2)
39
+ x2 = p_bin_str[1, 32]
40
+ y2 = p_bin_str[33, 32]
41
+
42
+ t = kdf(x2 + y2, data.bytesize)
43
+ t = kdf(x2 + y2, data.bytesize) while t[0, 8].uniq == [0] && t.uniq == [0]
44
+
45
+ c2 = data.each_byte.map.with_index { |b, i| b ^ t[i] }.pack("C*")
46
+
47
+ # c3 = hash(x2 || msg || y2)
48
+ c3 = OpenSSL::Digest.digest("SM3", x2 + data + y2)
49
+
50
+ cipher_mode == 0 ? c1 + c2 + c3 : c1 + c3 + c2
51
+ end
52
+
53
+ # Decrypt
54
+ #
55
+ # @param private_key [String] private key, format: binary string
56
+ # @param data [String] data to be decrypted, format: binary string
57
+ # @param cipher_mode [Integer] 0: C1C2C3, 1: C1C3C2, default: 1
58
+ # @return [String] encrypted data, format: binary string
59
+ def decrypt(private_key, data, cipher_mode: 1)
60
+ data = "\x04#{data}" if data[0] != "\x04"
61
+
62
+ c1 = data[0, 65]
63
+ c2_size = data.bytesize - 97
64
+ if cipher_mode == 0
65
+ c2 = data[65, c2_size]
66
+ c3 = data[65 + c2_size, 32]
67
+ else
68
+ c3 = data[65, 32]
69
+ c2 = data[97, c2_size]
70
+ end
71
+ point = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC::Group.new("SM2"), OpenSSL::BN.new(c1, 2))
72
+ pkey = OpenSSL::BN.new(private_key, 2)
73
+ p = point.mul(pkey)
74
+ p_bin_str = p.to_bn.to_s(2)
75
+ x2 = p_bin_str[1, 32]
76
+ y2 = p_bin_str[33, 32]
77
+
78
+ t = kdf(x2 + y2, c2_size)
79
+ raise ArgumentError, "KDF is 0" if t[0, 8].uniq == [0] && t.uniq == [0]
80
+
81
+ msg = c2.each_byte.map.with_index { |b, i| b ^ t[i] }.pack("C*")
82
+
83
+ digest = OpenSSL::Digest.digest("SM3", x2 + msg + y2)
84
+ raise ArgumentError, "Digest no match" if c3 != digest
85
+
86
+ msg
87
+ end
88
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "sm2-crypto"
5
+ spec.version = "0.1"
6
+ spec.authors = ["Seekr"]
7
+ spec.email = ["wzhao23@gmail.com"]
8
+
9
+ spec.summary = "An SM2 cryptographic algorithm encryption and decryption library for Ruby"
10
+ spec.description = "sm2-crypto is an implementation of the SM2 encryption and decryption algorithm in pure Ruby based on the OpenSSL"
11
+ spec.homepage = "https://github.com/numbcoder/sm2-crypto"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = ">= 2.7.0"
14
+
15
+ spec.metadata["rubygems_mfa_required"] = "true"
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(__dir__) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
24
+ end
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "minitest", ">= 5.0"
31
+ spec.add_development_dependency "rake", ">= 13.0"
32
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sm2-crypto
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Seekr
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-04-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ description: sm2-crypto is an implementation of the SM2 encryption and decryption
42
+ algorithm in pure Ruby based on the OpenSSL
43
+ email:
44
+ - wzhao23@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - CHANGELOG.md
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - lib/sm2_crypto.rb
56
+ - sm2-crypto.gemspec
57
+ homepage: https://github.com/numbcoder/sm2-crypto
58
+ licenses:
59
+ - MIT
60
+ metadata:
61
+ rubygems_mfa_required: 'true'
62
+ homepage_uri: https://github.com/numbcoder/sm2-crypto
63
+ source_code_uri: https://github.com/numbcoder/sm2-crypto
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 2.7.0
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.4.6
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: An SM2 cryptographic algorithm encryption and decryption library for Ruby
83
+ test_files: []