roostify_pkcs11_luna 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/.yardopts +1 -0
- data/Manifest.txt +24 -0
- data/README_LUNA.rdoc +103 -0
- data/Rakefile +91 -0
- data/examples/config.rb +5 -0
- data/examples/derive_aes_ecdh_key.rb +108 -0
- data/examples/encrypt_decrypt_aes.rb +41 -0
- data/examples/encrypt_decrypt_rsa.rb +47 -0
- data/examples/mechanism_list.rb +20 -0
- data/examples/multithread.rb +73 -0
- data/examples/objects_list.rb +23 -0
- data/examples/sign_verify.rb +56 -0
- data/examples/slot_info.rb +23 -0
- data/ext/extconf.rb +14 -0
- data/ext/generate_constants.rb +57 -0
- data/ext/generate_structs.rb +77 -0
- data/ext/pk11_const_macros.h +38 -0
- data/ext/pk11_struct_macros.h +435 -0
- data/ext/pk11_version.h +6 -0
- data/ext/pk11l.c +352 -0
- data/ext/pk11l_const_def.inc +656 -0
- data/ext/pk11l_struct.doc +650 -0
- data/ext/pk11l_struct_def.inc +253 -0
- data/ext/pk11l_struct_impl.inc +253 -0
- data/lib/pkcs11_luna.rb +11 -0
- data/lib/pkcs11_luna/extensions.rb +131 -0
- data/test/app_id_helper.rb +29 -0
- data/test/luna_helper.rb +57 -0
- data/test/test_pkcs11_luna.rb +112 -0
- data/test/test_pkcs11_luna_crypt.rb +260 -0
- metadata +154 -0
data/lib/pkcs11_luna.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Extend the search path for Windows binary gem, depending of the current ruby version
|
4
|
+
major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
|
5
|
+
raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
|
6
|
+
$: << File.join(File.dirname(__FILE__), major_minor)
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'pkcs11'
|
10
|
+
require 'pkcs11_luna_ext'
|
11
|
+
require 'pkcs11_luna/extensions'
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module PKCS11
|
4
|
+
module Luna
|
5
|
+
# Derive CK_ATTRIBUTE to get converted attributes.
|
6
|
+
class CK_ATTRIBUTE < PKCS11::CK_ATTRIBUTE
|
7
|
+
|
8
|
+
ATTRIBUTES = {
|
9
|
+
CKA_CCM_PRIVATE => :bool,
|
10
|
+
CKA_X9_31_GENERATED => :bool,
|
11
|
+
CKA_USAGE_COUNT => :ulong,
|
12
|
+
CKA_USAGE_LIMIT => :ulong
|
13
|
+
}
|
14
|
+
|
15
|
+
def value
|
16
|
+
case ATTRIBUTES[type]
|
17
|
+
when :bool
|
18
|
+
super != "\0"
|
19
|
+
when :ulong
|
20
|
+
super.unpack("L!")[0]
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# A Luna::Library instance holds a handle to the opened +cryptoki.dll+ or +cryptoki.so+ file.
|
28
|
+
#
|
29
|
+
# This class is derived from
|
30
|
+
# PKCS11::Library[http://pkcs11.rubyforge.org/pkcs11/PKCS11/Library.html] of pkcs11.gem.
|
31
|
+
class Library < PKCS11::Library
|
32
|
+
MechanismParameters = {
|
33
|
+
CKM_AES_GCM => CK_AES_GCM_PARAMS,
|
34
|
+
CKM_ECIES => CK_ECIES_PARAMS,
|
35
|
+
CKM_XOR_BASE_AND_DATA_W_KDF => CK_XOR_BASE_DATA_KDF_PARAMS,
|
36
|
+
CKM_PRF_KDF => CK_PRF_KDF_PARAMS,
|
37
|
+
CKM_NIST_PRF_KDF => CK_PRF_KDF_PARAMS,
|
38
|
+
CKM_SEED_CTR => CK_AES_CTR_PARAMS,
|
39
|
+
CKM_AES_CTR => CK_AES_CTR_PARAMS,
|
40
|
+
CKM_DES3_CTR => CK_DES_CTR_PARAMS,
|
41
|
+
CKM_AES_GMAC => CK_AES_GCM_PARAMS,
|
42
|
+
CKM_AES_CBC_PAD_EXTRACT => CK_AES_CBC_PAD_EXTRACT_PARAMS,
|
43
|
+
CKM_AES_CBC_PAD_INSERT => CK_AES_CBC_PAD_INSERT_PARAMS,
|
44
|
+
CKM_AES_CBC_PAD_EXTRACT_FLATTENED => CK_AES_CBC_PAD_EXTRACT_PARAMS,
|
45
|
+
CKM_AES_CBC_PAD_INSERT_FLATTENED => CK_AES_CBC_PAD_INSERT_PARAMS,
|
46
|
+
CKM_PKCS5_PBKD2 => Luna::CK_PKCS5_PBKD2_PARAMS
|
47
|
+
}
|
48
|
+
|
49
|
+
# Path and file name of the loaded cryptoki library.
|
50
|
+
attr_reader :so_path
|
51
|
+
|
52
|
+
# Load and initialize a pkcs11 dynamic library with Safenet Luna extensions.
|
53
|
+
#
|
54
|
+
# Set +so_path+ to +:config+, in order to autodetect the .dll or .so or
|
55
|
+
# set it to the full path of the .dll or .so file.
|
56
|
+
#
|
57
|
+
# @param [String, Symbol] so_path Shortcut-Symbol or path to the *.so or *.dll file to load.
|
58
|
+
# @param [Hash, CK_C_INITIALIZE_ARGS] args A Hash or CK_C_INITIALIZE_ARGS instance with load params.
|
59
|
+
#
|
60
|
+
# See also PKCS11::Library#initialize[http://pkcs11.rubyforge.org/pkcs11/PKCS11/Library.html#initialize-instance_method] of pkcs11.gem
|
61
|
+
alias unwrapped_initialize initialize
|
62
|
+
def initialize(so_path = :config, args = {})
|
63
|
+
unwrapped_initialize(so_path, args)
|
64
|
+
end
|
65
|
+
|
66
|
+
def load_library(so_path)
|
67
|
+
@so_path = resolve_so_path(so_path)
|
68
|
+
super(@so_path)
|
69
|
+
end
|
70
|
+
|
71
|
+
def resolve_so_path(so_path)
|
72
|
+
if so_path == :config
|
73
|
+
if RUBY_PLATFORM =~ /mswin|mingw/
|
74
|
+
config_file = File.join(ENV['ChrystokiConfigurationPath'], 'crystoki.ini')
|
75
|
+
config_content = File.read(config_file)
|
76
|
+
config_content.scan(/\[Chrystoki2\](.*?)\[/m) do |crystoki2|
|
77
|
+
section = $1
|
78
|
+
lib = 'LibNT'
|
79
|
+
section.scan(/#{lib}\s*=\s*(.*)/) do |lib_path|
|
80
|
+
return $1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
so_path = "C:\\Program Files\\SafeNet\\LunaClient\\win32\\cryptoki.dll"
|
84
|
+
else
|
85
|
+
config_content = File.read('/etc/Chrystoki.conf')
|
86
|
+
config_content.scan(/Chrystoki2.*?\{(.*?)\}/m) do |crystoki2|
|
87
|
+
section = $1
|
88
|
+
lib = if ['a'].pack("p").size == 8 then 'LibUNIX64' else 'LibUNIX' end
|
89
|
+
section.scan(/#{lib}\s*=\s*(.*);/) do |lib_path|
|
90
|
+
return $1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
so_path = '/usr/lib/libCryptoki2_64.so'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
so_path
|
97
|
+
end
|
98
|
+
|
99
|
+
private :resolve_so_path
|
100
|
+
|
101
|
+
|
102
|
+
def vendor_const_get(name)
|
103
|
+
return Luna.const_get(name) if Luna.const_defined?(name)
|
104
|
+
super
|
105
|
+
end
|
106
|
+
|
107
|
+
def vendor_all_attribute_names
|
108
|
+
return Luna::ATTRIBUTES.values + super
|
109
|
+
end
|
110
|
+
|
111
|
+
def vendor_mechanism_parameter_struct(mech)
|
112
|
+
MechanismParameters[mech] || super
|
113
|
+
end
|
114
|
+
|
115
|
+
def vendor_raise_on_return_value(rv)
|
116
|
+
if ex=PKCS11::RETURN_VALUES[rv]
|
117
|
+
raise(ex, rv.to_s)
|
118
|
+
end
|
119
|
+
if ex=Luna::RETURN_VALUES[rv]
|
120
|
+
raise(ex, rv.to_s)
|
121
|
+
end
|
122
|
+
super
|
123
|
+
end
|
124
|
+
|
125
|
+
def vendor_class_CK_ATTRIBUTE
|
126
|
+
Luna::CK_ATTRIBUTE
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "pkcs11_luna"
|
3
|
+
|
4
|
+
include PKCS11
|
5
|
+
|
6
|
+
slot_id = ARGV[0]
|
7
|
+
|
8
|
+
pkcs11 = Luna::Library.new
|
9
|
+
slot = Luna::Slot.new(pkcs11, slot_id.to_i)
|
10
|
+
session = slot.open(PKCS11::CKF_RW_SESSION | PKCS11::CKF_SERIAL_SESSION)
|
11
|
+
|
12
|
+
if session.info.state == CKS_RW_USER_FUNCTIONS
|
13
|
+
raise "Session info state had CKS_RW_USER_FUNCTIONS when not logged in!"
|
14
|
+
end
|
15
|
+
|
16
|
+
session.close
|
17
|
+
pkcs11.close
|
18
|
+
|
19
|
+
pkcs11 = Luna::Library.new
|
20
|
+
pkcs11.set_application_id(10, 10)
|
21
|
+
slot = Luna::Slot.new(pkcs11, slot_id.to_i)
|
22
|
+
session = slot.open(PKCS11::CKF_RW_SESSION | PKCS11::CKF_SERIAL_SESSION)
|
23
|
+
if session.info.state != CKS_RW_USER_FUNCTIONS
|
24
|
+
raise "Session info state was not CKS_RW_USER_FUNCTIONS when application id set."
|
25
|
+
end
|
26
|
+
session.close
|
27
|
+
pkcs11.close
|
28
|
+
|
29
|
+
exit(true)
|
data/test/luna_helper.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
begin
|
2
|
+
require 'io/console'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
class LunaHelper
|
7
|
+
|
8
|
+
@@slot = nil
|
9
|
+
@@password = nil
|
10
|
+
|
11
|
+
def self.get_password(prompt)
|
12
|
+
password = ""
|
13
|
+
if STDIN.respond_to?(:echo=) and STDIN.respond_to?(:getch)
|
14
|
+
print prompt
|
15
|
+
STDIN.echo = false
|
16
|
+
while true
|
17
|
+
c = STDIN.getch
|
18
|
+
if c.ord == 3
|
19
|
+
STDIN.echo = true
|
20
|
+
exit!
|
21
|
+
end
|
22
|
+
if [10, 13].include?(c.ord)
|
23
|
+
print "\n"
|
24
|
+
break
|
25
|
+
end
|
26
|
+
if [8, 127].include?(c.ord)
|
27
|
+
if password.length >= 1
|
28
|
+
print 8.chr
|
29
|
+
print 32.chr
|
30
|
+
print 8.chr
|
31
|
+
password = password[0..-2]
|
32
|
+
end
|
33
|
+
else
|
34
|
+
password << c
|
35
|
+
print '*'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
STDIN.echo = true
|
39
|
+
else
|
40
|
+
password = `read -s -p "#{prompt}" password; echo $password`.chomp
|
41
|
+
end
|
42
|
+
password
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def self.get_slot_password()
|
47
|
+
if @@slot.nil?
|
48
|
+
print "Enter slot id: "
|
49
|
+
@@slot = gets
|
50
|
+
end
|
51
|
+
if @@password.nil?
|
52
|
+
@@password = get_password("Enter user PIN : ")
|
53
|
+
end
|
54
|
+
return @@slot.to_i, @@password
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require "pkcs11_luna"
|
3
|
+
require "test/luna_helper"
|
4
|
+
|
5
|
+
class TestPkcs11Luna < Minitest::Test
|
6
|
+
include PKCS11
|
7
|
+
|
8
|
+
RUBY = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
|
9
|
+
FILE = File.dirname(__FILE__)
|
10
|
+
|
11
|
+
@slot = LunaHelper.get_slot_password()
|
12
|
+
|
13
|
+
def get_password
|
14
|
+
STDIN.echo = false
|
15
|
+
while ((c = STDIN.getch) != '\n')
|
16
|
+
print c
|
17
|
+
end
|
18
|
+
STDIN.echo = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup
|
22
|
+
@pk = Luna::Library.new
|
23
|
+
@slot, @password = LunaHelper.get_slot_password()
|
24
|
+
end
|
25
|
+
|
26
|
+
def teardown
|
27
|
+
@pk.close
|
28
|
+
end
|
29
|
+
|
30
|
+
=begin
|
31
|
+
def test_slots_are_luna
|
32
|
+
pkcs11 = @pk
|
33
|
+
pkcs11.slots.each do |slot|
|
34
|
+
assert_equal(slot.class.to_s, "PKCS11::Luna::Slot")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
MAJOR = 10
|
40
|
+
MINOR = 10
|
41
|
+
def test_application_id
|
42
|
+
pkcs11 = @pk
|
43
|
+
pkcs11.set_application_id(MAJOR, MINOR)
|
44
|
+
slot = Luna::Slot.new(pkcs11, @slot)
|
45
|
+
begin
|
46
|
+
slot.open_application_id(MAJOR, MINOR)
|
47
|
+
rescue CKR_DATA_INVALID
|
48
|
+
slot.close_application_id(MAJOR, MINOR)
|
49
|
+
end
|
50
|
+
session = slot.open(CKF_RW_SESSION | CKF_SERIAL_SESSION)
|
51
|
+
session.login(:USER, @password)
|
52
|
+
file = File.join(FILE, 'app_id_helper.rb')
|
53
|
+
cmd = "#{RUBY} #{file} #{@slot}"
|
54
|
+
IO.popen(cmd, 'r') do |p|
|
55
|
+
p.read
|
56
|
+
end
|
57
|
+
assert $?.success?, "The subprocess did not return successfully."
|
58
|
+
|
59
|
+
|
60
|
+
session.logout
|
61
|
+
session.close
|
62
|
+
slot.close_application_id(MAJOR, MINOR)
|
63
|
+
end
|
64
|
+
=end
|
65
|
+
|
66
|
+
def test_mechanisms_list
|
67
|
+
pkcs11 = @pk
|
68
|
+
slot = Slot.new(pkcs11, @slot)
|
69
|
+
mechanisms = slot.mechanisms
|
70
|
+
mechanisms.each do |mech_id|
|
71
|
+
assert(Luna::MECHANISMS.key?(mech_id))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_init_token
|
76
|
+
pkcs11 = @pk
|
77
|
+
slot = Slot.new(pkcs11, @slot)
|
78
|
+
|
79
|
+
assert_raises(Luna::CKR_OPERATION_NOT_ALLOWED, CKR_USER_TYPE_INVALID) {
|
80
|
+
slot.init_token("anypin", "new_label")
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_init_pin
|
85
|
+
pkcs11 = @pk
|
86
|
+
slot = Slot.new(pkcs11, @slot)
|
87
|
+
session = slot.open(CKF_RW_SESSION | CKF_SERIAL_SESSION)
|
88
|
+
session.login(:USER, @password)
|
89
|
+
assert_raises(Luna::CKR_OPERATION_NOT_ALLOWED, CKR_FUNCTION_NOT_SUPPORTED) {
|
90
|
+
session.init_pin("anypin")
|
91
|
+
}
|
92
|
+
session.logout
|
93
|
+
session.close
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_set_pin
|
97
|
+
pkcs11 = @pk
|
98
|
+
slot = Slot.new(pkcs11, @slot)
|
99
|
+
session = slot.open(CKF_RW_SESSION | CKF_SERIAL_SESSION)
|
100
|
+
session.login(:USER, @password)
|
101
|
+
session.set_pin(@password, @password)
|
102
|
+
session.logout
|
103
|
+
session.close
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_wait_for_slot_event
|
107
|
+
assert_raises(Luna::CKR_OPERATION_NOT_ALLOWED, CKR_FUNCTION_NOT_SUPPORTED) {
|
108
|
+
@pk.wait_for_slot_event
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require "pkcs11_luna"
|
3
|
+
require "test/luna_helper"
|
4
|
+
|
5
|
+
class TestPkcs11LunaCrypt < Minitest::Test
|
6
|
+
include PKCS11
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@pk = Luna::Library.new
|
10
|
+
slot_id, password = LunaHelper.get_slot_password()
|
11
|
+
@slot = Slot.new(@pk, slot_id)
|
12
|
+
@session = @slot.open(PKCS11::CKF_RW_SESSION | PKCS11::CKF_SERIAL_SESSION)
|
13
|
+
@session.login(:USER, password)
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
@session.logout
|
18
|
+
@session.close
|
19
|
+
@pk.close
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy_object(session, label)
|
23
|
+
session.find_objects(:LABEL=>label) do |obj|
|
24
|
+
obj.destroy
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def test_ec_pair_gen_derive_aes
|
30
|
+
pub_label = "EC Public Key"
|
31
|
+
priv_label = "EC Private Key"
|
32
|
+
derived_label = "EC Derived Key "
|
33
|
+
destroy_object(@session, pub_label)
|
34
|
+
destroy_object(@session, priv_label)
|
35
|
+
destroy_object(@session, derived_label + '1')
|
36
|
+
destroy_object(@session, derived_label + '2')
|
37
|
+
|
38
|
+
#DER encoding of OID 1.3.132.0.10 secp256k1
|
39
|
+
curve_oid_der = [0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A].pack("C*")
|
40
|
+
|
41
|
+
attributes_public = {:TOKEN=>true, :ENCRYPT=>true, :VERIFY=>true, :WRAP=>true,
|
42
|
+
:EC_PARAMS=>curve_oid_der, :LABEL=>pub_label}
|
43
|
+
attributes_private = {:TOKEN=>true, :DECRYPT=>true, :SIGN=>true,
|
44
|
+
:DERIVE=>true, :UNWRAP=>true, :SENSITIVE=>true, :LABEL=>priv_label}
|
45
|
+
|
46
|
+
pub_key1, priv_key1 = @session.generate_key_pair(:EC_KEY_PAIR_GEN, attributes_public, attributes_private)
|
47
|
+
pub_key2, priv_key2 = @session.generate_key_pair(:EC_KEY_PAIR_GEN, attributes_public, attributes_private)
|
48
|
+
|
49
|
+
shared_data = "SHARED DATA"
|
50
|
+
|
51
|
+
ec_point1 = pub_key1.attributes(:EC_POINT)[0].value
|
52
|
+
ec_point2 = pub_key2.attributes(:EC_POINT)[0].value
|
53
|
+
mechanism = {:ECDH1_DERIVE=>{:kdf=>Luna::CKD_SHA512_KDF, :pSharedData=>shared_data}}
|
54
|
+
|
55
|
+
derive_attributes = {:CLASS=>CKO_SECRET_KEY, :KEY_TYPE=>CKK_AES, :TOKEN=>true, :SENSITIVE=>true, :PRIVATE=>true,
|
56
|
+
:ENCRYPT=>true, :DECRYPT=>true, :SIGN=>true, :VERIFY=>true, :VALUE_LEN=>32, :LABEL=>derived_label+'1'}
|
57
|
+
|
58
|
+
assert_raises(Luna::CKR_ECC_POINT_INVALID) do
|
59
|
+
@session.derive_key(mechanism, priv_key1, derive_attributes)
|
60
|
+
end
|
61
|
+
|
62
|
+
mechanism[:ECDH1_DERIVE][:pPublicData] = ec_point2
|
63
|
+
derived_key1 = @session.derive_key(mechanism, priv_key1, derive_attributes)
|
64
|
+
mechanism[:ECDH1_DERIVE][:pPublicData] = ec_point1
|
65
|
+
derive_attributes[:LABEL] = derived_label + '2'
|
66
|
+
derived_key2 = @session.derive_key(mechanism, priv_key2, derive_attributes)
|
67
|
+
|
68
|
+
iv = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16].pack('C*')
|
69
|
+
message = "Text to encrypt"
|
70
|
+
cipher_text = @session.encrypt({:AES_CBC_PAD=>iv}, derived_key1, message)
|
71
|
+
decrypted = @session.decrypt({:AES_CBC_PAD=>iv}, derived_key2, cipher_text)
|
72
|
+
assert_equal(decrypted, message)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_encrypt_decrypt_aes
|
76
|
+
label = "Test AES Key"
|
77
|
+
destroy_object(@session, label)
|
78
|
+
key = @session.generate_key(:AES_KEY_GEN,
|
79
|
+
:CLASS=>CKO_SECRET_KEY, :ENCRYPT=>true, :DECRYPT=>true, :SENSITIVE=>true,
|
80
|
+
:TOKEN=>true, :VALUE_LEN=>32, :LABEL=>label)
|
81
|
+
|
82
|
+
assert key[Luna::CKA_FINGERPRINT_SHA256].size == 32
|
83
|
+
|
84
|
+
message = "Text to encrypt"
|
85
|
+
iv = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16].pack('C*')
|
86
|
+
cipher_text = @session.encrypt({:AES_CBC_PAD=>iv}, key, message)
|
87
|
+
decrypted_text = @session.decrypt({:AES_CBC_PAD=>iv}, key, cipher_text)
|
88
|
+
assert_equal(message, decrypted_text)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_generate_rsa_key_pair
|
92
|
+
pub_label = "Test RSA public key"
|
93
|
+
priv_label = "Test RSA private key"
|
94
|
+
destroy_object(@session, pub_label)
|
95
|
+
destroy_object(@session, priv_label)
|
96
|
+
|
97
|
+
pub_attr = {:ENCRYPT=>true, :VERIFY=>true,
|
98
|
+
:MODULUS_BITS=>2048, :TOKEN=>true, :WRAP=>true, :LABEL=>pub_label}
|
99
|
+
priv_attr = {:DECRYPT=>true, :SIGN=>true, :SENSITIVE=>true, :PRIVATE=>true,
|
100
|
+
:TOKEN=>true, :UNWRAP=>true, :LABEL=>priv_label}
|
101
|
+
|
102
|
+
pub_key, priv_key = @session.generate_key_pair(:RSA_FIPS_186_3_AUX_PRIME_KEY_PAIR_GEN, pub_attr, priv_attr)
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_encrypt_decrypt_rsa
|
106
|
+
pub_key, priv_key = test_generate_rsa_key_pair
|
107
|
+
message = "Text to encrypt using RSA keys"
|
108
|
+
encrypted = @session.encrypt(:RSA_PKCS, pub_key, message)
|
109
|
+
decrypted = @session.decrypt(:RSA_PKCS, priv_key, encrypted)
|
110
|
+
assert_equal(message, decrypted)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_sign_verify_rsa
|
114
|
+
pub_key, priv_key = test_generate_rsa_key_pair
|
115
|
+
data = "Text to sign/verify using RSA keys"
|
116
|
+
signature = @session.sign(:SHA512_RSA_PKCS, priv_key, data)
|
117
|
+
@session.verify(:SHA512_RSA_PKCS, pub_key, signature, data)
|
118
|
+
end
|
119
|
+
|
120
|
+
def generate_aes_key(label)
|
121
|
+
label = "Ruby AES Key"
|
122
|
+
destroy_object(@session, label)
|
123
|
+
key = @session.generate_key(:AES_KEY_GEN,
|
124
|
+
:CLASS=>CKO_SECRET_KEY, :ENCRYPT=>true, :DECRYPT=>true, :SENSITIVE=>true,
|
125
|
+
:TOKEN=>true, :EXTRACTABLE=>true, :VALUE_LEN=>32, :LABEL=>label)
|
126
|
+
|
127
|
+
return key
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_wrap_unwrap
|
131
|
+
pub_key, priv_key = test_generate_rsa_key_pair
|
132
|
+
|
133
|
+
aes_key = generate_aes_key("Wrapped AES Key")
|
134
|
+
|
135
|
+
wrapped = @session.wrap_key(:RSA_PKCS, pub_key, aes_key)
|
136
|
+
|
137
|
+
label = "Unwrapped AES Key"
|
138
|
+
destroy_object(@session, label)
|
139
|
+
|
140
|
+
attributes = {:CLASS=>CKO_SECRET_KEY, :KEY_TYPE=>CKK_AES, :ENCRYPT=>true, :DECRYPT=>true, :SENSITIVE=>true,
|
141
|
+
:TOKEN=>true, :VALUE_LEN=>32, :LABEL=>label}
|
142
|
+
|
143
|
+
unwrapped_key = @session.unwrap_key(:RSA_PKCS, priv_key, wrapped, attributes)
|
144
|
+
|
145
|
+
message = "Encrypt/Decrypt with a wrapped and unwrapped key"
|
146
|
+
iv = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16].pack('C*')
|
147
|
+
cipher_text = @session.encrypt({:AES_CBC_PAD=>iv}, aes_key, message)
|
148
|
+
decrypted_text = @session.decrypt({:AES_CBC_PAD=>iv}, unwrapped_key, cipher_text)
|
149
|
+
assert_equal(message, decrypted_text)
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_digest
|
153
|
+
data = "Data to digest."
|
154
|
+
digest = @session.digest(:SHA512, data)
|
155
|
+
hex = digest.bytes.map { |b| sprintf("%02X",b) }.join
|
156
|
+
assert_equal(hex, "B22A958E549B113FEC7FE2FBDE766A88D44E34FA47F3EED9DCBA9294AC46DA0CB2511F38943D1F1A533EB25C177F0FC38F2EFC87215D9043F67A103E849A2605")
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_des3_cmac_general
|
160
|
+
label = "DES Key"
|
161
|
+
destroy_object(@session, label)
|
162
|
+
des_key = @session.generate_key(:DES3_KEY_GEN,
|
163
|
+
:CLASS=>CKO_SECRET_KEY, :SIGN=>true, :VERIFY=>true, :ENCRYPT=>true, :DECRYPT=>true, :SENSITIVE=>true,
|
164
|
+
:TOKEN=>true, :EXTRACTABLE=>true, :LABEL=>label)
|
165
|
+
|
166
|
+
data = "Data to be signed."
|
167
|
+
signature = @session.sign({:DES3_CMAC_GENERAL=>8}, des_key, data)
|
168
|
+
@session.verify({:DES3_CMAC_GENERAL=>8}, des_key, signature, data)
|
169
|
+
end
|
170
|
+
|
171
|
+
def get_data
|
172
|
+
plaintext = ""
|
173
|
+
(0..10000).each do |i|
|
174
|
+
plaintext << (i%26+65).chr
|
175
|
+
end
|
176
|
+
plaintext
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_encrypt_decrypt_multipart
|
180
|
+
key = generate_aes_key("Ruby AES Key")
|
181
|
+
|
182
|
+
iv = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16].pack('C*')
|
183
|
+
mechanism = {:AES_CBC_PAD=>iv}
|
184
|
+
|
185
|
+
chunk_size = 1024
|
186
|
+
plaintext = get_data
|
187
|
+
|
188
|
+
encrypted = ""
|
189
|
+
index = 0
|
190
|
+
encrypted << @session.encrypt(mechanism, key) do |cipher|
|
191
|
+
while index < plaintext.size
|
192
|
+
s = plaintext.slice(index, chunk_size)
|
193
|
+
encrypted << cipher.update(s)
|
194
|
+
index += chunk_size
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
decrypted = ""
|
199
|
+
index = 0
|
200
|
+
decrypted << @session.decrypt(mechanism, key) do |cipher|
|
201
|
+
while index < encrypted.size
|
202
|
+
s = encrypted.slice(index, chunk_size)
|
203
|
+
decrypted << cipher.update(s)
|
204
|
+
index += chunk_size
|
205
|
+
end
|
206
|
+
end
|
207
|
+
assert plaintext == decrypted
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_sign_verify
|
211
|
+
pub_key, priv_key = test_generate_rsa_key_pair
|
212
|
+
|
213
|
+
plaintext = get_data
|
214
|
+
|
215
|
+
signature = @session.sign(:SHA512_RSA_PKCS, priv_key) {|c|
|
216
|
+
index = 0
|
217
|
+
while index < plaintext.size
|
218
|
+
c.update(plaintext.slice(index, 256))
|
219
|
+
index += 256
|
220
|
+
end
|
221
|
+
}
|
222
|
+
|
223
|
+
@session.verify(:SHA512_RSA_PKCS, pub_key, signature) {|c|
|
224
|
+
index = 0
|
225
|
+
while index < plaintext.size
|
226
|
+
c.update(plaintext.slice(index, 256))
|
227
|
+
index += 256
|
228
|
+
end
|
229
|
+
}
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_digest_encrypt_decrypt_update
|
233
|
+
assert_raises(CKR_FUNCTION_NOT_SUPPORTED) {
|
234
|
+
@session.C_DigestEncryptUpdate("Not supported")
|
235
|
+
}
|
236
|
+
assert_raises(CKR_FUNCTION_NOT_SUPPORTED) {
|
237
|
+
@session.C_DecryptDigestUpdate("Not supported")
|
238
|
+
}
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_verify_recover
|
242
|
+
pub_key, priv_key = test_generate_rsa_key_pair
|
243
|
+
assert_raises(CKR_FUNCTION_NOT_SUPPORTED) {
|
244
|
+
@session.C_VerifyRecoverInit(:SHA512_RSA_PKCS, pub_key)
|
245
|
+
}
|
246
|
+
assert_raises(CKR_FUNCTION_NOT_SUPPORTED) {
|
247
|
+
@session.C_VerifyRecover("Not supported")
|
248
|
+
}
|
249
|
+
end
|
250
|
+
|
251
|
+
def test_sign_verify_encrypt_decrypt_update
|
252
|
+
assert_raises(CKR_FUNCTION_NOT_SUPPORTED) {
|
253
|
+
@session.C_SignEncryptUpdate("Not supported")
|
254
|
+
}
|
255
|
+
assert_raises(CKR_FUNCTION_NOT_SUPPORTED) {
|
256
|
+
@session.C_DecryptVerifyUpdate("Not supported")
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|