tcrypto_java 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|