ccrypto-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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