tcrypto_java 0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b351db73e6d40dcdf0107f31640c1fd781c232b1766974cc2b06942070df824c
4
+ data.tar.gz: b43c75df02d215325cb8b3719deb2e61da04e1b56aa30e91e65f3225f4474044
5
+ SHA512:
6
+ metadata.gz: e107434dd46f95f9ca89146866cc5fed3ee1d6fa08a8b66a57dd968efe8edf8db2b0b477f5f7d82ffd3e159328a3721c13a2643c9a4db59c6f8f7e28e1ce2858
7
+ data.tar.gz: 8ceeb05241ef117600d7f4bebeb794c0a2ad197b573d386bd65b63d09bad343a905f3b54c8b23140b2a842d4c76dbe607f6c7bc3249091ad562ed9084ca41b74
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ tags
11
+
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in tcrypto_java.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+
8
+ gem 'pkernel', path: '../../pkernel/pkernel'
9
+ gem 'pkernel_jce', path: '../../pkernel/pkernel_jce'
10
+
11
+ gem 'gcrypto', path: '../../gcrypto/gcrypto'
12
+ gem 'gcrypto_jce', path: '../../gcrypto/gcrypto_jce'
13
+
14
+ # gem 'gcrypto_tag', path: '../gcrypto_tag'
15
+ # gem 'gcrypto_tag_java', path: '../gcrypto_tag_java'
data/Gemfile.lock ADDED
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: ../../gcrypto/gcrypto_jce
3
+ specs:
4
+ gcrypto_jce (0.2)
5
+ activesupport
6
+ pkernel
7
+ pkernel_jce
8
+ tlogger
9
+
10
+ PATH
11
+ remote: ../../gcrypto/gcrypto
12
+ specs:
13
+ gcrypto (0.2)
14
+ pkernel
15
+ tlogger
16
+
17
+ PATH
18
+ remote: ../../pkernel/pkernel_jce
19
+ specs:
20
+ pkernel_jce (0.3)
21
+ activesupport
22
+ tlogger
23
+
24
+ PATH
25
+ remote: ../../pkernel/pkernel
26
+ specs:
27
+ pkernel (0.2)
28
+ tlogger
29
+
30
+ PATH
31
+ remote: .
32
+ specs:
33
+ tcrypto_java (0.1.0)
34
+ tlogger
35
+
36
+ GEM
37
+ remote: https://rubygems.org/
38
+ specs:
39
+ activesupport (5.2.4.1)
40
+ concurrent-ruby (~> 1.0, >= 1.0.2)
41
+ i18n (>= 0.7, < 2)
42
+ minitest (~> 5.1)
43
+ tzinfo (~> 1.1)
44
+ concurrent-ruby (1.1.6)
45
+ i18n (1.8.2)
46
+ concurrent-ruby (~> 1.0)
47
+ minitest (5.14.0)
48
+ rake (12.3.3)
49
+ thread_safe (0.3.6-java)
50
+ tlogger (0.8.0)
51
+ tzinfo (1.2.6)
52
+ thread_safe (~> 0.1)
53
+
54
+ PLATFORMS
55
+ java
56
+
57
+ DEPENDENCIES
58
+ gcrypto!
59
+ gcrypto_jce!
60
+ pkernel!
61
+ pkernel_jce!
62
+ rake (~> 12.0)
63
+ tcrypto_java!
64
+
65
+ BUNDLED WITH
66
+ 2.1.4
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Chris Liaw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # TcryptoJava
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/tcrypto_java`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'tcrypto_java'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install tcrypto_java
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/tcrypto_java.
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "tcrypto_java"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,276 @@
1
+ require "tcrypto_java/version"
2
+
3
+ require 'tcrypto'
4
+
5
+ require_relative 'tcrypto_java/crypto'
6
+
7
+
8
+ module TcryptoJava
9
+ class Error < StandardError; end
10
+ # Your code goes here...
11
+
12
+ class Tcrypto::Cipher
13
+ extend TcryptoJava::Crypto
14
+
15
+ def self.method_missing(mtd,*args,&block)
16
+ if TcryptoJava::Crypto.respond_to?(mtd)
17
+ TcryptoJava::Crypto.send(mtd,*args,&block)
18
+ else
19
+ super
20
+ end
21
+ end
22
+ end
23
+
24
+ # injecting TagProvider class
25
+ class Tcrypto::TagProvider
26
+
27
+ def self.envp_type(bin)
28
+ dec = decode(bin)
29
+ dec.each_slice(2) do |e,f|
30
+ if e.is_a?(org.bouncycastle.asn1.DERSequence)
31
+ dat = e.to_a
32
+ if dat[0].to_s == Tcrypto::Tag.value(:envp_header)
33
+ return Tcrypto::Tag.key(dat[1].to_s)
34
+ end
35
+ elsif e.is_a?(org.bouncycastle.asn1.ASN1ObjectIdentifier)
36
+ if e.to_s == Tcrypto::Tag.value(:envp_header)
37
+ return Tcrypto::Tag.key(f.to_s)
38
+ end
39
+ else
40
+ raise TcryptoJava::Error, "Not a recognized tag? #{e.class}"
41
+ end
42
+ end
43
+
44
+ raise GcryptTag::Error, "Header not found"
45
+ end
46
+
47
+ def self.encode_id
48
+ encode(:oid,"#{Tcrypto::ENCODER_ID}.1")
49
+ end
50
+
51
+ def self.encode(type, val, opts = { }, &block)
52
+ case type
53
+ when :oid
54
+ org.bouncycastle.asn1.ASN1ObjectIdentifier.new(val)
55
+ when :octet_str, :bin
56
+ if not val.is_a?(Java::byte[])
57
+ val = val.encoded
58
+ end
59
+ org.bouncycastle.asn1.DEROctetString.new(val)
60
+ when :str, :utf8_str
61
+ org.bouncycastle.asn1.DERUTF8String.new(val)
62
+ when :pstr, :printable_str
63
+ org.bouncycastle.asn1.DERPrintableString.new(val)
64
+ when :vstr, :visible_str
65
+ org.bouncycastle.asn1.DERVisibleString.new(val)
66
+ when :nstr, :numeric_str
67
+ org.bouncycastle.asn1.DERNumericString.new(val)
68
+ when :int
69
+ org.bouncycastle.asn1.DERInteger.new(val)
70
+ when :seq
71
+ v = org.bouncycastle.asn1.ASN1EncodableVector.new
72
+ val.each do |vv|
73
+ v.add(vv)
74
+ end
75
+ org.bouncycastle.asn1.DERSequence.new(v)
76
+ when :date, :datetime, :time
77
+ org.bouncycastle.asn1.DERUTCTime.new(val)
78
+ when :long_content_write
79
+ # special case...
80
+ # derived from actual code of writing long asn1 code to a file
81
+ res = { }
82
+ raise TcryptoJava::Error, "Source to write long content is not available" if val[:src].nil?
83
+
84
+ srcHash = val[:src]
85
+ if not srcHash[:file_is].nil?
86
+ TcryptoJava::GConf.instance.glog.debug "Encrypted source is file"
87
+ src = srcHash[:file_is]
88
+ srcLen = srcHash[:file].length if not srcHash[:file].nil?
89
+ elsif not srcHash[:bin_is].nil?
90
+ TcryptoJava::GConf.instance.glog.debug "Encrypted source is memory buffer"
91
+ src = srcHash[:bin_is]
92
+ srcLen = srcHash[:bin].length if not srcHash[:bin].nil?
93
+ else
94
+ raise TcryptoJava::Error, "Source is unknown for long content write"
95
+ end
96
+
97
+ if val[:dest].nil?
98
+ TcryptoJava::GConf.instance.glog.debug "Staging output not given. Internal generation of output."
99
+ if val[:temp_dir].nil? or val[:temp_dir].empty?
100
+ tmpPayloadFile = java.io.File.createTempFile('payload_',nil)
101
+ else
102
+ Tcrypto::GConf.instance.glog.debug "temp_dir is defined: #{val[:temp_dir]}"
103
+ tmpPayloadFile = java.io.File.new(val[:temp_dir],"payload_#{SecureRandom.uuid}.tmp")
104
+ end
105
+
106
+ Tcrypto::GConf.instance.glog.debug "Payload staging temp file created : #{tmpPayloadFile.absolute_path}"
107
+ tmpPayloadFile.deleteOnExit if not val[:auto_remove_staging].nil? and val[:auto_remove_staging]
108
+ os = java.io.FileOutputStream.new(tmpPayloadFile)
109
+ res[:payload_path] = tmpPayloadFile.absolute_path
110
+ else
111
+ if val[:dest].is_a?(java.io.OutputStream)
112
+ TcryptoJava::GConf.instance.glog.debug "Given staging output is an OutputStream. Directly use the object."
113
+ os = val[:dest]
114
+ elsif val[:dest].is_a?(String)
115
+ TcryptoJava::GConf.instance.glog.debug "Staging output gave by application to be at #{val[:dest]}"
116
+ # assume is file path?
117
+ f = java.io.File.new(val[:dest])
118
+ raise TcryptoJava::Error, "Cannot write destination to a directory [#{f.absolute_path}]" if f.is_directory?
119
+ TcryptoJava::GConf.instance.glog.debug "Opening given path #{f.absolute_path} for payload staging"
120
+ os = java.io.FileOutputStream.new(f)
121
+ res[:payload_path] = f.absolute_path
122
+ else
123
+ raise TcryptoJava::Error, "Unsupported staging output #{val[:dest]}"
124
+ end
125
+ end
126
+
127
+ gos = org.bouncycastle.asn1.DERSequenceGenerator.new(os)
128
+ val[:header].each do |h|
129
+ gos.addObject(h)
130
+ end
131
+ gos.getRawOutputStream.flush
132
+
133
+ longOut = org.bouncycastle.asn1.BEROctetStringGenerator.new(gos.getRawOutputStream)
134
+
135
+ srcLen = -1 if srcLen.nil?
136
+
137
+ bufSize = val[:bufSize] || 102400
138
+ outOs = longOut.getOctetOutputStream(Java::byte[bufSize].new)
139
+ buf = Java::byte[bufSize].new
140
+ total = 0
141
+ while((read = src.read(buf,0,buf.length)) != -1)
142
+ if block
143
+ block.call(:before_write, { buf: buf, from: 0, len: read, total: srcLen })
144
+ end
145
+ outOs.write(buf,0,read)
146
+ total += read
147
+ #Tcrypto::GConf.instance.glog.debug "Copied #{read} bytes to final output (Total : #{total})"
148
+ end
149
+
150
+ outOs.flush
151
+ # write the octet string ending tag
152
+ outOs.close
153
+
154
+ # write the sequence ending tag
155
+ gos.close
156
+
157
+ os.close
158
+
159
+ #org.bouncycastle.asn1.BEROctetStringGenerator.new(os)
160
+ #org.bouncycastle.asn1.DERSequenceGenerator.new(os)
161
+ #org.bouncycastle.asn1.DEROutputStream.new(os)
162
+ #org.bouncycastle.asn1.ASN1OutputStream.new(os)
163
+
164
+ res
165
+
166
+ when :long_content_read
167
+ is = val
168
+ raise TcryptoJava::Error, "Long content (read) requires upstream input stream is given." if val.nil?
169
+ raise TcryptoJava::Error, "Given val is not input stream." if not val.is_a?(java.io.InputStream)
170
+
171
+ org.bouncycastle.asn1.ASN1InputStream.new(is)
172
+
173
+ else
174
+ raise TcryptoJava::Error, "Unknown type '#{type}' to encode"
175
+ end
176
+ end
177
+
178
+ def self.encode_timestamp(v = java.util.Calendar.getInstance.time)
179
+ self.encode(:datetime, v)
180
+ end
181
+
182
+ def self.decode(bin)
183
+ ais = org.bouncycastle.asn1.ASN1InputStream.new(bin)
184
+ res = ais.readObject
185
+ if res.is_a?(org.bouncycastle.asn1.DLSequence)
186
+ res = res.to_a
187
+ else
188
+ res
189
+ end
190
+
191
+ res
192
+ end
193
+
194
+ def self.value(tag, opts = { })
195
+ if not tag.nil?
196
+ case tag
197
+ when org.bouncycastle.asn1.ASN1ObjectIdentifier
198
+ tag.id
199
+ when org.bouncycastle.asn1.DEROctetString
200
+ tag.octets
201
+ when org.bouncycastle.asn1.BEROctetString
202
+ tag.octet_stream
203
+ when org.bouncycastle.asn1.ASN1Integer
204
+ tag.value
205
+ when org.bouncycastle.asn1.DLSequence
206
+ tag.to_a
207
+ when org.bouncycastle.asn1.DERUTF8String, org.bouncycastle.asn1.DERPrintableString, org.bouncycastle.asn1.DERVisibleString
208
+ tag.to_s
209
+ when org.bouncycastle.asn1.DERNumericString
210
+ "#{tag.to_i}"
211
+ when org.bouncycastle.asn1.DERUTCTime, org.bouncycastle.asn1.ASN1UTCTime
212
+ tag.adjusted_date
213
+ else
214
+ raise TcryptoJava::Error, "Unknown type '#{tag.class}'"
215
+ end
216
+ end
217
+ end
218
+
219
+ def self.to_string(buf, opts = { })
220
+ if not buf.nil?
221
+ case buf
222
+ when Java::byte[]
223
+ String.from_java_bytes(buf)
224
+ when String
225
+ buf
226
+ else
227
+ raise TcryptoJava::Error, "Unknown type to conver to string #{buf}"
228
+ end
229
+ else
230
+ ""
231
+ end
232
+ end
233
+
234
+ def self.to_bin(out, opts = { })
235
+ self.to_format(out, opts)
236
+ end
237
+
238
+ def self.to_format(out, opts = { })
239
+ if not (out.nil?)
240
+
241
+ case out
242
+ when org.bouncycastle.asn1.ASN1Encodable
243
+
244
+ if not (opts.nil? or opts.empty?)
245
+
246
+ case opts[:to_format]
247
+ when :der
248
+ out.encoded
249
+ when :pem
250
+ when :b64
251
+ else
252
+ out.encoded
253
+ end
254
+ else
255
+ out.encoded
256
+ end
257
+
258
+ when String
259
+ out.to_java.getBytes
260
+ else
261
+ out
262
+ end
263
+
264
+ else
265
+ out
266
+ end
267
+
268
+ end
269
+ # end to_format
270
+
271
+ end
272
+ #
273
+ # end Tcrypto::TagProvider
274
+ #
275
+
276
+ end
@@ -0,0 +1,540 @@
1
+
2
+ require 'pkernel'
3
+ require 'pkernel_jce'
4
+
5
+ require 'gcrypto'
6
+ require 'gcrypto_jce'
7
+
8
+ require 'tcrypto'
9
+
10
+ require_relative 'io_utils'
11
+ require_relative 'global'
12
+
13
+ module TcryptoJava
14
+ module Crypto
15
+
16
+ #
17
+ # encrypt()
18
+ #
19
+ def encrypt(opts = { })
20
+
21
+ rcpts = opts[:recipients]
22
+ if rcpts.nil? or rcpts.empty?
23
+ raise Tcrypto::Error, "No recipients given to encrypt"
24
+ end
25
+
26
+ #
27
+ # Generate session key for encryption
28
+ #
29
+ sessKey = opts[:session_key]
30
+ if sessKey.nil?
31
+ # generate session key...
32
+ cc = Gcrypto::CryptoContext.instance(:aes)
33
+ cc.mode = "GCM"
34
+ cc.random_iv
35
+ cc.random_key
36
+ sessKey = cc
37
+ else
38
+ # TODO: user provided session key?
39
+ TcryptoJava::GConf.instance.glog.error "User given session key is not yet supported."
40
+ cc = Gcrypto::CryptoContext.instance(:aes)
41
+ cc.mode = "GCM"
42
+ cc.random_iv
43
+ cc.random_key
44
+ sessKey = cc
45
+ end
46
+ #
47
+ # session key generated!
48
+ #
49
+
50
+ #
51
+ # Generate session key for data integrity check
52
+ # Security wise, using different key for different purpose
53
+ # has its objectives... So make new key then...
54
+ #
55
+ macKey = Gcrypto::CryptoContext.instance(:aes)
56
+ macKey.mode = "GCM"
57
+ macKey.random_iv
58
+ macKey.random_key
59
+ #
60
+ # MAC session key generated
61
+ #
62
+
63
+ #
64
+ # Create the encrypted key structure for recipients
65
+ #
66
+ keys = []
67
+ keys << Tcrypto::TagProvider.encode(:bin, Gcrypto::SecretKey.dump(sessKey.key))
68
+ keys << Tcrypto::TagProvider.encode(:bin, Gcrypto::SecretKey.dump(macKey.key))
69
+ keysSeq = Tcrypto::TagProvider.encode(:seq, keys)
70
+ keysBin = Tcrypto::TagProvider.to_bin(keysSeq)
71
+ #
72
+
73
+ #
74
+ # Construct recipient list
75
+ #
76
+ rcp = []
77
+ rcpts.each do |re|
78
+ if re.is_a?(Tcrypto::PasswordRecipient) #re.is_a?(String)
79
+ # password
80
+ if re.password.nil? or re.password.empty? or re.challenge.nil? or re.challenge.empty?
81
+ raise Tcrypto::Error, "Challenge and Password must present"
82
+ end
83
+
84
+ pc = Gcrypto::CryptoContext.instance(:aes)
85
+ pc.mode = "GCM"
86
+ pc.derive_key(re.password)
87
+ enc = Gcrypto::SecretKeyCrypto.encrypt({ bin: keysBin, crypto_context: pc })
88
+ rcp << Tcrypto::CryptoHeader::PassRecipient.new(enc,pc,re)
89
+
90
+ elsif Pkernel::Certificate.is_cert_object?(re)
91
+ # X509 certificate
92
+ TcryptoJava::GConf.instance.glog.error "Found certificate recipient"
93
+ #enc = Gcrypto::KeyPairCrypto.encrypt({ bin: Gcrypto::SecretKey.dump(sessKey.key), recipient: re })
94
+ enc = Gcrypto::KeyPairCrypto.encrypt({ bin: keysBin, recipient: re })
95
+ rcp << Tcrypto::CryptoHeader::CertRecipient.new(enc,re)
96
+
97
+ elsif Pkernel::KeyPair.is_public_key?(re)
98
+ # public key
99
+ TcryptoJava::GConf.instance.glog.error "Found public key recipient."
100
+ enc = Gcrypto::KeyPairCrypto.encrypt({ bin: keysBin, recipient: re })
101
+ rcp << Tcrypto::CryptoHeader::PublicKeyRecipient.new(enc,re)
102
+
103
+ elsif re.is_a?(Gcrypto::CryptoContext) #Gcrypto::SecretKey.is_secret_key?(re)
104
+ # crypto context... could be hardware key...
105
+ enc = Gcrypto::SecretKeyCrypto.encrypt({ bin: keysBin, crypto_context: re })
106
+ rcp << Tcrypto::CryptoHeader::SymKeyRecipient.new(enc, re)
107
+
108
+ else
109
+ raise TcryptoJava::Error, "Unknown recipient type #{re.class}"
110
+ end
111
+ end
112
+ #
113
+ # Recipient list done...
114
+ #
115
+
116
+ # check if data signing is defined...
117
+ #sid = opts[:identity]
118
+ #sign = nil
119
+ #if not sid.nil?
120
+ # # data signing activated...
121
+ # sign = Gcrypto::KeyPairCrypto.sign_init({ identity: sid })
122
+ #end
123
+
124
+ #
125
+ # construct parameter to encrypt the payload...
126
+ #
127
+ encPara = { crypto_context: sessKey }
128
+ if not opts[:file].nil?
129
+ encPara[:file] = opts[:file]
130
+ # if input is file, temporary content output also in file
131
+ #encPara[:outFile] = java.io.File.new(java.lang.System.getProperty('java.io.tmpdir'),SecureRandom.uuid).absolute_path
132
+ encPara[:outFile] = java.io.File.createTempFile('enc_',nil).absolute_path
133
+ #encPara[:outFile].deleteOnExit
134
+ elsif not opts[:bin].nil?
135
+ encPara[:bin] = opts[:bin]
136
+ else
137
+ raise Tcrypto::Error, "No input given for tc encryption."
138
+ end
139
+
140
+
141
+ #
142
+ # Initiate keyed-HMAC operation for plain text
143
+ #
144
+ macCtx = Gcrypto::SecretKeyCrypto.sign_init({ crypto_context: macKey })
145
+
146
+ #
147
+ # Encrypt output with session key
148
+ #
149
+ enc = Gcrypto::SecretKeyCrypto.encrypt(encPara) do |ops, para|
150
+
151
+ if ops == :before_enc
152
+ # Sign data along the way if it is defined
153
+ #if not sign.nil?
154
+ # Gcrypto::KeyPairCrypto.sign_update(sign, para)
155
+ #end
156
+
157
+ Gcrypto::SecretKeyCrypto.sign_update(macCtx, para)
158
+ end
159
+
160
+ end
161
+ #
162
+ # data encryption with session key done
163
+ #
164
+
165
+ mac = Gcrypto::SecretKeyCrypto.sign_finalize(macCtx)
166
+ #signature = nil
167
+ #if not sign.nil?
168
+ # signature = Gcrypto::KeyPairCrypto.sign_finalize(sign)
169
+ #end
170
+ #
171
+ # end encryption with session key
172
+ #
173
+
174
+ # recipient shall be in header
175
+ encodePara = { recipients: rcp }
176
+ # signature shall be in header
177
+ #encodePara[:signature] = signature if not signature.nil?
178
+ encodePara[:mac] = mac
179
+ # payload is payload
180
+ if encPara[:outFile].nil?
181
+ encodePara[:payload] = { bin: enc }
182
+ else
183
+ encodePara[:payload] = { file: encPara[:outFile] }
184
+ end
185
+
186
+ # crypto context
187
+ encodePara[:crypto_context] = cc
188
+ encodePara[:mac_context] = macKey
189
+ encodePara[:auto_remove_staging] = opts[:auto_remove_staging]
190
+ encodePara[:temp_dir] = opts[:temp_dir]
191
+ encodePara[:staging_path] = opts[:staging_path]
192
+
193
+ #
194
+ # Setting final completed/combined output destination
195
+ #
196
+ outFile = opts[:outFile]
197
+ if outFile.nil? or outFile.empty?
198
+ out = java.io.ByteArrayOutputStream.new
199
+ else
200
+ Tcrypto::GConf.instance.glog.debug "Setting final combined output file #{outFile}"
201
+ out = java.io.FileOutputStream.new(outFile)
202
+ end
203
+
204
+ # returns header and payload as seperate fields
205
+ res = Tcrypto.encode(:crypto, encodePara, { out: out })
206
+
207
+ if outFile.nil? or outFile.empty?
208
+ res[:bin] = out.toByteArray
209
+ else
210
+ out.flush
211
+ out.close
212
+
213
+ res[:file] = outFile
214
+ end
215
+
216
+ res
217
+ end
218
+ # end encrypt()
219
+
220
+
221
+ # decrypt()
222
+ def decrypt(opts = { }, &block)
223
+
224
+ raise Tcrypto::Error, "No input given for tagged decryption" if opts.nil? or opts.empty?
225
+ is = IoUtils.load_input(opts)
226
+
227
+ #
228
+ # read header section from the input
229
+ #
230
+ header = Tcrypto::CryptoHeaderEngine.decode(is)
231
+ TcryptoJava::GConf.instance.glog.debug "Header decoded successfully"
232
+
233
+ #
234
+ # Read Section 2...
235
+ #
236
+ headerMisc = Tcrypto::CryptoHeaderEngine.decode(is)
237
+ TcryptoJava::GConf.instance.glog.debug "Header misc decoded successfully"
238
+ #
239
+ # Done section 2 is in...
240
+ #
241
+
242
+ # decryption material
243
+ id = opts[:identity]
244
+ raise Tcrypto::Error, "No decryption material given via key :identity" if id.nil?
245
+
246
+ if id.is_a?(Pkernel::Identity)
247
+ idType = :identity
248
+ elsif id.is_a?(Gcrypto::CryptoContext)
249
+ idType = :secret_key
250
+ elsif id.is_a?(Tcrypto::PasswordRecipient) #(String)
251
+ idType = :password
252
+ else
253
+ raise Tcrypto::Error, "Unsupported decryption material #{id}"
254
+ end
255
+
256
+ foundRecp = nil
257
+ header[:recipients].each do |recp|
258
+ if recp[:type] == :crypto_cert_recp and (idType == :identity)
259
+ if id.certificate.nil?
260
+ else
261
+ if Pkernel::Certificate.is_equal?(recp[:cert],id.certificate)
262
+ TcryptoJava::GConf.instance.glog.debug "Given certificate matches cert recp from header"
263
+ foundRecp = recp
264
+ break
265
+ end
266
+ end
267
+ elsif recp[:type] == :crypto_symkey_recp and (idType == :secret_key)
268
+ TcryptoJava::GConf.instance.glog.debug "Given symkey matches symkey recp from header"
269
+ recp[:crypto_context] = id
270
+ foundRecp = recp
271
+ break
272
+ elsif recp[:type] == :crypto_pass_recp and (idType == :password)
273
+ # decode password recipient!
274
+ begin
275
+ if (id.challenge.nil? or id.challenge.empty?)
276
+ if block
277
+ id.challenge = block.call(:prompt_challenge, { })
278
+ else
279
+ raise Tcrypto::Error, "Challenge is not given. Either pass in via Tcrypto::PasswordRecipient or provide a block which response to key :prompt_challenge"
280
+ end
281
+ end
282
+
283
+ recp[:challenge_cc].key = Gcrypto::PBKDF2.derive(id.challenge, recp[:challenge_derive_key])[:key]
284
+ msgId = Gcrypto::SecretKeyCrypto.decrypt({ bin: recp[:challenge_nounce], crypto_context: recp[:challenge_cc] })
285
+ if Tcrypto::TagProvider.to_string(msgId) != header[:message_id]
286
+ raise Tcrypto::Error, "Password recipient challenge failed to be verified!"
287
+ end
288
+ rescue Exception => ex
289
+ if ex.message =~ /Tag mismatch/
290
+ raise Tcrypto::Error, "Password recipient challenge verification failed!"
291
+ else
292
+ raise Tcrypto::Error, ex
293
+ end
294
+ end
295
+
296
+ begin
297
+
298
+ TcryptoJava::GConf.instance.glog.debug "Given password matches challenge from header"
299
+
300
+ if (id.password.nil? or id.password.empty?)
301
+ if block
302
+ id.password = block.call(:prompt_password, { })
303
+ else
304
+ raise Tcrypto::Error, "Password is not given. Either pass in via Tcrypto::PasswordRecipient or provide a block which response to key :prompt_password"
305
+ end
306
+ end
307
+
308
+ derivedKey = Gcrypto::PBKDF2.derive(id.password, recp[:derive_func])
309
+ recp[:crypto_context].key = derivedKey[:key]
310
+ foundRecp = recp
311
+ break
312
+ rescue Exception => ex
313
+ raise Tcrypto::Error, ex
314
+ end
315
+
316
+ end
317
+ end
318
+
319
+ if foundRecp.nil?
320
+ TcryptoJava::GConf.instance.glog.debug "Given identity is not able to decrypt the data or not an intended recipient"
321
+ raise Tcrypto::Error, "Given identity is not able to decrypt the data or not an intended recipient"
322
+ else
323
+
324
+ TcryptoJava::GConf.instance.glog.debug "Given identity is capable to decrypt data."
325
+
326
+ # Ok, eligiable to decrypt... so decrypt the session key...
327
+ case idType
328
+ when :identity
329
+ keysBin = Gcrypto::KeyPairCrypto.decrypt({ enc_bin: foundRecp[:enc_key], identity: id })
330
+ when :password
331
+ keysBin = Gcrypto::SecretKeyCrypto.decrypt({ bin: foundRecp[:enc_key], crypto_context: foundRecp[:crypto_context] })
332
+ when :secret_key
333
+ keysBin = Gcrypto::SecretKeyCrypto.decrypt({ bin: foundRecp[:enc_key], crypto_context: foundRecp[:crypto_context] })
334
+ else
335
+ raise Tcrypto::Error, "Unsupported data decryption type #{idType}"
336
+ end
337
+
338
+ # keysBin has two keys...
339
+ keys = org.bouncycastle.asn1.ASN1InputStream.new(keysBin).readObject.to_a
340
+ # decode the keys
341
+ header[:crypto_context].key = Gcrypto::SecretKey.load({ bin: Tcrypto::TagProvider.value(keys[0]) })
342
+ header[:mac_context].key = Gcrypto::SecretKey.load({ bin: Tcrypto::TagProvider.value(keys[1]) })
343
+
344
+ #
345
+ # read payload section from the input
346
+ #
347
+ Tcrypto::GConf.instance.glog.debug "Loading payload section..."
348
+ payload = Tcrypto::CryptoHeaderEngine.decode(is)
349
+
350
+ #
351
+ # check if the header being changed unauthorised
352
+ #
353
+ if opts[:skip_header_integrity_check].nil? or opts[:skip_header_integrity_check] == false
354
+
355
+ if not (header[:bin].nil? and headerMisc[:header_sign].nil?)
356
+ # verify header signature first...
357
+ sign = Gcrypto::SecretKeyCrypto.sign({ bin: header[:bin], crypto_context: header[:crypto_context] })
358
+ if not java.util.Arrays.equals(sign, headerMisc[:header_sign])
359
+ raise Tcrypto::Error, "Header integrity check failed. The header info has been tampered."
360
+ else
361
+ TcryptoJava::GConf.instance.glog.debug "Header integrity verified!"
362
+ end
363
+ end
364
+
365
+ end
366
+
367
+ ## got session key... proceed decrypt content!
368
+ begin
369
+ mac = Gcrypto::SecretKeyCrypto.verify_init( { crypto_context: header[:mac_context] } )
370
+
371
+ decPara = { crypto_context: header[:crypto_context] , bin: payload[:payload] }
372
+ decPara[:outFile] = opts[:outFile] if not opts[:outFile].nil?
373
+
374
+ plain = Gcrypto::SecretKeyCrypto.decrypt(decPara) do |ops, opts|
375
+ if ops == :after_dec
376
+ Gcrypto::SecretKeyCrypto.verify_update(mac, opts)
377
+ end
378
+ end
379
+
380
+ if not header[:data_sign].nil?
381
+
382
+ match = Gcrypto::SecretKeyCrypto.verify_finalize(mac, { mac: header[:data_sign] })
383
+ TcryptoJava::GConf.instance.glog.debug "Data integrity check status : #{match}"
384
+
385
+ if not match and opts[:skip_data_integrity_check] == true
386
+ # remove the generated output if data integrity failed...
387
+ if not (decPara[:outFile].nil? or decPara[:outFile].empty?)
388
+ java.io.File.new(decPara[:outFile]).delete
389
+ end
390
+
391
+ plain = ""
392
+
393
+ raise Tcrypto::Error, "Original data integrity has compromised!"
394
+ end
395
+
396
+ end
397
+
398
+ if opts[:outFile].nil?
399
+ plain
400
+ end
401
+
402
+ rescue Exception => ex
403
+ raise Tcrypto::Error, "Error decrypting payload. Error was: #{ex.message}. Probably incorrect key?"
404
+ end
405
+
406
+ end
407
+
408
+
409
+ end
410
+ # end decrypt()
411
+
412
+ def Crypto.are_files_equal?(opts = { })
413
+ if not opts.nil? and not opts[:files].nil? and opts[:files].length > 1
414
+
415
+ equal = true
416
+
417
+ prevRes = nil
418
+ opts[:files].each do |f|
419
+ # path expected...
420
+ res = Gcrypto::Digest.generate({ file: f })
421
+ if not prevRes.nil?
422
+ if not java.util.Arrays.is_equals(res, preRes)
423
+ equal = false
424
+ break
425
+ end
426
+ end
427
+ end
428
+
429
+ equal
430
+
431
+ else
432
+ # if nothing sent to me or only single file sent to me
433
+ # then must be true since there would be no comparison
434
+ true
435
+ end
436
+ end
437
+
438
+
439
+ def Crypto.equals?(first, second)
440
+ if first.nil? or second.nil?
441
+ true
442
+ else
443
+ begin
444
+ java.util.Arrays.equals(first,second)
445
+ rescue Exception => ex
446
+ raise TcryptoJava::Error, ex
447
+ end
448
+ end
449
+ end
450
+
451
+ #
452
+ # utilities here is to assist crypto_header encode/decode operations
453
+ #
454
+ def Crypto.to_file(path)
455
+ IoUtils.to_file(path)
456
+ end
457
+
458
+ def Crypto.to_input(buf)
459
+ { bin_is: java.io.ByteArrayInputStream.new(buf), bin: buf }
460
+ end
461
+
462
+ def Crypto.input_length(input)
463
+ if not input[:file].nil?
464
+ input[:file].length
465
+ elsif not input[:bin].nil?
466
+ input[:bin].length
467
+ else
468
+ raise TcryptoJava::Error, "Unknown input for length extraction #{input}"
469
+ end
470
+ end
471
+
472
+ def Crypto.copy_file_to_output(srcFile, output, opts = { }, &block)
473
+ raise TcryptoJava::Error, "Source file cannot be nil or empty" if srcFile.nil? or srcFile.empty?
474
+ raise TcryptoJava::Error, "Output cannot be nil" if output.nil?
475
+
476
+ if srcFile.is_a?(java.io.InputStream)
477
+ src = srcFile
478
+ elsif srcFile.is_a?(String)
479
+ # assume is file path?
480
+ f = java.io.File.new(srcFile)
481
+ raise TcryptoJava::Error, "Cannot read source file from a directory [#{f.absolute_path}]" if f.is_directory?
482
+ raise TcryptoJava::Error, "Given file doesn't exist [#{f.absolute_path}]" if not f.exists
483
+ src = java.io.FileInputStream.new(f)
484
+ else
485
+ raise TcryptoJava::Error, "Unsupported source file type #{srcFile.class}"
486
+ end
487
+
488
+ if output.is_a?(java.io.OutputStream)
489
+ TcryptoJava::GConf.instance.glog.debug "Given output is an OutputStream. Direct use the object."
490
+ os = output
491
+ elsif output.is_a?(String)
492
+ # assume is file path?
493
+ f = java.io.File.new(output)
494
+ raise TcryptoJava::Error, "Cannot write output to a directory [#{f.absolute_path}]" if f.is_directory?
495
+
496
+ TcryptoJava::GConf.instance.glog.debug "Opening given path #{f.absolute_path} to copy file into"
497
+ os = java.io.FileOutputStream.new(f)
498
+
499
+ else
500
+ raise TcryptoJava::Error, "Unsupported destination type #{val[:dest].class}"
501
+ end
502
+
503
+ bufSize = opts[:bufSize] || 102400
504
+ b = Java::byte[bufSize].new
505
+ while((read = src.read(b,0,b.length)) != -1)
506
+ if block
507
+ block.call(:before_write, { buf: b, from: 0, len: read })
508
+ end
509
+
510
+ os.write(b,0,read)
511
+ end
512
+
513
+ end
514
+
515
+ def Crypto.load_file_into_memory(file, opts = { }, &block)
516
+ raise TcryptoJava::Error, "No file given" if file.nil?
517
+ f = java.io.File.new(file)
518
+ raise TcryptoJava::Error, "Given file #{f.absolute_path} does not exist" if not f.exists
519
+ raise TcryptoJava::Error, "Given file #{f.absolute_path} is a directory" if f.directory?
520
+
521
+ total = f.length
522
+ bufSize = opts[:bufSize] || 102400
523
+ b = Java::byte[bufSize].new
524
+ baos = java.io.ByteArrayOutputStream.new
525
+ processed = 0
526
+ fis = java.io.FileInputStream.new(f)
527
+ while((read = fis.read(b,0,b.length)) != -1)
528
+ baos.write(b,0,read)
529
+ processed += read
530
+
531
+ block.call(:progress, { total: total, processed: processed }) if block
532
+ end
533
+
534
+ baos.toByteArray
535
+
536
+ end
537
+ # end utilities
538
+
539
+ end
540
+ end
@@ -0,0 +1,27 @@
1
+
2
+ require 'singleton'
3
+ require 'tlogger'
4
+
5
+ module TcryptoJava
6
+ class GConf
7
+ include Singleton
8
+ attr_reader :logger_params, :glog
9
+ def initialize
10
+ @logger_params = STDOUT
11
+ @glog = Tlogger.new(STDOUT)
12
+ @glog.tag = :tcrypto_java
13
+ @glog.show_source
14
+ end
15
+
16
+ def java_version
17
+ if @java_ver.nil?
18
+ @java_ver = ENV_JAVA['java.version']
19
+ end
20
+
21
+ @java_ver
22
+ end
23
+ end
24
+ end
25
+
26
+
27
+
@@ -0,0 +1,135 @@
1
+
2
+ require_relative 'global'
3
+ require 'active_support'
4
+ class NumberHelper
5
+ extend ActiveSupport::NumberHelper
6
+ end
7
+
8
+
9
+ module TcryptoJava
10
+ module IoUtils
11
+
12
+ def IoUtils.load_input(opts = { })
13
+ if opts.nil? or opts.empty?
14
+ raise TcryptoJava::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 => e
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 TcryptoJava::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 TcryptoJava::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.to_file(path)
59
+
60
+ raise Tcrypto::Error, "Given path to convert to file object is nil or empty" if path.nil? or path.empty?
61
+
62
+ file = java.io.File.new(path)
63
+ raise Tcrypto::Error, "Given input file not available [#{file.absolute_path}]" if not file.exists
64
+ raise Tcrypto::Error, "Given file path is a directory [#{file.absolute_path}]" if file.is_directory?
65
+
66
+ src = java.io.FileInputStream.new(file)
67
+
68
+ res = { file: file, file_is: src }
69
+ res
70
+ end
71
+
72
+ def IoUtils.return_if_buffer(os)
73
+ if os.java_kind_of?(java.io.ByteArrayOutputStream)
74
+ os.toByteArray
75
+ end
76
+ end
77
+
78
+ def IoUtils.read_chunk(is, opts = { },&block)
79
+
80
+ raise TcryptoJava::Error, "Cannot read chunk from nil input stream" if is.nil?
81
+ raise TcryptoJava::Error, "Block required for read_chunk" if not block
82
+
83
+ if not is.java_kind_of?(java.io.InputStream)
84
+ raise TcryptoJava::Error, "Cannot read from '#{is.class}' object"
85
+ end
86
+
87
+ bufLen = opts[:buffer_size] || 1024*1024
88
+ TcryptoJava::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"
89
+
90
+ b = Java::byte[bufLen].new
91
+ while((read = is.read(b,0,b.length)) != -1)
92
+ block.call(b,0,read)
93
+ end
94
+ end
95
+ #
96
+ # end read_chunk
97
+ #
98
+
99
+ def IoUtils.file_to_memory_byte_array(path)
100
+ if path.nil? or path.empty?
101
+ raise TcryptoJava::Error, "Given path '#{path}' to load to memory is nil or empty"
102
+ else
103
+ f = java.io.File.new(path)
104
+ b = Java::byte[f.length].new
105
+ dis = java.io.DataInputStream.new(java.io.FileInputStream.new(f))
106
+ dis.readFully(b)
107
+ dis.close
108
+
109
+ b
110
+ end
111
+ end
112
+ # end file_to_memory_byte_array
113
+ #
114
+
115
+ def IoUtils.ensure_java_bytes(bin)
116
+ if not bin.java_kind_of?(Java::byte[])
117
+ bin.to_java_bytes
118
+ else
119
+ bin
120
+ end
121
+ end
122
+ # end ensure_java_bytes
123
+ #
124
+
125
+ def IoUtils.attempt_zeroise(var)
126
+ java.util.Arrays.fill(var, 0)
127
+ end
128
+ end
129
+ # end IoUtils
130
+ #
131
+
132
+ end
133
+ # end GcryptoJce
134
+ #
135
+
@@ -0,0 +1,3 @@
1
+ module TcryptoJava
2
+ VERSION = "0.1"
3
+ end
data/release.job ADDED
@@ -0,0 +1,53 @@
1
+
2
+
3
+ job :release do
4
+
5
+ include_job :prompt_version
6
+ #ver = prompt "Please provide version for this release:", required: true
7
+ #set :releasing_version, ver
8
+
9
+ include_job :build
10
+ include_job :check_in
11
+
12
+ end
13
+
14
+ job :prompt_version do
15
+ if get(:releasing_version) == nil
16
+ ver = prompt "Please provide version for this release:", required: true
17
+ set :releasing_version, ver
18
+ end
19
+ end
20
+
21
+ job :build do
22
+
23
+ dir File.dirname(__FILE__)
24
+
25
+ include_job :prompt_version
26
+
27
+ rubygem do
28
+ #publish build('alog.gemspec'), ignore_status: true #do |res|
29
+ build('tcrypto_java.gemspec') do |res|
30
+ publish(res, ignore_status: true)
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+
37
+ job :check_in do
38
+ dir File.dirname(__FILE__)
39
+ git do
40
+ commit
41
+ tag
42
+ push 'origin', 'master'
43
+ #push 'git','master'
44
+ end
45
+ end
46
+
47
+ job :reinstall do
48
+ rubygem do
49
+ uninstall 'tcrypto_java'
50
+ install 'tcrypto_java'
51
+ end
52
+ end
53
+
@@ -0,0 +1,31 @@
1
+ require_relative 'lib/tcrypto_java/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "tcrypto_java"
5
+ spec.version = TcryptoJava::VERSION
6
+ spec.authors = ["Chris Liaw"]
7
+ spec.email = ["chrisliaw@antrapol.com"]
8
+
9
+ spec.summary = %q{}
10
+ spec.description = %q{}
11
+ spec.homepage = ""
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
16
+ #
17
+ # spec.metadata["homepage_uri"] = spec.homepage
18
+ # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
19
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency 'tlogger'
31
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tcrypto_java
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Chris Liaw
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-03-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tlogger
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: ''
28
+ email:
29
+ - chrisliaw@antrapol.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - Gemfile
36
+ - Gemfile.lock
37
+ - LICENSE.txt
38
+ - README.md
39
+ - Rakefile
40
+ - bin/console
41
+ - bin/setup
42
+ - lib/tcrypto_java.rb
43
+ - lib/tcrypto_java/crypto.rb
44
+ - lib/tcrypto_java/global.rb
45
+ - lib/tcrypto_java/io_utils.rb
46
+ - lib/tcrypto_java/version.rb
47
+ - release.job
48
+ - tcrypto_java.gemspec
49
+ homepage: ''
50
+ licenses:
51
+ - MIT
52
+ metadata: {}
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 2.3.0
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 2.7.6
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: ''
73
+ test_files: []