gcrypto_jce 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ #