ccrypto-ruby 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 +12 -0
- data/Gemfile.lock +64 -0
- data/README.md +149 -0
- data/Rakefile +10 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ccrypto-ruby.gemspec +45 -0
- data/lib/ccrypto/provider.rb +175 -0
- data/lib/ccrypto/ruby/data_conversion.rb +68 -0
- data/lib/ccrypto/ruby/engines/asn1_engine.rb +110 -0
- data/lib/ccrypto/ruby/engines/asn1_object.rb +19 -0
- data/lib/ccrypto/ruby/engines/cipher_engine.rb +170 -0
- data/lib/ccrypto/ruby/engines/compression_engine.rb +61 -0
- data/lib/ccrypto/ruby/engines/data_conversion_engine.rb +9 -0
- data/lib/ccrypto/ruby/engines/decompression_engine.rb +70 -0
- data/lib/ccrypto/ruby/engines/digest_engine.rb +127 -0
- data/lib/ccrypto/ruby/engines/ecc_engine.rb +218 -0
- data/lib/ccrypto/ruby/engines/hkdf_engine.rb +54 -0
- data/lib/ccrypto/ruby/engines/hmac_engine.rb +53 -0
- data/lib/ccrypto/ruby/engines/pbkdf2_engine.rb +69 -0
- data/lib/ccrypto/ruby/engines/pkcs7_engine.rb +179 -0
- data/lib/ccrypto/ruby/engines/rsa_engine.rb +300 -0
- data/lib/ccrypto/ruby/engines/scrypt_engine.rb +34 -0
- data/lib/ccrypto/ruby/engines/secret_key_engine.rb +18 -0
- data/lib/ccrypto/ruby/engines/secret_sharing_engine.rb +331 -0
- data/lib/ccrypto/ruby/engines/secure_random_engine.rb +34 -0
- data/lib/ccrypto/ruby/engines/x509_engine.rb +213 -0
- data/lib/ccrypto/ruby/ext/secret_key.rb +24 -0
- data/lib/ccrypto/ruby/ext/x509_cert.rb +24 -0
- data/lib/ccrypto/ruby/keybundle_store/pem_store.rb +73 -0
- data/lib/ccrypto/ruby/keybundle_store/pkcs12.rb +111 -0
- data/lib/ccrypto/ruby/utils/comparator.rb +15 -0
- data/lib/ccrypto/ruby/utils/memory_buffer.rb +63 -0
- data/lib/ccrypto/ruby/utils/native_helper.rb +17 -0
- data/lib/ccrypto/ruby/version.rb +7 -0
- data/lib/ccrypto/ruby.rb +25 -0
- metadata +136 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
require_relative '../data_conversion'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Ruby
|
6
|
+
class HMACEngine
|
7
|
+
include TR::CondUtils
|
8
|
+
include DataConversion
|
9
|
+
|
10
|
+
def initialize(*args,&block)
|
11
|
+
@config = args.first
|
12
|
+
|
13
|
+
raise HMACEngineException, "HMAC config is expected" if not @config.is_a?(Ccrypto::HMACConfig)
|
14
|
+
|
15
|
+
raise HMACEngineException, "Signing key is required" if is_empty?(@config.key)
|
16
|
+
raise HMACEngineException, "Secret key as signing key is required. Given #{@config.key.class}" if not @config.key.is_a?(Ccrypto::SecretKey)
|
17
|
+
|
18
|
+
raise HMACEngineException, "Digest '#{@config.digest}' is not supported" if not DigestEngine.is_supported?(@config.digest)
|
19
|
+
|
20
|
+
dig = DigestEngine.digest(@config.digest)
|
21
|
+
|
22
|
+
@hmac = OpenSSL::HMAC.new(@config.key.to_bin, dig.native_digest_engine)
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def hmac_update(val)
|
27
|
+
@hmac.update(val)
|
28
|
+
end
|
29
|
+
|
30
|
+
def hmac_final
|
31
|
+
@hmac.digest
|
32
|
+
end
|
33
|
+
|
34
|
+
def hmac_digest(val, output = :binary)
|
35
|
+
hmac_update(val)
|
36
|
+
res = hmac_final
|
37
|
+
|
38
|
+
@hmac.reset
|
39
|
+
|
40
|
+
case output
|
41
|
+
when :hex
|
42
|
+
to_hex(res)
|
43
|
+
when :b64
|
44
|
+
to_b64(res)
|
45
|
+
else
|
46
|
+
res
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
require_relative '../data_conversion'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Ruby
|
6
|
+
class PBKDF2Engine
|
7
|
+
include TR::CondUtils
|
8
|
+
include DataConversion
|
9
|
+
|
10
|
+
def initialize(conf, &block)
|
11
|
+
raise KDFEngineException, "PBKDF2 config is expected" if not conf.is_a?(Ccrypto::PBKDF2Config)
|
12
|
+
raise KDFEngineException, "Output bit length (outBitLength) value is not given or not a positive value (#{conf.outBitLength})" if is_empty?(conf.outBitLength) or conf.outBitLength <= 0
|
13
|
+
|
14
|
+
@config = conf
|
15
|
+
if is_empty?(@config.salt)
|
16
|
+
@config.salt = SecureRandom.random_bytes(16)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def derive(input, output = :binary)
|
21
|
+
|
22
|
+
@config.digest = default_digest if is_empty?(@config.digest)
|
23
|
+
digest = init_digest(@config.digest)
|
24
|
+
|
25
|
+
logger.debug "Digest : #{@config.digest}"
|
26
|
+
logger.debug "Iterations : #{@config.iter}"
|
27
|
+
logger.debug "Out byte length : #{@config.outBitLength/8}"
|
28
|
+
|
29
|
+
res = OpenSSL::KDF.pbkdf2_hmac(input, salt: @config.salt, iterations: @config.iter, length: @config.outBitLength/8, hash: digest)
|
30
|
+
|
31
|
+
case output
|
32
|
+
when :hex
|
33
|
+
to_hex(res)
|
34
|
+
when :b64
|
35
|
+
to_b64(res)
|
36
|
+
else
|
37
|
+
res
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def init_digest(algo)
|
43
|
+
if DigestEngine.is_supported?(algo)
|
44
|
+
conf = DigestEngine.engineKeys[algo]
|
45
|
+
if not_empty?(conf)
|
46
|
+
OpenSSL::Digest.new(conf.provider_config)
|
47
|
+
else
|
48
|
+
raise DigestEngineException, "Algo config '#{algo}' not found"
|
49
|
+
end
|
50
|
+
else
|
51
|
+
raise DigestEngineException, "Digest algo '#{algo}' is not supported"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_digest
|
56
|
+
:sha3_256
|
57
|
+
end
|
58
|
+
|
59
|
+
def logger
|
60
|
+
if @logger.nil?
|
61
|
+
@logger = TeLogger::Tlogger.new
|
62
|
+
@logger.tag = :pbkdf2
|
63
|
+
end
|
64
|
+
@logger
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
|
2
|
+
require_relative '../data_conversion'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Ruby
|
6
|
+
|
7
|
+
class PKCS7EngineException < StandardError; end
|
8
|
+
|
9
|
+
class PKCS7Engine
|
10
|
+
include TR::CondUtils
|
11
|
+
include DataConversion
|
12
|
+
|
13
|
+
include TeLogger::TeLogHelper
|
14
|
+
|
15
|
+
teLogger_tag :r_p7
|
16
|
+
|
17
|
+
def initialize(config)
|
18
|
+
@config = config
|
19
|
+
raise PKCS7EngineException, "Ccrypto::PKCS7Config is expected" if not @config.is_a?(Ccrypto::PKCS7Config)
|
20
|
+
end
|
21
|
+
|
22
|
+
def sign(val, outFormat = :bin, &block)
|
23
|
+
validate_input(val, "signing")
|
24
|
+
validate_key_must_exist("signing")
|
25
|
+
raise PKCS7EngineException, "signerCert is required for PKCS7 sign operation" if is_empty?(@config.signerCert)
|
26
|
+
raise PKCS7EngineException, "Given signerCert must be a Ccrypto::X509Cert object" if not @config.signerCert.is_a?(Ccrypto::X509Cert)
|
27
|
+
|
28
|
+
privKey = @config.private_key.native_privKey
|
29
|
+
|
30
|
+
caCerts = []
|
31
|
+
attached = true
|
32
|
+
if block
|
33
|
+
caCerts = block.call(:ca_certs)
|
34
|
+
detachedSign = block.call(:detached_sign)
|
35
|
+
attached = ! detachedSign if is_bool?(detachedSign)
|
36
|
+
end
|
37
|
+
|
38
|
+
caCerts = [] if caCerts.nil?
|
39
|
+
attached = true if is_empty?(attached) and not is_bool?(attached)
|
40
|
+
|
41
|
+
if not attached
|
42
|
+
flag = OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::DETACHED
|
43
|
+
else
|
44
|
+
flag = OpenSSL::PKCS7::BINARY
|
45
|
+
end
|
46
|
+
|
47
|
+
res = OpenSSL::PKCS7.sign(@config.signerCert.nativeX509, privKey, val, caCerts, flag)
|
48
|
+
case outFormat
|
49
|
+
when :b64
|
50
|
+
to_b64(res.to_der)
|
51
|
+
when :hex
|
52
|
+
to_hex(res.to_der)
|
53
|
+
else
|
54
|
+
res.to_der
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def verify(val, inForm = :bin, &block)
|
59
|
+
validate_input(val, "verify")
|
60
|
+
|
61
|
+
case inForm
|
62
|
+
when :b64
|
63
|
+
v = from_b64(val)
|
64
|
+
when :hex
|
65
|
+
v = from_hex(val)
|
66
|
+
else
|
67
|
+
v = val
|
68
|
+
end
|
69
|
+
|
70
|
+
p7 = OpenSSL::PKCS7.new(v)
|
71
|
+
|
72
|
+
certVerified = true
|
73
|
+
store = OpenSSL::X509::Store.new
|
74
|
+
p7.certificates.each do |c|
|
75
|
+
if block
|
76
|
+
certVerified = block.call(:verify_certificate, c)
|
77
|
+
if is_empty?(certVerified)
|
78
|
+
teLogger.debug "Certificate with subject #{c.subject.to_s} / Issuer: #{c.issuer.to_s} / SN: #{c.serial.to_s(16)} passed through (no checking by application). Assumed good cert."
|
79
|
+
store.add_cert(c)
|
80
|
+
certVerified = true
|
81
|
+
else
|
82
|
+
if certVerified
|
83
|
+
teLogger.debug "Certificate with subject #{c.subject.to_s} / Issuer: #{c.issuer.to_s} / SN: #{c.serial.to_s(16)} accepted by application"
|
84
|
+
store.add_cert(c)
|
85
|
+
else
|
86
|
+
teLogger.debug "Certificate with subject #{c.subject.to_s} / Issuer: #{c.issuer.to_s} / SN: #{c.serial.to_s(16)} rejected by application"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
else
|
90
|
+
teLogger.debug "Certificate with subject #{c.subject.to_s} / Issuer: #{c.issuer.to_s} / SN: #{c.serial.to_s(16)} passed through (no checking by application)"
|
91
|
+
store.add_cert(c)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
if certVerified
|
96
|
+
|
97
|
+
if p7.detached?
|
98
|
+
teLogger.debug "Detached signature detected during signature verification"
|
99
|
+
raise PKCS7EngineException, "block is required for detached signature" if not block
|
100
|
+
data = block.call(:signed_data)
|
101
|
+
p7.data = data
|
102
|
+
else
|
103
|
+
teLogger.debug "Attached signature detected during signature verification"
|
104
|
+
end
|
105
|
+
|
106
|
+
res = p7.verify([], store, nil, OpenSSL::PKCS7::NOVERIFY)
|
107
|
+
|
108
|
+
if block
|
109
|
+
block.call(:verification_result, res)
|
110
|
+
if res and not p7.detached?
|
111
|
+
block.call(:attached_data, p7.data)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
res
|
116
|
+
|
117
|
+
else
|
118
|
+
certVerified
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
def encrypt(val, &block)
|
124
|
+
validate_input(val, "encrypt")
|
125
|
+
raise PKCS7EngineException, "At least one recipient_cert is required for PKCS7 encrypt" if is_empty?(@config.recipient_certs)
|
126
|
+
|
127
|
+
recps = @config.recipient_certs.map do |c|
|
128
|
+
raise PKCS7EngineException, "Given recipient_cert must be a Ccrypto::X509Cert object" if not c.is_a?(Ccrypto::X509Cert)
|
129
|
+
c.nativeX509
|
130
|
+
end
|
131
|
+
|
132
|
+
if block
|
133
|
+
cipher = block.call(:cipher)
|
134
|
+
teLogger.debug "Application given cipher : #{cipher}"
|
135
|
+
end
|
136
|
+
|
137
|
+
cipher = "AES-256-CBC" if is_empty?(cipher)
|
138
|
+
|
139
|
+
cip = OpenSSL::Cipher.new(cipher)
|
140
|
+
|
141
|
+
begin
|
142
|
+
OpenSSL::PKCS7.encrypt(recps, val, cip, OpenSSL::PKCS7::BINARY)
|
143
|
+
rescue OpenSSL::PKCS7::PKCS7Error => ex
|
144
|
+
raise PKCS7EngineException, ex
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
def decrypt(val, &block)
|
150
|
+
validate_input(val, "decrypt")
|
151
|
+
validate_key_must_exist("decrypt")
|
152
|
+
|
153
|
+
raise PKCS7EngineException, "certForDecryption is required for PKCS7 decrypt operation" if is_empty?(@config.certForDecryption)
|
154
|
+
raise PKCS7EngineException, "Given certForDecryption must be a Ccrypto::X509Cert object" if not @config.certForDecryption.is_a?(Ccrypto::X509Cert)
|
155
|
+
|
156
|
+
p7 = OpenSSL::PKCS7.new(val)
|
157
|
+
p7.decrypt(@config.private_key.native_privKey, @config.certForDecryption.nativeX509)
|
158
|
+
end
|
159
|
+
|
160
|
+
protected
|
161
|
+
def validate_input(val, ops)
|
162
|
+
raise PKCS7EngineException, "Given data to #{ops} operation is empty" if is_empty?(val)
|
163
|
+
end
|
164
|
+
|
165
|
+
def validate_key_must_exist(ops)
|
166
|
+
#raise PKCS7EngineException, "Keybundle is required for PKCS7 #{ops}" if is_empty?(@config.keybundle)
|
167
|
+
#raise PKCS7EngineException, "Given key must be a Ccrypto::KeyBundle object" if not @config.keybundle.is_a?(Ccrypto::KeyBundle)
|
168
|
+
raise PKCS7EngineException, "Private key is required for PKCS7 #{ops}" if is_empty?(@config.private_key)
|
169
|
+
raise PKCS7EngineException, "Given private key must be a Ccrypto::PrivateKey object" if not @config.private_key.is_a?(Ccrypto::PrivateKey)
|
170
|
+
end
|
171
|
+
|
172
|
+
#def validate_cert_must_exist(ops)
|
173
|
+
# raise PKCS7EngineException, "signerCert is required for PKCS7 #{ops}" if is_empty?(@config.signerCert)
|
174
|
+
# raise PKCS7EngineException, "Given signerCert must be a Ccrypto::X509Cert object" if not @config.signerCert.is_a?(Ccrypto::X509Cert)
|
175
|
+
#end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,300 @@
|
|
1
|
+
|
2
|
+
require_relative '../keybundle_store/pkcs12'
|
3
|
+
require_relative '../keybundle_store/pem_store'
|
4
|
+
|
5
|
+
module Ccrypto
|
6
|
+
module Ruby
|
7
|
+
|
8
|
+
class RSAPublicKey < Ccrypto::RSAPublicKey
|
9
|
+
|
10
|
+
def to_bin
|
11
|
+
@native_pubKey.to_der
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.to_key(bin)
|
15
|
+
rk = OpenSSL::PKey::RSA.new(bin)
|
16
|
+
RSAPublicKey.new(rk)
|
17
|
+
end
|
18
|
+
|
19
|
+
end # RSAPublicKey
|
20
|
+
|
21
|
+
class RSAKeyBundle
|
22
|
+
include Ccrypto::RSAKeyBundle
|
23
|
+
include TR::CondUtils
|
24
|
+
|
25
|
+
include PKCS12Store
|
26
|
+
include PEMStore
|
27
|
+
|
28
|
+
include TeLogger::TeLogHelper
|
29
|
+
|
30
|
+
teLogger_tag :r_rsa_keybundle
|
31
|
+
|
32
|
+
def initialize(kp)
|
33
|
+
@nativeKeypair = kp
|
34
|
+
end
|
35
|
+
|
36
|
+
def public_key
|
37
|
+
if @pubKey.nil?
|
38
|
+
@pubKey = RSAPublicKey.new(@nativeKeypair.public_key)
|
39
|
+
end
|
40
|
+
@pubKey
|
41
|
+
end
|
42
|
+
|
43
|
+
def private_key
|
44
|
+
if @privKey.nil?
|
45
|
+
@privKey = Ccrypto::RSAPrivateKey.new(@nativeKeypair)
|
46
|
+
end
|
47
|
+
@privKey
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_storage(format, &block)
|
51
|
+
case format
|
52
|
+
when :pkcs12, :p12
|
53
|
+
to_pkcs12 do |key|
|
54
|
+
case key
|
55
|
+
when :keypair
|
56
|
+
@nativeKeypair
|
57
|
+
else
|
58
|
+
block.call(key) if block
|
59
|
+
end
|
60
|
+
end
|
61
|
+
when :pem
|
62
|
+
to_pem do |key|
|
63
|
+
case key
|
64
|
+
when :keypair
|
65
|
+
@nativeKeypair
|
66
|
+
else
|
67
|
+
block.call(key) if block
|
68
|
+
end
|
69
|
+
end
|
70
|
+
else
|
71
|
+
raise KeyBundleStorageException, "Unknown storage format #{format}"
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.from_storage(bin, &block)
|
77
|
+
raise KeypairEngineException, "Given data to load is empty" if is_empty?(bin)
|
78
|
+
|
79
|
+
case bin
|
80
|
+
when String
|
81
|
+
teLogger.debug "Given String to load from storage"
|
82
|
+
if is_pem?(bin)
|
83
|
+
self.from_pem(bin, &block)
|
84
|
+
else
|
85
|
+
# binary buffer
|
86
|
+
teLogger.debug "Given binary to load from storage"
|
87
|
+
self.from_pkcs12(bin,&block)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
raise KeyBundleStorageException, "Unsupported input type #{bin}"
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def equal?(kp)
|
96
|
+
if kp.respond_to?(:to_der)
|
97
|
+
@nativeKeypair.to_der == kp.to_der
|
98
|
+
else
|
99
|
+
@nativeKeypair == kp
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def method_missing(mtd, *args, &block)
|
104
|
+
if @nativeKeypair.respond_to?(mtd)
|
105
|
+
teLogger.debug "Sending to nativeKeypair #{mtd}"
|
106
|
+
@nativeKeypair.send(mtd,*args, &block)
|
107
|
+
else
|
108
|
+
super
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def respond_to_missing?(mtd, *args, &block)
|
113
|
+
@nativeKeypair.respond_to?(mtd)
|
114
|
+
end
|
115
|
+
|
116
|
+
end # RSAKeyBundle
|
117
|
+
|
118
|
+
class RSAEngine
|
119
|
+
include TR::CondUtils
|
120
|
+
|
121
|
+
def initialize(*args, &block)
|
122
|
+
@config = args.first
|
123
|
+
raise KeypairEngineException, "1st parameter must be a #{Ccrypto::KeypairConfig.class} object" if not @config.is_a?(Ccrypto::KeypairConfig)
|
124
|
+
end
|
125
|
+
|
126
|
+
def generate_keypair(&block)
|
127
|
+
kp = OpenSSL::PKey::RSA.generate(@config.keysize)
|
128
|
+
RSAKeyBundle.new(kp)
|
129
|
+
end
|
130
|
+
|
131
|
+
def sign(val, &block)
|
132
|
+
if block
|
133
|
+
pss = block.call(:pss_mode)
|
134
|
+
pss = false if is_empty?(pss) or not is_bool?(pss)
|
135
|
+
|
136
|
+
if pss
|
137
|
+
sign_pss(val, &block)
|
138
|
+
else
|
139
|
+
sign_typical(val, &block)
|
140
|
+
end
|
141
|
+
else
|
142
|
+
sign_typical(val, &block)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.verify(pubKey, val, sign, &block)
|
147
|
+
if block
|
148
|
+
pss = block.call(:pss_mode)
|
149
|
+
pss = false if is_empty?(pss) or not is_bool?(pss)
|
150
|
+
|
151
|
+
if pss
|
152
|
+
verify_pss(pubKey, val, sign, &block)
|
153
|
+
else
|
154
|
+
verify_typical(pubKey, val, sign, &block)
|
155
|
+
end
|
156
|
+
else
|
157
|
+
verify_typical(pubKey, val, sign, &block)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.encrypt(pubKey, val, &block)
|
162
|
+
raise KeypairEngineException, "Public key is required" if is_empty?(pubKey)
|
163
|
+
|
164
|
+
padding = :oaep
|
165
|
+
if block
|
166
|
+
padding = block.call(:padding)
|
167
|
+
end
|
168
|
+
|
169
|
+
case padding
|
170
|
+
when :pkcs1
|
171
|
+
padVal = OpenSSL::PKey::RSA::PKCS1_PADDING
|
172
|
+
when :oaep
|
173
|
+
padVal = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
|
174
|
+
when :no_padding
|
175
|
+
padVal = OpenSSL::PKey::RSA::NO_PADDING
|
176
|
+
else
|
177
|
+
raise KeypairEngineException, "Padding requires either :pkcs1 or :oaep. Default is :oaep"
|
178
|
+
end
|
179
|
+
|
180
|
+
pubKey.public_encrypt(val, padVal)
|
181
|
+
end
|
182
|
+
|
183
|
+
def decrypt(enc, &block)
|
184
|
+
|
185
|
+
raise KeypairEngineException, "Private key is required" if not @config.has_private_key?
|
186
|
+
raise KeypairEngineException, "RSA private key is required" if not @config.private_key.is_a?(RSAPrivateKey)
|
187
|
+
|
188
|
+
padding = :oaep
|
189
|
+
if block
|
190
|
+
padding = block.call(:padding)
|
191
|
+
end
|
192
|
+
|
193
|
+
case padding
|
194
|
+
when :pkcs1
|
195
|
+
padVal = OpenSSL::PKey::RSA::PKCS1_PADDING
|
196
|
+
when :oaep
|
197
|
+
padVal = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
|
198
|
+
when :no_padding
|
199
|
+
padVal = OpenSSL::PKey::RSA::NO_PADDING
|
200
|
+
else
|
201
|
+
raise KeypairEngineException, "Padding requires either :pkcs1 or :oaep. Default is :oaep"
|
202
|
+
end
|
203
|
+
|
204
|
+
@config.private_key.private_decrypt(enc, padVal)
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
|
209
|
+
#####################
|
210
|
+
## Private section ##
|
211
|
+
private
|
212
|
+
def sign_typical(val, &block)
|
213
|
+
|
214
|
+
raise KeypairEngineException, "Private key is required" if not @config.has_private_key?
|
215
|
+
raise KeypairEngineException, "RSA private key is required" if not @config.private_key.is_a?(RSAPrivateKey)
|
216
|
+
|
217
|
+
privKey = @config.private_key
|
218
|
+
|
219
|
+
signHash = "sha256"
|
220
|
+
if block
|
221
|
+
signHash = block.call(:sign_hash)
|
222
|
+
end
|
223
|
+
|
224
|
+
begin
|
225
|
+
shash = OpenSSL::Digest.new(signHash)
|
226
|
+
rescue Exception => ex
|
227
|
+
raise KeypairEngineException, ex
|
228
|
+
end
|
229
|
+
|
230
|
+
privKey.sign(shash, val)
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
def sign_pss(val, &block)
|
235
|
+
|
236
|
+
raise KeypairEngineException, "Private key is required" if not @config.has_private_key?
|
237
|
+
raise KeypairEngineException, "RSA private key is required" if not @config.private_key.is_a?(RSAPrivateKey)
|
238
|
+
|
239
|
+
privKey = @config.private_key
|
240
|
+
|
241
|
+
signHash = "sha256"
|
242
|
+
mgf1Hash = "sha256"
|
243
|
+
saltLen = :max
|
244
|
+
if block
|
245
|
+
signHash = block.call(:sign_hash)
|
246
|
+
mgf1Hash = block.call("mgf1_hash")
|
247
|
+
saltLen = block.call("salt_length")
|
248
|
+
end
|
249
|
+
mgf1Hash = "sha256" if is_empty?(mgf1Hash)
|
250
|
+
saltLen = :max if is_empty?(saltLen)
|
251
|
+
signHash = "sha256" if is_empty?(signHash)
|
252
|
+
|
253
|
+
privKey.native_privKey.sign_pss(signHash, val, salt_length: saltLen, mgf1_hash: mgf1Hash)
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
def self.verify_typical(pubKey, val, sign, &block)
|
258
|
+
uPubKey = pubKey.native_pubKey
|
259
|
+
|
260
|
+
if block
|
261
|
+
signHash = block.call(:sign_hash)
|
262
|
+
end
|
263
|
+
signHash = "sha256" if is_empty?(signHash)
|
264
|
+
|
265
|
+
begin
|
266
|
+
shash = OpenSSL::Digest.new(signHash)
|
267
|
+
rescue Exception => ex
|
268
|
+
raise KeypairEngineException, ex
|
269
|
+
end
|
270
|
+
|
271
|
+
res = uPubKey.verify(shash, sign, val)
|
272
|
+
res
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
def self.verify_pss(pubKey, val, sign, &block)
|
277
|
+
uPubKey = pubKey.native_pubKey
|
278
|
+
|
279
|
+
signHash = "sha256"
|
280
|
+
mgf1Hash = "sha256"
|
281
|
+
saltLen = :auto
|
282
|
+
if block
|
283
|
+
signHash = block.call(:sign_hash)
|
284
|
+
mgf1Hash = block.call("mgf1_hash")
|
285
|
+
saltLen = block.call("salt_length")
|
286
|
+
end
|
287
|
+
mgf1Hash = "sha256" if is_empty?(mgf1Hash)
|
288
|
+
saltLen = :auto if is_empty?(saltLen)
|
289
|
+
signHash = "sha256" if is_empty?(signHash)
|
290
|
+
|
291
|
+
res = uPubKey.verify_pss(signHash, sign, val, salt_length: saltLen, mgf1_hash: mgf1Hash)
|
292
|
+
res
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|
300
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
require_relative '../data_conversion'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Ruby
|
6
|
+
class ScryptEngine
|
7
|
+
include DataConversion
|
8
|
+
include TR::CondUtils
|
9
|
+
|
10
|
+
def initialize(conf, &block)
|
11
|
+
raise KDFEngineException, "KDF config is expected" if not conf.is_a?(Ccrypto::KDFConfig)
|
12
|
+
raise KDFEngineException, "Output bit length (outBitLength) value is not given or not a positive value (#{conf.outBitLength})" if is_empty?(conf.outBitLength) or conf.outBitLength <= 0
|
13
|
+
@config = conf
|
14
|
+
|
15
|
+
if is_empty?(@config.salt)
|
16
|
+
@config.salt = SecureRandom.random_bytes(16)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def derive(input, output = :binary)
|
21
|
+
res = OpenSSL::KDF.scrypt(input, salt: @config.salt, N: @config.cost, r: @config.blockSize, p: @config.parallel, length: @config.outBitLength/8)
|
22
|
+
case output
|
23
|
+
when :hex
|
24
|
+
to_hex(res)
|
25
|
+
when :b64
|
26
|
+
to_b64(res)
|
27
|
+
else
|
28
|
+
res
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Ccrypto
|
4
|
+
module Ruby
|
5
|
+
class SecretKeyEngine
|
6
|
+
|
7
|
+
def self.generate(*args, &block)
|
8
|
+
config = args.first
|
9
|
+
|
10
|
+
raise SecretKeyEngineException, "KeyConfig is expected" if not config.is_a?(Ccrypto::KeyConfig)
|
11
|
+
|
12
|
+
key = SecureRandom.random_bytes(config.keysize/8)
|
13
|
+
|
14
|
+
Ccrypto::SecretKey.new(config.algo, key)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|