elliptic 0.2.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50c1f0afa4d55fd9b936ddc1ef0c38ede63054432aae99aa2b717ba21bc819c7
4
- data.tar.gz: e9d57e5bfece39941288e66fd9b087d99660dfa25a42e723b69f96f85c690fd0
3
+ metadata.gz: b669851bc198139a145ad4e0fcec669c63e5510836322db51787ceb8d09362c5
4
+ data.tar.gz: 1a125a73561286cf5670085f910e8c37c0ed48c9564400219885a24526dbe0de
5
5
  SHA512:
6
- metadata.gz: 56cc6e7d72f921b61701d6ca2d1d25383b91377607752db4f96a7d12c56881fdfda1bcccfe2177ff8695114de81822ea9fbc8b0ccecfa1546f4c678393b2b933
7
- data.tar.gz: c8ec4acab2b3495b8937bee4e7488d6d3922b31a6ec13473a877ea30249319e0c8eacc4c89062cd76d3e1a4c078c95d36579b2b420b2a55e931ace6be9b69692
6
+ metadata.gz: 9f1ed708148cf5c8dd47ab00c22dfeee9ce43f3967c1626b7f1ed90947d0fb01512e2dbbd6ce0e43ef49a913a59abec48c80c86ba95854d89d62f9061c0daaa8
7
+ data.tar.gz: bb86040e5624540f3f66368b0f1c1759fe2d0e1eaf0bc2c882f0c14d0e72b4cb685de6baebd84008262fb5f07cfe9775fa40394bf79fcef0142642113bab26ad
data/README.md CHANGED
@@ -194,7 +194,9 @@ That's all the magic.
194
194
 
195
195
 
196
196
 
197
- ## Public Key Formats
197
+ ### Private / Public Key Formats
198
+
199
+ #### Intro
198
200
 
199
201
  To get the all-in-one-string
200
202
  public key from a point with the coordinates x and y
@@ -237,6 +239,112 @@ point.to_s( :compressed )
237
239
  #=> "02e37648435c60dcd181b3d41d50857ba5b5abebe279429aa76558f6653f1658f2"
