ccipher_box 0.1.0
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/.rspec +3 -0
- data/Gemfile +35 -0
- data/Gemfile.lock-java +89 -0
- data/Gemfile.lock-ruby +91 -0
- data/README.md +35 -0
- data/Rakefile +10 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ccipher_box.gemspec +47 -0
- data/lib/ccipher_box/bin_struct.rb +167 -0
- data/lib/ccipher_box/binenc_constant.rb +38 -0
- data/lib/ccipher_box/decryption_engine.rb +74 -0
- data/lib/ccipher_box/enc_key_config.rb +78 -0
- data/lib/ccipher_box/encryption_engine.rb +77 -0
- data/lib/ccipher_box/keybox.rb +147 -0
- data/lib/ccipher_box/mem_key.rb +394 -0
- data/lib/ccipher_box/mem_vault.rb +93 -0
- data/lib/ccipher_box/secure_box.rb +299 -0
- data/lib/ccipher_box/secure_ring.rb +129 -0
- data/lib/ccipher_box/version.rb +5 -0
- data/lib/ccipher_box.rb +28 -0
- data/run_test.rb +27 -0
- metadata +148 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module CcipherBox
|
5
|
+
#
|
6
|
+
# Meant to encrypt large data
|
7
|
+
#
|
8
|
+
class EncryptionEngine
|
9
|
+
include TR::CondUtils
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
@keys = args
|
13
|
+
end
|
14
|
+
|
15
|
+
def init(output)
|
16
|
+
raise CcipherBox::Error, "Output is mandatory" if output.nil?
|
17
|
+
|
18
|
+
@output = output
|
19
|
+
@baseMat = SecureRandom.random_bytes(256/8)
|
20
|
+
@sk = CcipherFactory::SymKeyGenerator.derive(:aes, 256) do |ops|
|
21
|
+
case ops
|
22
|
+
when :password
|
23
|
+
@baseMat
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@intOut = Tempfile.new
|
28
|
+
|
29
|
+
@cipher = CcipherFactory::SymKeyCipher.encryptor
|
30
|
+
@cipher.output(@intOut)
|
31
|
+
@cipher.key = @sk
|
32
|
+
@cipher.encrypt_init
|
33
|
+
end
|
34
|
+
|
35
|
+
def update(data)
|
36
|
+
@cipher.encrypt_update(data)
|
37
|
+
end
|
38
|
+
|
39
|
+
def final(&block)
|
40
|
+
header = @cipher.encrypt_final
|
41
|
+
|
42
|
+
st = BinStruct.instance.struct(:ccipherbox_cipher)
|
43
|
+
st.keyConfig = @sk.encoded
|
44
|
+
|
45
|
+
encBaseMat = []
|
46
|
+
@keys.each do |k|
|
47
|
+
#logger.debug "Encrypt with key #{k.name}"
|
48
|
+
encBaseMat << k.encrypt(@baseMat)
|
49
|
+
end
|
50
|
+
st.baseMaterial = encBaseMat
|
51
|
+
|
52
|
+
st.cipherConfig = header
|
53
|
+
aheader = st.encoded
|
54
|
+
|
55
|
+
@output.write(aheader)
|
56
|
+
|
57
|
+
@intOut.rewind
|
58
|
+
while not @intOut.eof?
|
59
|
+
@output.write(@intOut.read)
|
60
|
+
end
|
61
|
+
|
62
|
+
@intOut.close
|
63
|
+
@intOut.delete
|
64
|
+
|
65
|
+
aheader
|
66
|
+
end
|
67
|
+
|
68
|
+
def logger
|
69
|
+
if @logger.nil?
|
70
|
+
@logger = TeLogger::Tlogger.new
|
71
|
+
@logger.tag = :enc_eng
|
72
|
+
end
|
73
|
+
@logger
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
|
2
|
+
require 'ccipher_factory'
|
3
|
+
|
4
|
+
module CcipherBox
|
5
|
+
|
6
|
+
# Abstraction of deriving a key from a given base key (baseMat)
|
7
|
+
# and the Key Derivation Function (KDF).
|
8
|
+
# With the two inputs, a derive key would be provided via dkey() API
|
9
|
+
class Keybox
|
10
|
+
include TR::CondUtils
|
11
|
+
|
12
|
+
attr_accessor :outBitLength, :kdf, :baseMat
|
13
|
+
|
14
|
+
def initialize(kdfEngine = nil)
|
15
|
+
raise KeyboxException, "Instance of KDF engine (CcipherFactory::KDF::KDFEngine) required" if not_empty?(kdfEngine) and not kdfEngine.is_a?(CcipherFactory::KDF::KDFEngine)
|
16
|
+
|
17
|
+
@kdfEng = kdfEngine
|
18
|
+
if not @kdfEng.nil?
|
19
|
+
@kdfOut = MemBuf.new
|
20
|
+
@kdfEng.output(@kdfOut)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.from_encoded(bin)
|
25
|
+
|
26
|
+
raise KeyboxException, "Given binary is empty" if is_empty?(bin)
|
27
|
+
|
28
|
+
st = BinStruct.instance.struct_from_bin(bin)
|
29
|
+
kdfEng = CcipherFactory::KDF.from_encoded(st.kdfConfig)
|
30
|
+
Keybox.new(kdfEng)
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def baseMat=(val)
|
35
|
+
|
36
|
+
case val
|
37
|
+
when CcipherFactory::SymKey
|
38
|
+
# taking the key value only will still can get
|
39
|
+
# derived key correctly even if the key type and size
|
40
|
+
# has changed. For example change from Blowfish to AES
|
41
|
+
# will not resulted in a different value
|
42
|
+
#
|
43
|
+
# Decided to take only the raw key value to allow
|
44
|
+
# flexibility at upper application to change from a
|
45
|
+
# symmetric algo to another, since the objective of this
|
46
|
+
# class is just to get a derived raw key, not SymKey object
|
47
|
+
@baseMat = val.key
|
48
|
+
|
49
|
+
# taking the encoded value however from symkey
|
50
|
+
# will make the base key sensitive to meta data changes,
|
51
|
+
# from key type, size, KDF config changes all will affect
|
52
|
+
# final result
|
53
|
+
#@baseMat = val.encoded
|
54
|
+
#when String
|
55
|
+
# test for String will means need a mechanism to test for Java::byte[]
|
56
|
+
# which is not yet there
|
57
|
+
# @baseMat = val
|
58
|
+
else
|
59
|
+
@baseMat = val
|
60
|
+
#raise KeyboxException, "Unsupported base material type '#{val}'"
|
61
|
+
end
|
62
|
+
|
63
|
+
@dkeyVal = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def dkey
|
67
|
+
|
68
|
+
if @dkeyVal.nil?
|
69
|
+
|
70
|
+
raise KeyboxException, "BaseMat not given" if is_empty?(@baseMat)
|
71
|
+
|
72
|
+
kdfEng.derive_update(@baseMat)
|
73
|
+
|
74
|
+
@kdfConfig = kdfEng.derive_final
|
75
|
+
|
76
|
+
@dkeyVal = @kdfOut.bytes.clone
|
77
|
+
@kdfOut.dispose
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
@dkeyVal
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
def encoded
|
86
|
+
st = BinStruct.instance.struct(:keybox)
|
87
|
+
st.kdfConfig = @kdfConfig
|
88
|
+
st.encoded
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
def kdfEng
|
93
|
+
|
94
|
+
if @kdfEng.nil?
|
95
|
+
|
96
|
+
raise KeyboxException, "OutBitLength is not given" if is_empty?(@outBitLength)
|
97
|
+
|
98
|
+
if @kdf.nil?
|
99
|
+
|
100
|
+
# random KDF
|
101
|
+
rEng = [:scrypt, :hkdf, :pbkdf2].sample
|
102
|
+
logger.debug "Random KDF : #{rEng}"
|
103
|
+
@kdfEng = CcipherFactory::KDF.instance(rEng)
|
104
|
+
@kdfEng.outByteLength = @outBitLength/8
|
105
|
+
|
106
|
+
@kdfOut = MemBuf.new
|
107
|
+
@kdfEng.output(@kdfOut)
|
108
|
+
@kdfEng.derive_init
|
109
|
+
|
110
|
+
else
|
111
|
+
|
112
|
+
case @kdf
|
113
|
+
when :scrypt, :hkdf, :pbkdf2
|
114
|
+
logger.debug "Given KDF : #{@kdf}"
|
115
|
+
@kdfEng = CcipherFactory::KDF.instance(@kdf)
|
116
|
+
@kdfEng.outByteLength = @outBitLength/8
|
117
|
+
else
|
118
|
+
raise KeyboxException, "Unknown KDF engine '#{@kdf}' requested"
|
119
|
+
end
|
120
|
+
|
121
|
+
@kdfOut = MemBuf.new
|
122
|
+
@kdfEng.output(@kdfOut)
|
123
|
+
@kdfEng.derive_init
|
124
|
+
|
125
|
+
end # @kdf.nil?
|
126
|
+
|
127
|
+
end # kdfEng.nil?
|
128
|
+
|
129
|
+
@kdfEng
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.logger
|
134
|
+
if @logger.nil?
|
135
|
+
@logger = TeLogger::Tlogger.new
|
136
|
+
@logger.tag = :keybox
|
137
|
+
end
|
138
|
+
@logger
|
139
|
+
end
|
140
|
+
|
141
|
+
def logger
|
142
|
+
self.class.logger
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
@@ -0,0 +1,394 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module CcipherBox
|
4
|
+
|
5
|
+
#
|
6
|
+
# Actual data encryption key that is encrypted in memory
|
7
|
+
# This class represents a single encryption key
|
8
|
+
#
|
9
|
+
class MemKey
|
10
|
+
include TR::CondUtils
|
11
|
+
|
12
|
+
class MemKeyException < Exception; end
|
13
|
+
|
14
|
+
attr_accessor :name, :ring
|
15
|
+
|
16
|
+
def initialize(ring, key, name = nil)
|
17
|
+
@dataConv = Ccrypto::UtilFactory.instance(:data_conversion)
|
18
|
+
@dataComp = Ccrypto::UtilFactory.instance(:comparator)
|
19
|
+
self.ring = ring
|
20
|
+
self.key = key
|
21
|
+
self.name = name
|
22
|
+
|
23
|
+
@activateCount = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def key=(val)
|
27
|
+
generateKeyID(val)
|
28
|
+
@key = mem_seal(val)
|
29
|
+
end
|
30
|
+
|
31
|
+
def keyID
|
32
|
+
@keyID
|
33
|
+
end
|
34
|
+
|
35
|
+
# keyID is stored as binary in the structure
|
36
|
+
# but was used as Hex value at application level
|
37
|
+
def self.to_KeyID(val)
|
38
|
+
Ccrypto::UtilFactory.instance(:data_conversion).to_hex(val)
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Encrypt by this key is generally consider key wrap
|
43
|
+
# therefore data is not expected to be very big.
|
44
|
+
#
|
45
|
+
# This is not really going to encrypt the actual data
|
46
|
+
# since there might have multiple key involved during
|
47
|
+
# data protection
|
48
|
+
#
|
49
|
+
def encrypt(data, &block)
|
50
|
+
|
51
|
+
if block
|
52
|
+
algo = block.call(:symkey_algo)
|
53
|
+
keysize = block.call(:symkey_length)
|
54
|
+
mode = block.call(:symkey_mode)
|
55
|
+
output = block.call(:output)
|
56
|
+
end
|
57
|
+
|
58
|
+
algo = :aes if is_empty?(algo)
|
59
|
+
keysize = 256 if is_empty?(keysize)
|
60
|
+
mode = :gcm if is_empty?(mode)
|
61
|
+
output = :binary if is_empty?(output)
|
62
|
+
|
63
|
+
key = mem_unseal(@key)
|
64
|
+
case key
|
65
|
+
when CcipherFactory::SymKey
|
66
|
+
sk = key
|
67
|
+
else
|
68
|
+
sk = CcipherFactory::SymKeyGenerator.derive(algo, keysize) do |k|
|
69
|
+
case k
|
70
|
+
when :password
|
71
|
+
key
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@activateCount += 1
|
77
|
+
# refresh the in-memory encryption
|
78
|
+
if @activateCount > 5
|
79
|
+
logger.debug "Seal refresh during encrypt ops"
|
80
|
+
@key = mem_seal(@key)
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
membuf = MemBuf.new
|
85
|
+
enc = CcipherFactory::SymKeyCipher.att_encryptor
|
86
|
+
enc.key = sk
|
87
|
+
enc.mode = mode
|
88
|
+
|
89
|
+
enc.output(membuf)
|
90
|
+
enc.att_encrypt_init
|
91
|
+
enc.att_encrypt_update(data)
|
92
|
+
enc.att_encrypt_final
|
93
|
+
|
94
|
+
encOut = membuf.bytes.clone
|
95
|
+
membuf.dispose
|
96
|
+
|
97
|
+
st = BinStruct.instance.struct(:ccipherbox_keywrap)
|
98
|
+
st.keyid = @dataConv.from_hex(self.keyID)
|
99
|
+
sk.attach_mode
|
100
|
+
st.keyConfig = sk.encoded
|
101
|
+
st.cipher = encOut
|
102
|
+
res = st.encoded
|
103
|
+
|
104
|
+
case output
|
105
|
+
when :hex
|
106
|
+
@dataConv.to_hex(res)
|
107
|
+
when :b64
|
108
|
+
@dataConv.to_b64(res)
|
109
|
+
else
|
110
|
+
res
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
def decrypt(bin, &block)
|
116
|
+
|
117
|
+
st = BinStruct.instance.struct_from_bin(bin)
|
118
|
+
st.keyid = @dataConv.to_hex(st.keyid)
|
119
|
+
|
120
|
+
raise MemKeyException, "Given data to decrypt is not cipher envelope" if CBTag.value_constant(st.oid) != :ccipherbox_keywrap
|
121
|
+
raise MemKeyException, "Give cipher envelope is not meant for this key. Current key ID '#{self.keyID}' and key ID inside envelope '#{st.keyid}'" if not @dataComp.is_equals?(self.keyID, st.keyid)
|
122
|
+
|
123
|
+
case @key
|
124
|
+
when CcipherFactory::SymKey
|
125
|
+
sk = @key
|
126
|
+
else
|
127
|
+
sk = CcipherFactory::SymKey.from_encoded(st.keyConfig) do |k|
|
128
|
+
case k
|
129
|
+
when :password
|
130
|
+
mem_unseal(@key)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
@activateCount += 1
|
136
|
+
# refresh the in-memory protection
|
137
|
+
if @activateCount > 5
|
138
|
+
logger.debug "Seal refresh during decrypt ops"
|
139
|
+
@key = mem_seal(@key)
|
140
|
+
end
|
141
|
+
|
142
|
+
membuf = MemBuf.new
|
143
|
+
dec = CcipherFactory::SymKeyCipher.att_decryptor
|
144
|
+
dec.key = sk
|
145
|
+
|
146
|
+
dec.output(membuf)
|
147
|
+
dec.att_decrypt_init
|
148
|
+
dec.att_decrypt_update(st.cipher)
|
149
|
+
dec.att_decrypt_final
|
150
|
+
|
151
|
+
plain = membuf.bytes.clone
|
152
|
+
membuf.dispose
|
153
|
+
|
154
|
+
if block
|
155
|
+
output = block.call(:output)
|
156
|
+
end
|
157
|
+
output = :binary if is_empty?(output)
|
158
|
+
|
159
|
+
case output
|
160
|
+
when :hex
|
161
|
+
@dataConv.to_hex(plain)
|
162
|
+
when :b64
|
163
|
+
@dataConv.to_b64(plain)
|
164
|
+
else
|
165
|
+
plain
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
#def derive(algo = :script)
|
171
|
+
# kb = Keybox.new(algo)
|
172
|
+
# kb.baseMat = mem_unseal(@key)
|
173
|
+
# kb
|
174
|
+
#end
|
175
|
+
|
176
|
+
#def encoded
|
177
|
+
# st = BinStruct.instance.struct(:mem_key)
|
178
|
+
# st.value = mem_unseal(@key)
|
179
|
+
# st.encoded
|
180
|
+
#end
|
181
|
+
|
182
|
+
def plain_key
|
183
|
+
mem_unseal(@key)
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
# Encrypt the actual key resides in memory
|
188
|
+
def mem_seal(key)
|
189
|
+
|
190
|
+
supported = CcipherFactory::SymKeyGenerator.supported_symkey
|
191
|
+
symAlgo = supported.keys
|
192
|
+
# randomly select which algo to start for in memory protection
|
193
|
+
startIndx = rand(0..symAlgo.length-1)
|
194
|
+
loopCnt = 0
|
195
|
+
|
196
|
+
logger.debug "Total supported symkey algo : #{symAlgo.length}"
|
197
|
+
|
198
|
+
indx = startIndx
|
199
|
+
|
200
|
+
#case key
|
201
|
+
#when CcipherFactory::SoftSymKey
|
202
|
+
# logger.debug "Given key to seal is Soft SymKey"
|
203
|
+
# payload = key.key.key
|
204
|
+
#when CcipherFactory::DerivedSymKey
|
205
|
+
# logger.debug "Given key to seal is Derived SymKey"
|
206
|
+
# payload = key.key
|
207
|
+
#else
|
208
|
+
# logger.debug "Given key to seal is native key"
|
209
|
+
# payload = key
|
210
|
+
#end
|
211
|
+
|
212
|
+
case key
|
213
|
+
when CcipherFactory::SymKey
|
214
|
+
logger.debug "Given key to seal is SymKey #{key.class}"
|
215
|
+
payload = key.raw_key
|
216
|
+
else
|
217
|
+
logger.debug "Given key to seal is native key"
|
218
|
+
payload = key
|
219
|
+
end
|
220
|
+
|
221
|
+
loop do
|
222
|
+
|
223
|
+
algo = symAlgo[indx]
|
224
|
+
ks = supported[algo][:keysize][-1]
|
225
|
+
mode = supported[algo][:mode][-1]
|
226
|
+
|
227
|
+
logger.debug "Utilizing symkey at index : #{indx} - #{algo}/#{ks}/#{mode}"
|
228
|
+
sk = CcipherFactory::SymKeyGenerator.generate(algo, ks)
|
229
|
+
|
230
|
+
#logger.debug "Generated key #{loopCnt} : #{sk.inspect}"
|
231
|
+
|
232
|
+
enc = CcipherFactory::SymKeyCipher.att_encryptor
|
233
|
+
enc.key = sk
|
234
|
+
enc.mode = mode
|
235
|
+
|
236
|
+
membuf = MemBuf.new
|
237
|
+
enc.output(membuf)
|
238
|
+
|
239
|
+
enc.att_encrypt_init
|
240
|
+
enc.att_encrypt_update(payload)
|
241
|
+
enc.att_encrypt_final
|
242
|
+
|
243
|
+
sk.attach_mode
|
244
|
+
encRes = membuf.bytes.clone
|
245
|
+
membuf.dispose
|
246
|
+
|
247
|
+
#logger.debug "Encrypted #{loopCnt} : #{encRes.inspect}"
|
248
|
+
|
249
|
+
st = BinStruct.instance.struct(:mem_key_layer)
|
250
|
+
st.material = sk.encoded
|
251
|
+
st.payload = encRes
|
252
|
+
payload = st.encoded
|
253
|
+
|
254
|
+
indx = ((indx+1) % symAlgo.length)
|
255
|
+
|
256
|
+
loopCnt += 1
|
257
|
+
break if loopCnt >= symAlgo.length
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
kkey = CcipherFactory::SymKeyGenerator.derive(:aes, 256) do |k|
|
262
|
+
case k
|
263
|
+
when :password
|
264
|
+
case key
|
265
|
+
when CcipherFactory::SoftSymKey
|
266
|
+
# SymKey -> Ccrypto::SecretKey -> raw key
|
267
|
+
key.key.key
|
268
|
+
when CcipherFactory::DerivedSymKey
|
269
|
+
key.key
|
270
|
+
else
|
271
|
+
key
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
st = BinStruct.instance.struct(:mem_key_envp)
|
277
|
+
|
278
|
+
kcv = CcipherFactory::KCV.new
|
279
|
+
kcv.key = kkey
|
280
|
+
|
281
|
+
st.kcv = kcv.encoded
|
282
|
+
st.kcvconfig = kkey.encoded
|
283
|
+
st.layer = payload
|
284
|
+
st.encoded
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
# Decrypt the in-memory protected key for operational
|
289
|
+
def mem_unseal(env)
|
290
|
+
|
291
|
+
begin
|
292
|
+
|
293
|
+
sti = BinStruct.instance.struct_from_bin(env)
|
294
|
+
|
295
|
+
payload = sti.layer
|
296
|
+
|
297
|
+
loop do
|
298
|
+
|
299
|
+
st = BinStruct.instance.struct_from_bin(payload)
|
300
|
+
|
301
|
+
break if st.nil?
|
302
|
+
|
303
|
+
key = CcipherFactory::SymKey.from_encoded(st.material)
|
304
|
+
#logger.debug "Unseal found : #{key.inspect}"
|
305
|
+
|
306
|
+
encData = st.payload
|
307
|
+
|
308
|
+
dec = CcipherFactory::SymKeyCipher.att_decryptor
|
309
|
+
|
310
|
+
membuf = MemBuf.new
|
311
|
+
dec.output(membuf)
|
312
|
+
|
313
|
+
dec.key = key
|
314
|
+
dec.att_decrypt_init
|
315
|
+
dec.att_decrypt_update(encData)
|
316
|
+
dec.att_decrypt_final
|
317
|
+
|
318
|
+
payload = membuf.bytes.clone
|
319
|
+
membuf.dispose
|
320
|
+
|
321
|
+
#logger.debug "Decrypted payload : #{payload.inspect}"
|
322
|
+
|
323
|
+
end
|
324
|
+
rescue Binenc::BinencDecodingError => ex
|
325
|
+
rescue Binenc::BinencEngineException => ex
|
326
|
+
#STDERR.puts ex.message
|
327
|
+
end
|
328
|
+
|
329
|
+
#begin
|
330
|
+
# dkey = CcipherFactory::SymKey.from_encoded(payload)
|
331
|
+
#rescue Binenc::BinencDecodingError => ex
|
332
|
+
payload
|
333
|
+
#end
|
334
|
+
|
335
|
+
end
|
336
|
+
|
337
|
+
def generateKeyID(key)
|
338
|
+
|
339
|
+
if @keyID.nil?
|
340
|
+
|
341
|
+
if key.is_a?(CcipherFactory::SymKey)
|
342
|
+
sk = key
|
343
|
+
else
|
344
|
+
sk = CcipherFactory::SymKeyGenerator.derive(:aes, 256) do |k|
|
345
|
+
case k
|
346
|
+
when :password
|
347
|
+
key
|
348
|
+
when :kdf
|
349
|
+
:scrypt
|
350
|
+
when :kdf_scrypt_cost
|
351
|
+
65536
|
352
|
+
when :kdf_scrypt_parallel
|
353
|
+
1
|
354
|
+
when :kdf_scrypt_blocksize
|
355
|
+
8
|
356
|
+
when :kdf_scrypt_salt
|
357
|
+
@dataConv.from_hex("FEDCBA0123456789")
|
358
|
+
when :kdf_scrypt_digestAlgo
|
359
|
+
:sha3_256
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
kcv = CcipherFactory::KCV.new
|
365
|
+
kcv.key = sk
|
366
|
+
kcv.nonce = "8"*32
|
367
|
+
kcvBin = kcv.encoded do |k|
|
368
|
+
case k
|
369
|
+
when :kcv_cipher_iv
|
370
|
+
# given key (sk) is AES key with GCM mode (default if mode not given)
|
371
|
+
# therefore the IV size has to be 12
|
372
|
+
# Other algo this must be adjusted accordingly
|
373
|
+
"1A2B3C4D5E6F"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
@keyID = @dataConv.to_hex(kcvBin)
|
378
|
+
end
|
379
|
+
|
380
|
+
@keyID
|
381
|
+
|
382
|
+
end
|
383
|
+
|
384
|
+
|
385
|
+
def logger
|
386
|
+
if @logger.nil?
|
387
|
+
@logger = TeLogger::Tlogger.new
|
388
|
+
@logger.tag = :mem_key
|
389
|
+
end
|
390
|
+
@logger
|
391
|
+
end
|
392
|
+
|
393
|
+
end
|
394
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
|
2
|
+
require_relative 'bin_struct'
|
3
|
+
|
4
|
+
require_relative 'mem_key'
|
5
|
+
|
6
|
+
module CcipherBox
|
7
|
+
|
8
|
+
# Collection of crypto keys in a vault to be used by application.
|
9
|
+
# Application can register a key that tie with a name here
|
10
|
+
# and later use the name to encrypt a data
|
11
|
+
# This only store keys that will be kept in memory
|
12
|
+
# Not meant to be persistance
|
13
|
+
class MemVault
|
14
|
+
include TR::CondUtils
|
15
|
+
|
16
|
+
class MemVaultException < Exception; end
|
17
|
+
|
18
|
+
def initialize(ringName)
|
19
|
+
@ringName = ringName
|
20
|
+
end
|
21
|
+
|
22
|
+
def register(name, key)
|
23
|
+
@dataConv = Ccrypto::UtilFactory.instance(:data_conversion)
|
24
|
+
vault[name] = MemKey.new(@ringName, key, name)
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def deregister(name)
|
29
|
+
vault.delete(name)
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def is_registered?(name)
|
34
|
+
vault.keys.include?(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def encrypt(name, data, &block)
|
38
|
+
key = vault[name]
|
39
|
+
key.encrypt(data, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def decrypt(cipher)
|
43
|
+
keyID = BinStruct.instance.struct_fields_from_bin(cipher, 2)[0]
|
44
|
+
keyID = MemKey.to_KeyID(keyID)
|
45
|
+
|
46
|
+
foundKey = nil
|
47
|
+
vault.values.each do |k|
|
48
|
+
if k.keyID == keyID
|
49
|
+
foundKey = k
|
50
|
+
break
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if not_empty?(foundKey)
|
55
|
+
logger.debug "Found decryption key with label #{vault.invert[foundKey]}"
|
56
|
+
foundKey.decrypt(cipher)
|
57
|
+
else
|
58
|
+
raise KeyNotRegistered, "Encryption key for this cipher not registered (KeyID : #{keyID})"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def derive(name)
|
64
|
+
vault[name].derive
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_key(name)
|
68
|
+
vault[name]
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
# internal structure to bind the application given name
|
73
|
+
# to a key.
|
74
|
+
# This allow application to select which key to be used for
|
75
|
+
# data protection
|
76
|
+
def vault
|
77
|
+
if @vault.nil?
|
78
|
+
@vault = { }
|
79
|
+
end
|
80
|
+
@vault
|
81
|
+
end
|
82
|
+
|
83
|
+
def logger
|
84
|
+
if @logger.nil?
|
85
|
+
@logger = TeLogger::Tlogger.new
|
86
|
+
@logger.tag = :mem_vault
|
87
|
+
end
|
88
|
+
@logger
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|