ccrypto-java 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.java-version +1 -1
  3. data/.release_history.yml +4 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +68 -53
  7. data/Rakefile +2 -1
  8. data/bin/console +14 -0
  9. data/jars/bcjmail-jdk18on-172.jar +0 -0
  10. data/jars/bcmail-jdk18on-172.jar +0 -0
  11. data/jars/bcpg-jdk18on-172.1.jar +0 -0
  12. data/jars/bcpkix-jdk18on-172.jar +0 -0
  13. data/jars/bcprov-ext-jdk18on-172.jar +0 -0
  14. data/jars/bcprov-jdk18on-172.jar +0 -0
  15. data/jars/bctls-jdk18on-172.jar +0 -0
  16. data/jars/bcutil-jdk18on-172.jar +0 -0
  17. data/lib/ccrypto/java/bc_const_mapping.rb +42 -0
  18. data/lib/ccrypto/java/data_conversion.rb +23 -2
  19. data/lib/ccrypto/java/engines/argon2_engine.rb +95 -0
  20. data/lib/ccrypto/java/engines/asn1_engine.rb +2 -1
  21. data/lib/ccrypto/java/engines/bcrypt_engine.rb +56 -0
  22. data/lib/ccrypto/java/engines/cipher_engine.rb +462 -130
  23. data/lib/ccrypto/java/engines/compression_engine.rb +7 -28
  24. data/lib/ccrypto/java/engines/crystal_dilithium_engine.rb +226 -0
  25. data/lib/ccrypto/java/engines/crystal_kyber_engine.rb +260 -0
  26. data/lib/ccrypto/java/engines/decompression_engine.rb +5 -4
  27. data/lib/ccrypto/java/engines/digest_engine.rb +221 -139
  28. data/lib/ccrypto/java/engines/ecc_engine.rb +249 -96
  29. data/lib/ccrypto/java/engines/ed25519_engine.rb +211 -0
  30. data/lib/ccrypto/java/engines/hkdf_engine.rb +82 -23
  31. data/lib/ccrypto/java/engines/hmac_engine.rb +98 -23
  32. data/lib/ccrypto/java/engines/pbkdf2_engine.rb +82 -33
  33. data/lib/ccrypto/java/engines/pkcs7_engine.rb +44 -33
  34. data/lib/ccrypto/java/engines/rsa_engine.rb +85 -31
  35. data/lib/ccrypto/java/engines/scrypt_engine.rb +12 -3
  36. data/lib/ccrypto/java/engines/secret_key_engine.rb +77 -12
  37. data/lib/ccrypto/java/engines/secret_sharing_engine.rb +17 -2
  38. data/lib/ccrypto/java/engines/x25519_engine.rb +249 -0
  39. data/lib/ccrypto/java/engines/x509_csr_engine.rb +141 -0
  40. data/lib/ccrypto/java/engines/x509_engine.rb +365 -71
  41. data/lib/ccrypto/java/ext/secret_key.rb +37 -25
  42. data/lib/ccrypto/java/ext/x509_cert.rb +429 -5
  43. data/lib/ccrypto/java/ext/x509_csr.rb +151 -0
  44. data/lib/ccrypto/java/jce_provider.rb +0 -11
  45. data/lib/ccrypto/java/keystore/jce_keystore.rb +205 -0
  46. data/lib/ccrypto/java/keystore/jks_keystore.rb +52 -0
  47. data/lib/ccrypto/java/keystore/keystore.rb +97 -0
  48. data/lib/ccrypto/java/keystore/pem_keystore.rb +147 -0
  49. data/lib/ccrypto/java/keystore/pkcs12_keystore.rb +56 -0
  50. data/lib/ccrypto/java/utils/comparator.rb +25 -2
  51. data/lib/ccrypto/java/version.rb +1 -1
  52. data/lib/ccrypto/java.rb +46 -0
  53. data/lib/ccrypto/provider.rb +139 -3
  54. metadata +40 -24
  55. data/ccrypto-java.gemspec +0 -44
  56. data/jars/bcmail-jdk15on-165.jar +0 -0
  57. data/jars/bcpg-jdk15on-165.jar +0 -0
  58. data/jars/bcpkix-jdk15on-165.jar +0 -0
  59. data/jars/bcprov-ext-jdk15on-165.jar +0 -0
  60. data/jars/bcprov-jdk15on-165.jar +0 -0
  61. data/jars/bctls-jdk15on-165.jar +0 -0
  62. data/lib/ccrypto/java/keybundle_store/pkcs12.rb +0 -125
@@ -7,159 +7,512 @@ module Ccrypto
7
7
  include TR::CondUtils
8
8
  include DataConversion
9
9
 
10
- include TeLogger::TeLogHelper
10
+ def self.supported_ciphers
11
11
 
12
- teLogger_tag :j_cipher
12
+ if @supported.nil?
13
13
 
14
- def self.supported_ciphers
15
- res = java.security.Security.getAlgorithms("Cipher").to_a.delete_if { |e| e.include?(".") }.sort
14
+ if is_refresh_always?
15
+ logger.debug "Refresh due to env flag"
16
+ @supported = SupportedCipherList.new
17
+ else
18
+ logger.debug "Load support cipher from storage"
19
+ @supported = SupportedCipherList.load_from_storage("#{Ccrypto::Java::Provider.provider_name}_supported_cipher")
20
+ end
21
+
22
+ if @supported.empty?
23
+ logger.debug "Supported cipher list is empty. Probe for supported algo and save to cache"
24
+ @supported = load_algo_into_cache(@supported)
25
+ @supported.save_to_storage("#{Ccrypto::Java::Provider.provider_name}_supported_cipher")
26
+ end
27
+ end
28
+
29
+ @supported
16
30
  end
17
31
 
18
- def self.is_supported_cipher?(c)
19
- case c
20
- when String, java.lang.String
21
- javax.crypto.Cipher.getInstance(c)
22
- when Hash
23
- spec = to_spec(c)
24
- javax.crypto.Cipher.getInstance(spec)
25
- else
26
- raise CipherEngineException, "Unsupported input #{c} to check supported cipher"
32
+ def self.is_refresh_always?
33
+ ENV['CC_J_SUPCIPHER_REFRESH_ALWAYS'] == "true"
34
+ end
35
+
36
+ def self.load_algo_into_cache(list)
37
+
38
+ skipped = []
39
+
40
+ java.security.Security.getAlgorithms("Cipher").to_a.delete_if { |e| e.include?(".") }.sort.each do |c|
41
+
42
+ #next if skipped.map { |e|
43
+ # if c.downcase =~ /#{e}/i
44
+ # 1
45
+ # else
46
+ # 0
47
+ # end
48
+ #}.include?(1)
49
+
50
+ testSpec = c
51
+ loop do
52
+
53
+ begin
54
+
55
+ kg = javax.crypto.KeyGenerator.getInstance(testSpec, JCEProvider::DEFProv)
56
+ logger.debug "#{testSpec} is good!"
57
+
58
+ native = { keygen_algo: testSpec, require_init_keysize: true }
59
+ opts = { fixed_input_length_in_byte: -1 }
60
+
61
+ #if ["chacha20-poly1305","xsalsa20","salsa20","chacha20","chacha","chacha7539"].include?(testSpec.downcase)
62
+ if ["chacha20-poly1305","xsalsa20","salsa20"].include?(testSpec.downcase)
63
+
64
+ begin
65
+ kg = javax.crypto.KeyGenerator.getInstance(testSpec, JCEProvider::DEFProv)
66
+ tkey = kg.generateKey
67
+ opts[:keysize] = tkey.encoded.length*8
68
+ native[:require_init_keysize] = false
69
+
70
+ cspec = [testSpec]
71
+ if ["chacha20-poly1305", "chacha20","chacha7539"].include?(testSpec.downcase)
72
+ ivLen = 12
73
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
74
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 12 bytes
75
+
76
+ elsif ["xsalsa20"].include?(testSpec.downcase)
77
+ ivLen = 24
78
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
79
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 24 bytes
80
+
81
+ elsif ["salsa20","chacha"].include?(testSpec.downcase)
82
+ ivLen = 8
83
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
84
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 8 bytes
85
+ end
86
+
87
+ decSuss, blocksize = test_encrypt_decrypt(cspec.join("/"), tkey, ivParam)
88
+
89
+ if decSuss
90
+
91
+ opts[:block_size] = blocksize
92
+
93
+ begin
94
+ test_encrypt_decrypt(cspec.join("/"), tkey, ivParam, blocksize+1)
95
+ rescue Exception => ex
96
+ opts[:mandatory_block_size] = blocksize
97
+ end
98
+
99
+ opts[:ivLength] = ivLen
100
+
101
+ opts[:authMode] = ["chacha20-poly1305"].include?(testSpec.downcase)
102
+
103
+ opts[:mode] = nil
104
+ opts[:padding] = nil
105
+
106
+ native[:cipher_str] = testSpec
107
+ # key generated from this provider
108
+ native[:key_jce_provider] = JCEProvider::DEFProv.name
109
+ # tested with cipher using this provider
110
+ native[:cipher_jce_provider] = JCEProvider::DEFProv.name
111
+
112
+ # construct the key config too as key config not depending on cipher
113
+ # but cipher depending on key config
114
+ kconf = Ccrypto::KeyConfig.new(testSpec, opts[:keysize])
115
+ kconf.provider_config = { keygen_algo: native[:keygen_algo], keysize: opts[:keysize], key_jce_provider: native[:key_jce_provider] }
116
+
117
+ conf = Ccrypto::CipherConfig.new(testSpec, opts)
118
+ conf.provider_config = native.clone
119
+ conf.key_config = kconf
120
+
121
+ logger.debug "Registering : #{testSpec}/#{opts[:keysize]}"
122
+
123
+ list.register(conf.clone)
124
+
125
+ end
126
+
127
+
128
+ rescue Exception => ex
129
+ logger.debug "Special algo '#{testSpec}' failed : #{ex}"
130
+ logger.debug ex.backtrace.join("\n")
131
+ end
132
+
133
+ break
134
+
135
+ else # other algo except those special one
136
+
137
+ goodKz = []
138
+ [128,192,224,256,384,512].each do |kz|
139
+ begin
140
+
141
+ kg = javax.crypto.KeyGenerator.getInstance(testSpec, JCEProvider::DEFProv)
142
+ kg.init(kz)
143
+ kg.generateKey
144
+
145
+ goodKz << kz
146
+
147
+ rescue Exception => ex
148
+ #logger.debug "Failed probing for cipher algo #{testSpec}/#{kz} : #{ex}"
149
+ end
150
+ end # keysize loop
151
+
152
+ authMode = [:gcm,:ccm]
153
+ [:none,:cbc,:cfb,:ecb,:gcm,:ofb,:ctr,:ccm].each do |mode|
154
+
155
+ goodKz.each do |kz|
156
+
157
+ begin
158
+
159
+ kg = javax.crypto.KeyGenerator.getInstance(testSpec, JCEProvider::DEFProv)
160
+ kg.init(kz)
161
+ tkey = kg.generateKey
162
+
163
+ [:NoPadding, :PKCS5Padding, :PKCS7Padding].each do |pad|
164
+
165
+ if [:gcm, :ccm].include?(mode) and pad != :NoPadding
166
+ next
167
+ end
168
+
169
+ begin
170
+
171
+ jceAlgo = [testSpec,mode,pad]
172
+ cs = jceAlgo.join("/")
173
+ logger.debug "Testing cipher with spec : #{cs} (#{kz})"
174
+ tc = javax.crypto.Cipher.getInstance(cs, JCEProvider::DEFProv)
175
+
176
+ ivParam = nil
177
+ ivLen = 0
178
+ if mode == :gcm
179
+ ivLen = 12
180
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
181
+ ivParam = javax.crypto.spec.GCMParameterSpec.new(iv.length*8, iv) # 16 bytes
182
+
183
+ elsif ["blowfish","cast5","gost28147","idea","skipjack","tea","xtea","des","desede", "gost3412-2015","rc2","rc5"].include?(testSpec.downcase)
184
+ if mode != :ecb
185
+ ivLen = 8
186
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
187
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 16 bytes
188
+ end
189
+
190
+ elsif ["shacal-2","shacal2"].include?(testSpec.downcase)
191
+ if mode != :ecb
192
+ ivLen = 32
193
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
194
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 16 bytes
195
+ opts[:min_input_length] = 32
196
+ end
197
+
198
+ elsif ["threefish-1024"].include?(testSpec.downcase)
199
+ if mode != :ecb
200
+ ivLen = 128
201
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
202
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 16 bytes
203
+ end
204
+
205
+ elsif ["threefish-256"].include?(testSpec.downcase)
206
+ if mode != :ecb
207
+ ivLen = 32
208
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
209
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 16 bytes
210
+ end
211
+
212
+ elsif ["threefish-512"].include?(testSpec.downcase)
213
+ if mode != :ecb
214
+ ivLen = 64
215
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
216
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 64 bytes
217
+ end
218
+
219
+ elsif ["chacha20","chacha7539"].include?(testSpec.downcase)
220
+ ivLen = 12
221
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
222
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 12 bytes
223
+
224
+ elsif ["xsalsa20"].include?(testSpec.downcase)
225
+ ivLen = 24
226
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
227
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 24 bytes
228
+
229
+ elsif ["salsa20","chacha"].include?(testSpec.downcase)
230
+ ivLen = 8
231
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
232
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 8 bytes
233
+
234
+ elsif testSpec.downcase[0...3] == "des"
235
+ ivLen = 8
236
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
237
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 8 bytes
238
+
239
+ elsif ["grain128","grainv1", "hc128","hc256","vmpc","vmpc-ksa3","zuc-128","zuc-256"].include?(testSpec.downcase)
240
+ ivLen = 16
241
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
242
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 8 bytes
243
+
244
+
245
+ elsif mode == :ccm
246
+ ivLen = 7
247
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
248
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 7 bytes
249
+
250
+ elsif mode != :ecb
251
+ #if not ["hc128","hc256"].include?(testSpec.downcase)
252
+ ivLen = 16
253
+ iv = Ccrypto::Java::SecureRandomEngine.random_bytes(ivLen)
254
+ ivParam = javax.crypto.spec.IvParameterSpec.new(iv) # 16 bytes
255
+ #end
256
+
257
+ else
258
+ ivLen = 0
259
+
260
+ end
261
+
262
+ decSuccess, blocksize = test_encrypt_decrypt(cs, tkey, ivParam)
263
+
264
+ if decSuccess
265
+
266
+ opts[:block_size] = blocksize
267
+
268
+ if blocksize > 0
269
+ opts[:mandatory_block_size] = -1
270
+ begin
271
+ test_encrypt_decrypt(cs, tkey, ivParam, blocksize+1)
272
+ rescue Exception => ex
273
+ logger.debug "Config #{cs} must work on block size"
274
+ opts[:mandatory_block_size] = blocksize
275
+ end
276
+ end
277
+
278
+ opts[:keysize] = kz
279
+ opts[:mode] = mode.to_s
280
+ opts[:ivLength] = ivLen
281
+ opts[:padding] = pad.to_s
282
+
283
+ opts[:authMode] = authMode.include?(mode)
284
+
285
+ native[:cipher_str] = cs
286
+ # key generated from this provider
287
+ native[:key_jce_provider] = JCEProvider::DEFProv.name
288
+ # tested with cipher using this provider
289
+ native[:cipher_jce_provider] = JCEProvider::DEFProv.name
290
+
291
+ # construct the key config too as key config not depending on cipher
292
+ # but cipher depending on key config
293
+ kconf = Ccrypto::KeyConfig.new(testSpec, opts[:keysize])
294
+ kconf.provider_config = { keygen_algo: native[:keygen_algo], keysize: opts[:keysize], key_jce_provider: native[:key_jce_provider] }
295
+
296
+ conf = Ccrypto::CipherConfig.new(testSpec, opts)
297
+ conf.provider_config = native.clone
298
+ conf.key_config = kconf
299
+
300
+ logger.debug "Registering : #{testSpec}/#{kz}/#{mode}/#{pad}"
301
+
302
+ list.register(conf.clone)
303
+
304
+ end # decryption successful!
305
+
306
+ rescue Exception => ex
307
+ logger.debug "Failed for cipher algo #{testSpec}/#{kz}/#{mode}/#{pad} : #{ex}"
308
+ if ex.message =~ /array length/
309
+ puts ex.backtrace.join("\n")
310
+ end
311
+ Ccrypto::Java.on_detail_debug ex.backtrace.join("\n")
312
+ #logger.debug ex.backtrace.join("\n")
313
+ end
314
+
315
+ end
316
+
317
+
318
+ rescue Exception => ex
319
+ #p ex
320
+ logger.debug "Failed for cipher algo #{testSpec}/#{kz}/#{mode} : #{ex}"
321
+ #logger.error ex.backtrace.join("\n")
322
+ end
323
+
324
+ end
325
+
326
+ end # mode loop
327
+
328
+ break
329
+
330
+ end
331
+ rescue Exception => ex
332
+ logger.debug "Probing for cipher algo : #{ex}"
333
+ #logger.error ex.backtrace.join("\n")
334
+ break
335
+ end
336
+
337
+ end # loop key type
338
+
27
339
  end
