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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +12 -0
  4. data/Gemfile.lock +64 -0
  5. data/README.md +149 -0
  6. data/Rakefile +10 -0
  7. data/bin/console +15 -0
  8. data/bin/setup +8 -0
  9. data/ccrypto-ruby.gemspec +45 -0
  10. data/lib/ccrypto/provider.rb +175 -0
  11. data/lib/ccrypto/ruby/data_conversion.rb +68 -0
  12. data/lib/ccrypto/ruby/engines/asn1_engine.rb +110 -0
  13. data/lib/ccrypto/ruby/engines/asn1_object.rb +19 -0
  14. data/lib/ccrypto/ruby/engines/cipher_engine.rb +170 -0
  15. data/lib/ccrypto/ruby/engines/compression_engine.rb +61 -0
  16. data/lib/ccrypto/ruby/engines/data_conversion_engine.rb +9 -0
  17. data/lib/ccrypto/ruby/engines/decompression_engine.rb +70 -0
  18. data/lib/ccrypto/ruby/engines/digest_engine.rb +127 -0
  19. data/lib/ccrypto/ruby/engines/ecc_engine.rb +218 -0
  20. data/lib/ccrypto/ruby/engines/hkdf_engine.rb +54 -0
  21. data/lib/ccrypto/ruby/engines/hmac_engine.rb +53 -0
  22. data/lib/ccrypto/ruby/engines/pbkdf2_engine.rb +69 -0
  23. data/lib/ccrypto/ruby/engines/pkcs7_engine.rb +179 -0
  24. data/lib/ccrypto/ruby/engines/rsa_engine.rb +300 -0
  25. data/lib/ccrypto/ruby/engines/scrypt_engine.rb +34 -0
  26. data/lib/ccrypto/ruby/engines/secret_key_engine.rb +18 -0
  27. data/lib/ccrypto/ruby/engines/secret_sharing_engine.rb +331 -0
  28. data/lib/ccrypto/ruby/engines/secure_random_engine.rb +34 -0
  29. data/lib/ccrypto/ruby/engines/x509_engine.rb +213 -0
  30. data/lib/ccrypto/ruby/ext/secret_key.rb +24 -0
  31. data/lib/ccrypto/ruby/ext/x509_cert.rb +24 -0
  32. data/lib/ccrypto/ruby/keybundle_store/pem_store.rb +73 -0
  33. data/lib/ccrypto/ruby/keybundle_store/pkcs12.rb +111 -0
  34. data/lib/ccrypto/ruby/utils/comparator.rb +15 -0
  35. data/lib/ccrypto/ruby/utils/memory_buffer.rb +63 -0
  36. data/lib/ccrypto/ruby/utils/native_helper.rb +17 -0
  37. data/lib/ccrypto/ruby/version.rb +7 -0
  38. data/lib/ccrypto/ruby.rb +25 -0
  39. metadata +136 -0
