ccrypto-java 0.1.0 → 0.2.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 (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