340
+
341
+ list
28
342
  end
29
343
 
30
- def self.to_spec(hash)
31
- res = []
32
- res << hash[:algo].to_s
33
- res << hash[:mode].to_s
34
- res << hash[:padding].to_s
35
- res.join("/")
344
+ def self.get_cipher_config(algo, keysize = nil, mode = nil, padding = nil)
345
+ params = { algo: algo }
346
+ params[:keysize] = keysize if not_empty?(keysize)
347
+ params[:mode] = mode if not_empty?(mode)
348
+ params[:padding] = padding if not_empty?(padding)
349
+
350
+ supported_ciphers.find(params).map { |c| c.dup }
36
351
  end
37
352
 
38
- def supported_ciphers
39
- self.class.supported_ciphers
353
+ private
354
+ def self.logger
355
+ Ccrypto::Java.logger(:cipher_eng)
40
356
  end
41
357
 
42
- def initialize(*args, &block)
358
+ def self.test_encrypt_decrypt(spec, tkey, ivParam, testDataLen = nil)
43
359
 
44
- @spec = args.first
360
+ tc = javax.crypto.Cipher.getInstance(spec, JCEProvider::DEFProv)
361
+ if ivParam.nil?
362
+ tc.init(javax.crypto.Cipher::ENCRYPT_MODE, tkey)
363
+ else
364
+ tc.init(javax.crypto.Cipher::ENCRYPT_MODE, tkey, ivParam)
365
+ end
45
366
 
