ecies 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9b17b5e59affac68ce47a7afe053747c90c287201202fffe9a97550644d6c5c
4
- data.tar.gz: 161fb791e8f8e67252ce565fa06fd1196228629e45b3ccbc07384b5b9f207a4a
3
+ metadata.gz: ccdc4376e7e505685dafd7456609bee87adb7909ee863dea0a02a46bc10ea9ec
4
+ data.tar.gz: c2c8c601e446e361ea28d9605108ba52b5df6d3444b20093f410ac6cee73621a
5
5
  SHA512:
6
- metadata.gz: df3185e4b726f977a8834c9718f0cbd9ffedec22f00ff597c7d7e877a1a730283b7d8ef66091a0351c3d5c71939cac60196b613a750c822d0d33e0b7d50b3d90
7
- data.tar.gz: 148151802478d20abde87b33cfe0765bda7bf1714507c0e6c818105beeb57fcaf55f5735625c42f9cd7d8b524a09c2e5550b7d91c205e74830988c2f5718b503
6
+ metadata.gz: 14dcb2ccec245e71d68eb63b520d320c6e39b330a2f01fd59848ce9ff0d6436d90e100eb5b5857bda40b780dedf365d2bfc4f14dbca9ca8b612560bb82a5c111
7
+ data.tar.gz: dd259230ce124924f5269b1fbb966ea17207ee41dcc206669d1eccc74e62ccd35803f9c96c869011333526cf5c8a03175d671abbf27356d117e5502d42e54d51
checksums.yaml.gz.sig CHANGED
@@ -1,2 +1,2 @@
1
- �=�PX�]
2
- 8 ohQPt05F{�����5��wf۟:��u�L /"Xs�G�*xR�O�(T~��Z9��Lf�����W�< gW�D��b��@�R�����Q�Yn�^D{Ie��_pd��z�߂$����&`5�(�?��A�Q��p��
1
+ �������=xu8
2
+ x��;���YED]B��'�Z�����r���c$�{1L���kWm�ѓ����2E��6z�p���
data/.gitignore CHANGED
@@ -5,3 +5,4 @@ Gemfile.lock
5
5
  coverage/
6
6
  doc/
7
7
  .yardoc/
8
+ .bundle/
data/CHANGELOG.md CHANGED
@@ -4,9 +4,33 @@ Change log
4
4
  This gem follows [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html).
5
5
  All classes and public methods are part of the public API.
6
6
 
7
+ 0.4.0
8
+ ---
9
+ Released on 2023-06-20
10
+
11
+ - Add support for OpenSSL 3.0.
12
+ - Remove `Crypt.private_key_from_hex` method.
13
+ - Users can still utilize `OpenSSL::PKey::EC.new` to construct a PKey.
14
+ - `Crypt.public_key_from_hex` now raises `ArgumentError` on an invalid key, rather than an `OpenSSL::PKey::EC::Point::Error`.
15
+ - Explicitly require 'stringio' (thanks thekuwayama!).
16
+
17
+ 0.3.0
18
+ ---
19
+ Released on 2018-04-22
20
+
21
+ - Prevent benign malleability, as suggested in sec1-v2 page 97.
22
+ - The ECIES process is modified to prevent benign malleability by including the ephemeral public key as an input to the KDF.
23
+ - All encrypted output generated with previous versions cannot be decrypted with this version, and older versions cannot decrypt output generated with this version.
24
+ - The choice was made to simply break compatibility early in this library's life, rather than add an extra configuration parameter that should almost always be unused.
25
+ - Add `Crypt.public_key_from_hex` method.
26
+ - Add `Crypt.private_key_from_hex` method.
27
+ - Remove support for hex-encoded keys in `Crypt#encrypt` and `Crypt#decrypt` methods. The above `*_from_hex` helper methods can be used instead.
28
+ - Remove `ec_group` option from `Crypt` constructor.
29
+ - Add `Crypt#to_s` method.
30
+
7
31
  0.2.0
8
32
  ---
9
- Release 2018-04-19
33
+ Released on 2018-04-19
10
34
 
11
35
  - Add support for hex-encoded keys in `Crypt#encrypt` and `Crypt#decrypt` methods.
12
36
  - Add new option `ec_group` in `Crypt` constructor.
data/README.md CHANGED
@@ -1,14 +1,12 @@
1
1
  # ECIES - Elliptical Curve Integrated Encryption System
2
2
 
