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,121 @@
1
+
2
+ require_relative 'global'
3
+ require 'active_support'
4
+ class NumberHelper
5
+ extend ActiveSupport::NumberHelper
6
+ end
7
+
8
+
9
+ module GcryptoJce
10
+ module IoUtils
11
+
12
+ def IoUtils.load_input(opts = { })
13
+ if opts.nil? or opts.empty?
14
+ raise GcryptoJce::Error, "No input given to load"
15
+ else
16
+ file = opts[:file]
17
+ bin = opts[:bin]
18
+
19
+ if not (file.nil? or file.empty?)
20
+ fis = java.io.FileInputStream.new(file)
21
+ fis
22
+ elsif not bin.nil?
23
+ begin
24
+ bais = java.io.ByteArrayInputStream.new(bin.to_java_bytes)
25
+ rescue NoMethodError
26
+ bais = java.io.ByteArrayInputStream.new(bin)
27
+ end
28
+ bais
29
+ else
30
+ if not (opts[:input_optional].nil? and opts[:input_optional])
31
+ raise GcryptoJce::Error, "Neither file nor bin given to load input"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ #
37
+ # end load_input()
38
+ #
39
+
40
+ def IoUtils.prep_output(opts = { })
41
+
42
+ if opts.nil? or opts.empty?
43
+ raise GcryptoJce::Error, "No opts given to prep output"
44
+ else
45
+ file = opts[:outFile]
46
+
47
+ if not (file.nil? or file.empty?)
48
+ fos = java.io.FileOutputStream.new(file)
49
+ fos
50
+ else
51
+ baos = java.io.ByteArrayOutputStream.new
52
+ baos
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ def IoUtils.return_if_buffer(os)
59
+ if os.java_kind_of?(java.io.ByteArrayOutputStream)
60
+ os.toByteArray
61
+ end
62
+ end
63
+
64
+ def IoUtils.read_chunk(is, opts = { },&block)
65
+
66
+ raise GcryptoJce::Error, "Cannot read chunk from nil input stream" if is.nil?
67
+ raise GcryptoJce::Error, "Block required for read_chunk" if not block
68
+
69
+ if not is.java_kind_of?(java.io.InputStream)
70
+ raise GcryptoJce::Error, "Cannot read from '#{is.class}' object"
71
+ end
72
+
73
+ bufLen = opts[:buffer_size] || 1024*1024
74
+ GcryptoJce::GConf.instance.glog.debug "read_chunk buffer size is #{NumberHelper.number_to_human_size(bufLen)}. Modifiable by caller app via key :in_buf -> :buffer_size"
75
+
76
+ b = Java::byte[bufLen].new
77
+ while((read = is.read(b,0,b.length)) != -1)
78
+ block.call(b,0,read)
79
+ end
80
+ end
81
+ #
82
+ # end read_chunk
83
+ #
84
+
85
+ def IoUtils.file_to_memory_byte_array(path)
86
+ if path.nil? or path.empty?
87
+ raise PkernelJce::Error, "Given path '#{path}' to load to memory is nil or empty"
88
+ else
89
+ f = java.io.File.new(path)
90
+ b = Java::byte[f.length].new
91
+ dis = java.io.DataInputStream.new(java.io.FileInputStream.new(f))
92
+ dis.readFully(b)
93
+ dis.close
94
+
95
+ b
96
+ end
97
+ end
98
+ # end file_to_memory_byte_array
99
+ #
100
+
101
+ def IoUtils.ensure_java_bytes(bin)
102
+ if not bin.java_kind_of?(Java::byte[])
103
+ bin.to_java_bytes
104
+ else
105
+ bin
106
+ end
107
+ end
108
+ # end ensure_java_bytes
109
+ #
110
+
111
+ def IoUtils.attempt_zeroise(var)
112
+ java.util.Arrays.fill(var, 0)
113
+ end
114
+ end
115
+ # end IoUtils
116
+ #
117
+
118
+ end
119
+ # end GcryptoJce
120
+ #
121
+
@@ -0,0 +1,278 @@
1
+
2
+
3
+ require 'pkernel'
4
+ require 'pkernel_jce'
5
+
6
+ require_relative 'error'
7
+ require_relative 'io_utils'
8
+ require_relative 'provider'
9
+ require_relative 'global'
10
+
11
+ module GcryptoJce
12
+
13
+ module KeyPairCrypto
14
+
15
+ def sign(opts = { })
16
+ raise GcryptoJce::Error, "Insufficient parameters for signature generation" if opts.nil? or opts.empty?
17
+
18
+ id = opts[:identity]
19
+ if id.nil?
20
+ raise GcryptoJce::Error, "Identity to sign the data is not available"
21
+ end
22
+
23
+ prov = GcryptoJce::Provider.handle_options(opts, nil)
24
+
25
+ is = IoUtils.load_input(opts)
26
+
27
+ if prov.nil?
28
+ GcryptoJce::GConf.instance.glog.debug "Provider is nil"
29
+ sign = java.security.Signature.getInstance(KeyPairCrypto.derive_signing_algo(id.privKey))
30
+ else
31
+ GcryptoJce::GConf.instance.glog.debug "Provider is '#{prov.name}'"
32
+ sign = java.security.Signature.getInstance(KeyPairCrypto.derive_signing_algo(id.privKey), prov)
33
+ end
34
+
35
+
36
+ GcryptoJce::GConf.instance.glog.debug "Private key is #{id.privKey.class}"
37
+ sign.initSign(id.privKey)
38
+
39
+ begin
40
+ IoUtils.read_chunk(is) do |buf, from, len|
41
+ sign.update(buf, from, len)
42
+ end
43
+ rescue Exception => ex
44
+ GcryptoJce::GConf.instance.glog.error ex.message
45
+ GcryptoJce::GConf.instance.glog.error ex.backtrace.join("\n")
46
+ ensure
47
+ begin
48
+ is.close
49
+ rescue Exception
50
+ end
51
+ end
52
+
53
+ sign.sign
54
+
55
+ end
56
+ #
57
+ # end method sign()
58
+ #
59
+
60
+ def KeyPairCrypto.derive_signing_algo(kp, hash = "SHA256")
61
+ PkernelJce::KeyPair.derive_signing_algo(kp,hash)
62
+ end
63
+
64
+ def verify(opts = { })
65
+
66
+ if opts.nil? or opts.empty?
67
+ raise GcryptoJce::Error, "Insufficient parameters for signature verification"
68
+ end
69
+
70
+ file = opts[:sign_file]
71
+ bin = opts[:sign_bin]
72
+ if not (file.nil? or file.empty?)
73
+ signBin = IoUtils.file_to_memory_byte_array(file)
74
+ elsif not bin.nil?
75
+ signBin = IoUtils.ensure_java_bytes(bin)
76
+ else
77
+ raise GcryptoJce::Error, "Neither signature in file or memory buffer given for signatur verification"
78
+ end
79
+
80
+ is = IoUtils.load_input(opts)
81
+ prov = GcryptoJce::Provider.handle_options(opts, nil)
82
+
83
+ cert = opts[:certificate]
84
+ pubKey = opts[:pubKey]
85
+ if not cert.nil?
86
+
87
+ if prov.nil?
88
+ GcryptoJce::GConf.instance.glog.debug "Provider is nil"
89
+ sign = java.security.Signature.getInstance(KeyPairCrypto.derive_signing_algo(cert))
90
+ else
91
+ GcryptoJce::GConf.instance.glog.debug "Provider is '#{prov.name}'"
92
+ sign = java.security.Signature.getInstance(KeyPairCrypto.derive_signing_algo(cert), prov)
93
+ end
94
+
95
+ sign.initVerify(cert)
96
+
97
+ elsif not pubKey.nil?
98
+
99
+ if prov.nil?
100
+ GcryptoJce::GConf.instance.glog.debug "Provider is nil"
101
+ sign = java.security.Signature.getInstance(KeyPairCrypto.derive_signing_algo(pubKey))
102
+ else
103
+ GcryptoJce::GConf.instance.glog.debug "Provider is '#{prov.name}'"
104
+ sign = java.security.Signature.getInstance(KeyPairCrypto.derive_signing_algo(pubKey), prov)
105
+ end
106
+
107
+ sign.initVerify(pubKey)
108
+
109
+ else
110
+ raise GcryptoJce::Error, "No public key or certificate during signature verification"
111
+ end
112
+
113
+ begin
114
+ IoUtils.read_chunk(is) do |buf, from, len|
115
+ sign.update(buf, from, len)
116
+ end
117
+ rescue Exception => ex
118
+ GcryptoJce::GConf.instance.glog.error ex.message
119
+ GcryptoJce::GConf.instance.glog.error ex.backtrace.join("\n")
120
+ ensure
121
+ begin
122
+ is.close
123
+ rescue Exception
124
+ end
125
+ end
126
+
127
+ sign.verify(signBin)
128
+
129
+ end
130
+ #
131
+ # end method verify()
132
+ #
133
+
134
+
135
+ def encrypt(opts = { })
136
+
137
+ file = opts[:file]
138
+ bin = opts[:bin]
139
+
140
+ # assumption:
141
+ # Data size is small (~kb)
142
+ # Because for RSA the max data = public key size
143
+ if not (file.nil? or file.empty?)
144
+ data = IoUtils.file_to_memory_byte_array(file)
145
+ elsif not bin.nil?
146
+ data = IoUtils.ensure_java_bytes(bin)
147
+ else
148
+ raise GcryptoJce::Error, "No input given for keypair encryption"
149
+ end
150
+
151
+ recp = opts[:recipient]
152
+ if recp.nil?
153
+ raise GcryptoJce::Error, "No recipient given for keypair encryption"
154
+ end
155
+
156
+ if Pkernel::Certificate.is_cert_object?(recp)
157
+ pubKey = Pkernel::Certificate.public_key(recp)
158
+ elsif Pkernel::KeyPair.is_public_key?(recp)
159
+ pubKey = recp
160
+ else
161
+ raise GcryptoJce::Error, "Given recipient is neither certificate nor public key."
162
+ end
163
+
164
+ prov = GcryptoJce::Provider.handle_options(opts, nil)
165
+
166
+ cipherSpec = opts[:cipher_spec] || "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
167
+ type = Pkernel::KeyPair.pub_key_type(pubKey)
168
+ case type
169
+ when Pkernel::KeyPair::RSA_KEY_NAME
170
+ if prov.nil?
171
+ GcryptoJce::GConf.instance.glog.debug "Provider is nil"
172
+ if cipherSpec =~ /PKCS5Padding/
173
+ GcryptoJce::GConf.instance.glog.warn "PKCS#1 1.5 may be vulnerable to Bleichenbacher's CCA attack"
174
+ end
175
+ GcryptoJce::GConf.instance.glog.debug "Using cipher spec '#{cipherSpec}'"
176
+ cipher = javax.crypto.Cipher.getInstance(cipherSpec)
177
+ else
178
+ GcryptoJce::GConf.instance.glog.debug "Provider is '#{prov.name}'"
179
+ cipher = javax.crypto.Cipher.getInstance(cipherSpec, prov)
180
+ end
181
+ else
182
+ raise GcryptoJce::Error, "Unsupported key type '#{pubKey}' for keypair data encryption operation"
183
+ end
184
+
185
+ cipher.init(javax.crypto.Cipher::ENCRYPT_MODE, pubKey)
186
+
187
+ outStream = opts[:outStream]
188
+ if not outStream.nil?
189
+ outStream.write(cipher.update(data))
190
+ outStream.write(cipher.doFinal)
191
+ outStream.flush
192
+ else
193
+ baos = java.io.ByteArrayOutputStream.new
194
+ baos.write(cipher.update(data))
195
+ baos.write(cipher.doFinal)
196
+ baos.toByteArray
197
+ end
198
+
199
+ end
200
+ #
201
+ # end encrypt()
202
+ #
203
+
204
+ def decrypt(opts = { })
205
+
206
+ file = opts[:enc_file]
207
+ bin = opts[:enc_bin]
208
+
209
+ # assumption:
210
+ # Data size is small (~kb)
211
+ # Because for RSA the max data = public key size
212
+ if not (file.nil? or file.empty?)
213
+ data = IoUtils.file_to_memory_byte_array(file)
214
+ elsif not bin.nil?
215
+ data = IoUtils.ensure_java_bytes(bin)
216
+ else
217
+ raise GcryptoJce::Error, "No input given for decrypt"
218
+ end
219
+
220
+ id = opts[:identity]
221
+ if id.nil?
222
+ raise GcryptoJce::Error, "No identity given for decrypt"
223
+ end
224
+
225
+ if id.privKey.nil?
226
+ raise GcryptoJce::Error, "Private key is nil for data decryption"
227
+ end
228
+
229
+ prov = GcryptoJce::Provider.handle_options(opts, nil)
230
+
231
+ cipherSpec = opts[:cipher_spec] || "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
232
+ type = Pkernel::KeyPair.key_type(id.privKey)
233
+ case type
234
+ when Pkernel::KeyPair::RSA_KEY_NAME
235
+ if prov.nil?
236
+ GcryptoJce::GConf.instance.glog.debug "Provider is nil"
237
+ if cipherSpec =~ /PKCS5Padding/
238
+ GcryptoJce::GConf.instance.glog.warn "PKCS#1 1.5 may be vulnerable to Bleichenbacher's CCA attack"
239
+ end
240
+ GcryptoJce::GConf.instance.glog.debug "Using cipher spec '#{cipherSpec}'"
241
+ cipher = javax.crypto.Cipher.getInstance(cipherSpec)
242
+ else
243
+ GcryptoJce::GConf.instance.glog.debug "Provider is '#{prov.name}'"
244
+ cipher = javax.crypto.Cipher.getInstance(cipherSpec, prov)
245
+ end
246
+ else
247
+ raise GcryptoJce::Error, "Unsupported key type '#{id.privKey}' for data decryption operation"
248
+ end
249
+
250
+ cipher.init(javax.crypto.Cipher::DECRYPT_MODE, id.privKey)
251
+
252
+ outStream = opts[:outStream]
253
+ if not outStream.nil?
254
+ outStream.write(cipher.update(data))
255
+ outStream.write(cipher.doFinal)
256
+ outStream.flush
257
+ else
258
+ baos = java.io.ByteArrayOutputStream.new
259
+ baos.write(cipher.update(data))
260
+ baos.write(cipher.doFinal)
261
+ baos.toByteArray
262
+ end
263
+
264
+ end
265
+ #
266
+ # end decrypt()
267
+ #
268
+
269
+ end
270
+ # end KeyPairCrypto
271
+ #
272
+
273
+ class KeyPairCryptoEngine
274
+ extend KeyPairCrypto
275
+ end
276
+
277
+ end
278
+ # end gcrypto
@@ -0,0 +1,95 @@
1
+
2
+ require 'gcrypto'
3
+ require_relative 'secretkey'
4
+ require_relative 'error'
5
+ require_relative 'io_utils'
6
+ require_relative 'provider'
7
+ require_relative 'global'
8
+ require_relative 'converter'
9
+
10
+ module GcryptoJce
11
+ module KDF
12
+ module PBKDF2
13
+
14
+ def derive(pass, opts = { })
15
+
16
+ if pass.nil? or pass.empty?
17
+ raise GcryptoJce::Error, "Password to derive is empty"
18
+ else
19
+ if pass.is_a?(String)
20
+ pa = pass.to_java.toCharArray
21
+ elsif pass.java_kind_of?(Java::byte[])
22
+ pa = String.from_java_bytes(pass).to_java.toCharArray
23
+ elsif pass.java_kind_of?(Java::char[])
24
+ pa = pass
25
+ else
26
+ raise GcryptoJce::Error, "Unknown password type '#{pass.class}'"
27
+ end
28
+ end
29
+
30
+ iter = opts[:iteration]
31
+ if iter.nil? or iter.to_i == 0
32
+ iter = rand(10000...20000)
33
+ end
34
+
35
+ keyLen = opts[:outKeyLen]
36
+ case keyLen
37
+ when 128
38
+ outKeyLen = 128
39
+ engSpec = "PBKDF2WithHMACSHA1"
40
+ when 256, 192
41
+ outKeyLen = 256
42
+ engSpec = "PBKDF2WithHMACSHA256"
43
+ when 512
44
+ outKeyLen = 512
45
+ engSpec = "PBKDF2WithHMACSHA512"
46
+ else
47
+ outKeyLen = 256
48
+ engSpec = "PBKDF2WithHMACSHA256"
49
+ end
50
+
51
+ prov = GcryptoJce::Provider.handle_options(opts, nil)
52
+
53
+ salt = opts[:salt]
54
+ if salt.nil?
55
+ salt = Java::byte[outKeyLen/8].new
56
+ java.security.SecureRandom.new.nextBytes(salt)
57
+ end
58
+
59
+ GcryptoJce::GConf.instance.glog.debug "PBKDF2 using config salt : #{Gcrypto::Converter.to_hex(salt)} / iteration : #{iter} / output hash length : #{outKeyLen} / Eng : #{engSpec}"
60
+ spec = javax.crypto.spec.PBEKeySpec.new(pa, salt, iter, outKeyLen)
61
+ if prov.nil?
62
+ fact = javax.crypto.SecretKeyFactory.getInstance(engSpec)
63
+ else
64
+ fact = javax.crypto.SecretKeyFactory.getInstance(engSpec, prov)
65
+ end
66
+
67
+ secKey = fact.generateSecret(spec)
68
+ key = javax.crypto.spec.SecretKeySpec.new(secKey.encoded,"AES")
69
+
70
+ res = { }
71
+ res[:key] = key
72
+ res[:hash] = secKey.getEncoded
73
+ res[:salt] = salt
74
+ res[:iteration] = iter
75
+ res[:hashLen] = outKeyLen
76
+ res[:eng] = :pbkdf2
77
+
78
+ res
79
+
80
+ end
81
+ end
82
+ # end PBKDF2
83
+ #
84
+
85
+ class PBKDF2Engine
86
+ extend PBKDF2
87
+ end
88
+
89
+ end
90
+ # end KDF
91
+ #
92
+
93
+ end
94
+ # end GcryptoJce
95
+ #