@@ -0,0 +1,53 @@
1
+
2
+ require_relative '../data_conversion'
3
+
4
+ module Ccrypto
5
+ module Ruby
6
+ class HMACEngine
7
+ include TR::CondUtils
8
+ include DataConversion
9
+
10
+ def initialize(*args,&block)
11
+ @config = args.first
12
+
13
+ raise HMACEngineException, "HMAC config is expected" if not @config.is_a?(Ccrypto::HMACConfig)
14
+
15
+ raise HMACEngineException, "Signing key is required" if is_empty?(@config.key)
16
+ raise HMACEngineException, "Secret key as signing key is required. Given #{@config.key.class}" if not @config.key.is_a?(Ccrypto::SecretKey)
17
+
18
+ raise HMACEngineException, "Digest '#{@config.digest}' is not supported" if not DigestEngine.is_supported?(@config.digest)
19
+
20
+ dig = DigestEngine.digest(@config.digest)
21
+
22
+ @hmac = OpenSSL::HMAC.new(@config.key.to_bin, dig.native_digest_engine)
23
+
24
+ end
25
+
26
+ def hmac_update(val)
27
+ @hmac.update(val)
28
+ end
29
+
30
+ def hmac_final
31
+ @hmac.digest
32
+ end
33
+
34
+ def hmac_digest(val, output = :binary)
35
+ hmac_update(val)
36
+ res = hmac_final
37
+
38
+ @hmac.reset
39
+
40
+ case output
41
+ when :hex
42
+ to_hex(res)
43
+ when :b64
44
+ to_b64(res)
45
+ else
46
+ res
47
+ end
48
+ end
49
+
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,69 @@
1
+
2
+ require_relative '../data_conversion'
3
+
4
+ module Ccrypto
5
+ module Ruby
6
+ class PBKDF2Engine
7
+ include TR::CondUtils
8
+ include DataConversion
9
+
10
+ def initialize(conf, &block)
11
+ raise KDFEngineException, "PBKDF2 config is expected" if not conf.is_a?(Ccrypto::PBKDF2Config)
12
+ raise KDFEngineException, "Output bit length (outBitLength) value is not given or not a positive value (#{conf.outBitLength})" if is_empty?(conf.outBitLength) or conf.outBitLength <= 0
13
+
14
+ @config = conf
15
+ if is_empty?(@config.salt)
16
+ @config.salt = SecureRandom.random_bytes(16)
17
+ end
18
+ end
19
+
20
+ def derive(input, output = :binary)
21
+
22
+ @config.digest = default_digest if is_empty?(@config.digest)
23
+ digest = init_digest(@config.digest)
24
+
25
+ logger.debug "Digest : #{@config.digest}"
26
+ logger.debug "Iterations : #{@config.iter}"
27
+ logger.debug "Out byte length : #{@config.outBitLength/8}"
28
+
29
+ res = OpenSSL::KDF.pbkdf2_hmac(input, salt: @config.salt, iterations: @config.iter, length: @config.outBitLength/8, hash: digest)
30
+
31
+ case output
32
+ when :hex
33
+ to_hex(res)
34
+ when :b64
35
+ to_b64(res)
36
+ else
37
+ res
38
+ end
39
+ end
40
+
41
+ private
42
+ def init_digest(algo)
43
+ if DigestEngine.is_supported?(algo)
44
+ conf = DigestEngine.engineKeys[algo]
45
+ if not_empty?(conf)
46
+ OpenSSL::Digest.new(conf.provider_config)
47
+ else
48
+ raise DigestEngineException, "Algo config '#{algo}' not found"
49
+ end
50
+ else
51
+ raise DigestEngineException, "Digest algo '#{algo}' is not supported"
52
+ end
53
+ end
54
+
55
+ def default_digest
56
+ :sha3_256
57
+ end
58
+
59
+ def logger
60
+ if @logger.nil?
61
+ @logger = TeLogger::Tlogger.new
62
+ @logger.tag = :pbkdf2
63
+ end
64
+ @logger
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,179 @@
1
+
2
+ require_relative '../data_conversion'
3
+
4
+ module Ccrypto
5
+ module Ruby
6
+
7
+ class PKCS7EngineException < StandardError; end
8
+
9
+ class PKCS7Engine
10
+ include TR::CondUtils
11
+ include DataConversion
12
+
13
+ include TeLogger::TeLogHelper
14
+
15
+ teLogger_tag :r_p7
16
+
17
+ def initialize(config)
18
+ @config = config
19
+ raise PKCS7EngineException, "Ccrypto::PKCS7Config is expected" if not @config.is_a?(Ccrypto::PKCS7Config)
20
+ end
21
+
22
+ def sign(val, outFormat = :bin, &block)
23
+ validate_input(val, "signing")
24
+ validate_key_must_exist("signing")
25
+ raise PKCS7EngineException, "signerCert is required for PKCS7 sign operation" if is_empty?(@config.signerCert)
26
+ raise PKCS7EngineException, "Given signerCert must be a Ccrypto::X509Cert object" if not @config.signerCert.is_a?(Ccrypto::X509Cert)
27
+
28
+ privKey = @config.private_key.native_privKey
29
+
30
+ caCerts = []
31
+ attached = true
32
+ if block
33
+ caCerts = block.call(:ca_certs)
34
+ detachedSign = block.call(:detached_sign)
35
+ attached = ! detachedSign if is_bool?(detachedSign)
36
+ end
37
+
38
+ caCerts = [] if caCerts.nil?
39
+ attached = true if is_empty?(attached) and not is_bool?(attached)
40
+
41
+ if not attached
42
+ flag = OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::DETACHED
43
+ else
44
+ flag = OpenSSL::PKCS7::BINARY
45
+ end
46
+
47
+ res = OpenSSL::PKCS7.sign(@config.signerCert.nativeX509, privKey, val, caCerts, flag)
48
+ case outFormat
49
+ when :b64
50
+ to_b64(res.to_der)
51
+ when :hex
52
+ to_hex(res.to_der)
53
+ else
54
+ res.to_der
55
+ end
56
+ end
57
+
58
+ def verify(val, inForm = :bin, &block)
59
+ validate_input(val, "verify")
60
+
61
+ case inForm
62
+ when :b64
63
+ v = from_b64(val)
64
+ when :hex
65
+ v = from_hex(val)
66
+ else
67
+ v = val
68
+ end
69
+
70
+ p7 = OpenSSL::PKCS7.new(v)
71
+
72
+ certVerified = true
73
+ store = OpenSSL::X509::Store.new
74
+ p7.certificates.each do |c|
75
+ if block
76
+ certVerified = block.call(:verify_certificate, c)
77
+ if is_empty?(certVerified)
78
+ teLogger.debug "Certificate with subject #{c.subject.to_s} / Issuer: #{c.issuer.to_s} / SN: #{c.serial.to_s(16)} passed through (no checking by application). Assumed good cert."
79
+ store.add_cert(c)
80
+ certVerified = true
81
+ else
82
+ if certVerified
83
+ teLogger.debug "Certificate with subject #{c.subject.to_s} / Issuer: #{c.issuer.to_s} / SN: #{c.serial.to_s(16)} accepted by application"
84
+ store.add_cert(c)
85
+ else
86
+ teLogger.debug "Certificate with subject #{c.subject.to_s} / Issuer: #{c.issuer.to_s} / SN: #{c.serial.to_s(16)} rejected by application"
87
+ end
88
+ end
89
+ else
90
+ teLogger.debug "Certificate with subject #{c.subject.to_s} / Issuer: #{c.issuer.to_s} / SN: #{c.serial.to_s(16)} passed through (no checking by application)"
91
+ store.add_cert(c)
92
+ end
93
+ end
94
+
95
+ if certVerified
96
+
97
+ if p7.detached?
98
+ teLogger.debug "Detached signature detected during signature verification"
99
+ raise PKCS7EngineException, "block is required for detached signature" if not block
100
+ data = block.call(:signed_data)
101
+ p7.data = data
102
+ else
103
+ teLogger.debug "Attached signature detected during signature verification"
104
+ end
105
+
106
+ res = p7.verify([], store, nil, OpenSSL::PKCS7::NOVERIFY)
107
+
108
+ if block
109
+ block.call(:verification_result, res)
110
+ if res and not p7.detached?
111
+ block.call(:attached_data, p7.data)
112
+ end
113
+ end
114
+
115
+ res
116
+
117
+ else
118
+ certVerified
119
+ end
120
+
121
+ end
122
+
123
+ def encrypt(val, &block)
124
+ validate_input(val, "encrypt")
125
+ raise PKCS7EngineException, "At least one recipient_cert is required for PKCS7 encrypt" if is_empty?(@config.recipient_certs)
126
+
127
+ recps = @config.recipient_certs.map do |c|
128
+ raise PKCS7EngineException, "Given recipient_cert must be a Ccrypto::X509Cert object" if not c.is_a?(Ccrypto::X509Cert)
129
+ c.nativeX509
130
+ end
131
+
132
+ if block
133
+ cipher = block.call(:cipher)
134
+ teLogger.debug "Application given cipher : #{cipher}"
135
+ end
136
+
137
+ cipher = "AES-256-CBC" if is_empty?(cipher)
138
+
139
+ cip = OpenSSL::Cipher.new(cipher)
140
+
141
+ begin
142
+ OpenSSL::PKCS7.encrypt(recps, val, cip, OpenSSL::PKCS7::BINARY)
143
+ rescue OpenSSL::PKCS7::PKCS7Error => ex
144
+ raise PKCS7EngineException, ex
145
+ end
146
+
147
+ end
148
+
149
+ def decrypt(val, &block)
150
+ validate_input(val, "decrypt")
151
+ validate_key_must_exist("decrypt")
152
+
153
+ raise PKCS7EngineException, "certForDecryption is required for PKCS7 decrypt operation" if is_empty?(@config.certForDecryption)
154
+ raise PKCS7EngineException, "Given certForDecryption must be a Ccrypto::X509Cert object" if not @config.certForDecryption.is_a?(Ccrypto::X509Cert)
155
+
156
+ p7 = OpenSSL::PKCS7.new(val)
157
+ p7.decrypt(@config.private_key.native_privKey, @config.certForDecryption.nativeX509)
158
+ end
159
+
160
+ protected
161
+ def validate_input(val, ops)
162
+ raise PKCS7EngineException, "Given data to #{ops} operation is empty" if is_empty?(val)
163
+ end
164
+
165
+ def validate_key_must_exist(ops)
166
+ #raise PKCS7EngineException, "Keybundle is required for PKCS7 #{ops}" if is_empty?(@config.keybundle)
167
+ #raise PKCS7EngineException, "Given key must be a Ccrypto::KeyBundle object" if not @config.keybundle.is_a?(Ccrypto::KeyBundle)
168
+ raise PKCS7EngineException, "Private key is required for PKCS7 #{ops}" if is_empty?(@config.private_key)
169
+ raise PKCS7EngineException, "Given private key must be a Ccrypto::PrivateKey object" if not @config.private_key.is_a?(Ccrypto::PrivateKey)
170
+ end
171
+
172
+ #def validate_cert_must_exist(ops)
173
+ # raise PKCS7EngineException, "signerCert is required for PKCS7 #{ops}" if is_empty?(@config.signerCert)
174
+ # raise PKCS7EngineException, "Given signerCert must be a Ccrypto::X509Cert object" if not @config.signerCert.is_a?(Ccrypto::X509Cert)
175
+ #end
176
+
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,300 @@
1
+
2
+ require_relative '../keybundle_store/pkcs12'
3
+ require_relative '../keybundle_store/pem_store'
4
+
5
+ module Ccrypto
6
+ module Ruby
7
+
8
+ class RSAPublicKey < Ccrypto::RSAPublicKey
9
+
10
+ def to_bin
11
+ @native_pubKey.to_der
12
+ end
13
+
14
+ def self.to_key(bin)
15
+ rk = OpenSSL::PKey::RSA.new(bin)
16
+ RSAPublicKey.new(rk)
17
+ end
18
+
19
+ end # RSAPublicKey
20
+
21
+ class RSAKeyBundle
22
+ include Ccrypto::RSAKeyBundle
23
+ include TR::CondUtils
24
+
25
+ include PKCS12Store
26
+ include PEMStore
27
+
28
+ include TeLogger::TeLogHelper
29
+
30
+ teLogger_tag :r_rsa_keybundle
31
+
32
+ def initialize(kp)
33
+ @nativeKeypair = kp
34
+ end
35
+
36
+ def public_key
37
+ if @pubKey.nil?
38
+ @pubKey = RSAPublicKey.new(@nativeKeypair.public_key)
39
+ end
40
+ @pubKey
41
+ end
42
+
43
+ def private_key
44
+ if @privKey.nil?
45
+ @privKey = Ccrypto::RSAPrivateKey.new(@nativeKeypair)
46
+ end
47
+ @privKey
48
+ end
49
+
50
+ def to_storage(format, &block)
51
+ case format
52
+ when :pkcs12, :p12
53
+ to_pkcs12 do |key|
54
+ case key
55
+ when :keypair
56
+ @nativeKeypair
57
+ else
58
+ block.call(key) if block
59
+ end
60
+ end
61
+ when :pem
62
+ to_pem do |key|
63
+ case key
64
+ when :keypair
65
+ @nativeKeypair
66
+ else
67
+ block.call(key) if block
68
+ end
69
+ end
70
+ else
71
+ raise KeyBundleStorageException, "Unknown storage format #{format}"
72
+ end
73
+
74
+ end
75
+
76
+ def self.from_storage(bin, &block)
77
+ raise KeypairEngineException, "Given data to load is empty" if is_empty?(bin)
78
+
79
+ case bin
80
+ when String
81
+ teLogger.debug "Given String to load from storage"
82
+ if is_pem?(bin)
83
+ self.from_pem(bin, &block)
84
+ else
85
+ # binary buffer
86
+ teLogger.debug "Given binary to load from storage"
87
+ self.from_pkcs12(bin,&block)
88
+ end
89
+ else
90
+ raise KeyBundleStorageException, "Unsupported input type #{bin}"
91
+ end
92
+
93
+ end
94
+
95
+ def equal?(kp)
96
+ if kp.respond_to?(:to_der)
97
+ @nativeKeypair.to_der == kp.to_der
98
+ else
99
+ @nativeKeypair == kp
100
+ end
101
+ end
102
+
103
+ def method_missing(mtd, *args, &block)
104
+ if @nativeKeypair.respond_to?(mtd)
105
+ teLogger.debug "Sending to nativeKeypair #{mtd}"
106
+ @nativeKeypair.send(mtd,*args, &block)
107
+ else
108
+ super
109
+ end
110
+ end
111
+
112
+ def respond_to_missing?(mtd, *args, &block)
113
+ @nativeKeypair.respond_to?(mtd)
114
+ end
115
+
116
+ end # RSAKeyBundle
117
+
118
+ class RSAEngine
119
+ include TR::CondUtils
120
+
121
+ def initialize(*args, &block)
122
+ @config = args.first
123
+ raise KeypairEngineException, "1st parameter must be a #{Ccrypto::KeypairConfig.class} object" if not @config.is_a?(Ccrypto::KeypairConfig)
124
+ end
125
+
126
+ def generate_keypair(&block)
127
+ kp = OpenSSL::PKey::RSA.generate(@config.keysize)
128
+ RSAKeyBundle.new(kp)
129
+ end
130
+
131
+ def sign(val, &block)
132
+ if block
133
+ pss = block.call(:pss_mode)
134
+ pss = false if is_empty?(pss) or not is_bool?(pss)
135
+
136
+ if pss
137
+ sign_pss(val, &block)
138
+ else
139
+ sign_typical(val, &block)
140
+ end
141
+ else
142
+ sign_typical(val, &block)
143
+ end
144
+ end
145
+
146
+ def self.verify(pubKey, val, sign, &block)
147
+ if block
148
+ pss = block.call(:pss_mode)
149
+ pss = false if is_empty?(pss) or not is_bool?(pss)
150
+
151
+ if pss
152
+ verify_pss(pubKey, val, sign, &block)
153
+ else
154
+ verify_typical(pubKey, val, sign, &block)
155
+ end
156
+ else
157
+ verify_typical(pubKey, val, sign, &block)
158
+ end
159
+ end
160
+
161
+ def self.encrypt(pubKey, val, &block)
162
+ raise KeypairEngineException, "Public key is required" if is_empty?(pubKey)
163
+
164
+ padding = :oaep
165
+ if block
166
+ padding = block.call(:padding)
167
+ end
168
+
169
+ case padding
170
+ when :pkcs1
171
+ padVal = OpenSSL::PKey::RSA::PKCS1_PADDING
172
+ when :oaep
173
+ padVal = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
174
+ when :no_padding
175
+ padVal = OpenSSL::PKey::RSA::NO_PADDING
176
+ else
177
+ raise KeypairEngineException, "Padding requires either :pkcs1 or :oaep. Default is :oaep"
178
+ end
179
+
180
+ pubKey.public_encrypt(val, padVal)
181
+ end
182
+
183
+ def decrypt(enc, &block)
184
+
185
+ raise KeypairEngineException, "Private key is required" if not @config.has_private_key?
186
+ raise KeypairEngineException, "RSA private key is required" if not @config.private_key.is_a?(RSAPrivateKey)
187
+
188
+ padding = :oaep
189
+ if block
190
+ padding = block.call(:padding)
191
+ end
192
+
193
+ case padding
194
+ when :pkcs1
195
+ padVal = OpenSSL::PKey::RSA::PKCS1_PADDING
196
+ when :oaep
197
+ padVal = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
198
+ when :no_padding
199
+ padVal = OpenSSL::PKey::RSA::NO_PADDING
200
+ else
201
+ raise KeypairEngineException, "Padding requires either :pkcs1 or :oaep. Default is :oaep"
202
+ end
203
+
204
+ @config.private_key.private_decrypt(enc, padVal)
205
+ end
206
+
207
+
208
+
209
+ #####################
210
+ ## Private section ##
211
+ private
212
+ def sign_typical(val, &block)
213
+
214
+ raise KeypairEngineException, "Private key is required" if not @config.has_private_key?
215
+ raise KeypairEngineException, "RSA private key is required" if not @config.private_key.is_a?(RSAPrivateKey)
216
+
217
+ privKey = @config.private_key
218
+
219
+ signHash = "sha256"
220
+ if block
221
+ signHash = block.call(:sign_hash)
222
+ end
223
+
224
+ begin
225
+ shash = OpenSSL::Digest.new(signHash)
226
+ rescue Exception => ex
227
+ raise KeypairEngineException, ex
228
+ end
229
+
230
+ privKey.sign(shash, val)
231
+
232
+ end
233
+
234
+ def sign_pss(val, &block)
235
+
236
+ raise KeypairEngineException, "Private key is required" if not @config.has_private_key?
237
+ raise KeypairEngineException, "RSA private key is required" if not @config.private_key.is_a?(RSAPrivateKey)
238
+
239
+ privKey = @config.private_key
240
+
241
+ signHash = "sha256"
242
+ mgf1Hash = "sha256"
243
+ saltLen = :max
244
+ if block
245
+ signHash = block.call(:sign_hash)
246
+ mgf1Hash = block.call("mgf1_hash")
247
+ saltLen = block.call("salt_length")
248
+ end
249
+ mgf1Hash = "sha256" if is_empty?(mgf1Hash)
250
+ saltLen = :max if is_empty?(saltLen)
251
+ signHash = "sha256" if is_empty?(signHash)
252
+
253
+ privKey.native_privKey.sign_pss(signHash, val, salt_length: saltLen, mgf1_hash: mgf1Hash)
254
+
255
+ end
256
+
257
+ def self.verify_typical(pubKey, val, sign, &block)
258
+ uPubKey = pubKey.native_pubKey
259
+
260
+ if block
261
+ signHash = block.call(:sign_hash)
262
+ end
263
+ signHash = "sha256" if is_empty?(signHash)
264
+
265
+ begin
266
+ shash = OpenSSL::Digest.new(signHash)
267
+ rescue Exception => ex
268
+ raise KeypairEngineException, ex
269
+ end
270
+
271
+ res = uPubKey.verify(shash, sign, val)
272
+ res
273
+
274
+ end
275
+
276
+ def self.verify_pss(pubKey, val, sign, &block)
277
+ uPubKey = pubKey.native_pubKey
278
+
279
+ signHash = "sha256"
280
+ mgf1Hash = "sha256"
281
+ saltLen = :auto
282
+ if block
283
+ signHash = block.call(:sign_hash)
284
+ mgf1Hash = block.call("mgf1_hash")
285
+ saltLen = block.call("salt_length")
286
+ end
287
+ mgf1Hash = "sha256" if is_empty?(mgf1Hash)
288
+ saltLen = :auto if is_empty?(saltLen)
289
+ signHash = "sha256" if is_empty?(signHash)
290
+
291
+ res = uPubKey.verify_pss(signHash, sign, val, salt_length: saltLen, mgf1_hash: mgf1Hash)
292
+ res
293
+
294
+ end
295
+
296
+
297
+ end
298
+
299
+ end
300
+ end
@@ -0,0 +1,34 @@
1
+
2
+ require_relative '../data_conversion'
3
+
4
+ module Ccrypto
5
+ module Ruby
6
+ class ScryptEngine
7
+ include DataConversion
8
+ include TR::CondUtils
9
+
10
+ def initialize(conf, &block)
11
+ raise KDFEngineException, "KDF config is expected" if not conf.is_a?(Ccrypto::KDFConfig)
12
+ raise KDFEngineException, "Output bit length (outBitLength) value is not given or not a positive value (#{conf.outBitLength})" if is_empty?(conf.outBitLength) or conf.outBitLength <= 0
13
+ @config = conf
14
+
15
+ if is_empty?(@config.salt)
16
+ @config.salt = SecureRandom.random_bytes(16)
17
+ end
18
+ end
19
+
20
+ def derive(input, output = :binary)
21
+ res = OpenSSL::KDF.scrypt(input, salt: @config.salt, N: @config.cost, r: @config.blockSize, p: @config.parallel, length: @config.outBitLength/8)
22
+ case output
23
+ when :hex
24
+ to_hex(res)
25
+ when :b64
26
+ to_b64(res)
27
+ else
28
+ res
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,18 @@
1
+
2
+
3
+ module Ccrypto
4
+ module Ruby
5
+ class SecretKeyEngine
6
+
7
+ def self.generate(*args, &block)
8
+ config = args.first
9
+
10
+ raise SecretKeyEngineException, "KeyConfig is expected" if not config.is_a?(Ccrypto::KeyConfig)
11
+
12
+ key = SecureRandom.random_bytes(config.keysize/8)
13
+
14
+ Ccrypto::SecretKey.new(config.algo, key)
15
+ end
16
+ end
17
+ end
18
+ end