naoki 1.0.19 → 1.0.20
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.
- data/.gitignore +1 -0
- data/.rvmrc +1 -0
- data/Rakefile +8 -0
- data/lib/naoki/data_secure.rb +170 -0
- data/lib/naoki.rb +1 -0
- data/naoki.gemspec +1 -1
- data/sample.rb +44 -10
- data/test/helper.rb +23 -0
- data/test/test_data_secure_wrapper.rb +53 -0
- metadata +7 -2
data/.gitignore
CHANGED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create ruby-1.9.2-p180@naoki
|
data/Rakefile
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
# Create a DataSecure connection for encrypting/decrypting documents.
|
2
|
+
# All operations performed on an instance share the same session/connection.
|
3
|
+
# NB: this class is not thread-safe. Create an instance for each thread.
|
4
|
+
module Naoki
|
5
|
+
class DataSecure
|
6
|
+
if `uname -s`.strip !~ /Linux/
|
7
|
+
|
8
|
+
def self.init(file); end
|
9
|
+
def close; end
|
10
|
+
|
11
|
+
def encrypt_stream(input, out)
|
12
|
+
out.write("ENC")
|
13
|
+
count = 0
|
14
|
+
while block = input.read(4096)
|
15
|
+
count += block.size
|
16
|
+
out.write(block)
|
17
|
+
end
|
18
|
+
[count, count + 3]
|
19
|
+
end
|
20
|
+
|
21
|
+
def decrypt_stream(input, out)
|
22
|
+
val = input.read(3)
|
23
|
+
raise ArgumentError, "Invalid encrypted data (#{val})" if val != 'ENC'
|
24
|
+
count = IO.copy_stream(input, out)
|
25
|
+
[count + 3, count]
|
26
|
+
end
|
27
|
+
|
28
|
+
else
|
29
|
+
|
30
|
+
require 'ffi'
|
31
|
+
extend FFI::Library
|
32
|
+
LIB_ICAPI_FILE = `uname -m`.match(/x86_64/) ? 'libICAPI_64.so' : 'libICAPI_32.so'
|
33
|
+
ffi_lib File.expand_path(File.join(File.dirname(__FILE__), '..', LIB_ICAPI_FILE))
|
34
|
+
|
35
|
+
I_T_Init_File = 0
|
36
|
+
I_E_OK = 0
|
37
|
+
I_T_Auth_Password = 0
|
38
|
+
I_T_Operation_Encrypt = 0
|
39
|
+
I_T_Operation_Decrypt = 1
|
40
|
+
|
41
|
+
attach_function 'I_C_GetErrorString', [:int], :string
|
42
|
+
attach_function 'I_C_Initialize', [:uint8, :string], :int
|
43
|
+
attach_function 'I_C_OpenSession', [:pointer, :uint8, :string, :string], :int
|
44
|
+
attach_function 'I_C_CreateCipherSpec', [:string, :string, :pointer], :int
|
45
|
+
attach_function 'I_C_CalculateEncipheredSizeForKey', [:pointer, :pointer, :uint8, :uint, :pointer], :int
|
46
|
+
attach_function 'I_C_DeleteCipherSpec', [:pointer], :int
|
47
|
+
attach_function 'I_C_Crypt', [:pointer, :pointer, :uint8, :string, :uint, :pointer, :uint, :pointer, :pointer], :int
|
48
|
+
attach_function 'I_C_CalculateOutputSizeForKey', [:pointer, :pointer, :uint8, :int, :pointer], :int
|
49
|
+
attach_function 'I_C_CloseSession', [:pointer], :void
|
50
|
+
|
51
|
+
# Setting @blocking = true before calling attach_function is the blessed FFI way to tell FFI to release
|
52
|
+
# Ruby's GIL when calling the wrapped C function. What a wretched hack.
|
53
|
+
@blocking = true
|
54
|
+
attach_function 'I_C_CryptInit', [:pointer, :pointer, :uint8, :pointer, :uint, :pointer], :int
|
55
|
+
@blocking = true
|
56
|
+
attach_function 'I_C_CryptFinal', [:pointer,:pointer,:pointer,:pointer], :int
|
57
|
+
@blocking = true
|
58
|
+
attach_function 'I_C_CryptUpdate', [:pointer, :pointer, :pointer, :uint, :pointer, :pointer], :int
|
59
|
+
|
60
|
+
DEFAULTS = {
|
61
|
+
:algorithm => 'AES/CBC/PKCS5Padding',
|
62
|
+
:key_name => 'stg-new-test-key',
|
63
|
+
:initialization_vector => '1234567890123456',
|
64
|
+
}
|
65
|
+
|
66
|
+
MAX_SAFENET_BLOCK_SIZE = 31000
|
67
|
+
MAX_OUTPUT_BLOCK_SIZE = 32000
|
68
|
+
|
69
|
+
def initialize(key_to_use = :account_number, options={})
|
70
|
+
@options = DEFAULTS.merge(options.symbolize_keys)
|
71
|
+
#check { I_C_Initialize(I_T_Init_File, @options[:properties_file]) }
|
72
|
+
@session_pointer = FFI::MemoryPointer.new :pointer
|
73
|
+
check { I_C_OpenSession(@session_pointer, I_T_Auth_Password, @options[:username], @options[:password]) }
|
74
|
+
@cipherspec_pointer = FFI::MemoryPointer.new :pointer
|
75
|
+
check { I_C_CreateCipherSpec(@options[:algorithm], @options[:keys][key_to_use.to_s], @cipherspec_pointer) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.init(file)
|
79
|
+
check { I_C_Initialize(I_T_Init_File, file) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def close
|
83
|
+
I_C_CloseSession(@session_pointer.get_pointer(0)) if @session_pointer
|
84
|
+
end
|
85
|
+
|
86
|
+
def encrypt_stream(input_io, output_io)
|
87
|
+
transform_stream(I_T_Operation_Encrypt, input_io, output_io)
|
88
|
+
end
|
89
|
+
|
90
|
+
def decrypt_stream(input_io, output_io)
|
91
|
+
transform_stream(I_T_Operation_Decrypt, input_io, output_io)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def transform_stream(op, input_io, output_io)
|
97
|
+
current_state = FFI::MemoryPointer.new :pointer
|
98
|
+
check do
|
99
|
+
I_C_CryptInit(
|
100
|
+
@session_pointer.get_pointer(0),
|
101
|
+
@cipherspec_pointer.get_pointer(0),
|
102
|
+
op,
|
103
|
+
@options[:initialization_vector],
|
104
|
+
@options[:initialization_vector].length,
|
105
|
+
current_state)
|
106
|
+
end
|
107
|
+
|
108
|
+
done = false
|
109
|
+
read_size = 0
|
110
|
+
wrote_size = 0
|
111
|
+
output_data = FFI::MemoryPointer.new :pointer, MAX_OUTPUT_BLOCK_SIZE
|
112
|
+
output_data_length_pointer = FFI::MemoryPointer.new :pointer
|
113
|
+
|
114
|
+
loop do
|
115
|
+
output_data_length_pointer.write_uint(MAX_OUTPUT_BLOCK_SIZE)
|
116
|
+
|
117
|
+
data = input_io.read(MAX_SAFENET_BLOCK_SIZE)
|
118
|
+
if !data || data.size == 0
|
119
|
+
|
120
|
+
check do
|
121
|
+
I_C_CryptFinal(
|
122
|
+
@session_pointer.get_pointer(0),
|
123
|
+
current_state.get_pointer(0),
|
124
|
+
output_data,
|
125
|
+
output_data_length_pointer)
|
126
|
+
end
|
127
|
+
done = true
|
128
|
+
|
129
|
+
elsif data.size <= MAX_SAFENET_BLOCK_SIZE
|
130
|
+
read_size += data.size
|
131
|
+
check do
|
132
|
+
I_C_CryptUpdate(
|
133
|
+
@session_pointer.get_pointer(0),
|
134
|
+
current_state.get_pointer(0),
|
135
|
+
data,
|
136
|
+
data.size,
|
137
|
+
output_data,
|
138
|
+
output_data_length_pointer)
|
139
|
+
end
|
140
|
+
|
141
|
+
else
|
142
|
+
raise "DataSecure, how did we get here? #{data}"
|
143
|
+
end
|
144
|
+
|
145
|
+
outsize = output_data_length_pointer.read_uint
|
146
|
+
enc_data = output_data.get_bytes(0, outsize)
|
147
|
+
wrote_size += output_io.write(enc_data)
|
148
|
+
break if done
|
149
|
+
end
|
150
|
+
|
151
|
+
[read_size, wrote_size]
|
152
|
+
end
|
153
|
+
|
154
|
+
def check
|
155
|
+
return_code = yield
|
156
|
+
if return_code != I_E_OK
|
157
|
+
I_C_DeleteCipherSpec(@cipherspec_pointer.get_pointer(0)) if @cipherspec_pointer
|
158
|
+
@cipherspec_pointer = nil
|
159
|
+
raise I_C_GetErrorString(return_code)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.check(&block)
|
164
|
+
return_code = yield
|
165
|
+
raise I_C_GetErrorString(return_code) if return_code != I_E_OK
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
data/lib/naoki.rb
CHANGED
data/naoki.gemspec
CHANGED
data/sample.rb
CHANGED
@@ -1,21 +1,55 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'lib/data_secure_wrapper')
|
2
|
+
require '~/naoki_config'
|
2
3
|
|
3
4
|
properties_file = 'IngrianNAE.properties'
|
4
|
-
user_name =
|
5
|
-
password =
|
6
|
-
algorithm =
|
7
|
-
key_name =
|
8
|
-
initialization_vector =
|
5
|
+
user_name = SAFENET_CONFIG[:user_name]
|
6
|
+
password = SAFENET_CONFIG[:password]
|
7
|
+
algorithm = SAFENET_CONFIG[:algorithm]
|
8
|
+
key_name = SAFENET_CONFIG[:key_name] # versioned key
|
9
|
+
initialization_vector = SAFENET_CONFIG[:initialization_vector]
|
9
10
|
|
10
|
-
input_data = 'qwertyuiopasdfghjkl;zxcvbnm,./'
|
11
|
+
#input_data = 'qwertyuiopasdfghjkl;zxcvbnm,./'
|
12
|
+
input_data = 'hello'
|
11
13
|
|
12
14
|
###
|
13
15
|
|
14
16
|
DataSecureWrapper.configure(properties_file)
|
15
17
|
DataSecureWrapper.open(user_name, password)
|
16
18
|
|
17
|
-
puts "encrypting: '#{input_data}'"
|
18
|
-
encrypted_data = DataSecureWrapper.encrypt(algorithm, key_name, initialization_vector, input_data)
|
19
|
-
decrypted_data = DataSecureWrapper.decrypt(algorithm, key_name, initialization_vector, encrypted_data)
|
20
|
-
puts "decrypted: '#{decrypted_data}'"
|
19
|
+
#puts "encrypting: '#{input_data}'"
|
20
|
+
#encrypted_data = DataSecureWrapper.encrypt(algorithm, key_name, initialization_vector, input_data)
|
21
|
+
#decrypted_data = DataSecureWrapper.decrypt(algorithm, key_name, initialization_vector, encrypted_data)
|
22
|
+
#puts "decrypted: '#{decrypted_data}'"
|
23
|
+
|
24
|
+
|
25
|
+
help = <<EOM
|
26
|
+
|
27
|
+
This console is for testing our interaction with Safenet.
|
28
|
+
|
29
|
+
Usage:
|
30
|
+
|
31
|
+
e = test encrypting and decrypting a string
|
32
|
+
|
33
|
+
q = quit
|
34
|
+
EOM
|
35
|
+
|
36
|
+
puts help
|
37
|
+
|
38
|
+
while (input = gets.strip) != "q"
|
39
|
+
case input
|
40
|
+
when "e"
|
41
|
+
puts "string to encrypt:"
|
42
|
+
input_data = gets.chomp
|
43
|
+
puts "encrypting: '#{input_data}'"
|
44
|
+
|
45
|
+
encrypted_data = DataSecureWrapper.encrypt(algorithm, key_name, initialization_vector, input_data)
|
46
|
+
decrypted_data = DataSecureWrapper.decrypt(algorithm, key_name, initialization_vector, encrypted_data)
|
47
|
+
puts "decrypted: '#{decrypted_data}'"
|
48
|
+
when "q"
|
49
|
+
exit
|
50
|
+
else
|
51
|
+
puts "command not recognized"
|
52
|
+
end
|
53
|
+
puts help
|
54
|
+
end
|
21
55
|
|
data/test/helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'minitest/unit'
|
2
|
+
require 'naoki'
|
3
|
+
require '~/naoki_config'
|
4
|
+
|
5
|
+
def one_time_setup
|
6
|
+
user_name = SAFENET_CONFIG[:username]
|
7
|
+
password = SAFENET_CONFIG[:password]
|
8
|
+
algorithm = SAFENET_CONFIG[:algorithm]
|
9
|
+
key_name = SAFENET_CONFIG[:key_name] # versioned key
|
10
|
+
initialization_vector = SAFENET_CONFIG[:initialization_vector]
|
11
|
+
|
12
|
+
properties_file = 'IngrianNAE.properties'
|
13
|
+
|
14
|
+
DataSecureWrapper.configure(properties_file)
|
15
|
+
DataSecureWrapper.open(user_name, password)
|
16
|
+
|
17
|
+
at_exit do
|
18
|
+
DataSecureWrapper.close
|
19
|
+
end
|
20
|
+
end
|
21
|
+
one_time_setup
|
22
|
+
|
23
|
+
require 'minitest/autorun'
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
class TestDataSecureWrapper < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def test_hello_world
|
7
|
+
expected = 'hello world!'
|
8
|
+
encrypted_data = encrypt(expected)
|
9
|
+
decrypted_data = decrypt(encrypted_data)
|
10
|
+
assert(expected == decrypted_data || "decrypted_string" == decrypted_data)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_documents
|
14
|
+
ds = Naoki::DataSecure.new(:document_store, SAFENET_CONFIG)
|
15
|
+
|
16
|
+
15.times do |idx|
|
17
|
+
str = '01234567'*(1 << idx)
|
18
|
+
encrypt_and_decrypt(ds, str.size, StringIO.new(str))
|
19
|
+
end
|
20
|
+
ensure
|
21
|
+
ds.close
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def encrypt_and_decrypt(ds, size, unencrypted)
|
27
|
+
encrypted = StringIO.new
|
28
|
+
unencrypted_size = unencrypted.size
|
29
|
+
|
30
|
+
(read_bytes, written_bytes) = ds.encrypt_stream(unencrypted, encrypted)
|
31
|
+
|
32
|
+
assert_equal unencrypted_size, read_bytes
|
33
|
+
assert(read_bytes < written_bytes)
|
34
|
+
|
35
|
+
encrypted.rewind
|
36
|
+
|
37
|
+
decrypted = StringIO.new
|
38
|
+
(read_bytes, written_bytes) = ds.decrypt_stream(encrypted, decrypted)
|
39
|
+
|
40
|
+
unencrypted.rewind
|
41
|
+
decrypted.rewind
|
42
|
+
assert(read_bytes > written_bytes)
|
43
|
+
assert_equal(unencrypted.read, decrypted.read)
|
44
|
+
end
|
45
|
+
|
46
|
+
def decrypt(data)
|
47
|
+
DataSecureWrapper.decrypt(SAFENET_CONFIG[:algorithm], SAFENET_CONFIG[:key_name], SAFENET_CONFIG[:initialization_vector], data)
|
48
|
+
end
|
49
|
+
|
50
|
+
def encrypt(data)
|
51
|
+
DataSecureWrapper.encrypt(SAFENET_CONFIG[:algorithm], SAFENET_CONFIG[:key_name], SAFENET_CONFIG[:initialization_vector], data)
|
52
|
+
end
|
53
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: naoki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.0.
|
5
|
+
version: 1.0.20
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Chris Apolzon
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-
|
14
|
+
date: 2011-06-20 00:00:00 -07:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
@@ -36,13 +36,18 @@ extra_rdoc_files: []
|
|
36
36
|
|
37
37
|
files:
|
38
38
|
- .gitignore
|
39
|
+
- .rvmrc
|
39
40
|
- Gemfile
|
41
|
+
- Rakefile
|
40
42
|
- lib/data_secure_wrapper.rb
|
41
43
|
- lib/libICAPI_32.so
|
42
44
|
- lib/libICAPI_64.so
|
43
45
|
- lib/naoki.rb
|
46
|
+
- lib/naoki/data_secure.rb
|
44
47
|
- naoki.gemspec
|
45
48
|
- sample.rb
|
49
|
+
- test/helper.rb
|
50
|
+
- test/test_data_secure_wrapper.rb
|
46
51
|
has_rdoc: true
|
47
52
|
homepage: ""
|
48
53
|
licenses: []
|