46
- case @spec
47
- when String, java.lang.String, Hash
48
- @spec = Ccrypto::DirectCipherConfig.new(@spec)
49
- when Ccrypto::CipherConfig
367
+ blocksize = tc.blockSize
368
+ if testDataLen.nil?
369
+ # stream cipher might have no block size
370
+ if blocksize > 0
371
+ data = Ccrypto::Java::SecureRandomEngine.random_bytes(blocksize)
372
+ else
373
+ data = Ccrypto::Java::SecureRandomEngine.random_bytes(16)
374
+ end
50
375
  else
51
- raise Ccrypto::CipherEngineException, "Unsupported config type #{@spec.class}"
376
+ data = Ccrypto::Java::SecureRandomEngine.random_bytes(testDataLen)
52
377
  end
53
378
 
379
+ encOut = java.io.ByteArrayOutputStream.new
380
+ encOut.write(tc.doFinal(data))
54
381
 
55
- if block
56
- @cipherJceProvider = block.call(:cipher_jceProvider)
57
- @keygenJceProvider = block.call(:keygen_jceProvider)
382
+ tc2 = javax.crypto.Cipher.getInstance(spec, JCEProvider::DEFProv)
383
+ if ivParam.nil?
384
+ tc2.init(javax.crypto.Cipher::DECRYPT_MODE, tkey)
385
+ else
386
+ tc2.init(javax.crypto.Cipher::DECRYPT_MODE, tkey, ivParam)
58
387
  end
