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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ed49b9ca739655cee06b71573b4ef1c7f8c799e2a3692fb35e7dd0f1d80d212
4
- data.tar.gz: a2a6f2e31558e35661eb5d882616c837d174359786a19f5e5ba85d03fb4326a6
3
+ metadata.gz: 1146c068eb45ee56e853601aab7d2cc529814e6667254579a9133d3a44977a63
4
+ data.tar.gz: 87ec42fb26124ec1d0d23fc6d11f74d4dc434c22f17dafc0ef803053555cba22
5
5
  SHA512:
6
- metadata.gz: d878db822fc637d3e9e9aa6a4c93b2b168c65a1432f4496b5dc013c1b16d4e7a0ee8acb946561091addc966e71479c00fd9467c8719e74454d3a46590c7ce456
7
- data.tar.gz: 0c1ea6ad5a25c496b2bb43c871f5ce7355bd7143ae7cbcdb2c1bc33755952f8854ef6a4c1fa4d96bbf42ca40bcee13cf399c739b903f961460b3148d6e68cded
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
- OpenSSL::PKey.new_raw_private_key("ED25519", seed.b)
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).raw_public_key
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
- OpenSSL::PKey.new_raw_public_key("ED25519", public_key.b).verify(nil, signature.b, msg.b)
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
- OpenSSL::PKey.new_raw_private_key("X25519", scalar.b).raw_public_key
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
- OpenSSL::PKey.new_raw_private_key("X25519", scalar.b)
163
- .derive(OpenSSL::PKey.new_raw_public_key("X25519", point.b))
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module SQRL
4
4
  # Version shared by every gem in the family.
5
- VERSION = "0.1.0"
5
+ VERSION = "0.1.1"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqrl-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel P. Clark