tcrypto_java 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.
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: []