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 +7 -0
- data/.gitignore +11 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +66 -0
- data/LICENSE.txt +21 -0
- data/README.md +40 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/tcrypto_java.rb +276 -0
- data/lib/tcrypto_java/crypto.rb +540 -0
- data/lib/tcrypto_java/global.rb +27 -0
- data/lib/tcrypto_java/io_utils.rb +135 -0
- data/lib/tcrypto_java/version.rb +3 -0
- data/release.job +53 -0
- data/tcrypto_java.gemspec +31 -0
- metadata +73 -0
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
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
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
data/lib/tcrypto_java.rb
ADDED
@@ -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
|
+
|
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: []
|