59
388
 
60
- cSpec = to_cipher_spec(@spec)
389
+ decOut = java.io.ByteArrayOutputStream.new
390
+ decOut.write(tc2.doFinal(encOut.toByteArray))
391
+
392
+ [decOut.toByteArray == (data), blocksize]
393
+
394
+ end
395
+
396
+
397
+ public
398
+ ##
399
+ # Instance variable
400
+ ##
401
+
402
+ #
403
+ # Design is by the object is initialized (new)
404
+ # all the parameter to setup the cipher shall need to be available
405
+ # including those aux data such as auth_data for GCM mode for example
406
+ #
407
+ def initialize(*args, &block)
408
+
409
+ @spec = args.first
410
+
411
+ raise Ccrypto::CipherEngineException, "Unsupported config type #{@spec.class}" if not @spec.is_a?(Ccrypto::CipherConfig)
412
+
413
+ @keyJceProvider = @spec.provider_config[:key_jce_provider] || JCEProvider::DEFProv
414
+ @cipherJceProvider = @spec.provider_config[:cipher_jce_provider] || JCEProvider::DEFProv
415
+
416
+ raise Ccrypto::CipherEngineException, "Key JCE provider '#{@keyJceProvider}' not registered." if not_empty?(@keyJceProvider) and not JCEProvider.instance.is_provider_registered?(@keyJceProvider)
417
+ raise Ccrypto::CipherEngineException, "Cipher JCE provider '#{@cipherJceProvider}' not registered." if not_empty?(@cipherJceProvider) and not JCEProvider.instance.is_provider_registered?(@cipherJceProvider)
418
+
419
+ cSpec = @spec.provider_config[:cipher_str]
61
420
  if @cipherJceProvider.nil?
62
421
  begin
63
- teLogger.debug "Cipher instance #{cSpec} with null provider"
422
+ logger.debug "Cipher instance #{cSpec} with null provider"
64
423
  @cipher = javax.crypto.Cipher.getInstance(cSpec)
65
424
  rescue Exception => ex
66
- teLogger.debug "Error #{ex.message} for spec '#{cSpec}' using null provider. Retest with BC provider"
425
+ logger.debug "Error #{ex.message} for spec '#{cSpec}' using null provider. Retest with BC provider"
67
426
  @cipher = javax.crypto.Cipher.getInstance(cSpec, Ccrypto::Java::JCEProvider::BCProv.name)
68
427
  end
69
428
  else
70
- teLogger.debug "Cipher instance #{cSpec} with provider '#{@cipherJceProvider.is_a?(String) ? @cipherJceProvider : @cipherJceProvider.name}'"
429
+ logger.debug "Cipher instance #{cSpec} with provider '#{@cipherJceProvider.is_a?(String) ? @cipherJceProvider : @cipherJceProvider.name}'"
71
430
  @cipher = javax.crypto.Cipher.getInstance(cSpec, @cipherJceProvider)
72
431
  end
73
432
 
74
433
 
75
434
  if @spec.has_key?
76
- teLogger.debug "Using given cipher key"
435
+ keyLen = @spec.ccrypto_key.length
436
+ logger.debug "Using given cipher key of length #{keyLen} bytes / #{keyLen*8}"
77
437
 
78
438
  else
79
439
 
80
- teLogger.debug "Generating cipher key"
440
+ logger.debug "Generating cipher key #{@spec.inspect}"
81
441
  if @keygenJceProvider.nil?
82
- kg = javax.crypto.KeyGenerator.getInstance(to_algo(@spec.algo))
442
+ kg = javax.crypto.KeyGenerator.getInstance(@spec.provider_config[:keygen_algo])
83
443
  else
84
- kg = javax.crypto.KeyGenerator.getInstance(to_algo(@spec.algo), @keygenJceProvider)
444
+ kg = javax.crypto.KeyGenerator.getInstance(@spec.provider_config[:keygen_algo], @keygenJceProvider)
85
445
  end
86
446
 
87
- kg.init(@spec.keysize.to_i)
88
- @spec.key = kg.generateKey
447
+ if @spec.provider_config[:require_init_keysize]
448
+ kg.init(@spec.keysize.to_i)
449
+ logger.debug "Init with keysize ; #{@spec.provider_config[:keygen_algo]} / #{@spec.keysize.to_i} bits / #{@spec.keysize.to_i/8} bytes"
450
+ end
89
451
 
90
- end
452
+ @spec.ccrypto_key = Ccrypto::SecretKey.new(@spec.algo, @spec.keysize, kg.generateKey)
453
+ @spec.ccrypto_key.provider_config = @spec.provider_config
91
454
 
92
- if @spec.iv.is_a?(String)
93
- @spec.iv = to_java_bytes(@spec.iv)
94
455
  end
95
456
 
96
- if @spec.is_mode?(:gcm) or @spec.is_algo?(:chacha20)
457
+ if @spec.iv_required?
458
+ logger.debug "IV required of length #{@spec.ivLength}"
97
459
  if is_empty?(@spec.iv)
98
- teLogger.debug "Generating 12 bytes of IV"
99
- @spec.iv = Ccrypto::Java::SecureRandomEngine.random_bytes(12)
460
+ @spec.iv = Ccrypto::Java::SecureRandomEngine.random_bytes(@spec.ivLength)
461
+ logger.debug "Generated IV of length #{to_hex(@spec.iv)}"
100
462
  else
101
- teLogger.debug "Using given IV"
463
+ if @spec.iv.is_a?(String)
464
+ @spec.iv = to_java_bytes(@spec.iv)
465
+ logger.debug "Converting IV into #{to_hex(@spec.iv)}"
466
+ end
102
467
  end
103
468
 
104
469
  if @spec.is_mode?(:gcm)
105
- ivParam = javax.crypto.spec.GCMParameterSpec.new(@spec.iv.length*8, @spec.iv) # 16 bytes
106
- else
107
- ivParam = javax.crypto.spec.IvParameterSpec.new(@spec.iv) # 16 bytes
108
- end
109
-
110
- elsif @spec.is_algo?(:blowfish)
111
- if is_empty?(@spec.iv)
112
- teLogger.debug "Generating 8 bytes of IV"
113
- @spec.iv = Ccrypto::Java::SecureRandomEngine.random_bytes(8)
470
+ ivParam = javax.crypto.spec.GCMParameterSpec.new(@spec.iv.length*8, @spec.iv) # 12 bytes
114
471
  else
115
- teLogger.debug "Using given IV"
472
+ ivParam = javax.crypto.spec.IvParameterSpec.new(@spec.iv)
116
473
  end
117
- ivParam = javax.crypto.spec.IvParameterSpec.new(@spec.iv)
118
474
 
119
- elsif @spec.is_mode?(:cbc) or @spec.is_mode?(:ctr) or @spec.is_mode?(:cfb) or @spec.is_mode?(:ofb)
120
- if is_empty?(@spec.iv)
121
- teLogger.debug "Generating 16 bytes of IV"
122
- @spec.iv = Ccrypto::Java::SecureRandomEngine.random_bytes(16)
123
- else
124
- teLogger.debug "Using given IV"
125
- end
126
- ivParam = javax.crypto.spec.IvParameterSpec.new(@spec.iv)
475
+ else
476
+ logger.debug "IV is not required"
127
477
 
128
478
  end
129
479
 
130
- #teLogger.debug "IV : #{@spec.iv}"
480
+ logger.debug "spec key : #{@spec.ccrypto_key.inspect}"
131
481
 
132
- case @spec.key
482
+ case @spec.ccrypto_key
133
483
  when Ccrypto::SecretKey
134
- skey = @spec.key.key
484
+ logger.debug "Given secret key"
485
+ skey = @spec.ccrypto_key.native_key
135
486
  when ::Java::byte[]
136
- skey = javax.crypto.spec.SecretKeySpec.new(@spec.key, @spec.algo.to_s)
487
+ logger.debug "Given byte array key"
488
+ skey = javax.crypto.spec.SecretKeySpec.new(@spec.ccrypto_key, @spec.algo.to_s)
137
489
  when String
138
- skey = javax.crypto.spec.SecretKeySpec.new(to_java_bytes(@spec.key), @spec.algo.to_s)
490
+ logger.debug "Given ruby string key"
491
+ skey = javax.crypto.spec.SecretKeySpec.new(to_java_bytes(@spec.ccrypto_key), @spec.algo.to_s)
139
492
  when javax.crypto.spec.SecretKeySpec
140
- skey = @spec.key
493
+ logger.debug "Given Java SecretKeySpec"
494
+ skey = @spec.ccrypto_key
141
495
  else
142
- raise CipherEngineException, "Unknown key type '#{@spec.key}'"
496
+ raise CipherEngineException, "Unknown key type '#{@spec.ccrypto_key}'"
143
497
  end
144
498
 
145
- #teLogger.debug "SKey : #{skey.encoded}"
499
+ #logger.debug "SKey : #{to_hex(skey.encoded)}"
146
500
 
147
- case @spec.cipherOps
148
- when :encrypt, :enc
501
+ if @spec.is_encrypt_cipher_mode?
149
502
  if ivParam.nil?
150
- teLogger.debug "Encryption mode"
503
+ logger.debug "Encryption mode"
151
504
  @cipher.init(javax.crypto.Cipher::ENCRYPT_MODE, skey)
152
505
  else
153
- teLogger.debug "Encryption mode with IV"
506
+ logger.debug "Encryption mode with IV"
154
507
  @cipher.init(javax.crypto.Cipher::ENCRYPT_MODE, skey, ivParam)
155
508
  end
156
509
 
157
- when :decrypt, :dec
510
+ elsif @spec.is_decrypt_cipher_mode?
158
511
  if ivParam.nil?
159
- teLogger.debug "Decryption mode"
512
+ logger.debug "Decryption mode"
160
513
  @cipher.init(javax.crypto.Cipher::DECRYPT_MODE, skey)
161
514
  else
162
- teLogger.debug "Decryption mode with IV"
515
+ logger.debug "Decryption mode with IV"
163
516
  @cipher.init(javax.crypto.Cipher::DECRYPT_MODE, skey, ivParam)
164
517
  end
165
518
 
@@ -167,20 +520,30 @@ module Ccrypto
167
520
  raise Ccrypto::CipherEngineException, "Cipher operation must be given"
168
521
  end
169
522
 
170
- if @spec.is_mode?(:gcm) and not_empty?(@spec.auth_data)
171
- teLogger.debug "Adding additional authenticated data for GCM mode"
172
- @cipher.updateAAD(to_java_bytes(@spec.auth_data))
523
+ if @spec.is_auth_mode_cipher?
524
+
525
+ # AAD can be added anytime before cipher final
526
+ # Special instance method for AAD capable cipher
527
+ instance_eval <<-END
528
+
529
+ def update_aad(val)
530
+ logger.debug "Adding Additional Authenticated Data of length : \#{val.length}"
531
+ @cipher.updateAAD(to_java_bytes(val))
532
+ end
533
+
534
+ END
535
+
173
536
  end
174
537
 
175
538
  end
176
539
 
177
540
  def update(val)
178
- teLogger.debug "Passing #{val.length} bytes to cipher"
541
+ logger.debug "Passing #{val.length} / #{to_java_bytes(val).length} bytes to cipher"
179
542
  res = @cipher.update(to_java_bytes(val))
180
543
  if res.nil?
181
- teLogger.debug "Cipher update returns nothing"
544
+ logger.debug "Cipher update returns nothing"
182
545
  else
183
- teLogger.debug "Cipher update output length #{res.length}"
546
+ logger.debug "Cipher update output length #{res.length}"
184
547
  end
185
548
  res
186
549
  end
@@ -188,23 +551,20 @@ module Ccrypto
188
551
  def final(val = nil, &block)
189
552
  baos = java.io.ByteArrayOutputStream.new
190
553
  if not_empty?(val)
191
- res = update(val)
554
+ res = update(to_java_bytes(val))
192
555
  baos.write(res) if not_empty?(res)
193
556
  end
194
557
 
195
558
  begin
196
559
  res = @cipher.doFinal
197
560
 
198
- teLogger.debug "Final output length : #{res.length}"
199
-
200
- if @spec.is_mode?(:gcm) and @spec.is_encrypt_cipher_mode?
201
- # extract auth_tag
202
- @spec.auth_tag = res[-16..-1]
203
- @spec.auth_tag = String.from_java_bytes(@spec.auth_tag) if not_empty?(@spec.auth_tag)
204
- end
561
+ logger.debug "Final output length : #{res.length}"
205
562
 
206
563
  baos.write(res) if not_empty?(res)
207
- baos.toByteArray
564
+ cres = baos.toByteArray
565
+ logger.debug "Cipher length : #{cres.length}"
566
+
567
+ cres
208
568
 
209
569
  rescue Exception => ex
210
570
  raise Ccrypto::CipherEngineException, ex
@@ -212,42 +572,14 @@ module Ccrypto
212
572
  end
213
573
 
214
574
  def reset
215
- #@cipher.reset
575
+ if not @spec.nil?
576
+ @cipher = javax.crypto.Cipher.getInstance(@spec.provider_config[:cipher_str])
577
+ end
216
578
  end
217
579
 
218
580
  private
219
- def to_algo(algo)
220
- algo.to_s.gsub("_","-")
221
- end
222
-
223
- def to_cipher_spec(spec)
224
- res = []
225
-
226
- res << spec.algo.to_s.gsub("_","-")
227
-
228
- res << spec.mode if not_empty?(spec.mode)
229
-
230
- if spec.algo.to_s.downcase == "aria" and spec.mode.to_s.downcase == "gcm"
231
- # for some reasons only aria gcm trigger this error
232
- res << "NoPadding"
233
- elsif spec.mode.to_s.downcase != "poly1305"
234
- case spec.padding
235
- when :pkcs5
236
- res << "PKCS5Padding"
237
- when :pkcs7
238
- res << "PKCS7Padding"
239
- when :nopadding
240
- res << "NOPadding"
241
- end
242
- end
243
-
244
- if spec.is_algo?(:chacha20)
245
- res.join("-")
246
- elsif spec.is_algo?(:blowfish)
247
- res[0]
248
- else
249
- res.join("/")
250
- end
581
+ def logger
582
+ Ccrypto::Java.logger(:cipher_eng)
251
583
  end
252
584
 
253
585
  end