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 +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +8 -0
- data/README.md +10 -2
- data/lib/eth/key.rb +14 -0
- data/lib/eth/key/decrypter.rb +87 -0
- data/lib/eth/key/encrypter.rb +127 -0
- data/lib/eth/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0519da7b184daeca3bf8e6a8012abd792f421f06'
|
4
|
+
data.tar.gz: d65b599489e12a20ee73a78e25abea66ffb635f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 744749e5509964bc220becaf7bf008146a4b4c2b437f3ea74abfbe4b63efeccb9faf8715e9fa260486a2212ca8ac93b16c3c658961832674da2106a3da4dc1b6
|
7
|
+
data.tar.gz: a217f4e86b31b2de76307f1bef5069e168e36b9e0000b07afc7fcb0759ffca14608c211624f7e33ae85f0cff472dbd8de7b1000c1be407b6050e9a61c7c38db6
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -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
|
-
|
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.
|
77
|
+
Eth::Utils.format_address "0x4bc787699093f11316e819b5692be04a712c4e69" # => "0x4bc787699093f11316e819B5692be04A712C4E69"
|
70
78
|
```
|
71
79
|
|
72
80
|
### Configure
|
data/lib/eth/key.rb
CHANGED
@@ -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
|
data/lib/eth/version.rb
CHANGED
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.
|
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-
|
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.
|
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:
|