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