eth 0.4.2 → 0.4.3

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
  SHA1:
3
- metadata.gz: c7f1809a30053f40f6c3c5682eeb7e95be171c56
4
- data.tar.gz: 9f521ec59a2069fe3f0786181d03ec41ae8622dd
3
+ metadata.gz: '0519da7b184daeca3bf8e6a8012abd792f421f06'
4
+ data.tar.gz: d65b599489e12a20ee73a78e25abea66ffb635f5
5
5
  SHA512:
6
- metadata.gz: 0b1802ce64192a04eee29893fce5e4da2bb30ebff491ae5ec5a8e6d71324d28e6b899b88b88bf502d56cdc159e29c38cbcbc04aeebf04fe8242b2282c1e5dc35
7
- data.tar.gz: 469313348eadc5fac799fe9364f7a1be450a7cc30cc3e105da8574c249022d5190f7d7d36852c31bd95617133b64e2fc7fdf4d310b6d5617639f23c8061b68b1
6
+ metadata.gz: 744749e5509964bc220becaf7bf008146a4b4c2b437f3ea74abfbe4b63efeccb9faf8715e9fa260486a2212ca8ac93b16c3c658961832674da2106a3da4dc1b6
7
+ data.tar.gz: a217f4e86b31b2de76307f1bef5069e168e36b9e0000b07afc7fcb0759ffca14608c211624f7e33ae85f0cff472dbd8de7b1000c1be407b6050e9a61c7c38db6
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ .ruby-version
@@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.4.3]
10
+
11
+ ### Added
12
+ - Eth::Key::Encrypter class to handle encrypting keys.
13
+ - Eth::Key.encrypt as a nice wrapper around Encrypter class.
14
+ - Eth::Key::Decrypter class to handle encrypting keys.
15
+ - Eth::Key.decrypt as a nice wrapper around Decrypter class.
16
+
9
17
  ## [0.4.2]
10
18
 
11
19
  ### Added
data/README.md CHANGED
@@ -28,10 +28,18 @@ key.private_hex
28
28
  key.public_hex
29
29
  key.address # EIP55 checksummed address
30
30
  ```
31
- Or import and existing one:
31
+ Import an existing key:
32
32
  ```ruby
33
33
  old_key = Eth::Key.new priv: private_key
34
34
  ```
35
+ Or decrypt an [encrypted key](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition):
36
+ ```ruby
37
+ decrypted_key = Eth::Key.decrypt File.read('./some/path.json'), 'p455w0rD'
38
+ ```
39
+ You can also encrypt your keys for use with other ethereum libraries:
40
+ ```ruby
41
+ encrypted_key_info = Eth::Key.encrypt key, 'p455w0rD'
42
+ ```
35
43
 
36
44
  ### Transactions
37
45
 
@@ -66,7 +74,7 @@ Eth::Utils.valid_address? address
66
74
 
67
75
  Or add a checksum to an existing address:
68
76
  ```ruby
