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.
- 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
|