sqrl-core 0.1.0 → 0.1.1
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/CHANGELOG.md +7 -0
- data/lib/sqrl/crypto.rb +49 -6
- data/lib/sqrl/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1146c068eb45ee56e853601aab7d2cc529814e6667254579a9133d3a44977a63
|
|
4
|
+
data.tar.gz: 87ec42fb26124ec1d0d23fc6d11f74d4dc434c22f17dafc0ef803053555cba22
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4fd9a937c4b7c134ca7c85900dd46184c9275bca550744b942864beacb4c486a704c99e18fb05e67096dca828aa205be1c8d52af077c112a5b128e80eb79aa28
|
|
7
|
+
data.tar.gz: 5a7477a6d9a87ab52987087c7afb009a21037928b446171a6e8353837be995f6a8c318020c7c48234ddbdd579e8bec6f42b960a65cebc3396ad238105d1073fa
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1 — 2026-10-20
|
|
4
|
+
|
|
5
|
+
- Fixed: Ed25519 and X25519 keys are built from their DER encodings when the openssl gem
|
|
6
|
+
has no `OpenSSL::PKey.new_raw_private_key` / `new_raw_public_key` (openssl 3.0 and 3.1,
|
|
7
|
+
bundled with Ruby 3.1 and 3.2). 0.1.0 raised `NoMethodError` on those Rubies as soon as
|
|
8
|
+
an identity was derived, signed or verified.
|
|
9
|
+
|
|
3
10
|
## 0.1.0 — 2026-10-20
|
|
4
11
|
|
|
5
12
|
First release.
|
data/lib/sqrl/crypto.rb
CHANGED
|
@@ -19,6 +19,25 @@ module SQRL
|
|
|
19
19
|
# Default scrypt log2(N) used by SQRL clients (N = 512).
|
|
20
20
|
DEFAULT_LOG_N = 9
|
|
21
21
|
|
|
22
|
+
# Whether the openssl gem has OpenSSL::PKey.new_raw_private_key / new_raw_public_key
|
|
23
|
+
# (openssl 3.2, bundled with Ruby 3.3). Older supported versions (openssl 3.0 and 3.1,
|
|
24
|
+
# bundled with Ruby 3.1 and 3.2) build the same keys from their DER encodings instead.
|
|
25
|
+
RAW_KEY_API = OpenSSL::PKey.respond_to?(:new_raw_private_key) && OpenSSL::PKey.respond_to?(:new_raw_public_key)
|
|
26
|
+
|
|
27
|
+
# DER prefixes that turn a 32-byte Ed25519 / X25519 key into a PKCS#8 PrivateKeyInfo or
|
|
28
|
+
# a SubjectPublicKeyInfo (RFC 8410): the key bytes follow the prefix verbatim.
|
|
29
|
+
DER_PREFIXES = {
|
|
30
|
+
"ED25519" => {
|
|
31
|
+
private: ["302e020100300506032b657004220420"].pack("H*"),
|
|
32
|
+
public: ["302a300506032b6570032100"].pack("H*")
|
|
33
|
+
},
|
|
34
|
+
"X25519" => {
|
|
35
|
+
private: ["302e020100300506032b656e04220420"].pack("H*"),
|
|
36
|
+
public: ["302a300506032b656e032100"].pack("H*")
|
|
37
|
+
}
|
|
38
|
+
}.freeze
|
|
39
|
+
private_constant :DER_PREFIXES
|
|
40
|
+
|
|
22
41
|
module_function
|
|
23
42
|
|
|
24
43
|
# SHA-256 digest.
|
|
@@ -130,12 +149,12 @@ module SQRL
|
|
|
130
149
|
def ed25519_from_seed(seed)
|
|
131
150
|
raise CryptoError, "ed25519 seed must be 32 bytes" unless seed.bytesize == 32
|
|
132
151
|
|
|
133
|
-
|
|
152
|
+
raw_private_key("ED25519", seed.b)
|
|
134
153
|
end
|
|
135
154
|
|
|
136
155
|
# Public key bytes of the Ed25519 key derived from +seed+.
|
|
137
156
|
def ed25519_public(seed)
|
|
138
|
-
ed25519_from_seed(seed)
|
|
157
|
+
raw_public_bytes(ed25519_from_seed(seed))
|
|
139
158
|
end
|
|
140
159
|
|
|
141
160
|
# Sign +msg+ with the Ed25519 key derived from +seed+; returns the 64-byte signature.
|
|
@@ -147,20 +166,44 @@ module SQRL
|
|
|
147
166
|
def ed25519_verify(public_key, msg, signature)
|
|
148
167
|
return false unless public_key.bytesize == 32 && signature.bytesize == 64
|
|
149
168
|
|
|
150
|
-
|
|
169
|
+
raw_public_key("ED25519", public_key.b).verify(nil, signature.b, msg.b)
|
|
151
170
|
rescue OpenSSL::PKey::PKeyError
|
|
152
171
|
false
|
|
153
172
|
end
|
|
154
173
|
|
|
155
174
|
# X25519 public key for a scalar (scalar multiplication of the base point).
|
|
156
175
|
def x25519_base(scalar)
|
|
157
|
-
|
|
176
|
+
raw_public_bytes(raw_private_key("X25519", scalar.b))
|
|
158
177
|
end
|
|
159
178
|
|
|
160
179
|
# X25519 Diffie-Hellman: +scalar * point+.
|
|
161
180
|
def x25519(scalar, point)
|
|
162
|
-
|
|
163
|
-
|
|
181
|
+
raw_private_key("X25519", scalar.b).derive(raw_public_key("X25519", point.b))
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Private key object of +type+ ("ED25519" or "X25519") from its 32 raw bytes.
|
|
185
|
+
# @api private
|
|
186
|
+
def raw_private_key(type, bytes)
|
|
187
|
+
return OpenSSL::PKey.new_raw_private_key(type, bytes) if RAW_KEY_API
|
|
188
|
+
|
|
189
|
+
OpenSSL::PKey.read(DER_PREFIXES.fetch(type)[:private] + bytes)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Public key object of +type+ ("ED25519" or "X25519") from its 32 raw bytes.
|
|
193
|
+
# @api private
|
|
194
|
+
def raw_public_key(type, bytes)
|
|
195
|
+
return OpenSSL::PKey.new_raw_public_key(type, bytes) if RAW_KEY_API
|
|
196
|
+
|
|
197
|
+
OpenSSL::PKey.read(DER_PREFIXES.fetch(type)[:public] + bytes)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# The 32 raw public key bytes of an Ed25519 or X25519 key object.
|
|
201
|
+
# @api private
|
|
202
|
+
def raw_public_bytes(pkey)
|
|
203
|
+
return pkey.raw_public_key if RAW_KEY_API
|
|
204
|
+
|
|
205
|
+
# A SubjectPublicKeyInfo for these key types is the 12-byte prefix followed by the key.
|
|
206
|
+
pkey.public_to_der[-32, 32]
|
|
164
207
|
end
|
|
165
208
|
end
|
|
166
209
|
end
|
data/lib/sqrl/version.rb
CHANGED