69
- Eth::Utils.valid_address? "0x4bc787699093f11316e819b5692be04a712c4e69" # => "0x4bc787699093f11316e819B5692be04A712C4E69"
77
+ Eth::Utils.format_address "0x4bc787699093f11316e819b5692be04a712c4e69" # => "0x4bc787699093f11316e819B5692be04A712C4E69"
70
78
  ```
71
79
 
72
80
  ### Configure
@@ -1,8 +1,22 @@
1
1
  module Eth
2
2
  class Key
3
+ autoload :Decrypter, 'eth/key/decrypter'
4
+ autoload :Encrypter, 'eth/key/encrypter'
3
5
 
4
6
  attr_reader :private_key, :public_key
5
7
 
8
+ def self.encrypt(key, password)
9
+ key = new(priv: key) unless key.is_a?(Key)
10
+
11
+ Encrypter.perform key.private_hex, password
12
+ end
13
+
14
+ def self.decrypt(data, password)
15
+ priv = Decrypter.perform data, password
16
+ new priv: priv
17
+ end
18
+
19
+
6
20
  def initialize(priv: nil)
7
21
  @private_key = MoneyTree::PrivateKey.new key: priv
8
22
  @public_key = MoneyTree::PublicKey.new private_key, compressed: false
@@ -0,0 +1,87 @@
1
+ require 'json'
2
+
3
+ class Eth::Key::Decrypter
4
+ include Eth::Utils
5
+
6
+ def self.perform(data, password)
7
+ new(data, password).perform
8
+ end
9
+
10
+ def initialize(data, password)
11
+ @data = JSON.parse(data)
12
+ @password = password
13
+ end
14
+
15
+ def perform
16
+ derive_key password
17
+ check_macs
18
+ bin_to_hex decrypted_data
19
+ end
20
+
21
+
22
+ private
23
+
24
+ attr_reader :data, :key, :password
25
+
26
+ def derive_key(password)
27
+ @key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, digest)
28
+ end
29
+
30
+ def check_macs
31
+ mac1 = keccak256(key[(key_length/2), key_length] + ciphertext)
32
+ mac2 = hex_to_bin crypto_data['mac']
33
+
34
+ if mac1 != mac2
35
+ raise "Message Authentications Codes do not match!"
36
+ end
37
+ end
38
+
39
+ def decrypted_data
40
+ @decrypted_data ||= cipher.update(ciphertext) + cipher.final
41
+ end
42
+
43
+ def crypto_data
44
+ @crypto_data ||= data['crypto'] || data['Crypto']
45
+ end
46
+
47
+ def ciphertext
48
+ hex_to_bin crypto_data['ciphertext']
49
+ end
50
+
51
+ def cipher_name
52
+ "aes-128-ctr"
53
+ end
54
+
55
+ def cipher
56
+ @cipher ||= OpenSSL::Cipher.new(cipher_name).tap do |cipher|
57
+ cipher.decrypt
58
+ cipher.key = key[0, (key_length/2)]
59
+ cipher.iv = iv
60
+ end
61
+ end
62
+
63
+ def iv
64
+ hex_to_bin crypto_data['cipherparams']['iv']
65
+ end
66
+
67
+ def salt
68
+ hex_to_bin crypto_data['kdfparams']['salt']
69
+ end
70
+
71
+ def iterations
72
+ crypto_data['kdfparams']['c'].to_i
73
+ end
74
+
75
+ def key_length
76
+ 32
77
+ end
78
+
79
+ def digest
80
+ OpenSSL::Digest.new digest_name
81
+ end
82
+
83
+ def digest_name
84
+ "sha256"
85
+ end
86
+
87
+ end
@@ -0,0 +1,127 @@
1
+ require 'json'
2
+
3
+ class Eth::Key::Encrypter
4
+ include Eth::Utils
5
+
6
+ def self.perform(key, password, options = {})
7
+ new(key, options).perform(password)
8
+ end
9
+
10
+ def initialize(key, options = {})
11
+ @key = key
12
+ @options = options
13
+ end
14
+
15
+ def perform(password)
16
+ derive_key password
17
+ encrypt
18
+
19
+ data.to_json
20
+ end
21
+
22
+ def data
23
+ {
24
+ crypto: {
25
+ cipher: cipher_name,
26
+ cipherparams: {
27
+ iv: bin_to_hex(iv),
28
+ },
29
+ ciphertext: bin_to_hex(encrypted_key),
30
+ kdf: "pbkdf2",
31
+ kdfparams: {
32
+ c: iterations,
33
+ dklen: 32,
34
+ prf: prf,
35
+ salt: bin_to_hex(salt),
36
+ },
37
+ mac: bin_to_hex(mac),
38
+ },
39
+ id: id,
40
+ version: 3,
41
+ }.tap do |data|
42
+ data[:address] = address unless options[:skip_address]
43
+ end
44
+ end
45
+
46
+ def id
47
+ @id ||= options[:id] || SecureRandom.uuid
48
+ end
49
+
50
+
51
+ private
52
+
53
+ attr_reader :derived_key, :encrypted_key, :key, :options
54
+
55
+ def cipher
56
+ @cipher ||= OpenSSL::Cipher.new(cipher_name).tap do |cipher|
57
+ cipher.encrypt
58
+ cipher.iv = iv
59
+ cipher.key = derived_key[0, (key_length/2)]
60
+ end
61
+ end
62
+
63
+ def digest
64
+ @digest ||= OpenSSL::Digest.new digest_name
65
+ end
66
+
67
+ def derive_key(password)
68
+ @derived_key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, digest)
69
+ end
70
+
71
+ def encrypt
72
+ @encrypted_key = cipher.update(hex_to_bin key) + cipher.final
73
+ end
74
+
75
+ def mac
76
+ keccak256(derived_key[(key_length/2), key_length] + encrypted_key)
77
+ end
78
+
79
+ def cipher_name
80
+ "aes-128-ctr"
81
+ end
82
+
83
+ def digest_name
84
+ "sha256"
85
+ end
86
+
87
+ def prf
88
+ "hmac-#{digest_name}"
89
+ end
90
+
91
+ def key_length
92
+ 32
93
+ end
94
+
95
+ def salt_length
96
+ 32
97
+ end
98
+
99
+ def iv_length
100
+ 16
101
+ end
102
+
103
+ def iterations
104
+ options[:iterations] || 262_144
105
+ end
106
+
107
+ def salt
108
+ @salt ||= if options[:salt]
109
+ hex_to_bin options[:salt]
110
+ else
111
+ SecureRandom.random_bytes(salt_length)
112
+ end
113
+ end
114
+
115
+ def iv
116
+ @iv ||= if options[:iv]
117
+ hex_to_bin options[:iv]
118
+ else
119
+ SecureRandom.random_bytes(iv_length)
120
+ end
121
+ end
122
+
123
+ def address
124
+ Eth::Key.new(priv: key).address
125
+ end
126
+
127
+ end
@@ -1,3 +1,3 @@
1
1
  module Eth
2
- VERSION = "0.4.2"
2
+ VERSION = "0.4.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Ellis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-03-28 00:00:00.000000000 Z
11
+ date: 2017-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: digest-sha3
@@ -145,6 +145,8 @@ files:
145
145
  - lib/eth/address.rb
146
146
  - lib/eth/gas.rb
147
147
  - lib/eth/key.rb
148
+ - lib/eth/key/decrypter.rb
149
+ - lib/eth/key/encrypter.rb
148
150
  - lib/eth/open_ssl.rb
149
151
  - lib/eth/secp256k1.rb
150
152
  - lib/eth/sedes.rb
@@ -171,9 +173,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
173
  version: '0'
172
174
  requirements: []
173
175
  rubyforge_project:
174
- rubygems_version: 2.5.1
176
+ rubygems_version: 2.6.8
175
177
  signing_key:
176
178
  specification_version: 4
177
179
  summary: Simple API to sign Ethereum transactions.
178
180
  test_files: []
179
- has_rdoc: