sygna 0.1.3 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sygna/crypt.rb +21 -72
- data/lib/sygna/signature.rb +7 -3
- data/lib/sygna/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 207581b951aa254c6b3db5d358a28ea78130312d96f480ecd0917c2729c9c5e0
|
4
|
+
data.tar.gz: 4f4257a9ac614e9d77c686eae821929112c6e6057de2bdc9f1e1a9f1ecf247a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74b1331f0a72b5ab457394f078fc6a19fe08cc8665140e59c84669a9859c74396ce19963a627f11f2f986d7b4d32a98e1782050b8d93277d086af915c97c41c2
|
7
|
+
data.tar.gz: 2d6f3f64d2d5c117ee1d7faba488bcf91fd3887c10a6d57ee8d86b1f7cda5398a6be99005bb6f6054b627b67dbe5802e2203947d367e7fbcfb50b944ac1d36e4
|
data/lib/sygna/crypt.rb
CHANGED
@@ -25,32 +25,14 @@ module Sygna
|
|
25
25
|
# {CIPHERS}.
|
26
26
|
# @param digest [String,OpenSSL::Digest] The digest algorithm to use for
|
27
27
|
# HMAC and KDF. Must be one of {DIGESTS}.
|
28
|
-
# @param mac_length [:half,:full] The length of the mac. If :half, the mac
|
29
|
-
# length will be equal to half the mac_digest's digest_legnth. If
|
30
|
-
# :full, the mac length will be equal to the mac_digest's
|
31
|
-
# digest_length.
|
32
|
-
# @param kdf_digest [String,OpenSSL::Digest,nil] The digest algorithm to
|
33
|
-
# use for KDF. If not specified, the `digest` argument will be used.
|
34
28
|
# @param mac_digest [String,OpenSSL::Digest,nil] The digest algorithm to
|
35
29
|
# use for HMAC. If not specified, the `digest` argument will be used.
|
36
|
-
|
37
|
-
# info used for KDF, also known as SharedInfo1.
|
38
|
-
# @param mac_shared_info [String] Optional. A string containing the shared
|
39
|
-
# info used for MAC, also known as SharedInfo2.
|
40
|
-
def initialize(cipher: 'AES-256-CTR', digest: 'SHA256', mac_length: :half, kdf_digest: nil, mac_digest: nil, kdf_shared_info: '', mac_shared_info: '')
|
30
|
+
def initialize(cipher: 'AES-256-CTR', digest: 'SHA256', mac_digest: nil)
|
41
31
|
@cipher = OpenSSL::Cipher.new(cipher)
|
42
32
|
@mac_digest = OpenSSL::Digest.new(mac_digest || digest)
|
43
|
-
@kdf_digest = OpenSSL::Digest.new(kdf_digest || digest)
|
44
|
-
@kdf_shared_info = kdf_shared_info
|
45
|
-
@mac_shared_info = mac_shared_info
|
46
33
|
|
47
34
|
CIPHERS.include?(@cipher.name) or raise "Cipher must be one of #{CIPHERS}"
|
48
35
|
DIGESTS.include?(@mac_digest.name) or raise "Digest must be one of #{DIGESTS}"
|
49
|
-
DIGESTS.include?(@kdf_digest.name) or raise "Digest must be one of #{DIGESTS}"
|
50
|
-
[:half, :full].include?(mac_length) or raise "mac_length must be :half or :full"
|
51
|
-
|
52
|
-
@mac_length = @mac_digest.digest_length
|
53
|
-
@mac_length /= 2 if mac_length == :half
|
54
36
|
end
|
55
37
|
|
56
38
|
# Encrypts a message to a public key using ECIES.
|
@@ -63,23 +45,27 @@ module Sygna
|
|
63
45
|
@cipher.reset
|
64
46
|
|
65
47
|
group_copy = OpenSSL::PKey::EC::Group.new(key.group)
|
66
|
-
|
48
|
+
|
67
49
|
ephemeral_key = OpenSSL::PKey::EC.new(group_copy).generate_key
|
68
50
|
ephemeral_public_key_octet = ephemeral_key.public_key.to_bn.to_s(2)
|
69
51
|
|
70
52
|
shared_secret = ephemeral_key.dh_compute_key(key.public_key)
|
71
53
|
|
72
|
-
|
73
|
-
|
74
|
-
|
54
|
+
hashed_secret = Digest::SHA512.digest(shared_secret)
|
55
|
+
|
56
|
+
cipher_key = hashed_secret.slice(0, 32)
|
57
|
+
hmac_key = hashed_secret.slice(32, hashed_secret.length - 32)
|
75
58
|
|
76
59
|
@cipher.encrypt
|
77
60
|
@cipher.iv = IV
|
78
61
|
@cipher.key = cipher_key
|
79
62
|
ciphertext = @cipher.update(message) + @cipher.final
|
80
63
|
|
81
|
-
|
64
|
+
data_to_mac = IV + ephemeral_public_key_octet + ciphertext
|
82
65
|
|
66
|
+
mac = OpenSSL::HMAC.digest(@mac_digest, hmac_key, data_to_mac)
|
67
|
+
|
68
|
+
# 65 + 20 + 16
|
83
69
|
ephemeral_public_key_octet + mac + ciphertext
|
84
70
|
end
|
85
71
|
|
@@ -93,25 +79,25 @@ module Sygna
|
|
93
79
|
@cipher.reset
|
94
80
|
|
95
81
|
group_copy = OpenSSL::PKey::EC::Group.new(key.group)
|
96
|
-
group_copy.point_conversion_form = :compressed
|
97
82
|
|
98
|
-
|
99
|
-
|
100
|
-
|
83
|
+
ephemeral_public_key_octet = encrypted_message.slice(0, 65)
|
84
|
+
|
85
|
+
mac = encrypted_message.slice(65, 20)
|
101
86
|
|
102
|
-
|
103
|
-
ciphertext = encrypted_message.byteslice(ephemeral_public_key_length, ciphertext_length)
|
104
|
-
mac = encrypted_message.byteslice(-@mac_length, @mac_length)
|
87
|
+
ciphertext = encrypted_message.slice(85, encrypted_message.size)
|
105
88
|
|
106
89
|
ephemeral_public_key = OpenSSL::PKey::EC::Point.new(group_copy, OpenSSL::BN.new(ephemeral_public_key_octet, 2))
|
107
90
|
|
108
91
|
shared_secret = key.dh_compute_key(ephemeral_public_key)
|
109
92
|
|
110
|
-
|
111
|
-
|
112
|
-
|
93
|
+
hashed_secret = Digest::SHA512.digest(shared_secret)
|
94
|
+
|
95
|
+
cipher_key = hashed_secret.slice(0, 32)
|
96
|
+
hmac_key = hashed_secret.slice(32, hashed_secret.length)
|
113
97
|
|
114
|
-
|
98
|
+
data_to_mac = IV + ephemeral_public_key_octet + ciphertext
|
99
|
+
|
100
|
+
computed_mac = OpenSSL::HMAC.digest("SHA1", hmac_key, data_to_mac)
|
115
101
|
computed_mac == mac or raise OpenSSL::PKey::ECError, "Invalid Message Authenticaton Code"
|
116
102
|
|
117
103
|
@cipher.decrypt
|
@@ -121,43 +107,6 @@ module Sygna
|
|
121
107
|
@cipher.update(ciphertext) + @cipher.final
|
122
108
|
end
|
123
109
|
|
124
|
-
# Key-derivation function, compatible with ANSI-X9.63-KDF
|
125
|
-
#
|
126
|
-
# @param shared_secret [String] The shared secret from which the key will
|
127
|
-
# be derived.
|
128
|
-
# @param length [Integer] The length of the key to generate.
|
129
|
-
# @param shared_info_suffix [String] The suffix to append to the
|
130
|
-
# shared_info.
|
131
|
-
# @return [String] Octet string of the derived key.
|
132
|
-
def kdf(shared_secret, length, shared_info_suffix)
|
133
|
-
length >=0 or raise "length cannot be negative"
|
134
|
-
return "" if length == 0
|
135
|
-
|
136
|
-
if length / @kdf_digest.digest_length >= 0xFF_FF_FF_FF
|
137
|
-
raise "length too large"
|
138
|
-
end
|
139
|
-
|
140
|
-
io = StringIO.new(String.new)
|
141
|
-
counter = 0
|
142
|
-
|
143
|
-
loop do
|
144
|
-
counter += 1
|
145
|
-
counter_bytes = [counter].pack('N')
|
146
|
-
|
147
|
-
io << @kdf_digest.digest(shared_secret + counter_bytes + @kdf_shared_info + shared_info_suffix)
|
148
|
-
if io.pos >= length
|
149
|
-
return io.string.byteslice(0, length)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
# @return [String] A string representing this Crypt's parameters.
|
155
|
-
def to_s
|
156
|
-
"KDF-#{@kdf_digest.name}_" +
|
157
|
-
"HMAC-SHA-#{@mac_digest.digest_length * 8}-#{@mac_length * 8}_" +
|
158
|
-
@cipher.name
|
159
|
-
end
|
160
|
-
|
161
110
|
# Converts a hex-encoded public key to an `OpenSSL::PKey::EC`.
|
162
111
|
#
|
163
112
|
# @param hex_string [String] The hex-encoded public key.
|
data/lib/sygna/signature.rb
CHANGED
@@ -8,14 +8,18 @@ module Sygna
|
|
8
8
|
Secp256k1::Utils.encode_hex(ecdsa_private_key.ecdsa_serialize_compact(ecdsa_private_key.ecdsa_sign(object_string)))
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.verify(object, signature)
|
11
|
+
def self.verify(object, signature, public_key)
|
12
12
|
object_string = object.merge(EMPTY_SIGNATURE).to_json
|
13
13
|
|
14
14
|
raw_signature = Secp256k1::Utils.decode_hex(signature)
|
15
15
|
|
16
|
-
|
16
|
+
public_key_binary = [public_key].pack("H*")
|
17
17
|
|
18
|
-
|
18
|
+
ecdsa_public_key = Secp256k1::PublicKey.new(pubkey: public_key)
|
19
|
+
|
20
|
+
signature = ecdsa_public_key.ecdsa_deserialize_compact(raw_signature)
|
21
|
+
|
22
|
+
ecdsa_public_key.ecdsa_verify(object_string, signature)
|
19
23
|
end
|
20
24
|
|
21
25
|
def self.ecdsa_private_key
|
data/lib/sygna/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sygna
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nic
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|