gcrypto_jce 0.1

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.
@@ -0,0 +1,66 @@
1
+
2
+
3
+ Dir.glob(File.join(File.dirname(__FILE__),'../../jars/*.jar')).each do |f|
4
+ require_relative File.expand_path(f)
5
+ end
6
+
7
+ require_relative 'global'
8
+
9
+ module GcryptoJce
10
+ module Provider
11
+
12
+ DefProvider = org.bouncycastle.jce.provider.BouncyCastleProvider.new
13
+
14
+ def Provider::add_default
15
+ add_provider(DefProvider)
16
+ DefProvider
17
+ end
18
+ #
19
+ # end add_default
20
+ #
21
+
22
+ def Provider::add_provider(prov)
23
+ if prov != nil
24
+ if prov.is_a?(String) and not prov.empty?
25
+ GcryptoJce::GConf.instance.glog.error "Unknown provider by string '#{prov}'. Please use provider object."
26
+ raise Exception, "Unknown provider by string '#{prov}'. Please use provider object."
27
+ elsif prov.is_a?(java.security.Provider)
28
+ if prov != nil
29
+ if not java.security.Security.get_providers.to_a.include?(prov)
30
+ GcryptoJce::GConf.instance.glog.debug "Adding security provider '#{prov.name}'"
31
+ java.security.Security.add_provider(prov)
32
+ end
33
+ prov
34
+ else
35
+ raise Exception, "Unknown provider object #{prov.inspect}"
36
+ end
37
+
38
+ end
39
+ end
40
+
41
+ end
42
+ #
43
+ # end add_provider
44
+ #
45
+
46
+ def Provider::handle_options(opts = { }, def_if_nil = DefProvider)
47
+ if opts.nil? or opts.empty?
48
+ else
49
+ prov = opts[:provider]
50
+ if prov.nil?
51
+ if def_if_nil != nil
52
+ Provider::add_provider(def_if_nil)
53
+ end
54
+ else
55
+ Provider::add_provider(prov)
56
+ end
57
+ end
58
+ end
59
+ #
60
+ # add handle_options
61
+ #
62
+
63
+ end
64
+ end
65
+
66
+
@@ -0,0 +1,159 @@
1
+
2
+ require 'pkernel'
3
+ require 'pkernel_jce'
4
+
5
+ require_relative 'error'
6
+ require_relative 'io_utils'
7
+ require_relative 'provider'
8
+ require_relative 'global'
9
+
10
+ module GcryptoJce
11
+ module SecretKey
12
+
13
+ def generate(opts = { })
14
+
15
+ skType = opts[:type]
16
+ if skType.nil?
17
+ raise GcryptoJce::Error, "Secret key type is not given for generation"
18
+ else
19
+ skType = to_algo_string(skType)
20
+ end
21
+
22
+ prov = GcryptoJce::Provider.handle_options(opts, nil)
23
+
24
+ if prov.nil?
25
+ GcryptoJce::GConf.instance.glog.debug "Provider is nil"
26
+ kg = javax.crypto.KeyGenerator.getInstance(skType)
27
+ else
28
+ GcryptoJce::GConf.instance.glog.debug "Provider is '#{prov.name}'"
29
+ kg = javax.crypto.KeyGenerator.getInstance(skType, prov)
30
+ end
31
+
32
+ keyLen = opts[:keyLen]
33
+ secRandom = opts[:secRandom]
34
+ if keyLen.nil? or keyLen.to_i == 0
35
+ raise GcryptoJce::Error, "Key length not given or invalid"
36
+ else
37
+ if secRandom.nil?
38
+ kg.init(keyLen.to_i)
39
+ else
40
+ kg.init(keyLen.to_i, secRandom)
41
+ end
42
+ end
43
+
44
+ kg.generateKey
45
+
46
+ end
47
+ # end generate()
48
+ #
49
+
50
+ def SecretKey.is_secret_key?(obj)
51
+ if obj.nil?
52
+ false
53
+ else
54
+ obj.java_kind_of?(javax.crypto.spec.SecretKeySpec)
55
+ end
56
+ end
57
+
58
+ def dump(sk, opts = { })
59
+ file = opts[:file]
60
+ baos = java.io.ByteArrayOutputStream.new
61
+
62
+ if not (file.nil? or file.empty?)
63
+ os = java.io.ObjectOutputStream.new(java.io.FileOutputStream.new(file))
64
+ else
65
+ os = java.io.ObjectOutputStream.new(baos)
66
+ end
67
+
68
+ os.writeObject(sk)
69
+ os.flush
70
+ os.close
71
+
72
+ if not (file.nil? or file.empty?)
73
+ else
74
+ baos.toByteArray
75
+ end
76
+ end
77
+ # end dump()
78
+
79
+ def load(opts = { })
80
+ file = opts[:file]
81
+ bin = opts[:bin]
82
+ if not (file.nil? or file.empty?)
83
+ skBin = IoUtils.file_to_memory_byte_array(file)
84
+ elsif not bin.nil?
85
+ skBin = IoUtils.ensure_java_bytes(bin)
86
+ else
87
+ raise GcryptoJce::Error, "No file or buffer given to load secret key"
88
+ end
89
+
90
+ skOs = java.io.ObjectInputStream.new(java.io.ByteArrayInputStream.new(skBin))
91
+ sk = skOs.readObject
92
+ skOs.close
93
+
94
+ sk
95
+ end
96
+ # end load()
97
+
98
+ def load_from_bin(opts = { })
99
+ file = opts[:file]
100
+ bin = opts[:bin]
101
+ if not (file.nil? or file.empty?)
102
+ skBin = IoUtils.file_to_memory_byte_array(file)
103
+ elsif not bin.nil?
104
+ skBin = IoUtils.ensure_java_bytes(bin)
105
+ else
106
+ raise GcryptoJce::Error, "No file or buffer given to load secret key from binary"
107
+ end
108
+
109
+ skType = opts[:type]
110
+ if skType.nil? or skType.empty?
111
+ raise GcryptoJce::Error, "Secret Key type is not given to load from binary"
112
+ end
113
+
114
+ javax.crypto.spec.SecretKeySpec.new(skBin, skType)
115
+ end
116
+
117
+ def to_algo_string(key)
118
+ key = key.to_s.upcase
119
+ case key
120
+ when "AES"
121
+ "AES"
122
+ when "3DES", "TRIPLEDES", "TRIPLE-DES", "3-DES"
123
+ "3DES"
124
+ else
125
+ "AES"
126
+ #raise GcryptoJce::Error, "Unknown algo '#{key}'"
127
+ end
128
+ end
129
+ #
130
+ # end to_algo_string
131
+ #
132
+
133
+ def SecretKey.key_type(secKeySpec)
134
+ algo = secKeySepc.algorithm
135
+ case algo
136
+ when "AES"
137
+ "AES"
138
+ when "3DES"
139
+ "3DES"
140
+ else
141
+ raise GcryptoJce::Error, "Unknown key type '#{algo}'"
142
+ end
143
+ end
144
+ #
145
+ # end key_type
146
+ #
147
+
148
+ end
149
+ #
150
+ # end module SecretKey
151
+ #
152
+
153
+ class SecretKeyFactory
154
+ extend SecretKey
155
+ end
156
+ end
157
+ #
158
+ # end module Gcrypto
159
+ #
@@ -0,0 +1,412 @@
1
+
2
+
3
+ require 'pkernel'
4
+ require 'pkernel_jce'
5
+
6
+ require 'gcrypto'
7
+
8
+ require_relative 'error'
9
+ require_relative 'io_utils'
10
+ require_relative 'provider'
11
+ require_relative 'global'
12
+ require_relative 'secretkey'
13
+ require_relative 'pbkdf2'
14
+
15
+ require 'securerandom'
16
+
17
+ require 'active_support'
18
+ class NumberHelper
19
+ extend ActiveSupport::NumberHelper
20
+ end
21
+
22
+ module Gcrypto #::SecretKeyCryptoContext
23
+ class AESCContext
24
+ attr_accessor :padding, :secure_random, :key_provider, :name
25
+ alias_method :ori_init, :initialize
26
+ def initialize
27
+ ori_init
28
+ #@keyType = :aes
29
+ #@keyLen = 256
30
+ #@mode = "GCM"
31
+ #@padding = "NoPadding"
32
+ @mode = "CBC"
33
+ #@padding = "PKCS5Padding"
34
+ @name = ::SecureRandom.hex(8) # KEK requires an ID, just generates it...
35
+ begin
36
+ # java 8 introduce getInstanceStrong()
37
+ @secure_random = java.security.SecureRandom.getInstanceStrong
38
+ rescue Exception
39
+ @secure_random = java.security.SecureRandom.getInstance('SHA1PRNG')
40
+ end
41
+ end
42
+
43
+ def padding
44
+ if @padding.nil? or @padding.empty?
45
+ case @mode
46
+ when "CBC"
47
+ @padding = "PKCS5Padding"
48
+ when "GCM"
49
+ @padding = "NoPadding"
50
+ else
51
+ @padding = "PKCS5Padding"
52
+ end
53
+ end
54
+
55
+ @padding
56
+ end
57
+
58
+ def random_iv
59
+ if @iv.nil? or @iv.empty?
60
+ if mode == "GCM"
61
+ @iv = Java::byte[12].new # for GCM mode
62
+ else
63
+ @iv = Java::byte[16].new # for CBC mode
64
+ end
65
+ #@iv = Java::byte[12].new # for GCM mode
66
+ #@iv = Java::byte[16].new # for CBC mode
67
+ @secure_random.nextBytes(@iv)
68
+ end
69
+
70
+ @iv
71
+ end
72
+ # end random_iv
73
+
74
+ def random_key
75
+ if @key.nil?
76
+ conf = { type: @keyType, keyLen: @keyLen }
77
+ if @key_provider.nil?
78
+ else
79
+ conf.merge!({ provider: @key_provider })
80
+ end
81
+
82
+ if not @secure_random.nil?
83
+ conf.merge!({ secRandom: @secure_random })
84
+ end
85
+
86
+ @key = GcryptoJce::SecretKeyFactory.generate(conf)
87
+ end
88
+
89
+ @key
90
+ end
91
+ # end ramdom_key
92
+
93
+ def raw_key=(val)
94
+ @raw_key = val
95
+
96
+ if not @raw_key.nil?
97
+ @key = GcryptoJce::SecretKeyFactory.load_from_bin({ bin: @raw_key, type: "AES" })
98
+ end
99
+ end
100
+
101
+ def raw_key
102
+ @raw_key
103
+ end
104
+
105
+ def derive_key(pass, opts = { })
106
+
107
+ eng = opts[:eng] || :pbkdf2
108
+
109
+ case eng
110
+ when :pbkdf2
111
+ opts.merge!( { reqKeyLen: @keyLen } )
112
+ res = GcryptoJce::KDF::PBKDF2Engine.derive(pass, opts)
113
+ @key = res[:key]
114
+ res.delete(:key)
115
+
116
+ res
117
+ else
118
+ raise GcryptoJce::Error, "Unknown derive key engine '#{eng}'"
119
+ end
120
+
121
+ end
122
+
123
+ def to_java_cipher_spec
124
+ "#{@keyType.to_s.upcase}/#{mode}/#{padding}"
125
+ end
126
+ # to_java_cipher_spec
127
+
128
+ def to_java_key_type
129
+ "AES"
130
+ end
131
+
132
+ def algo_params_spec
133
+ if @mode.upcase == "GCM"
134
+ if @iv.nil?
135
+ random_iv
136
+ end
137
+
138
+ # https://javainterviewpoint.com/java-aes-256-gcm-encryption-and-decryption/
139
+ javax.crypto.spec.GCMParameterSpec.new(16*8, @iv)
140
+
141
+ elsif mode == "CBC"
142
+ if @iv.nil?
143
+ random_iv
144
+ end
145
+
146
+ javax.crypto.spec.IvParameterSpec.new(@iv)
147
+ end
148
+ end
149
+ # end algo_params_spec
150
+
151
+ def mode
152
+ if not @mode.nil?
153
+ @mode.to_s.upcase
154
+ end
155
+
156
+ @mode
157
+ end
158
+ # end mode
159
+
160
+ def finalize
161
+ IoUtils.attempt_zeroise(@key) if not @key.nil?
162
+ IoUtils.attempt_zeroise(@iv) if not @iv.nil?
163
+ end
164
+ # end finalize
165
+
166
+ end
167
+ # end class AES
168
+ end
169
+ # end SecretKeyCryptoContext::AES
170
+
171
+ module GcryptoJce
172
+
173
+ module SecretKeyCrypto
174
+
175
+ def encrypt(opts = { })
176
+
177
+ is = IoUtils.load_input(opts)
178
+ spec = opts[:crypto_context]
179
+
180
+ if spec.nil?
181
+ raise GcryptoJce::Error, "Crypto context is not given for secret key encryption"
182
+ end
183
+
184
+ os = IoUtils.prep_output(opts)
185
+ #outFile = opts[:outFile]
186
+ #if not (outFile.nil? or outFile.empty?)
187
+ # GcryptoJce::GConf.instance.glog.debug "File output for result"
188
+ # os = java.io.FileOutputStream.new(outFile)
189
+ #else
190
+ # GcryptoJce::GConf.instance.glog.debug "Buffer output for result"
191
+ # os = java.io.ByteArrayOutputStream.new
192
+ #end
193
+
194
+ if not spec.key_provider.nil?
195
+ prov = GcryptoJce::Provider.add_provider(spec.key_provider)
196
+ GcryptoJce::GConf.instance.glog.debug "Cipher spec : #{spec.to_java_cipher_spec}"
197
+ c = javax.crypto.Cipher.getInstance(spec.to_java_cipher_spec, prov)
198
+ else
199
+ GcryptoJce::GConf.instance.glog.debug "Cipher spec : #{spec.to_java_cipher_spec}"
200
+ c = javax.crypto.Cipher.getInstance(spec.to_java_cipher_spec)
201
+ end
202
+
203
+ algoParam = spec.algo_params_spec
204
+ if algoParam.nil?
205
+ GcryptoJce::GConf.instance.glog.debug "With nil algo params"
206
+ c.init(javax.crypto.Cipher::ENCRYPT_MODE, spec.key)
207
+ else
208
+ GcryptoJce::GConf.instance.glog.debug "With algo params : #{algoParam}"
209
+ c.init(javax.crypto.Cipher::ENCRYPT_MODE, spec.key, algoParam)
210
+ end
211
+
212
+ # special for GCM mode
213
+ if spec.mode == "GCM"
214
+ addAuthData = opts[:addAuthData]
215
+ if not addAuthData.nil?
216
+ case addAuthData
217
+ when Java::byte[]
218
+ c.updateAAD(addAuthData)
219
+ when String
220
+ c.updateAAD(addAuthData.to_java.getBytes)
221
+ when Java::char[]
222
+ cc.updateAAD(String.from_java_bytes(addAuthData).to_java.getBytes)
223
+ else
224
+ raise GcryptoJce::Error, "Addtional authenticated data given is not string, byte[] or char[]."
225
+ end
226
+ end
227
+ end
228
+ # end special data for GCM
229
+
230
+ begin
231
+ bufConf = opts[:int_buf] || { }
232
+ total = 0
233
+ IoUtils.read_chunk(is, bufConf) do |buf, from, len|
234
+ os.write(c.update(buf, from, len))
235
+ total += len
236
+ GcryptoJce::GConf.instance.glog.debug "Processed #{NumberHelper.number_to_human_size(total)}"
237
+ end
238
+
239
+ os.write(c.doFinal)
240
+ rescue Exception
241
+ ensure
242
+ begin
243
+ is.close
244
+ os.flush
245
+ os.close
246
+ rescue Exception
247
+ end
248
+ end
249
+
250
+ IoUtils.return_if_buffer(os)
251
+ #if outFile.nil? or outFile.empty?
252
+ # os.toByteArray
253
+ #end
254
+
255
+ end
256
+ #
257
+ # end encrypt
258
+ #
259
+
260
+ def decrypt(opts = { })
261
+
262
+ is = IoUtils.load_input(opts)
263
+ spec = opts[:crypto_context]
264
+ if spec.nil?
265
+ raise GcryptoJce::Error, "Crypto context is not given for secret key decryption"
266
+ end
267
+
268
+ #outFile = opts[:outFile]
269
+ #if not (outFile.nil? or outFile.empty?)
270
+ # os = java.io.FileOutputStream.new(outFile)
271
+ #else
272
+ # os = java.io.ByteArrayOutputStream.new
273
+ #end
274
+ os = IoUtils.prep_output(opts)
275
+
276
+ if not spec.key_provider.nil?
277
+ prov = GcryptoJce::Provider.add_provider(spec.key_provider)
278
+ GcryptoJce::GConf.instance.glog.debug "Cipher spec : #{spec.to_java_cipher_spec}"
279
+ c = javax.crypto.Cipher.getInstance(spec.to_java_cipher_spec, prov)
280
+ else
281
+ GcryptoJce::GConf.instance.glog.debug "Cipher spec : #{spec.to_java_cipher_spec}"
282
+ c = javax.crypto.Cipher.getInstance(spec.to_java_cipher_spec)
283
+ end
284
+
285
+ algoParam = spec.algo_params_spec
286
+ if algoParam.nil?
287
+ GcryptoJce::GConf.instance.glog.debug "With nil algo params"
288
+ c.init(javax.crypto.Cipher::DECRYPT_MODE, spec.key)
289
+ else
290
+ GcryptoJce::GConf.instance.glog.debug "With algo params : #{algoParam}"
291
+ c.init(javax.crypto.Cipher::DECRYPT_MODE, spec.key, algoParam)
292
+ end
293
+
294
+ begin
295
+ bufConf = opts[:int_buf] || { }
296
+ total = 0
297
+ IoUtils.read_chunk(is, bufConf) do |buf, from, len|
298
+ os.write(c.update(buf, from, len))
299
+ total += len
300
+ GcryptoJce::GConf.instance.glog.debug "Processed #{NumberHelper.number_to_human_size(total)}"
301
+ end
302
+
303
+ os.write(c.doFinal)
304
+ rescue Exception
305
+ ensure
306
+ begin
307
+ is.close
308
+ os.flush
309
+ os.close
310
+ rescue Exception
311
+ end
312
+ end
313
+
314
+ IoUtils.return_if_buffer(os)
315
+ #if outFile.nil? or outFile.empty?
316
+ # os.toByteArray
317
+ #end
318
+
319
+ end
320
+ # end decrypt()
321
+
322
+ # generate mac as signature using secret key
323
+ def sign(opts = { })
324
+
325
+ spec = opts[:crypto_context]
326
+ if spec.nil?
327
+ raise GcryptoJce::Error, "Crypto context is not given for secret key signing"
328
+ end
329
+
330
+ is = IoUtils.load_input(opts)
331
+ if not opts[:associatedData].nil?
332
+ dat = opts[:associatedData]
333
+ dat.merge!( { input_optional: true })
334
+ addIs = IoUtils.load_input(dat)
335
+ end
336
+ os = IoUtils.prep_output(opts)
337
+
338
+ hmacHash = opts[:hmacHash] || "SHA256"
339
+ hmacHashEng = "Hmac#{hmacHash}"
340
+ GcryptoJce::GConf.instance.glog.debug "Using '#{hmacHashEng}'"
341
+
342
+ if not spec.key_provider.nil?
343
+ prov = GcryptoJce::Provider.add_provider(spec.key_provider)
344
+ hmac = javax.crypto.Mac.getInstance(hmacHashEng, prov)
345
+ else
346
+ hmac = javax.crypto.Mac.getInstance(hmacHashEng)
347
+ end
348
+
349
+ hmac.init(spec.key)
350
+
351
+ begin
352
+ bufConf = opts[:int_buf] || { }
353
+ total = 0
354
+ IoUtils.read_chunk(is, bufConf) do |buf, from, len|
355
+ hmac.update(buf, from, len)
356
+ total += len
357
+ GcryptoJce::GConf.instance.glog.debug "Processed #{NumberHelper.number_to_human_size(total)}"
358
+ end
359
+
360
+ if not addIs.nil?
361
+ GcryptoJce::GConf.instance.glog.debug "Processing associated data"
362
+ IoUtils.read_chunk(addIs, bufConf) do |buf, from, len|
363
+ hmac.update(buf, from, len)
364
+ total += len
365
+ GcryptoJce::GConf.instance.glog.debug "Processed #{NumberHelper.number_to_human_size(total)}"
366
+ end
367
+ end
368
+
369
+ os.write(hmac.doFinal)
370
+ rescue Exception => ex
371
+ ensure
372
+ begin
373
+ is.close
374
+ os.flush
375
+ os.close
376
+ rescue Exception
377
+ end
378
+ end
379
+
380
+ IoUtils.return_if_buffer(os)
381
+
382
+ end
383
+ # end sign()
384
+
385
+ def verify(opts = { })
386
+
387
+ # mac value obtained by caller app
388
+ # must be in byte array value
389
+ mac = opts[:mac]
390
+ macBin = IoUtils.ensure_java_bytes(mac)
391
+ # calculate again based on input
392
+ refMac = sign(opts)
393
+
394
+ # compare both byte array
395
+ #
396
+ java.security.MessageDigest.isEqual(macBin, refMac)
397
+ end
398
+ # end verify()
399
+
400
+ end
401
+ #
402
+ # end SecretKeyCrypto
403
+ #
404
+
405
+ class SecretKeyCryptoEngine
406
+ extend SecretKeyCrypto
407
+ end
408
+
409
+ end
410
+ #
411
+ # end GcryptoJce
412
+ #