ccrypto-ruby 0.1.0
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 +7 -0
- data/.rspec +3 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +64 -0
- data/README.md +149 -0
- data/Rakefile +10 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ccrypto-ruby.gemspec +45 -0
- data/lib/ccrypto/provider.rb +175 -0
- data/lib/ccrypto/ruby/data_conversion.rb +68 -0
- data/lib/ccrypto/ruby/engines/asn1_engine.rb +110 -0
- data/lib/ccrypto/ruby/engines/asn1_object.rb +19 -0
- data/lib/ccrypto/ruby/engines/cipher_engine.rb +170 -0
- data/lib/ccrypto/ruby/engines/compression_engine.rb +61 -0
- data/lib/ccrypto/ruby/engines/data_conversion_engine.rb +9 -0
- data/lib/ccrypto/ruby/engines/decompression_engine.rb +70 -0
- data/lib/ccrypto/ruby/engines/digest_engine.rb +127 -0
- data/lib/ccrypto/ruby/engines/ecc_engine.rb +218 -0
- data/lib/ccrypto/ruby/engines/hkdf_engine.rb +54 -0
- data/lib/ccrypto/ruby/engines/hmac_engine.rb +53 -0
- data/lib/ccrypto/ruby/engines/pbkdf2_engine.rb +69 -0
- data/lib/ccrypto/ruby/engines/pkcs7_engine.rb +179 -0
- data/lib/ccrypto/ruby/engines/rsa_engine.rb +300 -0
- data/lib/ccrypto/ruby/engines/scrypt_engine.rb +34 -0
- data/lib/ccrypto/ruby/engines/secret_key_engine.rb +18 -0
- data/lib/ccrypto/ruby/engines/secret_sharing_engine.rb +331 -0
- data/lib/ccrypto/ruby/engines/secure_random_engine.rb +34 -0
- data/lib/ccrypto/ruby/engines/x509_engine.rb +213 -0
- data/lib/ccrypto/ruby/ext/secret_key.rb +24 -0
- data/lib/ccrypto/ruby/ext/x509_cert.rb +24 -0
- data/lib/ccrypto/ruby/keybundle_store/pem_store.rb +73 -0
- data/lib/ccrypto/ruby/keybundle_store/pkcs12.rb +111 -0
- data/lib/ccrypto/ruby/utils/comparator.rb +15 -0
- data/lib/ccrypto/ruby/utils/memory_buffer.rb +63 -0
- data/lib/ccrypto/ruby/utils/native_helper.rb +17 -0
- data/lib/ccrypto/ruby/version.rb +7 -0
- data/lib/ccrypto/ruby.rb +25 -0
- metadata +136 -0
@@ -0,0 +1,170 @@
|
|
1
|
+
|
2
|
+
require_relative '../data_conversion'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Ruby
|
6
|
+
class CipherEngine
|
7
|
+
include TR::CondUtils
|
8
|
+
include DataConversion
|
9
|
+
|
10
|
+
include TeLogger::TeLogHelper
|
11
|
+
|
12
|
+
teLogger_tag :r_cipher_eng
|
13
|
+
|
14
|
+
def self.supported_ciphers
|
15
|
+
if @sCipher.nil?
|
16
|
+
@sCipher = OpenSSL::Cipher.ciphers
|
17
|
+
end
|
18
|
+
|
19
|
+
@sCipher
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.is_supported_cipher?(c)
|
24
|
+
case c
|
25
|
+
when String
|
26
|
+
supported_ciphers.include?(c)
|
27
|
+
when Hash
|
28
|
+
spec = to_openssl_spec(c)
|
29
|
+
begin
|
30
|
+
OpenSSL::Cipher.new(spec)
|
31
|
+
true
|
32
|
+
rescue Exception => ex
|
33
|
+
false
|
34
|
+
end
|
35
|
+
else
|
36
|
+
raise Ccrypto::CipherEngineException, "Unsupported input #{c} to check supported cipher"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.to_openssl_spec(spec)
|
41
|
+
res = []
|
42
|
+
|
43
|
+
teLogger.debug "to_openssl_spec #{spec}"
|
44
|
+
case spec.algo
|
45
|
+
when :blowfish
|
46
|
+
res << "bf"
|
47
|
+
else
|
48
|
+
res << spec.algo
|
49
|
+
end
|
50
|
+
|
51
|
+
res << spec.keysize if not_empty?(spec.keysize) and spec.keysize.to_i > 0 and not spec.is_algo?(:chacha20) and not spec.is_algo?(:seed) and not spec.is_algo?(:sm4) and not spec.is_algo?(:blowfish)
|
52
|
+
|
53
|
+
res << spec.mode
|
54
|
+
|
55
|
+
teLogger.debug "to_openssl_spec #{res}"
|
56
|
+
|
57
|
+
res.join("-")
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize(*args, &block)
|
62
|
+
@spec = args.first
|
63
|
+
|
64
|
+
#teLogger = TteLogger.new
|
65
|
+
teLogger.debug "Cipher spec : #{@spec}"
|
66
|
+
|
67
|
+
begin
|
68
|
+
case @spec
|
69
|
+
#when String
|
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
|
81
|
+
|
82
|
+
case @spec.cipherOps
|
83
|
+
when :encrypt, :enc
|
84
|
+
teLogger.debug "Operation encrypt"
|
85
|
+
@cipher.encrypt
|
86
|
+
when :decrypt, :dec
|
87
|
+
teLogger.debug "Operation decrypt"
|
88
|
+
@cipher.decrypt
|
89
|
+
else
|
90
|
+
raise Ccrypto::CipherEngineException, "Cipher operation (encrypt/decrypt) must be given"
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
if @spec.has_iv?
|
95
|
+
teLogger.debug "IV from spec"
|
96
|
+
@cipher.iv = @spec.iv
|
97
|
+
teLogger.debug "IV : #{to_hex(@spec.iv)}"
|
98
|
+
else
|
99
|
+
teLogger.debug "Generate random IV"
|
100
|
+
@spec.iv = @cipher.random_iv
|
101
|
+
teLogger.debug "IV : #{to_hex(@spec.iv)}"
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
if @spec.has_key?
|
106
|
+
teLogger.debug "Key from spec"
|
107
|
+
case @spec.key
|
108
|
+
when Ccrypto::SecretKey
|
109
|
+
@cipher.key = @spec.key.to_bin
|
110
|
+
when String
|
111
|
+
@cipher.key = @spec.key
|
112
|
+
else
|
113
|
+
raise Ccrypto::CipherEngineException, "Unknown key type for processing #{@spec.key}"
|
114
|
+
end
|
115
|
+
else
|
116
|
+
teLogger.debug "Generate random Key"
|
117
|
+
@spec.key = @cipher.random_key
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
if @spec.is_mode?(:gcm)
|
122
|
+
|
123
|
+
if not_empty?(@spec.auth_data)
|
124
|
+
teLogger.debug "Setting auth data"
|
125
|
+
@cipher.auth_data = @spec.auth_data
|
126
|
+
end
|
127
|
+
|
128
|
+
if not_empty?(@spec.auth_tag)
|
129
|
+
raise CipherEngineException, "Tag length of 16 bytes is expected" if @spec.auth_tag.bytesize != 16
|
130
|
+
teLogger.debug "Setting auth tag"
|
131
|
+
@cipher.auth_tag = @spec.auth_tag
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
def update(val)
|
139
|
+
@cipher.update(val)
|
140
|
+
end
|
141
|
+
|
142
|
+
def final(val = nil)
|
143
|
+
res = []
|
144
|
+
|
145
|
+
begin
|
146
|
+
|
147
|
+
if not_empty?(val)
|
148
|
+
res << @cipher.update(val)
|
149
|
+
end
|
150
|
+
|
151
|
+
res << @cipher.final
|
152
|
+
|
153
|
+
rescue Exception => ex
|
154
|
+
raise CipherEngineException, ex
|
155
|
+
end
|
156
|
+
|
157
|
+
if @spec.is_mode?(:gcm) and @spec.is_encrypt_cipher_mode?
|
158
|
+
@spec.auth_tag = @cipher.auth_tag
|
159
|
+
end
|
160
|
+
|
161
|
+
res.join
|
162
|
+
end
|
163
|
+
|
164
|
+
def reset
|
165
|
+
@cipher.reset
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Ccrypto
|
4
|
+
module Ruby
|
5
|
+
class Compression
|
6
|
+
|
7
|
+
include TeLogger::TeLogHelper
|
8
|
+
|
9
|
+
teLogger_tag :r_compression
|
10
|
+
|
11
|
+
def initialize(*args, &block)
|
12
|
+
|
13
|
+
@config = args.first
|
14
|
+
raise CompressionError, "Compress Config is expected. Given #{@config}" if not @config.is_a?(Ccrypto::CompressionConfig)
|
15
|
+
|
16
|
+
if block
|
17
|
+
|
18
|
+
outPath = block.call(:out_path)
|
19
|
+
if is_empty?(outPath)
|
20
|
+
outFile = block.call(:out_file)
|
21
|
+
raise CompressionError, "Given out_file required to support write() call" if not outFile.respond_to?(:write)
|
22
|
+
@out = outFile
|
23
|
+
else
|
24
|
+
@out = Tempfile.new(SecureRandom.hex(24))
|
25
|
+
end
|
26
|
+
|
27
|
+
@intBufSize = block.call(:int_buf_size) || 102400
|
28
|
+
|
29
|
+
else
|
30
|
+
@intBufSize = 102400
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
case @config.level
|
35
|
+
when :best_compression
|
36
|
+
teLogger.debug "Best compression"
|
37
|
+
@eng = Zlib::Deflate.new(Zlib::BEST_COMPRESSION)
|
38
|
+
when :best_speed
|
39
|
+
teLogger.debug "Best compression"
|
40
|
+
@eng = Zlib::Deflate.new(Zlib::BEST_SPEED)
|
41
|
+
when :no_compression
|
42
|
+
teLogger.debug "No compression"
|
43
|
+
@eng = Zlib::Deflate.new(Zlib::NO_COMPRESSION)
|
44
|
+
else
|
45
|
+
teLogger.debug "Default compression"
|
46
|
+
@eng = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def update(val)
|
52
|
+
@eng.deflate(val, Zlib::SYNC_FLUSH)
|
53
|
+
end
|
54
|
+
|
55
|
+
def final
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Ccrypto
|
4
|
+
module Ruby
|
5
|
+
class Decompression
|
6
|
+
|
7
|
+
def initialize(*args, &block)
|
8
|
+
if block
|
9
|
+
|
10
|
+
outPath = block.call(:out_path)
|
11
|
+
if is_empty?(outPath)
|
12
|
+
outFile = block.call(:out_file)
|
13
|
+
raise CompressionError, "Given out_file required to support write() call" if not outFile.respond_to?(:write)
|
14
|
+
@out = outFile
|
15
|
+
else
|
16
|
+
@out = Tempfile.new(SecureRandom.hex(16))
|
17
|
+
end
|
18
|
+
|
19
|
+
@intBufSize = block.call(:int_buf_size) || 102400
|
20
|
+
|
21
|
+
else
|
22
|
+
@intBufSize = 102400
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
@eng = Zlib::Inflate.new
|
27
|
+
|
28
|
+
#@in = Tempfile.new(SecureRandom.hex(16))
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(val)
|
32
|
+
begin
|
33
|
+
@eng.inflate(val)
|
34
|
+
rescue Zlib::DataError
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def final
|
39
|
+
|
40
|
+
#eng = Zlib::Inflate.new
|
41
|
+
|
42
|
+
#@in.seek(0)
|
43
|
+
|
44
|
+
#intBuf = false
|
45
|
+
#if @out.nil?
|
46
|
+
# @out = StringIO.new
|
47
|
+
# intBuf = true
|
48
|
+
#end
|
49
|
+
|
50
|
+
#chunk = 102400
|
51
|
+
#loop do
|
52
|
+
# compressed = @in.read(chunk)
|
53
|
+
# res = eng.inflate(compressed) #, Zlib::SYNC_FLUSH)
|
54
|
+
# @out.write(res)
|
55
|
+
|
56
|
+
# break if @in.eof?
|
57
|
+
#end
|
58
|
+
|
59
|
+
#if intBuf
|
60
|
+
# @out.string
|
61
|
+
#else
|
62
|
+
# @out
|
63
|
+
#end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
|
2
|
+
require_relative '../data_conversion'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Ruby
|
6
|
+
class DigestEngine
|
7
|
+
include Ccrypto::Ruby::DataConversion
|
8
|
+
include TR::CondUtils
|
9
|
+
|
10
|
+
include TeLogger::TeLogHelper
|
11
|
+
|
12
|
+
teLogger_tag :r_digest
|
13
|
+
|
14
|
+
SupportedDigest = [
|
15
|
+
Ccrypto::SHA1.provider_info("sha1"),
|
16
|
+
Ccrypto::SHA224.provider_info("sha224"),
|
17
|
+
Ccrypto::SHA256.provider_info("sha256"),
|
18
|
+
Ccrypto::SHA384.provider_info("sha384"),
|
19
|
+
Ccrypto::SHA512.provider_info("sha512"),
|
20
|
+
Ccrypto::SHA512_224.provider_info("sha512-224"),
|
21
|
+
Ccrypto::SHA512_256.provider_info("sha512-256"),
|
22
|
+
Ccrypto::SHA3_224.provider_info("sha3-224"),
|
23
|
+
Ccrypto::SHA3_256.provider_info("sha3-256"),
|
24
|
+
Ccrypto::SHA3_384.provider_info("sha3-384"),
|
25
|
+
Ccrypto::SHA3_512.provider_info("sha3-512"),
|
26
|
+
Ccrypto::SHAKE128.provider_info("shake128"),
|
27
|
+
Ccrypto::SHAKE256.provider_info("shake256"),
|
28
|
+
Ccrypto::BLAKE2b512.provider_info("BLAKE2b512"),
|
29
|
+
Ccrypto::BLAKE2s256.provider_info("BLAKE2s256"),
|
30
|
+
Ccrypto::SM3.provider_info("SM3"),
|
31
|
+
Ccrypto::RIPEMD160.provider_info("RIPEMD160"),
|
32
|
+
Ccrypto::WHIRLPOOL.provider_info("whirlpool")
|
33
|
+
]
|
34
|
+
|
35
|
+
|
36
|
+
def self.supported
|
37
|
+
SupportedDigest
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.is_supported?(eng)
|
41
|
+
res = supported.include?(eng)
|
42
|
+
begin
|
43
|
+
res = digest(eng) if not res
|
44
|
+
rescue DigestEngineException => ex
|
45
|
+
res = false
|
46
|
+
end
|
47
|
+
|
48
|
+
res
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.instance(*args, &block)
|
52
|
+
conf = args.first
|
53
|
+
if not_empty?(conf.provider_config)
|
54
|
+
teLogger.debug "Creating digest engine #{conf.provider_config}"
|
55
|
+
DigestEngine.new(OpenSSL::Digest.new(conf.provider_config))
|
56
|
+
else
|
57
|
+
raise DigestEngineException, "Given digest config #{conf.algo} does not have provider key mapping. Most likely this config is not supported by provider #{Ccrypto::Ruby::Provider.provider_name}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.digest(key)
|
62
|
+
|
63
|
+
res = engineKeys[key]
|
64
|
+
if is_empty?(res)
|
65
|
+
teLogger.debug "No digest available for #{key}"
|
66
|
+
raise DigestEngineException, "Not supported digest engine #{key}"
|
67
|
+
else
|
68
|
+
teLogger.debug "Found digest #{key.to_sym}"
|
69
|
+
DigestEngine.new(OpenSSL::Digest.new(res.provider_config))
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.engineKeys
|
75
|
+
if @engineKeys.nil?
|
76
|
+
@engineKeys = {}
|
77
|
+
supported.map do |e|
|
78
|
+
@engineKeys[e.algo.to_sym] = e
|
79
|
+
end
|
80
|
+
end
|
81
|
+
@engineKeys
|
82
|
+
end
|
83
|
+
|
84
|
+
def initialize(inst)
|
85
|
+
@inst = inst
|
86
|
+
end
|
87
|
+
|
88
|
+
def native_digest_engine
|
89
|
+
@inst
|
90
|
+
end
|
91
|
+
alias_method :native_instance, :native_digest_engine
|
92
|
+
|
93
|
+
def digest(val, output = :binary)
|
94
|
+
digest_update(val)
|
95
|
+
digest_final(output)
|
96
|
+
end
|
97
|
+
|
98
|
+
def digest_update(val)
|
99
|
+
case val
|
100
|
+
when MemoryBuffer
|
101
|
+
@inst.update(val.bytes)
|
102
|
+
else
|
103
|
+
@inst.update(val)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def digest_final(output = :binary)
|
108
|
+
|
109
|
+
res = @inst.digest
|
110
|
+
@inst.reset
|
111
|
+
case output
|
112
|
+
when :hex
|
113
|
+
to_hex(res)
|
114
|
+
when :b64
|
115
|
+
to_b64(res)
|
116
|
+
else
|
117
|
+
res
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def reset
|
122
|
+
@inst.reset
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
|
2
|
+
require 'openssl'
|
3
|
+
module PKeyPatch
|
4
|
+
def to_pem; public_key.to_pem end
|
5
|
+
def to_der; public_key.to_der end
|
6
|
+
|
7
|
+
#private
|
8
|
+
def public_key
|
9
|
+
key = ::OpenSSL::PKey::EC.new group
|
10
|
+
key.public_key = self
|
11
|
+
key
|
12
|
+
end
|
13
|
+
end
|
14
|
+
OpenSSL::PKey::EC::Point.prepend PKeyPatch
|
15
|
+
|
16
|
+
require_relative '../keybundle_store/pkcs12'
|
17
|
+
require_relative '../keybundle_store/pem_store'
|
18
|
+
|
19
|
+
module Ccrypto
|
20
|
+
module Ruby
|
21
|
+
|
22
|
+
class ECCPublicKey < Ccrypto::ECCPublicKey
|
23
|
+
|
24
|
+
def to_bin
|
25
|
+
@native_pubKey.to_der
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.to_key(bin)
|
29
|
+
ek = OpenSSL::PKey::EC.new(bin)
|
30
|
+
ECCPublicKey.new(ek)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
class ECCKeyBundle
|
36
|
+
include Ccrypto::ECCKeyBundle
|
37
|
+
include TR::CondUtils
|
38
|
+
|
39
|
+
include PKCS12Store
|
40
|
+
include PEMStore
|
41
|
+
|
42
|
+
include TeLogger::TeLogHelper
|
43
|
+
|
44
|
+
teLogger_tag :r_ecc_keybundle
|
45
|
+
|
46
|
+
def initialize(keypair)
|
47
|
+
@nativeKeypair = keypair
|
48
|
+
end
|
49
|
+
|
50
|
+
def public_key
|
51
|
+
if @pubKey.nil?
|
52
|
+
@pubKey = ECCPublicKey.new(@nativeKeypair.public_key)
|
53
|
+
end
|
54
|
+
@pubKey
|
55
|
+
end
|
56
|
+
|
57
|
+
def private_key
|
58
|
+
ECCPrivateKey.new(@nativeKeypair)
|
59
|
+
end
|
60
|
+
|
61
|
+
def derive_dh_shared_secret(pubKey)
|
62
|
+
|
63
|
+
case pubKey
|
64
|
+
when OpenSSL::PKey::EC::Point
|
65
|
+
tkey = pubKey
|
66
|
+
when Ccrypto::ECCPublicKey
|
67
|
+
tkey = pubKey.native_pubKey
|
68
|
+
tkey = tkey.public_key if not tkey.is_a?(OpenSSL::PKey::EC::Point)
|
69
|
+
else
|
70
|
+
raise KeypairEngineException, "Unknown public key type #{pubKey.class}"
|
71
|
+
end
|
72
|
+
|
73
|
+
raise KeypairEngineException, "OpenSSL::PKey::EC::Point is required. Given #{tkey.inspect}" if not tkey.is_a?(OpenSSL::PKey::EC::Point)
|
74
|
+
@nativeKeypair.dh_compute_key(tkey)
|
75
|
+
end
|
76
|
+
|
77
|
+
def is_public_key_equal?(pubKey)
|
78
|
+
|
79
|
+
case pubKey
|
80
|
+
when OpenSSL::PKey::EC
|
81
|
+
targetKey = pubKey
|
82
|
+
when ECCKeyBundle
|
83
|
+
targetKey = pubKey.public_key
|
84
|
+
when ECCPublicKey
|
85
|
+
targetKey = pubKey.native_pubKey
|
86
|
+
else
|
87
|
+
raise KeypairEngineException, "Unknown public key type #{pubKey.class}"
|
88
|
+
end
|
89
|
+
|
90
|
+
public_key.to_bin == targetKey.to_der
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_storage(format, &block)
|
94
|
+
case format
|
95
|
+
when :pkcs12, :p12
|
96
|
+
to_pkcs12 do |key|
|
97
|
+
case key
|
98
|
+
when :keypair
|
99
|
+
@nativeKeypair
|
100
|
+
else
|
101
|
+
block.call(key) if block
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
when :pem
|
106
|
+
to_pem do |key|
|
107
|
+
case key
|
108
|
+
when :keypair
|
109
|
+
@nativeKeypair
|
110
|
+
else
|
111
|
+
block.call(key) if block
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
else
|
116
|
+
raise KeyBundleStorageException, "Unknown storage format #{format}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.from_storage(bin, &block)
|
121
|
+
raise KeypairEngineException, "Given data to load is empty" if is_empty?(bin)
|
122
|
+
|
123
|
+
case bin
|
124
|
+
when String
|
125
|
+
begin
|
126
|
+
teLogger.debug "Given String to load from storage"
|
127
|
+
if is_pem?(bin)
|
128
|
+
self.from_pem(bin, &block)
|
129
|
+
else
|
130
|
+
# binary buffer
|
131
|
+
teLogger.debug "Given binary to load from storage"
|
132
|
+
self.from_pkcs12(bin,&block)
|
133
|
+
end
|
134
|
+
rescue Ccrypto::Ruby::PKCS12Store::PKCS12StoreException => ex
|
135
|
+
raise KeyBundleStorageException, ex
|
136
|
+
end
|
137
|
+
else
|
138
|
+
raise KeyBundleStorageException, "Unsupported input type #{bin}"
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
def equal?(kp)
|
144
|
+
if kp.respond_to?(:to_der)
|
145
|
+
@nativeKeypair.to_der == kp.to_der
|
146
|
+
else
|
147
|
+
@nativeKeypair == kp
|
148
|
+
#false
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def method_missing(mtd, *args, &block)
|
153
|
+
if @nativeKeypair.respond_to?(mtd)
|
154
|
+
teLogger.debug "Sending to nativeKeypair #{mtd}"
|
155
|
+
@nativeKeypair.send(mtd,*args, &block)
|
156
|
+
else
|
157
|
+
super
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def respond_to_missing?(mtd, *args, &block)
|
162
|
+
@nativeKeypair.respond_to?(mtd)
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
class ECCEngine
|
168
|
+
include TR::CondUtils
|
169
|
+
|
170
|
+
include TeLogger::TeLogHelper
|
171
|
+
|
172
|
+
teLogger_tag :r_ecc
|
173
|
+
|
174
|
+
def self.supported_curves
|
175
|
+
if @curves.nil?
|
176
|
+
@curves = OpenSSL::PKey::EC.builtin_curves.map { |c| Ccrypto::ECCConfig.new(c[0]) }
|
177
|
+
end
|
178
|
+
@curves
|
179
|
+
end
|
180
|
+
|
181
|
+
def initialize(*args, &block)
|
182
|
+
@config = args.first
|
183
|
+
raise KeypairEngineException, "1st parameter must be a #{Ccrypto::KeypairConfig.class} object" if not @config.is_a?(Ccrypto::KeypairConfig)
|
184
|
+
teLogger.debug "Config #{@config}"
|
185
|
+
end
|
186
|
+
|
187
|
+
def generate_keypair(&block)
|
188
|
+
teLogger.debug "Generating keypair of curve #{@config.curve}"
|
189
|
+
kp = OpenSSL::PKey::EC.generate(@config.curve.to_s)
|
190
|
+
#teLogger.debug "Generated keypair #{kp.inspect}"
|
191
|
+
ECCKeyBundle.new(kp)
|
192
|
+
end
|
193
|
+
|
194
|
+
def sign(val)
|
195
|
+
raise KeypairEngineException, "Keypair is required" if @config.keypair.nil?
|
196
|
+
raise KeypairEngineException, "ECC keypair is required" if not @config.keypair.is_a?(ECCKeyBundle)
|
197
|
+
kp = @config.keypair
|
198
|
+
|
199
|
+
res = kp.nativeKeypair.dsa_sign_asn1(val)
|
200
|
+
teLogger.debug "Data of length #{val.length} signed "
|
201
|
+
|
202
|
+
res
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.verify(pubKey, val, sign)
|
206
|
+
uPubKey = pubKey.native_pubKey
|
207
|
+
if pubKey.native_pubKey.is_a?(OpenSSL::PKey::EC::Point)
|
208
|
+
uPubKey = OpenSSL::PKey::EC.new(uPubKey.group)
|
209
|
+
uPubKey.public_key = pubKey.native_pubKey
|
210
|
+
end
|
211
|
+
|
212
|
+
res = uPubKey.dsa_verify_asn1(val, sign)
|
213
|
+
res
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
require_relative '../data_conversion'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Ruby
|
6
|
+
class HKDFEngine
|
7
|
+
include DataConversion
|
8
|
+
include TR::CondUtils
|
9
|
+
|
10
|
+
def initialize(*args, &block)
|
11
|
+
@config = args.first
|
12
|
+
|
13
|
+
raise KDFEngineException, "KDF config is expected" if not @config.is_a?(Ccrypto::KDFConfig)
|
14
|
+
raise KDFEngineException, "Output bit length (outBitLength) value is not given or not a positive value (#{@config.outBitLength})" if is_empty?(@config.outBitLength) or @config.outBitLength <= 0
|
15
|
+
|
16
|
+
|
17
|
+
@config.salt = SecureRandom.random_bytes(16) if is_empty?(@config.salt)
|
18
|
+
end
|
19
|
+
|
20
|
+
def derive(input, output = :binary)
|
21
|
+
|
22
|
+
digest = init_digest(@config.digest)
|
23
|
+
|
24
|
+
@config.info = "" if @config.info.nil?
|
25
|
+
|
26
|
+
res = OpenSSL::KDF.hkdf(input, salt: @config.salt, info: @config.info, length: @config.outBitLength/8, hash: digest)
|
27
|
+
|
28
|
+
case output
|
29
|
+
when :hex
|
30
|
+
to_hex(res)
|
31
|
+
when :b64
|
32
|
+
to_b64(res)
|
33
|
+
else
|
34
|
+
res
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def init_digest(algo)
|
40
|
+
if DigestEngine.is_supported?(algo)
|
41
|
+
conf = DigestEngine.engineKeys[algo]
|
42
|
+
if not_empty?(conf)
|
43
|
+
OpenSSL::Digest.new(conf.provider_config)
|
44
|
+
else
|
45
|
+
raise DigestEngineException, "Algo config '#{algo}' not found"
|
46
|
+
end
|
47
|
+
else
|
48
|
+
raise DigestEngineException, "Digest algo '#{algo}' is not supported"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|