238
240
  ```
239
241
 
242
+ #### PEM, DER, BASE64(DER)
243
+
244
+ **Export**
245
+
246
+ To export a private or public key to
247
+ the Privacy Enhanced Mail (PEM) format use `to_pem`:
248
+
249
+
250
+ ``` ruby
251
+ private_key = EC::PrivateKey.generate
252
+ private_key.to_pem
253
+ #=> "-----BEGIN EC PRIVATE KEY-----
254
+ # MHQCAQEEIDIWkCIC58Yo1E5noSiXbHdR/8zUqB+vvTK4nSk8tZ1RoAcGBSuBBAAK
255
+ # oUQDQgAEoll8rYerfDH4q6nT1miTZZ315a8BFsKA13Z8Zif5Mh+qavIr/6HpI/Kq
256
+ # Q0bnuOZiCD9gpEIWo7VGN8wJgcu6ZA==
257
+ # -----END EC PRIVATE KEY-----"
258
+
259
+ public_key = private_key.public_key
260
+ public_key.to_pem
261
+ #=> "-----BEGIN PUBLIC KEY-----
262
+ # MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEoll8rYerfDH4q6nT1miTZZ315a8BFsKA
263
+ # 13Z8Zif5Mh+qavIr/6HpI/KqQ0bnuOZiCD9gpEIWo7VGN8wJgcu6ZA==
264
+ # -----END PUBLIC KEY-----"
265
+ ```
266
+
267
+ To export a private or public key to
268
+ the (binary) Distinguished Encoding Rules (DER)
269
+ in ASN.1 format use `to_der`:
270
+
271
+ ``` ruby
272
+ private_key.to_der
273
+ #=> "\xA1D\x03B\x00\x04\xA2Y|\xAD\x87\xAB|1
274
+ # \xF8\xAB\xA9\xD3\xD6h\x93e\x9D\xF5\xE5\xAF\x01\x16\xC2\x80
275
+ # \xD7v|f'\xF92\x1F\xAAj\xF2+\xFF\xA1\xE9#\xF2\xAACF\xE7\xB8
276
+ # \xE6b\b?`\xA4B\x16\xA3\xB5F7\xCC\t\x81\xCB\xBAd"
277
+
278
+ public_key = private_key.public_key
279
+ public_key.to_der
280
+ #=> "0V0\x10\x06\a*\x86H\xCE=\x02\x01\x06\x05+\x81\x04\x00
281
+ # \x03B\x00\x04\xA2Y|\xAD\x87\xAB|1\xF8\xAB\xA9
282
+ # \xD3\xD6h\x93e\x9D\xF5\xE5\xAF\x01\x16\xC2\x80\xD7v|f'\xF92
283
+ # \x1F\xAAj\xF2+\xFF\xA1\xE9#\xF2\xAACF\xE7\xB8\xE6b
284
+ # \b?`\xA4B\x16\xA3\xB5F7\xCC\t\x81\xCB\xBAd"
285
+ ```
286
+
287
+ To export a private or public key to
288
+ the Base64-encoded Distinguished Encoding Rules (DER)
289
+ in ASN.1 format use `to_base64`:
290
+
291
+ ``` ruby
292
+ private_key.to_base64
293
+ #=> "MHQCAQEEIDIWkCIC58Yo1E5noSiXbHdR/8zUqB+vvTK4nSk8tZ1RoAcGBSuBBAAK
294
+ # oUQDQgAEoll8rYerfDH4q6nT1miTZZ315a8BFsKA13Z8Zif5Mh+qavIr/6HpI/Kq
295
+ # Q0bnuOZiCD9gpEIWo7VGN8wJgcu6ZA=="
296
+
297
+ public_key = private_key.public_key
298
+ public_key.to_base64
299
+ #=> "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEoll8rYerfDH4q6nT1miTZZ315a8BFsKA
300
+ # 13Z8Zif5Mh+qavIr/6HpI/KqQ0bnuOZiCD9gpEIWo7VGN8wJgcu6ZA=="
301
+ ```
302
+
303
+ **Import**
304
+
305
+ To import a private or public key
306
+ in the PEM or DER format use the all-in-one convenience constructor:
307
+
308
+
309
+ ``` ruby
310
+ private_key = EC::PrivateKey.new( "-----BEGIN EC PRIVATE KEY-----
311
+ MHQCAQEEIDIWkCIC58Yo1E5noSiXbHdR/8zUqB+vvTK4nSk8tZ1RoAcGBSuBBAAK
312
+ oUQDQgAEoll8rYerfDH4q6nT1miTZZ315a8BFsKA13Z8Zif5Mh+qavIr/6HpI/Kq
313
+ Q0bnuOZiCD9gpEIWo7VGN8wJgcu6ZA==
314
+ -----END EC PRIVATE KEY-----" )
315
+
316
+ public_key = EC::PublicKey.new( "-----BEGIN PUBLIC KEY-----
317
+ MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEoll8rYerfDH4q6nT1miTZZ315a8BFsKA
318
+ 13Z8Zif5Mh+qavIr/6HpI/KqQ0bnuOZiCD9gpEIWo7VGN8wJgcu6ZA==
319
+ -----END PUBLIC KEY-----" )
320
+
321
+ ## or
322
+
323
+ private_key = EC::PrivateKey.new( "\xA1D\x03B\x00\x04\xA2Y|\xAD\x87\xAB|1
324
+ \xF8\xAB\xA9\xD3\xD6h\x93e\x9D\xF5\xE5\xAF\x01\x16\xC2\x80
325
+ \xD7v|f'\xF92\x1F\xAAj\xF2+\xFF\xA1\xE9#\xF2\xAACF\xE7\xB8
326
+ \xE6b\b?`\xA4B\x16\xA3\xB5F7\xCC\t\x81\xCB\xBAd".b )
327
+
328
+ public_key = EC::PublicKey.new( "0V0\x10\x06\a*\x86H\xCE=\x02\x01\x06\x05+\x81\x04\x00
329
+ \x03B\x00\x04\xA2Y|\xAD\x87\xAB|1\xF8\xAB\xA9
330
+ \xD3\xD6h\x93e\x9D\xF5\xE5\xAF\x01\x16\xC2\x80\xD7v|f'\xF92
331
+ \x1F\xAAj\xF2+\xFF\xA1\xE9#\xF2\xAACF\xE7\xB8\xE6b
332
+ \b?`\xA4B\x16\xA3\xB5F7\xCC\t\x81\xCB\xBAd".b )
333
+ ```
334
+
335
+ or use the decode/from helper:
336
+
337
+ ``` ruby
338
+ private_key = EC::PrivateKey.decode_pem( ... ) # or from_pem( ... )
339
+ EC::PrivateKey.decode_der( ... ) # or from_der( ... )
340
+ EC::PrivateKey.decode_base64( ... ) # or from_base64( ... )
341
+
342
+ public_key = EC::PublicKey.decode_pem( ... ) # or from_pem( ... )
343
+ EC::PublicKey.decode_der( ... ) # or from_der( ... )
344
+ EC::PublicKey.decode_base64( ... ) # or from_base64( ... )
345
+ ```
346
+
347
+
240
348
 
241
349
  That's it.
242
350
 
@@ -5,39 +5,14 @@ require 'openssl'
5
5
 
6
6
  ## our own code
7
7
  require 'elliptic/version' # note: let version always go first
8
+ require 'elliptic/private_key'
9
+ require 'elliptic/public_key'
10
+ require 'elliptic/signature'
8
11
 
9
12
 
10
13
 
11
14
  module EC
12
15
 
13
-
14
-
15
- class Signature
16
-
17
- def self.decode_der( der )
18
- asn1 = OpenSSL::ASN1.decode(der )
19
- r = asn1.value[0].value.to_i
20
- s = asn1.value[1].value.to_i
21
- new(r, s)
22
- end
23
-
24
- attr_reader :r, :s
25
- def initialize(r, s)
26
- @r, @s = r, s
27
- end
28
-
29
- def to_der
30
- asn1 = OpenSSL::ASN1::Sequence.new [
31
- OpenSSL::ASN1::Integer.new( @r ),
32
- OpenSSL::ASN1::Integer.new( @s ),
33
- ]
34
- asn1.to_der
35
- end
36
- end ## class Signature
37
-
38
-
39
-
40
-
41
16
  ## "cached" / available groups for now include:
42
17
  GROUP = {
43
18
  ## todo/check: is there a more direct way to get a group object?
@@ -93,123 +68,6 @@ module EC
93
68
 
94
69
 
95
70
 
96
-
97
- class PublicKey
98
- def self.convert( *args, **kwargs )
99
- if args.size==1 && args[0].is_a?( PublicKey )
100
- args[0] ## pass through as is (already a public key)
101
- else
102
- new( *args, group: kwargs[:group] )
103
- end
104
- end
105
-
106
-
107
-
108
- def initialize( *args, group: nil )
109
- point = if args.size == 2 ## assume (x,y) raw integer points
110
- @pt = Point.new( *args, group: group )
111
- @pt.to_ec_point ## convert point to openssl (native) class
112
- else
113
- ## "restore" public key (only) from point for verify
114
- ## - OpenSSL::PKey::EC::Point ## assume public key only (restore pkey object for verify?)
115
- ## - Point
116
- if args[0].is_a?( Point )
117
- @pt = args[0]
118
- @pt.to_ec_point
119
- else
120
- args[0] ## assume it is already OpenSSL::PKey::EC::Point
121
- end
122
- end
123
-
124
- ## note: (auto)get group from point
125
- @pkey = OpenSSL::PKey::EC.new( point.group )
126
- @pkey.public_key = point
127
- end
128
-
129
- def group() @pkey.group; end
130
-
131
-
132
- def point
133
- ## cache returned point - why? why not?
134
- @pt ||= Point.new( @pkey.public_key )
135
- @pt
136
- end
137
-
138
-
139
-
140
- def verify?( message, signature )
141
- signature_der = signature.to_der
142
- @pkey.dsa_verify_asn1( message, signature_der )
143
- end
144
- alias_method :valid_signature?, :verify?
145
-
146
- ## helpers for debugging
147
- def to_text() @pkey.to_text; end
148
- def public?() @pkey.public?; end ## todo/check: keep - needed? - why? why not?
149
- end # class PublicKey
150
-
151
-
152
-
153
-
154
- class PrivateKey
155
- def self.convert( *args, **kwargs )
156
- if args.size==1 && args[0].is_a?( PrivateKey )
157
- args[0] ## pass through as is (alread a private key)
158
- else
159
- new( args[0], group: kwargs[:group] )
160
- end
161
- end
162
-
163
-
164
- def self.generate( group: nil ) new( group: group ); end
165
-
166
- def initialize( input=nil, group: nil )
167
- ec_group = GROUP[ group || 'secp256k1' ]
168
- @pkey = OpenSSL::PKey::EC.new( ec_group )
169
-
170
- if input.nil? ## auto-generate new key
171
- @pkey.generate_key
172
- else
173
- num = if input.is_a?( String ) ## assume hex string
174
- input.to_i( 16 )
175
- else ## assume integer
176
- input
177
- end
178
- @pkey.private_key = OpenSSL::BN.new( num )
179
- ## auto-calculate public key too
180
- @pkey.public_key = @pkey.group.generator.mul( @pkey.private_key )
181
- end
182
- end
183
-
184
- def to_i() @pkey.private_key.to_i; end
185
- ## todo/check/fix: make it always a 32 byte (64 hex chars) string
186
- ## even with leading zeros !!! - why? why not?
187
- def to_s() @pkey.private_key.to_i.to_s(16); end
188
-
189
- def group() @pkey.group; end
190
-
191
-
192
- def public_key
193
- ## cache returned public key - why? why not?
194
- @pub ||= PublicKey.new( @pkey.public_key )
195
- @pub
196
- end
197
-
198
-
199
- def sign( message )
200
- signature_der = @pkey.dsa_sign_asn1( message )
201
- Signature.decode_der( signature_der )
202
- end
203
-
204
- ## helpers for debugging
205
- def to_text() @pkey.to_text; end
206
- def private?() @pkey.private?; end ## todo/check: keep - needed? - why? why not?
207
- end # class PrivateKey
208
-
209
-
210
-
211
-
212
-
213
71
  def self.sign( message, priv_key )
214
72
  signer = PrivateKey.convert( priv_key )
215
73
  signer.sign( message )
@@ -3,8 +3,8 @@
3
3
 
4
4
  module EC
5
5
 
6
- MAJOR = 0
7
- MINOR = 2
6
+ MAJOR = 1
7
+ MINOR = 0
8
8
  PATCH = 0
9
9
  VERSION = [MAJOR,MINOR,PATCH].join('.')
10
10
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elliptic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-23 00:00:00.000000000 Z
11
+ date: 2021-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc