ccrypto-java 0.1.0 → 0.2.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 +4 -4
- data/.java-version +1 -1
- data/.release_history.yml +4 -0
- data/.ruby-version +1 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +68 -53
- data/Rakefile +2 -1
- data/bin/console +14 -0
- data/jars/bcjmail-jdk18on-172.jar +0 -0
- data/jars/bcmail-jdk18on-172.jar +0 -0
- data/jars/bcpg-jdk18on-172.1.jar +0 -0
- data/jars/bcpkix-jdk18on-172.jar +0 -0
- data/jars/bcprov-ext-jdk18on-172.jar +0 -0
- data/jars/bcprov-jdk18on-172.jar +0 -0
- data/jars/bctls-jdk18on-172.jar +0 -0
- data/jars/bcutil-jdk18on-172.jar +0 -0
- data/lib/ccrypto/java/bc_const_mapping.rb +42 -0
- data/lib/ccrypto/java/data_conversion.rb +23 -2
- data/lib/ccrypto/java/engines/argon2_engine.rb +95 -0
- data/lib/ccrypto/java/engines/asn1_engine.rb +2 -1
- data/lib/ccrypto/java/engines/bcrypt_engine.rb +56 -0
- data/lib/ccrypto/java/engines/cipher_engine.rb +462 -130
- data/lib/ccrypto/java/engines/compression_engine.rb +7 -28
- data/lib/ccrypto/java/engines/crystal_dilithium_engine.rb +226 -0
- data/lib/ccrypto/java/engines/crystal_kyber_engine.rb +260 -0
- data/lib/ccrypto/java/engines/decompression_engine.rb +5 -4
- data/lib/ccrypto/java/engines/digest_engine.rb +221 -139
- data/lib/ccrypto/java/engines/ecc_engine.rb +249 -96
- data/lib/ccrypto/java/engines/ed25519_engine.rb +211 -0
- data/lib/ccrypto/java/engines/hkdf_engine.rb +82 -23
- data/lib/ccrypto/java/engines/hmac_engine.rb +98 -23
- data/lib/ccrypto/java/engines/pbkdf2_engine.rb +82 -33
- data/lib/ccrypto/java/engines/pkcs7_engine.rb +44 -33
- data/lib/ccrypto/java/engines/rsa_engine.rb +85 -31
- data/lib/ccrypto/java/engines/scrypt_engine.rb +12 -3
- data/lib/ccrypto/java/engines/secret_key_engine.rb +77 -12
- data/lib/ccrypto/java/engines/secret_sharing_engine.rb +17 -2
- data/lib/ccrypto/java/engines/x25519_engine.rb +249 -0
- data/lib/ccrypto/java/engines/x509_csr_engine.rb +141 -0
- data/lib/ccrypto/java/engines/x509_engine.rb +365 -71
- data/lib/ccrypto/java/ext/secret_key.rb +37 -25
- data/lib/ccrypto/java/ext/x509_cert.rb +429 -5
- data/lib/ccrypto/java/ext/x509_csr.rb +151 -0
- data/lib/ccrypto/java/jce_provider.rb +0 -11
- data/lib/ccrypto/java/keystore/jce_keystore.rb +205 -0
- data/lib/ccrypto/java/keystore/jks_keystore.rb +52 -0
- data/lib/ccrypto/java/keystore/keystore.rb +97 -0
- data/lib/ccrypto/java/keystore/pem_keystore.rb +147 -0
- data/lib/ccrypto/java/keystore/pkcs12_keystore.rb +56 -0
- data/lib/ccrypto/java/utils/comparator.rb +25 -2
- data/lib/ccrypto/java/version.rb +1 -1
- data/lib/ccrypto/java.rb +46 -0
- data/lib/ccrypto/provider.rb +139 -3
- metadata +40 -24
- data/ccrypto-java.gemspec +0 -44
- data/jars/bcmail-jdk15on-165.jar +0 -0
- data/jars/bcpg-jdk15on-165.jar +0 -0
- data/jars/bcpkix-jdk15on-165.jar +0 -0
- data/jars/bcprov-ext-jdk15on-165.jar +0 -0
- data/jars/bcprov-jdk15on-165.jar +0 -0
- data/jars/bctls-jdk15on-165.jar +0 -0
- data/lib/ccrypto/java/keybundle_store/pkcs12.rb +0 -125
@@ -1,12 +1,11 @@
|
|
1
1
|
|
2
2
|
require_relative '../data_conversion'
|
3
|
-
require_relative '../keybundle_store/pkcs12'
|
4
|
-
#require_relative '../keybundle_store/pem_store'
|
5
3
|
|
6
4
|
module Ccrypto
|
7
5
|
module Java
|
8
6
|
|
9
7
|
class RSAPublicKey < Ccrypto::RSAPublicKey
|
8
|
+
include DataConversion
|
10
9
|
|
11
10
|
def to_bin
|
12
11
|
@native_pubKey.encoded
|
@@ -17,19 +16,87 @@ module Ccrypto
|
|
17
16
|
RSAPublicKey.new(pubKey)
|
18
17
|
end
|
19
18
|
|
19
|
+
def to_pem
|
20
|
+
cont = ["-----BEGIN RSA PUBLIC KEY-----\n"]
|
21
|
+
cont << to_b64(to_bin)
|
22
|
+
cont << "\n-----END RSA PUBLIC KEY-----"
|
23
|
+
cont.join
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.from_pem(str)
|
27
|
+
if str =~ /RSA PUBLIC/
|
28
|
+
cont = str.lines[1..-2].join.strip
|
29
|
+
to_key(from_b64(cont))
|
30
|
+
else
|
31
|
+
raise KeypairEngineException, "Not an RSA public key"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
20
35
|
def method_missing(mtd, *args, &block)
|
21
36
|
@native_pubKey.send(mtd, *args, &block)
|
22
37
|
end
|
23
38
|
|
24
39
|
end # RSAPublicKey
|
25
40
|
|
41
|
+
|
42
|
+
class RSAPrivateKey < Ccrypto::RSAPrivateKey
|
43
|
+
include DataConversion
|
44
|
+
|
45
|
+
def self.to_key(bin, &block)
|
46
|
+
if block
|
47
|
+
prov = block.call(:jce_provider)
|
48
|
+
else
|
49
|
+
prov = JCEProvider::BCProv
|
50
|
+
end
|
51
|
+
|
52
|
+
kf = java.security.KeyFactory.getInstance("RSA",prov)
|
53
|
+
priv = kf.generate_private(java.security.spec.PKCS8EncodedKeySpec.new(bin))
|
54
|
+
RSAPrivateKey.new(priv)
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_pem
|
59
|
+
cont = ["-----BEGIN RSA PRIVATE KEY-----\n"]
|
60
|
+
cont << to_b64(@native_privKey.encoded)
|
61
|
+
cont << "\n-----END RSA PRIVATE KEY-----"
|
62
|
+
cont.join
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.from_pem(str)
|
66
|
+
if str =~ /RSA PRIVATE/
|
67
|
+
cont = str.lines[1..-2].join.strip
|
68
|
+
to_key(from_b64(cont))
|
69
|
+
else
|
70
|
+
raise KeypairEngineException, "Not an RSA private key"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_bin
|
75
|
+
@native_privKey.encoded
|
76
|
+
end
|
77
|
+
|
78
|
+
def equals?(privKey)
|
79
|
+
if not @native_privKey.nil?
|
80
|
+
case privKey
|
81
|
+
when RSAPrivateKey
|
82
|
+
@native_privKey.encoded == privKey.to_bin
|
83
|
+
else
|
84
|
+
logger.warn "Unmatched private key : (native) #{@native_privKey} vs. (subject) #{privKey}"
|
85
|
+
false
|
86
|
+
end
|
87
|
+
else
|
88
|
+
logger.warn "RSAPrivateKey equals? returned false because native_privKey is nil"
|
89
|
+
false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
alias_method :key_equals?, :equals?
|
93
|
+
|
94
|
+
end # class RSAPrivateKey
|
95
|
+
|
26
96
|
class RSAKeyBundle
|
27
97
|
include Ccrypto::RSAKeyBundle
|
28
98
|
include TR::CondUtils
|
29
99
|
|
30
|
-
include PKCS12
|
31
|
-
#include PEMStore
|
32
|
-
|
33
100
|
include TeLogger::TeLogHelper
|
34
101
|
|
35
102
|
teLogger_tag :j_rsa_keybundle
|
@@ -52,11 +119,11 @@ module Ccrypto
|
|
52
119
|
@privKey
|
53
120
|
end
|
54
121
|
|
55
|
-
def
|
56
|
-
|
57
|
-
case
|
58
|
-
when :
|
59
|
-
|
122
|
+
def write_keystore(type, &block)
|
123
|
+
ksType = Keystore.map_keystore_type(type)
|
124
|
+
case ksType
|
125
|
+
when :pkcs12
|
126
|
+
Keystore::PKCS12Keystore.to_p12 do |key, *val|
|
60
127
|
case key
|
61
128
|
when :keypair
|
62
129
|
@nativeKeypair
|
@@ -64,43 +131,26 @@ module Ccrypto
|
|
64
131
|
block.call(key) if block
|
65
132
|
end
|
66
133
|
end
|
67
|
-
|
68
134
|
when :jks
|
69
|
-
|
135
|
+
Keystore::JKSKeystore.to_jks do |key, *val|
|
70
136
|
case key
|
71
|
-
when :storeType
|
72
|
-
"JKS"
|
73
137
|
when :keypair
|
74
138
|
@nativeKeypair
|
75
139
|
else
|
76
140
|
block.call(key) if block
|
77
141
|
end
|
78
142
|
end
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
143
|
|
83
|
-
def self.from_storage(bin, &block)
|
84
|
-
|
85
|
-
if is_pem?(bin)
|
86
144
|
else
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.is_pem?(bin)
|
93
|
-
begin
|
94
|
-
(bin =~ /BEGIN/) != nil
|
95
|
-
rescue ArgumentError => ex
|
96
|
-
false
|
145
|
+
raise Ccrypto::Keystore::KeystoreException, "Unsupported keystore type '#{type}' for engine '#{self.class.name}'"
|
97
146
|
end
|
98
147
|
end
|
99
148
|
|
149
|
+
|
100
150
|
def equal?(kp)
|
101
151
|
case kp
|
102
152
|
when Ccrypto::RSAKeyBundle
|
103
|
-
|
153
|
+
private_key.encoded == kp.private_key.encoded
|
104
154
|
else
|
105
155
|
false
|
106
156
|
end
|
@@ -126,6 +176,10 @@ module Ccrypto
|
|
126
176
|
|
127
177
|
teLogger_tag :j_rsa
|
128
178
|
|
179
|
+
def self.supported_params
|
180
|
+
[1024,2048,4096,8192]
|
181
|
+
end
|
182
|
+
|
129
183
|
def initialize(*args, &block)
|
130
184
|
@config = args.first
|
131
185
|
raise KeypairEngineException, "1st parameter must be a #{Ccrypto::KeypairConfig.class} object" if not @config.is_a?(Ccrypto::KeypairConfig)
|
@@ -8,18 +8,22 @@ module Ccrypto
|
|
8
8
|
include TR::CondUtils
|
9
9
|
|
10
10
|
def initialize(conf, &block)
|
11
|
+
|
11
12
|
raise KDFEngineException, "KDF config is expected" if not conf.is_a?(Ccrypto::KDFConfig)
|
12
13
|
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
|
14
15
|
|
15
16
|
if is_empty?(@config.salt)
|
16
|
-
@config.salt = Java::byte[16].new
|
17
|
-
java.security.SecureRandom.getInstance("NativePRNG").
|
17
|
+
@config.salt = ::Java::byte[16].new
|
18
|
+
java.security.SecureRandom.getInstance("NativePRNG").next_bytes(@config.salt)
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
22
|
def derive(input, output = :binary)
|
22
|
-
res = org.bouncycastle.crypto.generators.SCrypt.generate(to_java_bytes(input), to_java_bytes(@config.salt),@config.cost, @config.
|
23
|
+
res = org.bouncycastle.crypto.generators.SCrypt.generate(to_java_bytes(input), to_java_bytes(@config.salt),@config.cost, @config.blocksize, @config.parallel, @config.outBitLength/8)
|
24
|
+
|
25
|
+
#logger.debug "scrypt output : #{res.inspect}"
|
26
|
+
|
23
27
|
case output
|
24
28
|
when :hex
|
25
29
|
to_hex(res)
|
@@ -30,6 +34,11 @@ module Ccrypto
|
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
37
|
+
private
|
38
|
+
def logger
|
39
|
+
Ccrypto::Java.logger(:scrypt_eng)
|
40
|
+
end
|
41
|
+
|
33
42
|
end
|
34
43
|
end
|
35
44
|
end
|
@@ -2,41 +2,106 @@
|
|
2
2
|
|
3
3
|
module Ccrypto
|
4
4
|
module Java
|
5
|
+
|
6
|
+
class SecretKeyEngineException < StandardError; end
|
7
|
+
|
5
8
|
class SecretKeyEngine
|
9
|
+
include TR::CondUtils
|
10
|
+
include DataConversion
|
11
|
+
|
12
|
+
def self.supported_secret_key_configs
|
13
|
+
if @supKeyConf.nil?
|
14
|
+
@supKeyConf = []
|
15
|
+
supported_secret_key_config_table.each do |algo, keysize|
|
16
|
+
keysize.each do |k,v|
|
17
|
+
@supKeyConf << v
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
@supKeyConf
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.find_supported_secret_key_config(algo, keysize = nil)
|
25
|
+
res = supported_secret_key_config_table[algo] || {}
|
26
|
+
res[keysize] || nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.is_secret_key_config_supported?(algo, keysize = nil)
|
30
|
+
not find_supported_secret_key_config(algo. keysize).nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def self.supported_secret_key_config_table
|
35
|
+
if @seckey_configs.nil?
|
36
|
+
@seckey_configs = {}
|
6
37
|
|
7
|
-
|
8
|
-
|
9
|
-
|
38
|
+
CipherEngine.supported_ciphers.each do |cf|
|
39
|
+
kf = cf.key_config
|
40
|
+
algo = kf.algo.to_sym
|
41
|
+
keysize = kf.keysize
|
42
|
+
|
43
|
+
if @seckey_configs[algo].nil?
|
44
|
+
@seckey_configs[algo] = { }
|
45
|
+
@seckey_configs[algo][keysize] = kf
|
46
|
+
else
|
47
|
+
if is_empty?(@seckey_configs[algo][keysize])
|
48
|
+
@seckey_configs[algo][keysize] = kf
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
@seckey_configs
|
55
|
+
end
|
56
|
+
|
57
|
+
public
|
10
58
|
def self.generate(*args, &block)
|
11
59
|
config = args.first
|
12
60
|
|
13
|
-
raise SecretKeyEngineException, "KeyConfig is expected" if not config.is_a?(Ccrypto::KeyConfig)
|
61
|
+
raise SecretKeyEngineException, "KeyConfig is expected but got '#{config.class.name}'" if not config.is_a?(Ccrypto::KeyConfig)
|
62
|
+
raise SecretKeyEngineException, "Provider initialized KeyConfig is expected" if is_empty?(config.provider_config)
|
14
63
|
|
15
64
|
if block
|
16
65
|
kgProv = block.call(:keygen_jceProvider)
|
17
66
|
ranProv = block.call(:random_jceProvider)
|
67
|
+
else
|
68
|
+
kgProv = config.provider_config[:key_jce_provider] || JCEProvider::DEFProv
|
18
69
|
end
|
19
70
|
|
20
71
|
if kgProv.nil?
|
21
|
-
|
22
|
-
keyGen = javax.crypto.KeyGenerator.getInstance(config.
|
72
|
+
logger.debug "KeyGen using algo #{config.algo.to_s} with null provider"
|
73
|
+
keyGen = javax.crypto.KeyGenerator.getInstance(config.provider_config[:keygen_algo])
|
23
74
|
else
|
24
|
-
|
25
|
-
keyGen = javax.crypto.KeyGenerator.getInstance(config.
|
75
|
+
logger.debug "KeyGen using algo #{config.algo.to_s} with provider #{kgProv.is_a?(String) ? kgProv : kgProv.name}"
|
76
|
+
keyGen = javax.crypto.KeyGenerator.getInstance(config.provider_config[:keygen_algo], kgProv)
|
26
77
|
end
|
27
78
|
|
28
79
|
if ranProv.nil?
|
29
|
-
|
80
|
+
logger.debug "Init KeyGen with keysize #{config.keysize.to_i}"
|
30
81
|
keyGen.init(config.keysize.to_i)
|
31
82
|
else
|
32
|
-
|
83
|
+
logger.debug "Init KeyGen with keysize #{config.keysize.to_i} with provider #{ranProv.is_a?(String) ? ranProv : ranProv.name}"
|
33
84
|
keyGen.init(config.keysize.to_i, ranProv)
|
34
85
|
end
|
35
86
|
|
36
87
|
key = keyGen.generateKey
|
37
|
-
|
38
|
-
Ccrypto::SecretKey.new(config.algo, key)
|
88
|
+
logger.debug "Secret key #{config} generated"
|
89
|
+
sk = Ccrypto::SecretKey.new(config.algo, config.keysize, key)
|
90
|
+
sk.provider_config = config.provider_config
|
91
|
+
sk
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.secret_key_from_bin(bin, algo, keysize)
|
96
|
+
raise SecretKeyEngineException, "No data given to convert to secret key" if is_empty?(bin)
|
97
|
+
raise SecretKeyEngineException, "Algo cannot be empty" if is_empty?(algo)
|
98
|
+
|
99
|
+
Ccrypto::SecretKey.new(algo, keysize, javax.crypto.spec.SecretKeySpec.new(to_java_bytes(bin), algo.to_s))
|
100
|
+
end
|
39
101
|
|
102
|
+
private
|
103
|
+
def self.logger
|
104
|
+
Ccrypto::Java.logger(:seckey_eng)
|
40
105
|
end
|
41
106
|
|
42
107
|
end
|
@@ -3,14 +3,22 @@ require_relative '../data_conversion'
|
|
3
3
|
|
4
4
|
module Ccrypto
|
5
5
|
module Java
|
6
|
+
|
7
|
+
class SecretSharingException < Ccrypto::SecretSharingException; end
|
8
|
+
|
6
9
|
class SecretSharingEngine
|
7
10
|
include DataConversion
|
8
11
|
|
12
|
+
|
9
13
|
def initialize(*args, &block)
|
10
14
|
@config = args.first
|
15
|
+
|
11
16
|
raise SecretSharingException, "SecretSharingConfig is required" if not @config.is_a?(Ccrypto::SecretSharingConfig)
|
12
|
-
|
13
|
-
|
17
|
+
sit = @config.split_into.to_i
|
18
|
+
rp = @config.required_parts.to_i
|
19
|
+
raise SecretSharingException, "split_into value must be more than 1" if not sit > 1
|
20
|
+
raise SecretSharingException, "required_parts value must be more than 0" if not rp > 0
|
21
|
+
raise SecretSharingException, "required_parts value (#{@config.required_parts}) must be less than or equal split_into value (#{@config.split_into})." if not rp <= sit.to_i
|
14
22
|
end
|
15
23
|
|
16
24
|
def split(secVal)
|
@@ -36,6 +44,7 @@ module Ccrypto
|
|
36
44
|
# as the automated conversion of JRuby will turn the key into
|
37
45
|
# java.lang.Long instead of java.lang.Integer
|
38
46
|
# Using Map with parameterize auto conversion will failed inside the Java
|
47
|
+
partLength = -1
|
39
48
|
parts.each do |k,v|
|
40
49
|
if not v.is_a?(::Java::byte[])
|
41
50
|
vv = to_java_bytes(v)
|
@@ -43,6 +52,12 @@ module Ccrypto
|
|
43
52
|
vv = v
|
44
53
|
end
|
45
54
|
|
55
|
+
if partLength == -1
|
56
|
+
partLength = vv.length
|
57
|
+
else
|
58
|
+
raise SecretSharingException, "Invalid parts are given. Inconsistant part length (#{partLength} vs. #{vv.length})" if partLength != vv.length
|
59
|
+
end
|
60
|
+
|
46
61
|
jhash.put(java.lang.Integer.new(k),vv)
|
47
62
|
end
|
48
63
|
when java.util.Map
|
@@ -0,0 +1,249 @@
|
|
1
|
+
|
2
|
+
require_relative '../data_conversion'
|
3
|
+
|
4
|
+
module Ccrypto
|
5
|
+
module Java
|
6
|
+
|
7
|
+
class X25519PublicKey < Ccrypto::X25519PublicKey
|
8
|
+
include DataConversion
|
9
|
+
|
10
|
+
def to_bin
|
11
|
+
res = @native_pubKey.encoded
|
12
|
+
#puts "to_bion : #{to_hex(res)}"
|
13
|
+
res
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.to_key(bin)
|
17
|
+
pubKey = java.security.KeyFactory.getInstance("X25519", "BC").generatePublic(java.security.spec.X509EncodedKeySpec.new(bin))
|
18
|
+
X25519PublicKey.new(pubKey)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_pem
|
22
|
+
cont = ["-----BEGIN X25519 PUBLIC KEY-----\n"]
|
23
|
+
cont << to_b64(to_bin)
|
24
|
+
cont << "\n-----END X25519 PUBLIC KEY-----"
|
25
|
+
cont.join
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.from_pem(str)
|
29
|
+
if str =~ /X25519 PUBLIC/
|
30
|
+
cont = str.lines[1..-2].join.strip
|
31
|
+
to_key(from_b64(cont))
|
32
|
+
else
|
33
|
+
raise KeypairEngineException, "Not an X25519 public key"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end # X25519PublicKey
|
38
|
+
|
39
|
+
class X25519PrivateKey < Ccrypto::X25519PrivateKey
|
40
|
+
include DataConversion
|
41
|
+
|
42
|
+
def to_bin
|
43
|
+
@native_privKey.encoded
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.to_key(bin, &block)
|
47
|
+
if block
|
48
|
+
prov = block.call(:jce_provider)
|
49
|
+
else
|
50
|
+
prov = JCEProvider::BCProv
|
51
|
+
end
|
52
|
+
|
53
|
+
kf = java.security.KeyFactory.getInstance("X25519",prov)
|
54
|
+
priv = kf.generate_private(java.security.spec.PKCS8EncodedKeySpec.new(bin))
|
55
|
+
X25519PrivateKey.new(priv)
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_pem
|
60
|
+
cont = ["-----BEGIN X25519 PRIVATE KEY-----\n"]
|
61
|
+
cont << to_b64(@native_privKey.encoded)
|
62
|
+
cont << "\n-----END X25519 PRIVATE KEY-----"
|
63
|
+
cont.join
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.from_pem(str)
|
67
|
+
if str =~ /X25519 PRIVATE/
|
68
|
+
cont = str.lines[1..-2].join.strip
|
69
|
+
to_key(from_b64(cont))
|
70
|
+
else
|
71
|
+
raise KeypairEngineException, "Not an X25519 private key"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def equals?(privKey)
|
76
|
+
if not @native_privKey.nil?
|
77
|
+
case privKey
|
78
|
+
when X25519PrivateKey
|
79
|
+
@native_privKey.encoded == privKey.to_bin
|
80
|
+
else
|
81
|
+
logger.warn "Unmatched private key : (native) #{@native_privKey} vs. (subject) #{privKey}"
|
82
|
+
false
|
83
|
+
end
|
84
|
+
else
|
85
|
+
logger.warn "X25519PrivateKey equals? returned false because native_privKey is nil"
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
alias_method :key_equals?, :equals?
|
90
|
+
|
91
|
+
end # X25519PrivateKey
|
92
|
+
|
93
|
+
class X25519KeyBundle
|
94
|
+
include Ccrypto::X25519KeyBundle
|
95
|
+
include Ccrypto::X25519KeyBundle
|
96
|
+
|
97
|
+
include TR::CondUtils
|
98
|
+
include DataConversion
|
99
|
+
|
100
|
+
include TeLogger::TeLogHelper
|
101
|
+
teLogger_tag :x25519_kb_j
|
102
|
+
|
103
|
+
def initialize(kp)
|
104
|
+
@nativeKeypair = kp
|
105
|
+
end
|
106
|
+
|
107
|
+
def public_key
|
108
|
+
if @pubKey.nil?
|
109
|
+
@pubKey = X25519PublicKey.new(@nativeKeypair.getPublic)
|
110
|
+
end
|
111
|
+
@pubKey
|
112
|
+
end
|
113
|
+
|
114
|
+
def private_key
|
115
|
+
X25519PrivateKey.new(@nativeKeypair.getPrivate)
|
116
|
+
end
|
117
|
+
|
118
|
+
def derive_dh_shared_secret(pubKey, &block)
|
119
|
+
|
120
|
+
JCEProvider.instance.add_bc_provider
|
121
|
+
|
122
|
+
ka = javax.crypto.KeyAgreement.getInstance("X25519",JCEProvider::BCProv.name)
|
123
|
+
ka.init(@nativeKeypair.getPrivate)
|
124
|
+
|
125
|
+
case pubKey
|
126
|
+
when X25519PublicKey
|
127
|
+
uPubKey = pubKey.native_pubKey
|
128
|
+
else
|
129
|
+
raise KeypairEngineException, "Unsupported public key type '#{pubKey.class}'"
|
130
|
+
end
|
131
|
+
|
132
|
+
ka.doPhase(uPubKey, true)
|
133
|
+
ka.generateSecret()
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
## should be under keybundle_store but not sure how to do this
|
138
|
+
def to_storage(eng = :ccrypto, &block)
|
139
|
+
case eng
|
140
|
+
when :ccrypto
|
141
|
+
res = { }
|
142
|
+
|
143
|
+
rawPrivate = false
|
144
|
+
rawPublic = false
|
145
|
+
if block
|
146
|
+
rawPrivate = block.call(:export_raw_private_key)
|
147
|
+
rawPublic = block.call(:export_raw_public_key)
|
148
|
+
end
|
149
|
+
|
150
|
+
res[:private] = private_key.to_bin
|
151
|
+
if rawPrivate == true
|
152
|
+
# 5th Sept 2022 - untested code
|
153
|
+
res[:private] = org.bouncycastle.crypto.params.X25519PrivateKeyParameters.new(res[:private],0).encoded
|
154
|
+
res[:raw_private] = true
|
155
|
+
end
|
156
|
+
|
157
|
+
res[:public] = public_key.to_bin
|
158
|
+
if rawPublic == true
|
159
|
+
# 5th Sept 2022 - untested code
|
160
|
+
res[:public] = org.bouncycastle.crypto.params.X25519PublicKeyParameters.new(res[:public],0).encoded
|
161
|
+
res[:raw_public] = true
|
162
|
+
end
|
163
|
+
|
164
|
+
res
|
165
|
+
else
|
166
|
+
raise KeypairEngineException, "Unsupported storage type '#{eng}'"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.from_storage(bin)
|
171
|
+
case bin
|
172
|
+
when Hash
|
173
|
+
res = { }
|
174
|
+
JCEProvider.instance.add_bc_provider
|
175
|
+
|
176
|
+
kf = java.security.KeyFactory.getInstance("X25519", JCEProvider::BCProv.name)
|
177
|
+
|
178
|
+
if not_empty?(bin[:private])
|
179
|
+
# raw_private = true means the given private key is in its raw data form
|
180
|
+
# 5th Sept 22 - Not tested not sure how to generate raw key
|
181
|
+
if bin[:raw_private] == true
|
182
|
+
# 5th Sept 2022 - untested code
|
183
|
+
info = org.bouncycastle.asn1.pkcs.PrivateKeyInfo.new(org.bouncycastle.asn1.x509.AlgorithmIdentifier.new(org.bouncycastle.asn1.edec.EdECObjectIdentifiers::id_X25519), org.bouncycastle.asn1.DEROctetString.new(bin[:private]))
|
184
|
+
|
185
|
+
spec = java.security.spec.PKCS8EncodedKeySpec.new(info.encoded)
|
186
|
+
else
|
187
|
+
spec = java.security.spec.PKCS8EncodedKeySpec.new(bin[:private])
|
188
|
+
end
|
189
|
+
|
190
|
+
res[:private] = X25519PrivateKey.new(kf.generatePrivate(spec))
|
191
|
+
|
192
|
+
#res[:private] = X25519PrivateKey.new(org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters.new(bin[:private],0))
|
193
|
+
end
|
194
|
+
|
195
|
+
if not_empty?(bin[:public])
|
196
|
+
if bin[:raw_public] == true
|
197
|
+
# 5th Sept 2022 - untested code
|
198
|
+
#pubRaw = org.bouncycastle.crypto.params.Ed25519PublicKeyParameters.new(bin[:public],0).encoded
|
199
|
+
pubRaw = bin[:public]
|
200
|
+
info = org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.new(org.bouncycastle.asn1.x509.AlgorithmIdentifier.new(org.bouncycastle.asn1.edec.EdECObjectIdentifiers::id_X25519), bin[:public])
|
201
|
+
|
202
|
+
spec = java.security.spec.X509EncodedKeySpec.new(info.encoded)
|
203
|
+
else
|
204
|
+
spec = java.security.spec.X509EncodedKeySpec.new(bin[:public])
|
205
|
+
end
|
206
|
+
|
207
|
+
res[:public] = X25519PublicKey.new(kf.generatePublic(spec))
|
208
|
+
end
|
209
|
+
|
210
|
+
res[:keypair] = X25519KeyBundle.new(java.security.KeyPair.new(res[:public].native_pubKey, res[:private].native_privKey)) if not_empty?(res[:public]) and not_empty?(res[:private])
|
211
|
+
|
212
|
+
res
|
213
|
+
|
214
|
+
else
|
215
|
+
raise KeypairEngineException, "No sure how to handle storage input '#{bin.class}'"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
end # X25519KeyBundle
|
220
|
+
|
221
|
+
class X25519Engine
|
222
|
+
include TR::CondUtils
|
223
|
+
include DataConversion
|
224
|
+
|
225
|
+
include TeLogger::TeLogHelper
|
226
|
+
teLogger_tag :x25519_eng_j
|
227
|
+
|
228
|
+
def self.supported_params
|
229
|
+
[]
|
230
|
+
end
|
231
|
+
|
232
|
+
def initialize(*args, &block)
|
233
|
+
@config = args.first
|
234
|
+
end
|
235
|
+
|
236
|
+
def generate_keypair(&block)
|
237
|
+
|
238
|
+
JCEProvider.instance.add_bc_provider
|
239
|
+
kg = java.security.KeyPairGenerator.getInstance("X25519", JCEProvider::BCProv.name)
|
240
|
+
kg.java_send(:initialize, [java.security.spec.AlgorithmParameterSpec], org.bouncycastle.jcajce.spec.XDHParameterSpec.new(org.bouncycastle.jcajce.spec.XDHParameterSpec::X25519))
|
241
|
+
X25519KeyBundle.new(kg.generateKeyPair)
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
end
|