ccrypto-ruby 0.1.0 → 0.1.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 +4 -4
- data/.release_history.yml +6 -0
- data/Dockerfile.dockerun +29 -0
- data/Gemfile.lock +60 -33
- data/ccrypto-ruby.gemspec +4 -1
- data/gen_ecc_const.rb +13 -0
- data/lib/ccrypto/provider.rb +52 -44
- data/lib/ccrypto/ruby/ecc_const.rb +82 -0
- data/lib/ccrypto/ruby/engines/cipher_engine.rb +214 -55
- data/lib/ccrypto/ruby/engines/digest_engine.rb +39 -17
- data/lib/ccrypto/ruby/engines/ecc_engine.rb +89 -14
- data/lib/ccrypto/ruby/engines/ed25519_engine.rb +84 -0
- data/lib/ccrypto/ruby/engines/pkcs7_engine.rb +1 -0
- data/lib/ccrypto/ruby/engines/rsa_engine.rb +9 -0
- data/lib/ccrypto/ruby/engines/x25519_engine.rb +65 -0
- data/lib/ccrypto/ruby/engines/x509_csr_engine.rb +128 -0
- data/lib/ccrypto/ruby/engines/x509_engine.rb +208 -8
- data/lib/ccrypto/ruby/ext/x509_csr.rb +153 -0
- data/lib/ccrypto/ruby/keybundle_store/pem_store.rb +3 -3
- data/lib/ccrypto/ruby/keybundle_store/pkcs12.rb +6 -5
- data/lib/ccrypto/ruby/version.rb +1 -1
- data/lib/ccrypto/ruby.rb +1 -0
- metadata +39 -3
@@ -11,73 +11,194 @@ module Ccrypto
|
|
11
11
|
|
12
12
|
teLogger_tag :r_cipher_eng
|
13
13
|
|
14
|
+
NotAbleToFigureOutOnOpenSSLv2 = [
|
15
|
+
"aes-128-cbc-hmac-sha1",
|
16
|
+
"aes-256-cbc-hmac-sha1",
|
17
|
+
"aes-128-cbc-hmac-sha256",
|
18
|
+
"aes-256-cbc-hmac-sha256",
|
19
|
+
"aes-128-ccm",
|
20
|
+
"aes-192-ccm",
|
21
|
+
"aes-256-ccm",
|
22
|
+
"aria-128-ccm",
|
23
|
+
"aria-192-ccm",
|
24
|
+
"aria-256-ccm",
|
25
|
+
"rc4-hmac-md5"
|
26
|
+
]
|
27
|
+
|
28
|
+
#CherryPick = [
|
29
|
+
# "aes-128-cbc", "aes-192-cbc", "aes-256-cbc",
|
30
|
+
# "aes-128-gcm", "aes-192-gcm", "aes-256-gcm",
|
31
|
+
# "aria-128-cbc","aria-192-cbc", "aria-256-cbc",
|
32
|
+
# "aria-128-gcm","aria-192-gcm", "aria-256-gcm",
|
33
|
+
# "camellia-128-cbc","camellia-192-cbc", "camellia-256-cbc",
|
34
|
+
# "camellia-128-ctr","camellia-192-ctr", "camellia-256-ctr",
|
35
|
+
# "chacha20-poly1305"
|
36
|
+
#]
|
37
|
+
|
14
38
|
def self.supported_ciphers
|
15
39
|
if @sCipher.nil?
|
16
|
-
@
|
40
|
+
@sCipherStr = []
|
41
|
+
@sCipher = []
|
42
|
+
|
43
|
+
OpenSSL::Cipher.ciphers.each do |c|
|
44
|
+
|
45
|
+
teLogger.debug "found cipher : #{c}"
|
46
|
+
next if c =~ /^id-\w*/
|
47
|
+
teLogger.debug "loading cipher : #{c}"
|
48
|
+
|
49
|
+
if OpenSSL::VERSION < "3.0.0" and NotAbleToFigureOutOnOpenSSLv2.include?(c)
|
50
|
+
teLogger.debug "Running on OpenSSL < v3. Skipping cipher #{c}"
|
51
|
+
next
|
52
|
+
end
|
53
|
+
|
54
|
+
begin
|
55
|
+
co = OpenSSL::Cipher.new(c)
|
56
|
+
#teLogger.debug "Algo #{c} : authenticated? #{co.authenticated?}"
|
57
|
+
#p co.methods.sort
|
58
|
+
cc = c.split("-")
|
59
|
+
@sCipherStr << c
|
60
|
+
|
61
|
+
algo = cc.first
|
62
|
+
exclusion = ["chacha20","sm4"]
|
63
|
+
# to find string like aes128, aes256 from openssl
|
64
|
+
if not exclusion.include?(algo) and (algo =~ /[0-9]/) != nil
|
65
|
+
# match the one before the numbers
|
66
|
+
algo = $`
|
67
|
+
end
|
68
|
+
|
69
|
+
native = { algo_str: c }
|
70
|
+
keysize = co.key_len*8
|
71
|
+
opts = { keysize: keysize, ivLength: co.iv_len, authMode: co.authenticated? }
|
72
|
+
|
73
|
+
if c.downcase =~ /\w*(gcm|ecb|cbc|cfb|cfb1|cfb8|ofb|ctr|ccm|xts|wrap|poly1305)/
|
74
|
+
teLogger.debug "Mode extraction : #{$&} / #{$'}"
|
75
|
+
# after the match
|
76
|
+
if not_empty?($')
|
77
|
+
opts[:mode] = "#{$&}#{$'}"
|
78
|
+
else
|
79
|
+
# the match
|
80
|
+
opts[:mode] = $&.downcase
|
81
|
+
end
|
82
|
+
else
|
83
|
+
# no mode defined. Seems defaulted to cbc according to document
|
84
|
+
if co.authenticated?
|
85
|
+
opts[:mode] = "gcm"
|
86
|
+
else
|
87
|
+
opts[:mode] = "cbc"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
teLogger.debug "Mode : #{opts[:mode]}"
|
92
|
+
if opts[:mode] == :xts.to_s
|
93
|
+
opts[:min_input_length] = 16
|
94
|
+
elsif opts[:mode] == "cbc-hmac-sha1"
|
95
|
+
opts[:min_input_length] = 16
|
96
|
+
opts[:mandatory_block_size] = 16
|
97
|
+
elsif opts[:mode] == "cbc-hmac-sha256"
|
98
|
+
opts[:min_input_length] = 32
|
99
|
+
opts[:mandatory_block_size] = 32
|
100
|
+
elsif opts[:mode] == "wrap"
|
101
|
+
case algo
|
102
|
+
when "aes"
|
103
|
+
case keysize
|
104
|
+
when 128
|
105
|
+
opts[:min_input_length] = 16
|
106
|
+
opts[:mandatory_block_size] = 8
|
107
|
+
when 192
|
108
|
+
opts[:min_input_length] = 24
|
109
|
+
opts[:mandatory_block_size] = 8
|
110
|
+
when 256
|
111
|
+
opts[:min_input_length] = 32
|
112
|
+
opts[:mandatory_block_size] = 8
|
113
|
+
end
|
114
|
+
when "des3", "des"
|
115
|
+
opts[:min_input_length] = 8
|
116
|
+
opts[:mandatory_block_size] = 8
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
conf = Ccrypto::CipherConfig.new(algo, opts)
|
121
|
+
conf.native_config = native
|
122
|
+
|
123
|
+
Ccrypto::SupportedCipherList.instance.register(conf)
|
124
|
+
|
125
|
+
@sCipher << conf
|
126
|
+
rescue OpenSSL::Cipher::CipherError => ex
|
127
|
+
teLogger.debug "Algo '#{c}' hit error : #{ex.message}"
|
128
|
+
end
|
129
|
+
end
|
17
130
|
end
|
18
131
|
|
19
132
|
@sCipher
|
20
133
|
|
21
134
|
end
|
22
135
|
|
136
|
+
def self.get_cipher(algo, keysize = nil, mode = nil)
|
137
|
+
supported_ciphers if Ccrypto::SupportedCipherList.instance.algo_count == 0
|
138
|
+
|
139
|
+
if is_empty?(algo)
|
140
|
+
[]
|
141
|
+
elsif is_empty?(keysize) and is_empty?(mode)
|
142
|
+
teLogger.debug "get_cipher algo #{algo} only"
|
143
|
+
Ccrypto::SupportedCipherList.instance.find_algo(algo)
|
144
|
+
elsif is_empty?(mode) and not_empty?(keysize)
|
145
|
+
teLogger.debug "get_cipher algo #{algo} keysize #{keysize}"
|
146
|
+
Ccrypto::SupportedCipherList.instance.find_algo_keysize(algo, keysize)
|
147
|
+
elsif not_empty?(mode) and is_empty?(keysize)
|
148
|
+
teLogger.debug "get_cipher algo #{algo} mode #{mode}"
|
149
|
+
Ccrypto::SupportedCipherList.instance.find_algo_mode(algo, mode)
|
150
|
+
elsif not_empty?(keysize) and not_empty?(mode)
|
151
|
+
teLogger.debug "get_cipher #{algo}/#{keysize}/#{mode}"
|
152
|
+
Ccrypto::SupportedCipherList.instance.find_algo_keysize_mode(algo, keysize, mode)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
class << self
|
156
|
+
alias_method :get_cipher_config, :get_cipher
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.supported_cipher_list
|
160
|
+
supported_ciphers if Ccrypto::SupportedCipherList.instance.algo_count == 0
|
161
|
+
Ccrypto::SupportedCipherList.instance
|
162
|
+
end
|
163
|
+
|
23
164
|
def self.is_supported_cipher?(c)
|
24
165
|
case c
|
25
166
|
when String
|
26
|
-
supported_ciphers.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
true
|
32
|
-
rescue Exception => ex
|
167
|
+
supported_ciphers if @sCipherStr.nil?
|
168
|
+
|
169
|
+
if not @sCipherStr.nil?
|
170
|
+
@sCipherStr.include?(C)
|
171
|
+
else
|
33
172
|
false
|
34
173
|
end
|
174
|
+
when Ccrypto::CipherConfig
|
175
|
+
@sCipher.include?(c)
|
35
176
|
else
|
36
177
|
raise Ccrypto::CipherEngineException, "Unsupported input #{c} to check supported cipher"
|
37
178
|
end
|
38
179
|
end
|
39
180
|
|
40
181
|
def self.to_openssl_spec(spec)
|
41
|
-
res = []
|
42
182
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
183
|
+
case spec
|
184
|
+
when Ccrypto::CipherConfig
|
185
|
+
spec.native_config[:algo_str]
|
186
|
+
#@sCipher[spec]
|
47
187
|
else
|
48
|
-
|
188
|
+
raise Ccrypto::Error, "Unknown spec #{spec.inspect}"
|
49
189
|
end
|
50
190
|
|
51
|
-
|
52
|
-
|
53
|
-
res << spec.mode
|
54
|
-
|
55
|
-
teLogger.debug "to_openssl_spec #{res}"
|
56
|
-
|
57
|
-
res.join("-")
|
58
|
-
|
59
|
-
end
|
191
|
+
end # self.to_openssl_spec(spec)
|
60
192
|
|
61
193
|
def initialize(*args, &block)
|
194
|
+
|
62
195
|
@spec = args.first
|
63
196
|
|
64
|
-
#
|
65
|
-
teLogger.debug "Cipher spec : #{@spec}"
|
197
|
+
raise Ccrypto::CipherEngineException, "Not supported cipher spec #{@spec.class}" if not @spec.is_a?(Ccrypto::CipherConfig)
|
66
198
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
# @cipher = OpenSSL::Cipher.new(@spec)
|
71
|
-
when Ccrypto::CipherEngineConfig
|
72
|
-
@cipher = OpenSSL::Cipher.new(@spec.provider_config)
|
73
|
-
when Ccrypto::DirectCipherConfig
|
74
|
-
@cipher = OpenSSL::Cipher.new(self.class.to_openssl_spec(@spec))
|
75
|
-
else
|
76
|
-
raise Ccrypto::CipherEngineException, "Not supported cipher init type #{@spec.class}"
|
77
|
-
end
|
78
|
-
rescue OpenSSL::Cipher::CipherError, RuntimeError => ex
|
79
|
-
raise Ccrypto::CipherEngineException, ex
|
80
|
-
end
|
199
|
+
teLogger.debug "Cipher spec : #{@spec} (Native algo : #{@spec.native_config[:algo_str]})"
|
200
|
+
|
201
|
+
@cipher = OpenSSL::Cipher.new(@spec.native_config[:algo_str])
|
81
202
|
|
82
203
|
case @spec.cipherOps
|
83
204
|
when :encrypt, :enc
|
@@ -94,11 +215,11 @@ module Ccrypto
|
|
94
215
|
if @spec.has_iv?
|
95
216
|
teLogger.debug "IV from spec"
|
96
217
|
@cipher.iv = @spec.iv
|
97
|
-
teLogger.debug "IV : #{to_hex(@spec.iv)}"
|
218
|
+
teLogger.debug "IV : #{to_hex(@spec.iv)} / #{@spec.iv.length}"
|
98
219
|
else
|
99
220
|
teLogger.debug "Generate random IV"
|
100
221
|
@spec.iv = @cipher.random_iv
|
101
|
-
teLogger.debug "IV : #{to_hex(@spec.iv)}"
|
222
|
+
teLogger.debug "IV : #{to_hex(@spec.iv)} / #{@spec.iv.length}"
|
102
223
|
end
|
103
224
|
|
104
225
|
|
@@ -118,25 +239,50 @@ module Ccrypto
|
|
118
239
|
end
|
119
240
|
|
120
241
|
|
121
|
-
if @spec.is_mode?(:
|
122
|
-
|
123
|
-
|
124
|
-
|
242
|
+
if @spec.is_mode?(:ccm)
|
243
|
+
#if not_empty?(@spec.auth_data)
|
244
|
+
if @spec.is_encrypt_cipher_mode?
|
245
|
+
teLogger.debug "Setting ccm plaintext data length (ccm mode) [#{@spec.plaintext_length}]"
|
246
|
+
@cipher.ccm_data_len = @spec.plaintext_length
|
247
|
+
teLogger.debug "Setting auth data (ccm mode)"
|
248
|
+
@cipher.auth_data = @spec.auth_data.nil? ? "" : @spec.auth_data
|
249
|
+
teLogger.debug "Setting auth tag len (ccm mode)"
|
250
|
+
@cipher.auth_tag_len = 12
|
251
|
+
elsif @spec.is_decrypt_cipher_mode?
|
252
|
+
teLogger.debug "Setting ccm cipher data length (ccm mode) #{@spec.ciphertext_length}"
|
253
|
+
@cipher.ccm_data_len = @spec.ciphertext_length
|
254
|
+
teLogger.debug "Setting auth data (ccm mode)"
|
255
|
+
@cipher.auth_data = @spec.auth_data.nil? ? "" : @spec.auth_data
|
256
|
+
teLogger.debug "Setting auth tag (ccm mode)"
|
257
|
+
@cipher.auth_tag = @spec.auth_tag
|
258
|
+
end
|
259
|
+
#end
|
260
|
+
|
261
|
+
|
262
|
+
elsif @spec.is_auth_mode_cipher?
|
263
|
+
|
264
|
+
if not_empty?(@spec.auth_data) and not ((@spec.is_mode?("cbc-hmac-sha1") or @spec.is_mode?("cbc-hmac-sha256")))
|
265
|
+
teLogger.debug "Setting auth data (generic mode)"
|
125
266
|
@cipher.auth_data = @spec.auth_data
|
126
|
-
end
|
127
267
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
268
|
+
if @spec.is_decrypt_cipher_mode?
|
269
|
+
teLogger.debug "Setting auth tag (generic mode)"
|
270
|
+
raise CipherEngineException, "Tag length of 16 bytes is expected" if @spec.auth_tag.bytesize != 16 and @spec.is_mode?(:gcm)
|
271
|
+
@cipher.auth_tag = @spec.auth_tag
|
272
|
+
end
|
132
273
|
end
|
133
274
|
|
134
275
|
end
|
135
276
|
|
136
|
-
|
277
|
+
|
278
|
+
end # initialize
|
137
279
|
|
138
280
|
def update(val)
|
139
|
-
|
281
|
+
if not_empty?(val)
|
282
|
+
res = @cipher.update(val)
|
283
|
+
teLogger.debug "(update) Written #{val.length} bytes"
|
284
|
+
res
|
285
|
+
end
|
140
286
|
end
|
141
287
|
|
142
288
|
def final(val = nil)
|
@@ -145,17 +291,22 @@ module Ccrypto
|
|
145
291
|
begin
|
146
292
|
|
147
293
|
if not_empty?(val)
|
148
|
-
|
294
|
+
teLogger.debug "(final) Written #{val.length} bytes"
|
295
|
+
res << @cipher.update(val)
|
149
296
|
end
|
150
297
|
|
151
298
|
res << @cipher.final
|
299
|
+
teLogger.debug "(final) cipher finalized"
|
152
300
|
|
153
301
|
rescue Exception => ex
|
302
|
+
teLogger.error self
|
303
|
+
teLogger.error ex.backtrace.join("\n")
|
154
304
|
raise CipherEngineException, ex
|
155
305
|
end
|
156
306
|
|
157
|
-
if @spec.is_mode?(:gcm)
|
158
|
-
|
307
|
+
#if @spec.is_mode?(:gcm)
|
308
|
+
if @spec.is_auth_mode_cipher? and @spec.is_encrypt_cipher_mode?
|
309
|
+
@spec.auth_tag = @cipher.auth_tag
|
159
310
|
end
|
160
311
|
|
161
312
|
res.join
|
@@ -165,6 +316,14 @@ module Ccrypto
|
|
165
316
|
@cipher.reset
|
166
317
|
end
|
167
318
|
|
319
|
+
def method_missing(mtd, *args, &block)
|
320
|
+
if not @cipher.nil?
|
321
|
+
@cipher.send(mtd, *args, &block)
|
322
|
+
else
|
323
|
+
super
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
168
327
|
end
|
169
328
|
end
|
170
329
|
end
|
@@ -27,9 +27,10 @@ module Ccrypto
|
|
27
27
|
Ccrypto::SHAKE256.provider_info("shake256"),
|
28
28
|
Ccrypto::BLAKE2b512.provider_info("BLAKE2b512"),
|
29
29
|
Ccrypto::BLAKE2s256.provider_info("BLAKE2s256"),
|
30
|
-
Ccrypto::SM3.provider_info("SM3")
|
31
|
-
|
32
|
-
Ccrypto::
|
30
|
+
Ccrypto::SM3.provider_info("SM3")
|
31
|
+
# deprecated starting OpenSSL v3.0
|
32
|
+
#Ccrypto::RIPEMD160.provider_info("RIPEMD160"),
|
33
|
+
#Ccrypto::WHIRLPOOL.provider_info("whirlpool")
|
33
34
|
]
|
34
35
|
|
35
36
|
|
@@ -38,14 +39,21 @@ module Ccrypto
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def self.is_supported?(eng)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
|
43
|
+
case eng
|
44
|
+
when Ccrypto::DigestConfig
|
45
|
+
SupportedDigest.include?(eng)
|
46
|
+
when String, Symbol
|
47
|
+
if eng.is_a?(Symbol)
|
48
|
+
engineKeys.include?(eng)
|
49
|
+
else
|
50
|
+
e = eng.gsub("-","_")
|
51
|
+
engineKeys.include?(e.to_sym)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
raise DigestEngineException, "Unknown engine '#{eng}'"
|
46
55
|
end
|
47
56
|
|
48
|
-
res
|
49
57
|
end
|
50
58
|
|
51
59
|
def self.instance(*args, &block)
|
@@ -59,16 +67,30 @@ module Ccrypto
|
|
59
67
|
end
|
60
68
|
|
61
69
|
def self.digest(key)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
70
|
+
|
71
|
+
case key
|
72
|
+
when Ccrypto::DigestConfig
|
73
|
+
DigestEngine.new(OpenSSL::Digest.new(key.provider_config))
|
74
|
+
when String, Symbol
|
75
|
+
if key.is_a?(Symbol)
|
76
|
+
res = engineKeys[key]
|
77
|
+
else
|
78
|
+
k = key.gsub("-","_")
|
79
|
+
res = engineKeys[k.to_sym]
|
80
|
+
end
|
81
|
+
|
82
|
+
if is_empty?(res)
|
83
|
+
teLogger.debug "No digest available for #{key}"
|
84
|
+
raise DigestEngineException, "Not supported digest engine #{key}"
|
85
|
+
else
|
86
|
+
teLogger.debug "Found digest #{key.to_sym}"
|
87
|
+
DigestEngine.new(OpenSSL::Digest.new(res.provider_config))
|
88
|
+
end
|
89
|
+
|
67
90
|
else
|
68
|
-
|
69
|
-
DigestEngine.new(OpenSSL::Digest.new(res.provider_config))
|
91
|
+
raise DigestEngineException, "Not supported digest engine #{key}"
|
70
92
|
end
|
71
|
-
|
93
|
+
|
72
94
|
end
|
73
95
|
|
74
96
|
def self.engineKeys
|
@@ -1,5 +1,7 @@
|
|
1
1
|
|
2
2
|
require 'openssl'
|
3
|
+
if OpenSSL::VERSION < "3.0.0"
|
4
|
+
|
3
5
|
module PKeyPatch
|
4
6
|
def to_pem; public_key.to_pem end
|
5
7
|
def to_der; public_key.to_der end
|
@@ -13,20 +15,51 @@ module PKeyPatch
|
|
13
15
|
end
|
14
16
|
OpenSSL::PKey::EC::Point.prepend PKeyPatch
|
15
17
|
|
18
|
+
end
|
19
|
+
|
16
20
|
require_relative '../keybundle_store/pkcs12'
|
17
21
|
require_relative '../keybundle_store/pem_store'
|
22
|
+
require_relative '../ecc_const'
|
18
23
|
|
19
24
|
module Ccrypto
|
20
25
|
module Ruby
|
21
26
|
|
22
27
|
class ECCPublicKey < Ccrypto::ECCPublicKey
|
23
|
-
|
28
|
+
|
24
29
|
def to_bin
|
25
|
-
|
30
|
+
if OpenSSL::VERSION < "3.0.0"
|
31
|
+
@native_pubKey.to_der
|
32
|
+
else
|
33
|
+
const = ECCConst[@native_pubKey.group.curve_name]
|
34
|
+
# At 01 April 2023
|
35
|
+
# at Ruby 3.2.1/OpenSSL gem 3.1.0/OpenSSL 3.0.2
|
36
|
+
# The gem has bug that the encoding is incorrect
|
37
|
+
OpenSSL::ASN1::Sequence.new([
|
38
|
+
OpenSSL::ASN1::ObjectId.new("2.8.8.128.0"),
|
39
|
+
OpenSSL::ASN1::Integer.new(0x0100),
|
40
|
+
OpenSSL::ASN1::Integer.new(const),
|
41
|
+
OpenSSL::ASN1::BitString.new(@native_pubKey.to_bn)
|
42
|
+
]).to_der
|
43
|
+
end
|
26
44
|
end
|
27
45
|
|
28
46
|
def self.to_key(bin)
|
29
|
-
|
47
|
+
if OpenSSL::VERSION > "3.0.0"
|
48
|
+
ek = OpenSSL::PKey::EC.new(bin)
|
49
|
+
else
|
50
|
+
seq = OpenSSL::ASN1Object.decode(bin).value
|
51
|
+
envp = ASN1Object.decode(seq[0]).value
|
52
|
+
raise KeypairEngineException, "Not ECC public key" if envp != "2.8.8.8.128.0"
|
53
|
+
ver = ASN1Object.decode(seq[1]).value
|
54
|
+
raise KeypairEngineException, "Unsupported version" if ver != 0x0100
|
55
|
+
cv = ASN1Object.decode(seq[2]).value
|
56
|
+
curve = ECCConst.invert[cv]
|
57
|
+
raise KeypairEngineException, "Unknown curve '#{curve}'" if curve.nil?
|
58
|
+
kv = ASN1Object.decode(seq[3]).value
|
59
|
+
|
60
|
+
ek = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC::Group.new(curve), kv)
|
61
|
+
end
|
62
|
+
|
30
63
|
ECCPublicKey.new(ek)
|
31
64
|
end
|
32
65
|
|
@@ -49,7 +82,11 @@ module Ccrypto
|
|
49
82
|
|
50
83
|
def public_key
|
51
84
|
if @pubKey.nil?
|
52
|
-
|
85
|
+
#if OpenSSL::VERSION < "3.0.0"
|
86
|
+
@pubKey = ECCPublicKey.new(@nativeKeypair.public_key)
|
87
|
+
#else
|
88
|
+
# @pubKey = ECCPublicKey.new(@nativeKeypair.public_key.to_bn)
|
89
|
+
#end
|
53
90
|
end
|
54
91
|
@pubKey
|
55
92
|
end
|
@@ -65,12 +102,21 @@ module Ccrypto
|
|
65
102
|
tkey = pubKey
|
66
103
|
when Ccrypto::ECCPublicKey
|
67
104
|
tkey = pubKey.native_pubKey
|
68
|
-
|
105
|
+
if OpenSSL::VERSION < "3.0.0"
|
106
|
+
tkey = tkey.public_key if not tkey.is_a?(OpenSSL::PKey::EC::Point)
|
107
|
+
else
|
108
|
+
tkey = OpenSSL::PKey::EC.new(tkey)
|
109
|
+
end
|
69
110
|
else
|
70
111
|
raise KeypairEngineException, "Unknown public key type #{pubKey.class}"
|
71
112
|
end
|
72
113
|
|
73
|
-
|
114
|
+
if OpenSSL::VERSION < "3.0.0"
|
115
|
+
raise KeypairEngineException, "OpenSSL::PKey::EC::Point is required. Given #{tkey.inspect}" if not tkey.is_a?(OpenSSL::PKey::EC::Point)
|
116
|
+
else
|
117
|
+
raise KeypairEngineException, "OpenSSL::PKey::EC is required. Given #{tkey.inspect}" if not tkey.is_a?(OpenSSL::PKey::EC)
|
118
|
+
end
|
119
|
+
|
74
120
|
@nativeKeypair.dh_compute_key(tkey)
|
75
121
|
end
|
76
122
|
|
@@ -171,9 +217,24 @@ module Ccrypto
|
|
171
217
|
|
172
218
|
teLogger_tag :r_ecc
|
173
219
|
|
220
|
+
NotAbleToFigureOutOnOpenSSLv2 = [
|
221
|
+
"Oakley-EC2N-3",
|
222
|
+
"Oakley-EC2N-4"
|
223
|
+
]
|
224
|
+
|
174
225
|
def self.supported_curves
|
175
226
|
if @curves.nil?
|
176
|
-
@curves =
|
227
|
+
@curves = []
|
228
|
+
OpenSSL::PKey::EC.builtin_curves.sort.map { |c|
|
229
|
+
|
230
|
+
next if c[0] =~ /^wap/ or NotAbleToFigureOutOnOpenSSLv2.include?(c[0])
|
231
|
+
|
232
|
+
if c[0] == "prime256v1"
|
233
|
+
@curves << Ccrypto::ECCConfig.new(c[0], Ccrypto::KeypairConfig::Algo_Active, true)
|
234
|
+
else
|
235
|
+
@curves << Ccrypto::ECCConfig.new(c[0])
|
236
|
+
end
|
237
|
+
}
|
177
238
|
end
|
178
239
|
@curves
|
179
240
|
end
|
@@ -203,14 +264,28 @@ module Ccrypto
|
|
203
264
|
end
|
204
265
|
|
205
266
|
def self.verify(pubKey, val, sign)
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
uPubKey
|
210
|
-
|
267
|
+
if OpenSSL::VERSION > "3.0.0"
|
268
|
+
p pubKey.native_pubKey
|
269
|
+
p pubKey.native_pubKey.methods.sort
|
270
|
+
uPubKey = pubKey.native_pubKey
|
271
|
+
if uPubKey.is_a?(OpenSSL::PKey::EC::Point)
|
272
|
+
res = uPubKey.dsa_verify_asn1(val, sign)
|
273
|
+
res
|
274
|
+
else
|
275
|
+
raise KeypairEngineException, "Unsupported public key type '#{uPubKey.class}'"
|
276
|
+
end
|
211
277
|
|
212
|
-
|
213
|
-
|
278
|
+
else
|
279
|
+
# OpenSSL v2 - Ruby 2.x
|
280
|
+
uPubKey = pubKey.native_pubKey
|
281
|
+
if pubKey.native_pubKey.is_a?(OpenSSL::PKey::EC::Point)
|
282
|
+
uPubKey = OpenSSL::PKey::EC.new(uPubKey.group)
|
283
|
+
uPubKey.public_key = pubKey.native_pubKey
|
284
|
+
end
|
285
|
+
|
286
|
+
res = uPubKey.dsa_verify_asn1(val, sign)
|
287
|
+
res
|
288
|
+
end
|
214
289
|
end
|
215
290
|
|
216
291
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
|
2
|
+
require 'ed25519'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Ruby
|
6
|
+
|
7
|
+
class ED25519Exception < StandardError; end
|
8
|
+
|
9
|
+
class ED25519PublicKey < Ccrypto::ED25519PublicKey
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class ED25519KeyBundle
|
14
|
+
include Ccrypto::ED25519KeyBundle
|
15
|
+
|
16
|
+
include TR::CondUtils
|
17
|
+
|
18
|
+
include TeLogger::TeLogHelper
|
19
|
+
teLogger_tag :ed25519_kb
|
20
|
+
|
21
|
+
def initialize(kp)
|
22
|
+
@nativeKeypair = kp
|
23
|
+
end
|
24
|
+
|
25
|
+
def public_key
|
26
|
+
if @pubKey.nil?
|
27
|
+
@pubKey = ED25519PublicKey.new(@nativeKeypair.verify_key)
|
28
|
+
end
|
29
|
+
@pubKey
|
30
|
+
end
|
31
|
+
|
32
|
+
def private_key
|
33
|
+
ED25519PrivateKey.new(@nativeKeypair)
|
34
|
+
end
|
35
|
+
|
36
|
+
end # ED25519KeyBundle
|
37
|
+
|
38
|
+
class ED25519Engine
|
39
|
+
include TeLogger::TeLogHelper
|
40
|
+
teLogger_tag :ed25519_eng
|
41
|
+
|
42
|
+
def initialize(*args, &block)
|
43
|
+
@config = args.first
|
44
|
+
teLogger.debug "Config : #{@config}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_keypair(&block)
|
48
|
+
teLogger.debug "Generating ED25519 keypair"
|
49
|
+
ED25519KeyBundle.new(Ed25519::SigningKey.generate)
|
50
|
+
end
|
51
|
+
|
52
|
+
def sign(val)
|
53
|
+
|
54
|
+
raise KeypairEngineException, "Keypair is required" if @config.keypair.nil?
|
55
|
+
raise KeypairEngineException, "ED25519 keypair is required" if not @config.keypair.is_a?(ED25519KeyBundle)
|
56
|
+
|
57
|
+
kp = @config.keypair
|
58
|
+
|
59
|
+
res = kp.nativeKeypair.sign(val)
|
60
|
+
teLogger.debug "Data of length #{val.length} signed using ED25519"
|
61
|
+
|
62
|
+
res
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.verify(pubKey, val, sign)
|
67
|
+
case pubKey
|
68
|
+
when Ccrypto::ED25519PublicKey
|
69
|
+
uPubKey = pubKey
|
70
|
+
else
|
71
|
+
raise KeypairEngineException, "Unsupported public key '#{pubKey.class}' for ED25519 operation"
|
72
|
+
end
|
73
|
+
|
74
|
+
begin
|
75
|
+
uPubKey.verify(sign, val)
|
76
|
+
rescue Ed25519::VerifyError => ex
|
77
|
+
false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|