3
- [![Build Status](https://travis-ci.org/jamoes/ecies.svg?branch=master)](https://travis-ci.org/jamoes/ecies)
4
-
5
3
  ## Description
6
4
 
7
5
  This library implements Elliptical Curve Integrated Encryption System (ECIES), as specified by [SEC 1: Elliptic Curve Cryptography, Version 2.0](http://www.secg.org/sec1-v2.pdf).
8
6
 
9
7
  ECIES is a public-key encryption scheme based on ECC. It is designed to be semantically secure in the presence of an adversary capable of launching chosen-plaintext and chosen-ciphertext attacks.
10
8
 
11
- ECIES can be used to encrypt messages to bitcoin addresses with keys published on the blockchain, and subsequently to decrypt messages by the holders of the address's private key.
9
+ ECIES can be used to encrypt messages to bitcoin addresses with public keys published on the blockchain, and subsequently to decrypt messages by the holders of the address's private key.
12
10
 
13
11
  ## Installation
14
12
 
@@ -27,7 +25,7 @@ require 'ecies'
27
25
  Intitlialize a key and a `Crypt` object.
28
26
 
29
27
  ```ruby
30
- key = OpenSSL::PKey::EC.new('secp256k1').generate_key
28
+ key = OpenSSL::PKey::EC.generate('secp256k1')
31
29
  crypt = ECIES::Crypt.new
32
30
  ```
33
31
 
@@ -48,17 +46,17 @@ crypt.decrypt(key, encrypted) # => "secret message"
48
46
  Bitcoin P2PKH addresses themselves contain only *hashes* of public keys (hence the name, pay-to-public-key-hash). However, any time a P2PKH output is spent, the public key associated with the address is published on the blockchain in the transaction's scriptSig. This allows you to encrypt a message to any bitcoin address that has sent a transaction (or published its public key in other ways). To demonstrate this, we'll encrypt a message to Satoshi's public key from Bitcoin's genesis block:
49
47
 
50
48
  ```ruby
51
- public_key_hex =
49
+ public_key = ECIES::Crypt.public_key_from_hex(
52
50
  "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb"\
53
- "649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"
54
- encrypted = ECIES::Crypt.new.encrypt(public_key_hex, 'you rock!')
51
+ "649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f")
52
+ encrypted = ECIES::Crypt.new.encrypt(public_key, 'secret message')
55
53
  ```
56
54
 
57
55
  To decrypt this message, Satoshi would follow these steps:
58
56
 
59
57
  ```ruby
60
- private_key_hex = "<satoshi's private key>"
61
- ECIES::Crypt.new.decrypt(private_key_hex, encrypted) # => "you rock!"
58
+ private_key = OpenSSL::PKey::EC.new("<PEM/DER encoded private key for genesis block>")
59
+ ECIES::Crypt.new.decrypt(private_key, encrypted) # => "secret message"
62
60
  ```
63
61
 
64
62
  ### Default parameters
@@ -74,8 +72,7 @@ These defaults work well for encrypting messages to bitcoin keys. This library a
74
72
 
75
73
  ## Compatibility
76
74
 
77
- The sec1-v2 document allows for a many combinations of various algorithms for ECIES. This library only supports a subset of the allowable algorithms.
78
-
75
+ The sec1-v2 document allows for many combinations of various algorithms for ECIES. This library only supports a subset of the allowable algorithms:
79
76
  - Key Derivation Functions
80
77
  - Supported:
81
78
  - ANSI-X9.63-KDF
@@ -119,6 +116,10 @@ The sec1-v2 document allows for a many combinations of various algorithms for EC
119
116
  - 3-key TDES in CBC mode
120
117
  - XOR encryption scheme
121
118
 
119
+ In addition, the following options have been chosen:
120
+ - Elliptical curve points are represented in compressed form.
121
+ - Benign malleability is prevented by including the ephemeral public key as an input to the KDF (sec1-v2 p97).
122
+
122
123
  ## Supported platforms
123
124
 
124
125
  Ruby 2.0 and above.
data/certs/jamoes.pem CHANGED
@@ -1,21 +1,26 @@
1
1
  -----BEGIN CERTIFICATE-----
2
- MIIDeDCCAmCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBBMRMwEQYDVQQDDApzam1j
2
+ MIIEeDCCAuCgAwIBAgIBATANBgkqhkiG9w0BAQsFADBBMRMwEQYDVQQDDApzam1j
3
3
  Y2FydGh5MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNj
4
- b20wHhcNMTgwNDExMDAxMzI4WhcNMTkwNDExMDAxMzI4WjBBMRMwEQYDVQQDDApz
4
+ b20wHhcNMjMwNjIwMjEwMTI2WhcNMjQwNjE5MjEwMTI2WjBBMRMwEQYDVQQDDApz
5
5
  am1jY2FydGh5MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
6
- FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOk2n/6xgIgrG7
7
- avtiI8I9DtcdA326qWYpdQSDLhpSsLNiqiIpo8KF1Zfy3lnAj6JBBIbjiaUsbA/i
8
- Wcip0307dHNXZjr+AgYcL7OEp8EBkfAeZaYWMcVBbjiSxkzYesDxm7nvTOaD317h
9
- cThBfB9KW1vGEzazomTxSI9sgqCDtWrogMLGag7uTDJ7fKRK6YXz2xncI0uCsmGb
10
- 7vekXpfn0xb6tr4ljSseCsPJHnXK7SKB4dzHsmQJ12A57aaV7C/bGqbQAC6odb6k
11
- V8dw0fnmHC9OSYjV1b2Xr0VmoiT3YA4XsR0/LbeZvGOyQj8S4eHxgFg7wTVhCkCZ
12
- D89+p8H5AgMBAAGjezB5MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
13
- BBQffCJK6PE+9XaH56VJoFoCl3ECeDAfBgNVHREEGDAWgRRzam1jY2FydGh5QGdt
14
- YWlsLmNvbTAfBgNVHRIEGDAWgRRzam1jY2FydGh5QGdtYWlsLmNvbTANBgkqhkiG
15
- 9w0BAQUFAAOCAQEApvFGCB9uyF1mh1UV77YICagARejAIOhzOcZXjlpulI9xXjQY
16
- 0QK6P1GdwwE/pgT7YjfJR7VNFobare4WdfCzoWCFc34t2vJwrqkkOB3U7v3TjB+p
17
- z/o2pZKLpNEL4bYJBEbd+vAad/nP1v5e2sCmLm86vSoOwiyQnifmP6PSORObbJF4
18
- 455zxYw1un6NfN0m+pnIKwvshKoOCgI05VJGtEolJoo42fnolmNxa2t6B30Mfmf+
19
- kts216EGG4oP6dVuZmf2Ii2F4lQTBDdZM/cisW8jCkO7KeEzJAPhIw1JJwHltHya
20
- 0TpOI3t2Mz/FJ+rudtz9PJ/d8QvhrF7M7+qH4w==
21
- -----END CERTIFICATE-----
6
+ FgNjb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDOGmdomo9zQxUD
7
+ PMEtDYtzY7Fnb/T/TVXAhKMO06Fw84eEMdU4yOUOMapsv6DinBMm0kDjseFkuqm+
8
+ BFYcU7AaGfKOuoPJQ23LuQOBXg5STw+pDKGdoq1th26M1v05Q9hCH4HVlGIiNPzx
9
+ J+0jFoH9qmiNhHxCD03702etb/ppJsCbBGzpMzofbgKQEHIKZNAkVi2RU2QLqXDt
10
+ A44wknz8NkiWahgN24cpLn/euz5G+J4nFgJ32YUBgA/mVXdeEOhxgMCPIbHIxiez
11
+ 3c/yymARogxf6e9b3Pcwo1k63zTZYf9YHIM+Q5lKiOWOGQ1lUG3nanB9NhFdUkAk
12
+ PcuEzQUp5/pQmnoM/j+VpeXyvwiNLTzsxNRGfePSZU+oDpkEvlN1qaJXmHRpedWp
13
+ zOcUlVUpwFSWM1WWDGm4FCxoYH8GdYdHVXmUWWm/iPcfLCkXwNUXL+i38OXbVSp2
14
+ aqaXrRtkwZsfmE4PCHVUJyHFeVXLqvgK3DLVPfCGk6ty4X7wuXcCAwEAAaN7MHkw
15
+ CQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFELj2NEPT2elfT1kefaM
16
+ tcBz+k6QMB8GA1UdEQQYMBaBFHNqbWNjYXJ0aHlAZ21haWwuY29tMB8GA1UdEgQY
17
+ MBaBFHNqbWNjYXJ0aHlAZ21haWwuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQBvbFzT
18
+ zHTVmJ2J3VvWf1J4HFTkLDtRi9lFLtPqvsNczd+FeO3s/pI9/gr56mBgpZ/vLypN
19
+ 9CBkk4wR4GLifl8+xuDtVkYYh3Ru9S3ru8iu225aOIfg6MpKH7x+IsShxm7jdEva
20
+ AnqMQ47KEOdRetbBMIHeWtCSxyKhXSJsfoIh+fkQZlIM6+3l0ljTiRxo5Eb1JyEn
21
+ Wb+jyVwJugHuGPb2tB9dx+khKgrv0YQ0lxsIaqSYRT5pb3xZuJNoxj00IsZGOx0J
22
+ s5SzopHnmHWPS0h9CVcTa9QgEz5MbCk1X2rWhmUkGR0pzHdeq6vvWr0pxhpiWJdA
23
+ eaD1Uldg06Zi31RbAARghTuRKzg+SA9/DmglkO479GuEhZvGA0P2fBvKTaVAZR+4
24
+ Lb3ESftZmM+MReXZS5FfAeYJBG5+R/LDyMiuQIz6WLYcPpfHpSX873IXAcNYTCd4
25
+ RVHpiTyCFYjchqoOvSC7rHgf1HpEQbuXsl9RKWhSQOyTGlUGbCCGFDx10Dg=
26
+ -----END CERTIFICATE-----
data/ecies.gemspec CHANGED
@@ -14,17 +14,14 @@ Gem::Specification.new do |s|
14
14
  s.homepage = 'https://github.com/jamoes/ecies'
15
15
  s.license = 'MIT'
16
16
 
17
- s.cert_chain = ['certs/jamoes.pem']
18
- s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
19
-
20
17
  s.files = `git ls-files`.split("\n")
21
18
  s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
22
19
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
23
20
 
24
21
  s.required_ruby_version = '>= 2.0'
25
22
 
26
- s.add_development_dependency 'bundler', '~> 1'
27
- s.add_development_dependency 'rake', '~> 12'
23
+ s.add_development_dependency 'bundler', '~> 2'
24
+ s.add_development_dependency 'rake', '~> 13'
28
25
  s.add_development_dependency 'rspec', '~> 3.7'
29
26
  s.add_development_dependency 'simplecov', '~> 0'
30
27
  s.add_development_dependency 'yard', '~> 0.9.12'
data/lib/ecies/crypt.rb CHANGED
@@ -27,9 +27,6 @@ module ECIES
27
27
  # length will be equal to half the mac_digest's digest_legnth. If
28
28
  # :full, the mac length will be equal to the mac_digest's
29
29
  # digest_length.
30
- # @param ec_group [OpenSSL::PKey::EC::Group,String] The elliptical curve
31
- # group to use when the key is passed in hex form to `encrypt` or
32
- # `decrypt`.
33
30
  # @param kdf_digest [String,OpenSSL::Digest,nil] The digest algorithm to
34
31
  # use for KDF. If not specified, the `digest` argument will be used.
35
32
  # @param mac_digest [String,OpenSSL::Digest,nil] The digest algorithm to
@@ -38,9 +35,8 @@ module ECIES
38
35
  # info used for KDF, also known as SharedInfo1.
39
36
  # @param mac_shared_info [String] Optional. A string containing the shared
40
37
  # info used for MAC, also known as SharedInfo2.
41
- def initialize(cipher: 'AES-256-CTR', digest: 'SHA256', mac_length: :half, ec_group: 'secp256k1', kdf_digest: nil, mac_digest: nil, kdf_shared_info: '', mac_shared_info: '')
38
+ def initialize(cipher: 'AES-256-CTR', digest: 'SHA256', mac_length: :half, kdf_digest: nil, mac_digest: nil, kdf_shared_info: '', mac_shared_info: '')
42
39
  @cipher = OpenSSL::Cipher.new(cipher)
43
- @ec_group = OpenSSL::PKey::EC::Group.new(ec_group)
44
40
  @mac_digest = OpenSSL::Digest.new(mac_digest || digest)
45
41
  @kdf_digest = OpenSSL::Digest.new(kdf_digest || digest)
46
42
  @kdf_shared_info = kdf_shared_info
@@ -57,27 +53,19 @@ module ECIES
57
53
 
58
54
  # Encrypts a message to a public key using ECIES.
59
55
  #
60
- # @param key [OpenSSL::EC:PKey,String] The public key. An OpenSSL::EC:PKey
61
- # containing the public key, or a hex-encoded string representing the
62
- # public key on this Crypt's `ec_group`.
56
+ # @param key [OpenSSL::EC:PKey] The public key.
63
57
  # @param message [String] The plain-text message.
64
58
  # @return [String] The octet string of the encrypted message.
65
59
  def encrypt(key, message)
66
- if key.is_a?(String)
67
- new_key = OpenSSL::PKey::EC.new(@ec_group)
68
- new_key.public_key = OpenSSL::PKey::EC::Point.new(@ec_group, OpenSSL::BN.new(key, 16))
69
- key = new_key
70
- end
71
60
  key.public_key? or raise "Must have public key to encrypt"
72
61
  @cipher.reset
73
62
 
74
- group_copy = OpenSSL::PKey::EC::Group.new(key.group)
75
- group_copy.point_conversion_form = :compressed
76
- ephemeral_key = OpenSSL::PKey::EC.new(group_copy).generate_key
63
+ ephemeral_key = OpenSSL::PKey::EC.generate(key.group)
64
+ ephemeral_public_key_octet = ephemeral_key.public_key.to_octet_string(:compressed)
77
65
 
78
66
  shared_secret = ephemeral_key.dh_compute_key(key.public_key)
79
67
 
80
- key_pair = kdf(shared_secret, @cipher.key_len + @mac_length)
68
+ key_pair = kdf(shared_secret, @cipher.key_len + @mac_length, ephemeral_public_key_octet)
81
69
  cipher_key = key_pair.byteslice(0, @cipher.key_len)
82
70
  hmac_key = key_pair.byteslice(-@mac_length, @mac_length)
83
71
 
@@ -88,42 +76,31 @@ module ECIES
88
76
 
89
77
  mac = OpenSSL::HMAC.digest(@mac_digest, hmac_key, ciphertext + @mac_shared_info).byteslice(0, @mac_length)
90
78
 
91
- ephemeral_key.public_key.to_bn.to_s(2) + ciphertext + mac
79
+ ephemeral_public_key_octet + ciphertext + mac
92
80
  end
93
81
 
94
82
  # Decrypts a message with a private key using ECIES.
95
83
  #
96
84
  # @param key [OpenSSL::EC:PKey] The private key.
97
- # @param key [OpenSSL::EC:PKey,String] The private key. An OpenSSL::EC:PKey
98
- # containing the private key, or a hex-encoded string representing the
99
- # private key on this Crypt's `ec_group`.
100
85
  # @param encrypted_message [String] Octet string of the encrypted message.
101
86
  # @return [String] The plain-text message.
102
87
  def decrypt(key, encrypted_message)
103
- if key.is_a?(String)
104
- new_key = OpenSSL::PKey::EC.new(@ec_group)
105
- new_key.private_key = OpenSSL::BN.new(key, 16)
106
- key = new_key
107
- end
108
88
  key.private_key? or raise "Must have private key to decrypt"
109
89
  @cipher.reset
110
90
 
111
- group_copy = OpenSSL::PKey::EC::Group.new(key.group)
112
- group_copy.point_conversion_form = :compressed
113
-
114
- ephemeral_public_key_length = group_copy.generator.to_bn.to_s(2).bytesize
91
+ ephemeral_public_key_length = key.group.generator.to_octet_string(:compressed).bytesize
115
92
  ciphertext_length = encrypted_message.bytesize - ephemeral_public_key_length - @mac_length
116
93
  ciphertext_length > 0 or raise OpenSSL::PKey::ECError, "Encrypted message too short"
117
94
 
118
- ephemeral_public_key_text = encrypted_message.byteslice(0, ephemeral_public_key_length)
95
+ ephemeral_public_key_octet = encrypted_message.byteslice(0, ephemeral_public_key_length)
119
96
  ciphertext = encrypted_message.byteslice(ephemeral_public_key_length, ciphertext_length)
120
97
  mac = encrypted_message.byteslice(-@mac_length, @mac_length)
121
98
 
122
- ephemeral_public_key = OpenSSL::PKey::EC::Point.new(group_copy, OpenSSL::BN.new(ephemeral_public_key_text, 2))
99
+ ephemeral_public_key = OpenSSL::PKey::EC::Point.new(key.group, OpenSSL::BN.new(ephemeral_public_key_octet, 2))
123
100
 
124
101
  shared_secret = key.dh_compute_key(ephemeral_public_key)
125
102
 
126
- key_pair = kdf(shared_secret, @cipher.key_len + @mac_length)
103
+ key_pair = kdf(shared_secret, @cipher.key_len + @mac_length, ephemeral_public_key_octet)
127
104
  cipher_key = key_pair.byteslice(0, @cipher.key_len)
128
105
  hmac_key = key_pair.byteslice(-@mac_length, @mac_length)
129
106
 
@@ -139,11 +116,13 @@ module ECIES
139
116
 
140
117
  # Key-derivation function, compatible with ANSI-X9.63-KDF
141
118
  #
142
- # @param shared_secret [String] The shared secret from which the key will be
143
- # derived.
119
+ # @param shared_secret [String] The shared secret from which the key will
120
+ # be derived.
144
121
  # @param length [Integer] The length of the key to generate.
122
+ # @param shared_info_suffix [String] The suffix to append to the
123
+ # shared_info.
145
124
  # @return [String] Octet string of the derived key.
146
- def kdf(shared_secret, length)
125
+ def kdf(shared_secret, length, shared_info_suffix)
147
126
  length >=0 or raise "length cannot be negative"
148
127
  return "" if length == 0
149
128
 
@@ -158,11 +137,39 @@ module ECIES
158
137
  counter += 1
159
138
  counter_bytes = [counter].pack('N')
160
139
 
161
- io << @kdf_digest.digest(shared_secret + counter_bytes + @kdf_shared_info)
140
+ io << @kdf_digest.digest(shared_secret + counter_bytes + @kdf_shared_info + shared_info_suffix)
162
141
  if io.pos >= length
163
142
  return io.string.byteslice(0, length)
164
143
  end
165
144
  end
166
145
  end
146
+
147
+ # @return [String] A string representing this Crypt's parameters.
148
+ def to_s
149
+ "KDF-#{@kdf_digest.name}_" +
150
+ "HMAC-SHA-#{@mac_digest.digest_length * 8}-#{@mac_length * 8}_" +
151
+ @cipher.name
152
+ end
153
+
154
+ # Converts a hex-encoded public key to an `OpenSSL::PKey::EC`.
155
+ #
156
+ # @param hex_string [String] The hex-encoded public key.
157
+ # @param ec_group [OpenSSL::PKey::EC::Group,String] The elliptical curve
158
+ # group for this public key.
159
+ # @return [OpenSSL::PKey::EC] The public key.
160
+ # @raise [ArgumentError] If the public key is invalid.
161
+ def self.public_key_from_hex(hex_string, ec_group = 'secp256k1')
162
+ ec_group = OpenSSL::PKey::EC::Group.new(ec_group) if ec_group.is_a?(String)
163
+
164
+ sequence = OpenSSL::ASN1.Sequence([
165
+ OpenSSL::ASN1.Sequence([
166
+ OpenSSL::ASN1.ObjectId("id-ecPublicKey"),
167
+ OpenSSL::ASN1::ObjectId(ec_group.curve_name),
168
+ ]),
169
+ OpenSSL::ASN1.BitString([hex_string].pack('H*')),
170
+ ])
171
+
172
+ OpenSSL::PKey::EC.new(sequence.to_der)
173
+ end
167
174
  end
168
175
  end
data/lib/ecies/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module ECIES
2
2
  # This gem's version.
3
- VERSION = '0.2.0'
3
+ VERSION = '0.4.0'
4
4
  end
data/lib/ecies.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  require 'openssl'
2
+ require 'stringio'
2
3
 
3
- require 'ecies/crypt.rb'
4
- require 'ecies/version.rb'
4
+ require_relative 'ecies/crypt.rb'
5
+ require_relative 'ecies/version.rb'
5
6
 
6
7
  # The top-level module for the ecies gem.
7
8
  module ECIES
data/spec/crypt_spec.rb CHANGED
@@ -5,89 +5,79 @@ describe ECIES::Crypt do
5
5
  describe 'Encryption and decryption' do
6
6
 
7
7
  it 'Encrypts and decrypts' do
8
- key = OpenSSL::PKey::EC.new('secp256k1').generate_key
8
+ key = OpenSSL::PKey::EC.generate('secp256k1')
9
9
  crypt = ECIES::Crypt.new
10
10
 
11
11
  encrypted = crypt.encrypt(key, 'secret')
12
12
  expect(crypt.decrypt(key, encrypted)).to eq 'secret'
13
+
14
+ expect{ ECIES::Crypt.new(mac_length: :full).decrypt(key, encrypted) }.to raise_error(OpenSSL::PKey::ECError)
15
+ expect{ ECIES::Crypt.new(mac_digest: 'sha512').decrypt(key, encrypted) }.to raise_error(OpenSSL::PKey::ECError)
13
16
  end
14
17
 
15
18
  it 'Supports hex-encoded keys' do
16
- key = OpenSSL::PKey::EC.new('secp256k1').generate_key
19
+ key = OpenSSL::PKey::EC.generate('secp256k1')
17
20
  public_key_hex = key.public_key.to_bn.to_s(16)
18
- private_key_hex = key.private_key.to_s(16)
19
21
 
20
- crypt = ECIES::Crypt.new
22
+ public_key = ECIES::Crypt.public_key_from_hex(public_key_hex)
23
+
24
+ expect(public_key.public_key).to eq key.public_key
21
25
 
22
- encrypted = crypt.encrypt(public_key_hex, 'secret')
23
- expect(crypt.decrypt(private_key_hex, encrypted)).to eq 'secret'
26
+ expect{ ECIES::Crypt.public_key_from_hex(public_key_hex, 'secp224k1') }.to raise_error(ArgumentError)
24
27
  end
25
28
 
26
29
  it 'Supports other EC curves' do
27
- key = OpenSSL::PKey::EC.new('secp224k1').generate_key
28
- crypt = ECIES::Crypt.new(ec_group: key.group)
30
+ key = OpenSSL::PKey::EC.generate('secp224k1')
31
+ crypt = ECIES::Crypt.new
29
32
 
30
33
  encrypted = crypt.encrypt(key, 'secret')
31
34
  expect(crypt.decrypt(key, encrypted)).to eq 'secret'
32
-
33
- encrypted = crypt.encrypt(key.public_key.to_bn.to_s(16), 'secret')
34
- expect(crypt.decrypt(key.private_key.to_s(16), encrypted)).to eq 'secret'
35
35
  end
36
36
 
37
- it 'Detects invalid hex-encoded points' do
38
- key = OpenSSL::PKey::EC.new('secp224k1').generate_key
39
- public_key_hex = key.public_key.to_bn.to_s(16)
37
+ context 'known value' do
38
+ before(:all) do
39
+ OpenSSL::PKey::EC.instance_eval do
40
+ # Overwrites `generate` for both the key generated below, and the
41
+ # ephemeral_key generated in the `encrypt` method.
42
+ # The private_key is equal to '2', and the group is 'secp256k1'.
43
+ def generate(group)
44
+ OpenSSL::PKey::EC.new("0t\x02\x01\x01\x04 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xA0\a\x06\x05+\x81\x04\x00\n\xA1D\x03B\x00\x04\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5\x1A\xE1h\xFE\xA6=\xC39\xA3\xC5\x84\x19Fl\xEA\xEE\xF7\xF62e2f\xD0\xE1#d1\xA9P\xCF\xE5*")
45
+ end
46
+ end
40
47
 
41
- expect{ ECIES::Crypt.new.encrypt(public_key_hex, 'secret') }.to raise_error(OpenSSL::PKey::EC::Point::Error)
42
- end
48
+ @key = OpenSSL::PKey::EC.generate('secp256k1')
49
+ end
43
50
 
44
- it 'Encrypts to known values' do
45
- OpenSSL::PKey::EC.class_eval do
46
- # Overwrites `generate_key` for both the test code below, and the
47
- # ephemeral_key generated in the `encrypt` method.
48
- def generate_key
49
- self.private_key = 2
50
- self.public_key = group.generator.mul(private_key)
51
- self
51
+ [
52
+ [ECIES::Crypt.new, "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5C\x9E\xE0\x0FYBZ\xBB\xC8\x95\x93\xC1@\xC6+\xE2/yb\x065\xFF".b],
53
+ [ECIES::Crypt.new(mac_length: :full), "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5C\x9E\xE0\x0FYB\x03.\x1E\x92,[\rI\xBC\xCC\xFD%\xCD)9\v!]]A\xE0\xADc\xBA[\xA4\xF2\xB1\xB5\xC5)\xA4".b],
54
+ [ECIES::Crypt.new(digest: 'sha512', mac_length: :full), "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5\xA2Y\x1A\x7F\xB3\xB2\xA7\xDE\x03\xF4\xA6\e\xD1\x9F\xF9\xD5P\x06\x91\x8EiW\xC82\xD9\xBB\xD2\xC92\xE2\x9F\x15F.\x8C]\xE3Y2\xD3L\xE8\xC4\x9F\xBF\xA5S\x98\x9AYy_Y\xF8\x05\xE7\x19\x9E\xDA\vn;Bvm\xA2`i5:".b],
55
+ [ECIES::Crypt.new(cipher: 'aes-256-cbc', mac_length: :full), "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5\xDF\xCD\x95\xAD!m\xAA/Xv\"\x97\x04\xEE\x9F\xEB^\x1F\xA7\xC9n\xE3\x94l;\xBA\xF2\xBE\xCD\x83\x02+\x02\x9D\x18\x11\x9A\xBEz_\x8A\xDB\xA3\x00\xF7\x8A\x94G".b],
56
+ [ECIES::Crypt.new(mac_digest: 'sha256', kdf_digest: 'sha512'), "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5\xA2Y\x1A\x7F\xB3\xB2l\x9E|\xC4\xBCE r\xA6\xB1k\x93W\xE5d\xE4".b],
57
+ ].each do |crypt, expected_value|
58
+ it "matches for #{crypt.to_s}" do
59
+ encrypted = crypt.encrypt(@key, 'secret')
60
+ expect(encrypted).to eq expected_value
61
+ expect(crypt.decrypt(@key, encrypted)).to eq 'secret'
52
62
  end
53
63
  end
64
+ end
54
65
 
55
- key = OpenSSL::PKey::EC.new('secp256k1').generate_key
56
-
57
- crypt = ECIES::Crypt.new
58
- crypt_full = ECIES::Crypt.new(mac_length: :full)
59
- crypt_sha512 = ECIES::Crypt.new(digest: 'sha512', mac_length: :full)
60
- crypt_cbc = ECIES::Crypt.new(cipher: 'aes-256-cbc', mac_length: :full)
61
- crypt_mixed = ECIES::Crypt.new(mac_digest: 'sha256', kdf_digest: 'sha512')
62
-
63
- encrypted = crypt.encrypt(key, 'secret')
64
- expect(encrypted).to eq "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5B;\x12:\x17\xCE\x84\xAB\x9F\x0E%\xCD\x94~\x1E\xBC\x89$\x11\xEE6\xE4".force_encoding(Encoding::BINARY)
65
- expect(crypt.decrypt(key, encrypted)).to eq 'secret'
66
- expect{ crypt_full.decrypt(key, encrypted) }.to raise_error(OpenSSL::PKey::ECError)
67
-
68
- encrypted = crypt_full.encrypt(key, 'secret')
69
- expect(encrypted).to eq "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5B;\x12:\x17\xCEo\x9B\xA7\x955\x89\x9FR\xDF\x1C\xED\x00\x86<\n\x04\v\xD6(\x9D\xF5\xF9\x13\xC8/\xD7os(ZsF".force_encoding(Encoding::BINARY)
70
- expect(crypt_full.decrypt(key, encrypted)).to eq 'secret'
71
- expect{ crypt_sha512.decrypt(key, encrypted) }.to raise_error(OpenSSL::PKey::ECError)
72
-
73
- encrypted = crypt_sha512.encrypt(key, 'secret')
74
- expect(encrypted).to eq "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5%\r^\xA9\xD9\xDC\xFB\xD7\x14b\xB4\x00\x84\xABl\xEAh\x0Fc\x805\xAF\x1DT\x05\x87`\xA5\xC4\xB7\xB5r\xF6\x89\xB1U0\x0E \xD4\x1E\x16\x184\xE9:\xE7\x951\xF4\xB3\x93\"A\x85\x1F\x9A\x8E\xAD\xE1(\x1D\xB3\xC4\x15\xD3\xB1\xA8\xFB\x1D".force_encoding(Encoding::BINARY)
75
- expect(crypt_sha512.decrypt(key, encrypted)).to eq 'secret'
76
- expect{ crypt_full.decrypt(key, encrypted) }.to raise_error(OpenSSL::PKey::ECError)
77
-
78
- encrypted = crypt_cbc.encrypt(key, 'secret')
79
- expect(encrypted).to eq "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5\x1Fj\x04N\eg($\xD4\xFBD\xFFd\xA1\xA3z\x90T#\x1D\x12{3IM\x93!|\xA5\xAF&\xD4+;\e\xA6i.wD\x1F\xCB\xE1\x90{\xB6\x8B\xAF".force_encoding(Encoding::BINARY)
80
- expect(crypt_cbc.decrypt(key, encrypted)).to eq 'secret'
81
- expect{ crypt_mixed.decrypt(key, encrypted) }.to raise_error(OpenSSL::PKey::ECError)
82
-
83
- encrypted = crypt_mixed.encrypt(key, 'secret')
84
- expect(encrypted).to eq "\x02\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5%\r^\xA9\xD9\xDC\xF5\\\x9A\x04\xE0T\x91\xEA=\xA6W\x84X\xBB\xCA\xB4".force_encoding(Encoding::BINARY)
85
- expect(crypt_mixed.decrypt(key, encrypted)).to eq 'secret'
86
- expect{ crypt_full.decrypt(key, encrypted) }.to raise_error(OpenSSL::PKey::ECError)
66
+ it '#to_s' do
67
+ [
68
+ [ECIES::Crypt.new, "KDF-SHA256_HMAC-SHA-256-128_AES-256-CTR"],
69
+ [ECIES::Crypt.new(mac_length: :full), "KDF-SHA256_HMAC-SHA-256-256_AES-256-CTR"],
70
+ [ECIES::Crypt.new(digest: 'sha512'), "KDF-SHA512_HMAC-SHA-512-256_AES-256-CTR"],
71
+ [ECIES::Crypt.new(mac_digest: 'sha512'), "KDF-SHA256_HMAC-SHA-512-256_AES-256-CTR"],
72
+ [ECIES::Crypt.new(mac_digest: 'sha512', kdf_digest: 'sha224'), "KDF-SHA224_HMAC-SHA-512-256_AES-256-CTR"],
73
+ [ECIES::Crypt.new(cipher: 'aes-128-cbc'), "KDF-SHA256_HMAC-SHA-256-128_AES-128-CBC"],
74
+ ].each do |crypt, expected_value|
75
+ expect(crypt.to_s).to eq expected_value
76
+ end
87
77
  end
88
78
 
89
79
  it 'Raises on unknown cipher or digest' do
90
- key = OpenSSL::PKey::EC.new('secp256k1').generate_key
80
+ key = OpenSSL::PKey::EC.generate('secp256k1')
91
81
 
92
82
  expect{ ECIES::Crypt.new(digest: 'foo') }.to raise_error(RuntimeError)
93
83
  expect{ ECIES::Crypt.new(digest: 'md5') }.to raise_error(RuntimeError)
@@ -103,10 +93,8 @@ describe ECIES::Crypt do
103
93
  end
104
94
  end
105
95
 
106
-
107
-
108
96
  describe '#kdf' do
109
- it 'derivates keys correctly' do
97
+ it 'derives keys correctly' do
110
98
  sha256_test_vectors = [
111
99
  # [shared_secret, shared_info, expected_key]
112
100
  ['96c05619d56c328ab95fe84b18264b08725b85e33fd34f08', '', '443024c3dae66b95e6f5670601558f71'],
@@ -120,16 +108,24 @@ describe ECIES::Crypt do
120
108
  shared_info = [shared_info].pack('H*')
121
109
  expected_key = [expected_key].pack('H*')
122
110
 
123
- computed_key = ECIES::Crypt.new(kdf_shared_info: shared_info).kdf(shared_secret, expected_key.size)
124
-
111
+ computed_key = ECIES::Crypt.new(kdf_shared_info: shared_info).kdf(shared_secret, expected_key.size, '')
125
112
  expect(computed_key).to eq expected_key
126
113
  end
127
114
  end
128
115
 
116
+ it 'concats kdf_shared_info with shared_info_suffix' do
117
+ shared_secret = ['22518b10e70f2a3f243810ae3254139efbee04aa57c7af7d'].pack('H*')
118
+ shared_info = ['75eef81aa3041e33'].pack('H*')
119
+ shared_info_suffix = ['b80971203d2c0c52'].pack('H*')
120
+ expected_key = ['c498af77161cc59f2962b9a713e2b215152d139766ce34a776df11866a69bf2e52a13d9c7c6fc878c50c5ea0bc7b00e0da2447cfd874f6cf92f30d0097111485500c90c3af8b487872d04685d14c8d1dc8d7fa08beb0ce0ababc11f0bd496269142d43525a78e5bc79a17f59676a5706dc54d54d4d1f0bd7e386128ec26afc21'].pack('H*')
121
+
122
+ computed_key = ECIES::Crypt.new(kdf_shared_info: shared_info).kdf(shared_secret, expected_key.size, shared_info_suffix)
123
+ expect(computed_key).to eq expected_key
124
+ end
125
+
129
126
  it 'raises when size is invalid' do
130
- expect{ ECIES::Crypt.new.kdf('a', -1) }.to raise_error(RuntimeError)
131
- expect{ ECIES::Crypt.new.kdf('a', 32 * 2**32) }.to raise_error(RuntimeError)
127
+ expect{ ECIES::Crypt.new.kdf('a', -1, '') }.to raise_error(RuntimeError)
128
+ expect{ ECIES::Crypt.new.kdf('a', 32 * 2**32, '') }.to raise_error(RuntimeError)
132
129
  end
133
130
  end
134
-
135
131
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,36 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecies
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen McCarthy
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDeDCCAmCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBBMRMwEQYDVQQDDApzam1j
13
+ MIIEeDCCAuCgAwIBAgIBATANBgkqhkiG9w0BAQsFADBBMRMwEQYDVQQDDApzam1j
14
14
  Y2FydGh5MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNj
15
- b20wHhcNMTgwNDExMDAxMzI4WhcNMTkwNDExMDAxMzI4WjBBMRMwEQYDVQQDDApz
15
+ b20wHhcNMjMwNjIwMjEwMTI2WhcNMjQwNjE5MjEwMTI2WjBBMRMwEQYDVQQDDApz
16
16
  am1jY2FydGh5MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
17
- FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOk2n/6xgIgrG7
18
- avtiI8I9DtcdA326qWYpdQSDLhpSsLNiqiIpo8KF1Zfy3lnAj6JBBIbjiaUsbA/i
19
- Wcip0307dHNXZjr+AgYcL7OEp8EBkfAeZaYWMcVBbjiSxkzYesDxm7nvTOaD317h
20
- cThBfB9KW1vGEzazomTxSI9sgqCDtWrogMLGag7uTDJ7fKRK6YXz2xncI0uCsmGb
21
- 7vekXpfn0xb6tr4ljSseCsPJHnXK7SKB4dzHsmQJ12A57aaV7C/bGqbQAC6odb6k
22
- V8dw0fnmHC9OSYjV1b2Xr0VmoiT3YA4XsR0/LbeZvGOyQj8S4eHxgFg7wTVhCkCZ
23
- D89+p8H5AgMBAAGjezB5MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
24
- BBQffCJK6PE+9XaH56VJoFoCl3ECeDAfBgNVHREEGDAWgRRzam1jY2FydGh5QGdt
25
- YWlsLmNvbTAfBgNVHRIEGDAWgRRzam1jY2FydGh5QGdtYWlsLmNvbTANBgkqhkiG
26
- 9w0BAQUFAAOCAQEApvFGCB9uyF1mh1UV77YICagARejAIOhzOcZXjlpulI9xXjQY
27
- 0QK6P1GdwwE/pgT7YjfJR7VNFobare4WdfCzoWCFc34t2vJwrqkkOB3U7v3TjB+p
28
- z/o2pZKLpNEL4bYJBEbd+vAad/nP1v5e2sCmLm86vSoOwiyQnifmP6PSORObbJF4
29
- 455zxYw1un6NfN0m+pnIKwvshKoOCgI05VJGtEolJoo42fnolmNxa2t6B30Mfmf+
30
- kts216EGG4oP6dVuZmf2Ii2F4lQTBDdZM/cisW8jCkO7KeEzJAPhIw1JJwHltHya
31
- 0TpOI3t2Mz/FJ+rudtz9PJ/d8QvhrF7M7+qH4w==
17
+ FgNjb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDOGmdomo9zQxUD
18
+ PMEtDYtzY7Fnb/T/TVXAhKMO06Fw84eEMdU4yOUOMapsv6DinBMm0kDjseFkuqm+
19
+ BFYcU7AaGfKOuoPJQ23LuQOBXg5STw+pDKGdoq1th26M1v05Q9hCH4HVlGIiNPzx
20
+ J+0jFoH9qmiNhHxCD03702etb/ppJsCbBGzpMzofbgKQEHIKZNAkVi2RU2QLqXDt
21
+ A44wknz8NkiWahgN24cpLn/euz5G+J4nFgJ32YUBgA/mVXdeEOhxgMCPIbHIxiez
22
+ 3c/yymARogxf6e9b3Pcwo1k63zTZYf9YHIM+Q5lKiOWOGQ1lUG3nanB9NhFdUkAk
23
+ PcuEzQUp5/pQmnoM/j+VpeXyvwiNLTzsxNRGfePSZU+oDpkEvlN1qaJXmHRpedWp
24
+ zOcUlVUpwFSWM1WWDGm4FCxoYH8GdYdHVXmUWWm/iPcfLCkXwNUXL+i38OXbVSp2
25
+ aqaXrRtkwZsfmE4PCHVUJyHFeVXLqvgK3DLVPfCGk6ty4X7wuXcCAwEAAaN7MHkw
26
+ CQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFELj2NEPT2elfT1kefaM
27
+ tcBz+k6QMB8GA1UdEQQYMBaBFHNqbWNjYXJ0aHlAZ21haWwuY29tMB8GA1UdEgQY
28
+ MBaBFHNqbWNjYXJ0aHlAZ21haWwuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQBvbFzT
29
+ zHTVmJ2J3VvWf1J4HFTkLDtRi9lFLtPqvsNczd+FeO3s/pI9/gr56mBgpZ/vLypN
30
+ 9CBkk4wR4GLifl8+xuDtVkYYh3Ru9S3ru8iu225aOIfg6MpKH7x+IsShxm7jdEva
31
+ AnqMQ47KEOdRetbBMIHeWtCSxyKhXSJsfoIh+fkQZlIM6+3l0ljTiRxo5Eb1JyEn
32
+ Wb+jyVwJugHuGPb2tB9dx+khKgrv0YQ0lxsIaqSYRT5pb3xZuJNoxj00IsZGOx0J
33
+ s5SzopHnmHWPS0h9CVcTa9QgEz5MbCk1X2rWhmUkGR0pzHdeq6vvWr0pxhpiWJdA
34
+ eaD1Uldg06Zi31RbAARghTuRKzg+SA9/DmglkO479GuEhZvGA0P2fBvKTaVAZR+4
35
+ Lb3ESftZmM+MReXZS5FfAeYJBG5+R/LDyMiuQIz6WLYcPpfHpSX873IXAcNYTCd4
36
+ RVHpiTyCFYjchqoOvSC7rHgf1HpEQbuXsl9RKWhSQOyTGlUGbCCGFDx10Dg=
32
37
  -----END CERTIFICATE-----
33
- date: 2018-04-19 00:00:00.000000000 Z
38
+ date: 2023-06-20 00:00:00.000000000 Z
34
39
  dependencies:
35
40
  - !ruby/object:Gem::Dependency
36
41
  name: bundler
@@ -38,28 +43,28 @@ dependencies:
38
43
  requirements:
39
44
  - - "~>"
40
45
  - !ruby/object:Gem::Version
41
- version: '1'
46
+ version: '2'
42
47
  type: :development
43
48
  prerelease: false
44
49
  version_requirements: !ruby/object:Gem::Requirement
45
50
  requirements:
46
51
  - - "~>"
47
52
  - !ruby/object:Gem::Version
48
- version: '1'
53
+ version: '2'
49
54
  - !ruby/object:Gem::Dependency
50
55
  name: rake
51
56
  requirement: !ruby/object:Gem::Requirement
52
57
  requirements:
53
58
  - - "~>"
54
59
  - !ruby/object:Gem::Version
55
- version: '12'
60
+ version: '13'
56
61
  type: :development
57
62
  prerelease: false
58
63
  version_requirements: !ruby/object:Gem::Requirement
59
64
  requirements:
60
65
  - - "~>"
61
66
  - !ruby/object:Gem::Version
62
- version: '12'
67
+ version: '13'
63
68
  - !ruby/object:Gem::Dependency
64
69
  name: rspec
65
70
  requirement: !ruby/object:Gem::Requirement
@@ -158,7 +163,7 @@ homepage: https://github.com/jamoes/ecies
158
163
  licenses:
159
164
  - MIT
160
165
  metadata: {}
161
- post_install_message:
166
+ post_install_message:
162
167
  rdoc_options: []
163
168
  require_paths:
164
169
  - lib
@@ -173,9 +178,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
178
  - !ruby/object:Gem::Version
174
179
  version: '0'
175
180
  requirements: []
176
- rubyforge_project:
177
- rubygems_version: 2.7.6
178
- signing_key:
181
+ rubygems_version: 3.3.25
182
+ signing_key:
179
183
  specification_version: 4
180
184
  summary: Elliptical Curve Integrated Encryption System (ECIES), as specified by SEC
181
185
  1 - Ver. 2.0
metadata.gz.sig CHANGED
Binary file