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.
- checksums.yaml +4 -4
- data/.java-version +1 -1
- data/.release_history.yml +4 -0
- data/.ruby-version +1 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +68 -53
- data/Rakefile +2 -1
- data/bin/console +14 -0
- data/jars/bcjmail-jdk18on-172.jar +0 -0
- data/jars/bcmail-jdk18on-172.jar +0 -0
- data/jars/bcpg-jdk18on-172.1.jar +0 -0
- data/jars/bcpkix-jdk18on-172.jar +0 -0
- data/jars/bcprov-ext-jdk18on-172.jar +0 -0
- data/jars/bcprov-jdk18on-172.jar +0 -0
- data/jars/bctls-jdk18on-172.jar +0 -0
- data/jars/bcutil-jdk18on-172.jar +0 -0
- data/lib/ccrypto/java/bc_const_mapping.rb +42 -0
- data/lib/ccrypto/java/data_conversion.rb +23 -2
- data/lib/ccrypto/java/engines/argon2_engine.rb +95 -0
- data/lib/ccrypto/java/engines/asn1_engine.rb +2 -1
- data/lib/ccrypto/java/engines/bcrypt_engine.rb +56 -0
- data/lib/ccrypto/java/engines/cipher_engine.rb +462 -130
- data/lib/ccrypto/java/engines/compression_engine.rb +7 -28
- data/lib/ccrypto/java/engines/crystal_dilithium_engine.rb +226 -0
- data/lib/ccrypto/java/engines/crystal_kyber_engine.rb +260 -0
- data/lib/ccrypto/java/engines/decompression_engine.rb +5 -4
- data/lib/ccrypto/java/engines/digest_engine.rb +221 -139
- data/lib/ccrypto/java/engines/ecc_engine.rb +249 -96
- data/lib/ccrypto/java/engines/ed25519_engine.rb +211 -0
- data/lib/ccrypto/java/engines/hkdf_engine.rb +82 -23
- data/lib/ccrypto/java/engines/hmac_engine.rb +98 -23
- data/lib/ccrypto/java/engines/pbkdf2_engine.rb +82 -33
- data/lib/ccrypto/java/engines/pkcs7_engine.rb +44 -33
- data/lib/ccrypto/java/engines/rsa_engine.rb +85 -31
- data/lib/ccrypto/java/engines/scrypt_engine.rb +12 -3
- data/lib/ccrypto/java/engines/secret_key_engine.rb +77 -12
- data/lib/ccrypto/java/engines/secret_sharing_engine.rb +17 -2
- data/lib/ccrypto/java/engines/x25519_engine.rb +249 -0
- data/lib/ccrypto/java/engines/x509_csr_engine.rb +141 -0
- data/lib/ccrypto/java/engines/x509_engine.rb +365 -71
- data/lib/ccrypto/java/ext/secret_key.rb +37 -25
- data/lib/ccrypto/java/ext/x509_cert.rb +429 -5
- data/lib/ccrypto/java/ext/x509_csr.rb +151 -0
- data/lib/ccrypto/java/jce_provider.rb +0 -11
- data/lib/ccrypto/java/keystore/jce_keystore.rb +205 -0
- data/lib/ccrypto/java/keystore/jks_keystore.rb +52 -0
- data/lib/ccrypto/java/keystore/keystore.rb +97 -0
- data/lib/ccrypto/java/keystore/pem_keystore.rb +147 -0
- data/lib/ccrypto/java/keystore/pkcs12_keystore.rb +56 -0
- data/lib/ccrypto/java/utils/comparator.rb +25 -2
- data/lib/ccrypto/java/version.rb +1 -1
- data/lib/ccrypto/java.rb +46 -0
- data/lib/ccrypto/provider.rb +139 -3
- metadata +40 -24
- data/ccrypto-java.gemspec +0 -44
- data/jars/bcmail-jdk15on-165.jar +0 -0
- data/jars/bcpg-jdk15on-165.jar +0 -0
- data/jars/bcpkix-jdk15on-165.jar +0 -0
- data/jars/bcprov-ext-jdk15on-165.jar +0 -0
- data/jars/bcprov-jdk15on-165.jar +0 -0
- data/jars/bctls-jdk15on-165.jar +0 -0
- 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
|
-
|
10
|
+
def self.supported_ciphers
|
11
11
|
|
12
|
-
|
12
|
+
if @supported.nil?
|
13
13
|
|
14
|
-
|
15
|
-
|
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.
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
39
|
-
|
353
|
+
private
|
354
|
+
def self.logger
|
355
|
+
Ccrypto::Java.logger(:cipher_eng)
|
40
356
|
end
|
41
357
|
|
42
|
-
def
|
358
|
+
def self.test_encrypt_decrypt(spec, tkey, ivParam, testDataLen = nil)
|
43
359
|
|
44
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
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
|
-
|
422
|
+
logger.debug "Cipher instance #{cSpec} with null provider"
|
64
423
|
@cipher = javax.crypto.Cipher.getInstance(cSpec)
|
65
424
|
rescue Exception => ex
|
66
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
440
|
+
logger.debug "Generating cipher key #{@spec.inspect}"
|
81
441
|
if @keygenJceProvider.nil?
|
82
|
-
kg = javax.crypto.KeyGenerator.getInstance(
|
442
|
+
kg = javax.crypto.KeyGenerator.getInstance(@spec.provider_config[:keygen_algo])
|
83
443
|
else
|
84
|
-
kg = javax.crypto.KeyGenerator.getInstance(
|
444
|
+
kg = javax.crypto.KeyGenerator.getInstance(@spec.provider_config[:keygen_algo], @keygenJceProvider)
|
85
445
|
end
|
86
446
|
|
87
|
-
|
88
|
-
|
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
|
-
|
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.
|
457
|
+
if @spec.iv_required?
|
458
|
+
logger.debug "IV required of length #{@spec.ivLength}"
|
97
459
|
if is_empty?(@spec.iv)
|
98
|
-
|
99
|
-
@spec.iv
|
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
|
-
|
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) #
|
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
|
-
|
472
|
+
ivParam = javax.crypto.spec.IvParameterSpec.new(@spec.iv)
|
116
473
|
end
|
117
|
-
ivParam = javax.crypto.spec.IvParameterSpec.new(@spec.iv)
|
118
474
|
|
119
|
-
|
120
|
-
|
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
|
-
|
480
|
+
logger.debug "spec key : #{@spec.ccrypto_key.inspect}"
|
131
481
|
|
132
|
-
case @spec.
|
482
|
+
case @spec.ccrypto_key
|
133
483
|
when Ccrypto::SecretKey
|
134
|
-
|
484
|
+
logger.debug "Given secret key"
|
485
|
+
skey = @spec.ccrypto_key.native_key
|
135
486
|
when ::Java::byte[]
|
136
|
-
|
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
|
-
|
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
|
-
|
493
|
+
logger.debug "Given Java SecretKeySpec"
|
494
|
+
skey = @spec.ccrypto_key
|
141
495
|
else
|
142
|
-
raise CipherEngineException, "Unknown key type '#{@spec.
|
496
|
+
raise CipherEngineException, "Unknown key type '#{@spec.ccrypto_key}'"
|
143
497
|
end
|
144
498
|
|
145
|
-
#
|
499
|
+
#logger.debug "SKey : #{to_hex(skey.encoded)}"
|
146
500
|
|
147
|
-
|
148
|
-
when :encrypt, :enc
|
501
|
+
if @spec.is_encrypt_cipher_mode?
|
149
502
|
if ivParam.nil?
|
150
|
-
|
503
|
+
logger.debug "Encryption mode"
|
151
504
|
@cipher.init(javax.crypto.Cipher::ENCRYPT_MODE, skey)
|
152
505
|
else
|
153
|
-
|
506
|
+
logger.debug "Encryption mode with IV"
|
154
507
|
@cipher.init(javax.crypto.Cipher::ENCRYPT_MODE, skey, ivParam)
|
155
508
|
end
|
156
509
|
|
157
|
-
|
510
|
+
elsif @spec.is_decrypt_cipher_mode?
|
158
511
|
if ivParam.nil?
|
159
|
-
|
512
|
+
logger.debug "Decryption mode"
|
160
513
|
@cipher.init(javax.crypto.Cipher::DECRYPT_MODE, skey)
|
161
514
|
else
|
162
|
-
|
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.
|
171
|
-
|
172
|
-
|
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
|
-
|
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
|
-
|
544
|
+
logger.debug "Cipher update returns nothing"
|
182
545
|
else
|
183
|
-
|
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
|
-
|
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
|
-
|
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
|
220
|
-
|
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
|