block_io 3.0.0 → 3.0.4
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/.travis.yml +2 -2
- data/README.md +5 -1
- data/block_io.gemspec +5 -5
- data/lib/block_io/chainparams/BTC.yml +1 -1
- data/lib/block_io/chainparams/BTCTEST.yml +1 -1
- data/lib/block_io/chainparams/LTC.yml +2 -2
- data/lib/block_io/chainparams/LTCTEST.yml +1 -1
- data/lib/block_io/client.rb +5 -4
- data/lib/block_io/extended_bitcoinrb.rb +9 -4
- data/lib/block_io/helper.rb +75 -15
- data/lib/block_io/version.rb +1 -1
- data/spec/helper_spec.rb +116 -6
- data/spec/larger_transaction_spec.rb +21 -1
- data/spec/test-cases/json/create_and_sign_transaction_response_witness_v1_output.json +11 -0
- data/spec/test-cases/json/prepare_transaction_response_witness_v1_output.json +64 -0
- metadata +30 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eed2e36f43cdd4162187d87cc37d1a7262cf3bb49c74dd0ee5fa419287700805
|
4
|
+
data.tar.gz: c8841cd420bd57b9c29b8617aaf39f26d2e8a7050d432c2a0cc9b35bf3b0d602
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54d0ba740aa4cfbe535ae9a3c57f42d72f70422840609634c2810e9d2f491d53281fbb8afd6739da7e13d9329bfd0234e8b82e50b649f419dc963ae1dd465660
|
7
|
+
data.tar.gz: 60275bf0b7acffcdc354c095e557b34f1815aa5819e000384ef182f9439287188d9fd660951aa195b329a1cb0959a58b9ef8a397ba6f533625733a094124c240
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -14,9 +14,13 @@ And then execute:
|
|
14
14
|
|
15
15
|
Or install it yourself as:
|
16
16
|
|
17
|
-
$ gem install block_io
|
17
|
+
$ gem install block_io
|
18
18
|
|
19
19
|
## Changelog
|
20
|
+
*12/26/21*: Version 3.0.4 drops support for EOL Ruby 2.4, 2.5. Supports Ruby 3.1.
|
21
|
+
*09/28/21*: Version 3.0.3 supports witness_v1 outputs (Bech32m).
|
22
|
+
*07/21/21*: Version 3.0.2 fixes Litecoin P2SH address version.
|
23
|
+
*06/09/21*: Version 3.0.1 implements use of dynamic decryption algorithms.
|
20
24
|
*04/14/21*: BREAKING CHANGES. Version 3.0.0. Remove support for Ruby < 2.4.0, and Windows. Behavior and interfaces have changed. By upgrading you'll need to revise your code and tests.
|
21
25
|
|
22
26
|
## Important Notes
|
data/block_io.gemspec
CHANGED
@@ -15,15 +15,15 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
16
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
-
spec.required_ruby_version = '>= 2.
|
18
|
+
spec.required_ruby_version = '>= 2.6.0'
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", ">= 1.16", "< 3.0"
|
22
22
|
spec.add_development_dependency "rake", "~> 13.0", ">= 13.0"
|
23
23
|
spec.add_development_dependency "rspec", "~> 3.6", ">= 3.6"
|
24
24
|
spec.add_development_dependency "webmock", "~> 3.12", "< 4.0"
|
25
|
-
spec.add_runtime_dependency "bitcoinrb", "~>
|
26
|
-
spec.add_runtime_dependency "http", "
|
27
|
-
spec.add_runtime_dependency "oj", "~> 3.
|
28
|
-
spec.add_runtime_dependency "connection_pool", "
|
25
|
+
spec.add_runtime_dependency "bitcoinrb", "~> 1.0", "= 1.0.0"
|
26
|
+
spec.add_runtime_dependency "http", ">= 4.4.1", "< 6.0"
|
27
|
+
spec.add_runtime_dependency "oj", "~> 3.0", "< 4.0"
|
28
|
+
spec.add_runtime_dependency "connection_pool", ">= 2.2", "< 3.0"
|
29
29
|
end
|
data/lib/block_io/client.rb
CHANGED
@@ -16,7 +16,7 @@ module BlockIo
|
|
16
16
|
raise "Must provide an API Key." unless args.key?(:api_key) and args[:api_key].to_s.size > 0
|
17
17
|
|
18
18
|
@api_key = args[:api_key]
|
19
|
-
@
|
19
|
+
@pin = args[:pin]
|
20
20
|
@version = args[:version] || 2
|
21
21
|
@hostname = args[:hostname] || "block.io"
|
22
22
|
@proxy = args[:proxy] || {}
|
@@ -131,9 +131,10 @@ module BlockIo
|
|
131
131
|
if !encrypted_key.nil? and !@keys.key?(encrypted_key['public_key']) then
|
132
132
|
# decrypt the key with PIN
|
133
133
|
|
134
|
-
raise Exception.new("PIN not set and no keys provided. Cannot sign transaction.") unless
|
135
|
-
|
136
|
-
key = Helper.
|
134
|
+
raise Exception.new("PIN not set and no keys provided. Cannot sign transaction.") unless !@pin.nil? or @keys.size > 0
|
135
|
+
|
136
|
+
key = Helper.dynamicExtractKey(encrypted_key, @pin)
|
137
|
+
|
137
138
|
raise Exception.new("Public key mismatch for requested signer and ourselves. Invalid Secret PIN detected.") unless key.public_key_hex.eql?(encrypted_key["public_key"])
|
138
139
|
|
139
140
|
# store this key for later use
|
@@ -21,7 +21,7 @@ module Bitcoin
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.init(name)
|
24
|
-
i = YAML.
|
24
|
+
i = YAML.safe_load(File.open("#{__dir__}/chainparams/#{name}.yml"), :permitted_classes => [Bitcoin::ChainParams])
|
25
25
|
i.dust_relay_fee ||= Bitcoin::DUST_RELAY_TX_FEE
|
26
26
|
i
|
27
27
|
end
|
@@ -46,12 +46,17 @@ module Bitcoin
|
|
46
46
|
r = point_field.mod(r_point.x)
|
47
47
|
return nil if r.zero?
|
48
48
|
|
49
|
+
rec = r_point.y & 1
|
50
|
+
|
49
51
|
e = ECDSA.normalize_digest(data, GROUP.bit_length)
|
50
52
|
s = point_field.mod(point_field.inverse(nonce) * (e + r * private_key))
|
51
53
|
|
52
54
|
# covert to low-s
|
53
|
-
|
54
|
-
|
55
|
+
if s > (GROUP.order / 2)
|
56
|
+
s = GROUP.order - s
|
57
|
+
rec = r_point.y & 1
|
58
|
+
end
|
59
|
+
|
55
60
|
return nil if s.zero?
|
56
61
|
|
57
62
|
signature = ECDSA::Signature.new(r, s).to_der
|
@@ -60,7 +65,7 @@ module Bitcoin
|
|
60
65
|
# public_key = Bitcoin::Key.new(priv_key: privkey.bth, :key_type => Bitcoin::Key::TYPES[:compressed]).pubkey # get rid of the key_type warning
|
61
66
|
# raise 'Creation of signature failed.' unless Bitcoin::Secp256k1::Ruby.verify_sig(data, signature, public_key)
|
62
67
|
|
63
|
-
signature
|
68
|
+
[signature, rec]
|
64
69
|
end
|
65
70
|
|
66
71
|
end
|
data/lib/block_io/helper.rb
CHANGED
@@ -2,6 +2,18 @@ module BlockIo
|
|
2
2
|
|
3
3
|
class Helper
|
4
4
|
|
5
|
+
LEGACY_DECRYPTION_ALGORITHM = {
|
6
|
+
:pbkdf2_salt => "",
|
7
|
+
:pbkdf2_iterations => 2048,
|
8
|
+
:pbkdf2_hash_function => "SHA256",
|
9
|
+
:pbkdf2_phase1_key_length => 16,
|
10
|
+
:pbkdf2_phase2_key_length => 32,
|
11
|
+
:aes_iv => nil,
|
12
|
+
:aes_cipher => "AES-256-ECB",
|
13
|
+
:aes_auth_tag => nil,
|
14
|
+
:aes_auth_data => nil
|
15
|
+
}
|
16
|
+
|
5
17
|
def self.allSignaturesPresent?(tx, inputs, signatures, input_address_data)
|
6
18
|
# returns true if transaction has all signatures present
|
7
19
|
|
@@ -152,6 +164,44 @@ module BlockIo
|
|
152
164
|
sighash
|
153
165
|
|
154
166
|
end
|
167
|
+
|
168
|
+
def self.getDecryptionAlgorithm(user_key_algorithm = nil)
|
169
|
+
# mainly used so existing unit tests do not break
|
170
|
+
|
171
|
+
algorithm = ({}).merge(LEGACY_DECRYPTION_ALGORITHM)
|
172
|
+
|
173
|
+
if !user_key_algorithm.nil? then
|
174
|
+
algorithm[:pbkdf2_salt] = user_key_algorithm['pbkdf2_salt']
|
175
|
+
algorithm[:pbkdf2_iterations] = user_key_algorithm['pbkdf2_iterations']
|
176
|
+
algorithm[:pbkdf2_hash_function] = user_key_algorithm['pbkdf2_hash_function']
|
177
|
+
algorithm[:pbkdf2_phase1_key_length] = user_key_algorithm['pbkdf2_phase1_key_length']
|
178
|
+
algorithm[:pbkdf2_phase2_key_length] = user_key_algorithm['pbkdf2_phase2_key_length']
|
179
|
+
algorithm[:aes_iv] = user_key_algorithm['aes_iv']
|
180
|
+
algorithm[:aes_cipher] = user_key_algorithm['aes_cipher']
|
181
|
+
algorithm[:aes_auth_tag] = user_key_algorithm['aes_auth_tag']
|
182
|
+
algorithm[:aes_auth_data] = user_key_algorithm['aes_auth_data']
|
183
|
+
end
|
184
|
+
|
185
|
+
algorithm
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.dynamicExtractKey(user_key, pin)
|
190
|
+
# user_key object contains the encrypted user key and decryption algorithm
|
191
|
+
|
192
|
+
algorithm = self.getDecryptionAlgorithm(user_key['algorithm'])
|
193
|
+
|
194
|
+
aes_key = self.pinToAesKey(pin, algorithm[:pbkdf2_iterations],
|
195
|
+
algorithm[:pbkdf2_salt],
|
196
|
+
algorithm[:pbkdf2_hash_function],
|
197
|
+
algorithm[:pbkdf2_phase1_key_length],
|
198
|
+
algorithm[:pbkdf2_phase2_key_length])
|
199
|
+
|
200
|
+
decrypted = self.decrypt(user_key['encrypted_passphrase'], aes_key, algorithm[:aes_iv], algorithm[:aes_cipher], algorithm[:aes_auth_tag], algorithm[:aes_auth_data])
|
201
|
+
|
202
|
+
Key.from_passphrase(decrypted)
|
203
|
+
|
204
|
+
end
|
155
205
|
|
156
206
|
def self.extractKey(encrypted_data, b64_enc_key)
|
157
207
|
# passphrase is in plain text
|
@@ -169,24 +219,25 @@ module BlockIo
|
|
169
219
|
OpenSSL::Digest::SHA256.digest(value).unpack("H*")[0]
|
170
220
|
end
|
171
221
|
|
172
|
-
def self.pinToAesKey(secret_pin, iterations = 2048)
|
222
|
+
def self.pinToAesKey(secret_pin, iterations = 2048, salt = "", hash_function = "SHA256", pbkdf2_phase1_key_length = 16, pbkdf2_phase2_key_length = 32)
|
173
223
|
# converts the pincode string to PBKDF2
|
174
224
|
# returns a base64 version of PBKDF2 pincode
|
175
|
-
salt = ""
|
176
225
|
|
226
|
+
raise Exception.new("Unknown hash function specified. Are you using current version of this library?") unless hash_function == "SHA256"
|
227
|
+
|
177
228
|
part1 = OpenSSL::PKCS5.pbkdf2_hmac(
|
178
229
|
secret_pin,
|
179
|
-
|
180
|
-
|
181
|
-
|
230
|
+
salt,
|
231
|
+
iterations/2,
|
232
|
+
pbkdf2_phase1_key_length,
|
182
233
|
OpenSSL::Digest::SHA256.new
|
183
234
|
).unpack("H*")[0]
|
184
235
|
|
185
236
|
part2 = OpenSSL::PKCS5.pbkdf2_hmac(
|
186
237
|
part1,
|
187
|
-
|
188
|
-
|
189
|
-
|
238
|
+
salt,
|
239
|
+
iterations/2,
|
240
|
+
pbkdf2_phase2_key_length,
|
190
241
|
OpenSSL::Digest::SHA256.new
|
191
242
|
) # binary
|
192
243
|
|
@@ -195,15 +246,19 @@ module BlockIo
|
|
195
246
|
end
|
196
247
|
|
197
248
|
# Decrypts a block of data (encrypted_data) given an encryption key
|
198
|
-
def self.decrypt(encrypted_data, b64_enc_key, iv = nil, cipher_type = "AES-256-ECB")
|
249
|
+
def self.decrypt(encrypted_data, b64_enc_key, iv = nil, cipher_type = "AES-256-ECB", auth_tag = nil, auth_data = nil)
|
250
|
+
|
251
|
+
raise Exception.new("Auth tag must be 16 bytes exactly.") unless auth_tag.nil? or auth_tag.size == 32
|
199
252
|
|
200
253
|
response = nil
|
201
254
|
|
202
255
|
begin
|
203
|
-
aes = OpenSSL::Cipher.new(cipher_type)
|
256
|
+
aes = OpenSSL::Cipher.new(cipher_type.downcase)
|
204
257
|
aes.decrypt
|
205
258
|
aes.key = b64_enc_key.unpack("m0")[0]
|
206
|
-
aes.iv = iv unless iv.nil?
|
259
|
+
aes.iv = [iv].pack("H*") unless iv.nil?
|
260
|
+
aes.auth_tag = [auth_tag].pack("H*") unless auth_tag.nil?
|
261
|
+
aes.auth_data = [auth_data].pack("H*") unless auth_data.nil?
|
207
262
|
response = aes.update(encrypted_data.unpack("m0")[0]) << aes.final
|
208
263
|
rescue Exception => e
|
209
264
|
# decryption failed, must be an invalid Secret PIN
|
@@ -214,12 +269,17 @@ module BlockIo
|
|
214
269
|
end
|
215
270
|
|
216
271
|
# Encrypts a block of data given an encryption key
|
217
|
-
def self.encrypt(data, b64_enc_key, iv = nil, cipher_type = "AES-256-ECB")
|
218
|
-
aes = OpenSSL::Cipher.new(cipher_type)
|
272
|
+
def self.encrypt(data, b64_enc_key, iv = nil, cipher_type = "AES-256-ECB", auth_data = nil)
|
273
|
+
aes = OpenSSL::Cipher.new(cipher_type.downcase)
|
219
274
|
aes.encrypt
|
220
275
|
aes.key = b64_enc_key.unpack("m0")[0]
|
221
|
-
aes.iv = iv unless iv.nil?
|
222
|
-
|
276
|
+
aes.iv = [iv].pack("H*") unless iv.nil?
|
277
|
+
aes.auth_data = [auth_data].pack("H*") unless auth_data.nil?
|
278
|
+
result = [aes.update(data) << aes.final].pack("m0")
|
279
|
+
auth_tag = (cipher_type.end_with?("-GCM") ? aes.auth_tag.unpack("H*")[0] : nil)
|
280
|
+
|
281
|
+
{:aes_auth_tag => auth_tag, :aes_cipher_text => result, :aes_iv => iv, :aes_cipher => cipher_type, :aes_auth_data => auth_data}
|
282
|
+
|
223
283
|
end
|
224
284
|
|
225
285
|
# courtesy bitcoin-ruby
|
data/lib/block_io/version.rb
CHANGED
data/spec/helper_spec.rb
CHANGED
@@ -6,24 +6,31 @@ describe "Helper.sha256" do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
describe "Helper.pinToAesKey" do
|
9
|
-
|
10
|
-
|
9
|
+
describe "no_salt" do
|
10
|
+
it "deadbeef" do
|
11
|
+
expect(BlockIo::Helper.pinToAesKey("deadbeef")).to eq([["b87ddac3d84865782a0edbc21b5786d56795dd52bab0fe49270b3726372a83fe"].pack("H*")].pack("m0"))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
describe "salt" do
|
15
|
+
it "922445847c173e90667a19d90729e1fb" do
|
16
|
+
expect(BlockIo::Helper.pinToAesKey("deadbeef", 500000, "922445847c173e90667a19d90729e1fb")).to eq([["f206403c6bad20e1c8cb1f3318e17cec5b2da0560ed6c7b26826867452534172"].pack("H*")].pack("m0"))
|
17
|
+
end
|
11
18
|
end
|
12
19
|
end
|
13
20
|
|
14
|
-
describe "Helper.
|
21
|
+
describe "Helper.encrypt_aes256ecb" do
|
15
22
|
before(:each) do
|
16
23
|
@encryption_key = BlockIo::Helper.pinToAesKey("deadbeef")
|
17
24
|
@encrypted_data = BlockIo::Helper.encrypt("beadbeef", @encryption_key)
|
18
25
|
end
|
19
26
|
|
20
27
|
it "beadbeef" do
|
21
|
-
expect(@encrypted_data).to eq("3wIJtPoC8KO6S7x6LtrN0g==")
|
28
|
+
expect(@encrypted_data[:aes_cipher_text]).to eq("3wIJtPoC8KO6S7x6LtrN0g==")
|
22
29
|
end
|
23
30
|
|
24
31
|
end
|
25
32
|
|
26
|
-
describe "Helper.
|
33
|
+
describe "Helper.decrypt_aes256ecb" do
|
27
34
|
before(:each) do
|
28
35
|
@encryption_key = BlockIo::Helper.pinToAesKey("deadbeef")
|
29
36
|
@bad_encryption_key = BlockIo::Helper.pinToAesKey(SecureRandom.hex(8))
|
@@ -31,7 +38,7 @@ describe "Helper.decrypt" do
|
|
31
38
|
end
|
32
39
|
|
33
40
|
it "encryption_key" do
|
34
|
-
@decrypted_data = BlockIo::Helper.decrypt(@encrypted_data, @encryption_key)
|
41
|
+
@decrypted_data = BlockIo::Helper.decrypt(@encrypted_data[:aes_cipher_text], @encryption_key)
|
35
42
|
expect(@decrypted_data).to eq("beadbeef")
|
36
43
|
end
|
37
44
|
|
@@ -42,3 +49,106 @@ describe "Helper.decrypt" do
|
|
42
49
|
end
|
43
50
|
|
44
51
|
end
|
52
|
+
|
53
|
+
describe "Helper.encrypt_aes256cbc" do
|
54
|
+
before(:each) do
|
55
|
+
@encryption_key = BlockIo::Helper.pinToAesKey("deadbeef", 500000, "922445847c173e90667a19d90729e1fb")
|
56
|
+
@encrypted_data = BlockIo::Helper.encrypt("beadbeef", @encryption_key, "11bc22166c8cf8560e5fa7e5c622bb0f", "AES-256-CBC")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "beadbeef" do
|
60
|
+
expect(@encrypted_data[:aes_cipher_text]).to eq("LExu1rUAtIBOekslc328Lw==")
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "Helper.decrypt_aes256cbc" do
|
66
|
+
before(:each) do
|
67
|
+
@encryption_key = BlockIo::Helper.pinToAesKey("deadbeef", 500000, "922445847c173e90667a19d90729e1fb")
|
68
|
+
@bad_encryption_key = BlockIo::Helper.pinToAesKey(SecureRandom.hex(8))
|
69
|
+
@encrypted_data = BlockIo::Helper.encrypt("beadbeef", @encryption_key, "11bc22166c8cf8560e5fa7e5c622bb0f", "AES-256-CBC")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "encryption_key" do
|
73
|
+
@decrypted_data = BlockIo::Helper.decrypt(@encrypted_data[:aes_cipher_text], @encryption_key, @encrypted_data[:aes_iv], @encrypted_data[:aes_cipher])
|
74
|
+
expect(@decrypted_data).to eq("beadbeef")
|
75
|
+
end
|
76
|
+
|
77
|
+
it "bad_encryption_key" do
|
78
|
+
expect{
|
79
|
+
BlockIo::Helper.decrypt(@encrypted_data[:aes_cipher_text], @bad_encryption_key, @encrypted_data[:aes_iv], @encrypted_data[:aes_cipher])
|
80
|
+
}.to raise_error(Exception, "Invalid Secret PIN provided.")
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "Helper.decrypt_aes256gcm" do
|
86
|
+
before(:each) do
|
87
|
+
@encryption_key = BlockIo::Helper.pinToAesKey("deadbeef", 500000, "922445847c173e90667a19d90729e1fb")
|
88
|
+
@bad_encryption_key = BlockIo::Helper.pinToAesKey(SecureRandom.hex(8))
|
89
|
+
@encrypted_data = BlockIo::Helper.encrypt("beadbeef", @encryption_key, "a57414b88b67f977829cbdca", "AES-256-GCM", "")
|
90
|
+
end
|
91
|
+
|
92
|
+
it "encryption_key" do
|
93
|
+
@decrypted_data = BlockIo::Helper.decrypt(@encrypted_data[:aes_cipher_text],
|
94
|
+
@encryption_key, @encrypted_data[:aes_iv],
|
95
|
+
@encrypted_data[:aes_cipher],
|
96
|
+
@encrypted_data[:aes_auth_tag],
|
97
|
+
@encrypted_data[:aes_auth_data])
|
98
|
+
expect(@decrypted_data).to eq("beadbeef")
|
99
|
+
end
|
100
|
+
|
101
|
+
it "encryption_key_bad_auth_tag" do
|
102
|
+
expect{
|
103
|
+
BlockIo::Helper.decrypt(@encrypted_data[:aes_cipher_text],
|
104
|
+
@encryption_key, @encrypted_data[:aes_iv],
|
105
|
+
@encrypted_data[:aes_cipher],
|
106
|
+
@encrypted_data[:aes_auth_tag][0..30],
|
107
|
+
@encrypted_data[:aes_auth_data])
|
108
|
+
}.to raise_error(Exception, "Auth tag must be 16 bytes exactly.")
|
109
|
+
end
|
110
|
+
|
111
|
+
it "bad_encryption_key" do
|
112
|
+
expect{
|
113
|
+
BlockIo::Helper.decrypt(@encrypted_data[:aes_cipher_text], @bad_encryption_key, @encrypted_data[:aes_iv], @encrypted_data[:aes_cipher], @encrypted_data[:aes_auth_tag],
|
114
|
+
@encrypted_data[:aes_auth_data])
|
115
|
+
}.to raise_error(Exception, "Invalid Secret PIN provided.")
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "Helper.encrypt_aes256gcm" do
|
121
|
+
before(:each) do
|
122
|
+
@encryption_key = BlockIo::Helper.pinToAesKey("deadbeef", 500000, "922445847c173e90667a19d90729e1fb")
|
123
|
+
@encrypted_data = BlockIo::Helper.encrypt("beadbeef", @encryption_key, "a57414b88b67f977829cbdca", "AES-256-GCM", "")
|
124
|
+
end
|
125
|
+
|
126
|
+
it "beadbeef" do
|
127
|
+
expect(@encrypted_data[:aes_cipher_text]).to eq("ELV56Z57KoA=")
|
128
|
+
expect(@encrypted_data[:aes_auth_tag]).to eq("adeb7dfe53027bdda5824dc524d5e55a")
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "Helper.dynamicExtractKey" do
|
134
|
+
|
135
|
+
before(:each) do
|
136
|
+
@aes256cbc_user_key = Oj.safe_load('{"encrypted_passphrase":"LExu1rUAtIBOekslc328Lw==","public_key":"02f87f787bffb30396984cb6b3a9d6830f32d5b656b3e39b0abe4f3b3c35d99323","algorithm":{"pbkdf2_salt":"922445847c173e90667a19d90729e1fb","pbkdf2_iterations":500000,"pbkdf2_hash_function":"SHA256","pbkdf2_phase1_key_length":16,"pbkdf2_phase2_key_length":32,"aes_iv":"11bc22166c8cf8560e5fa7e5c622bb0f","aes_cipher":"AES-256-CBC","aes_auth_tag":null,"aes_auth_data":null}}')
|
137
|
+
@aes256gcm_user_key = Oj.safe_load('{"encrypted_passphrase":"ELV56Z57KoA=","public_key":"02f87f787bffb30396984cb6b3a9d6830f32d5b656b3e39b0abe4f3b3c35d99323","algorithm":{"pbkdf2_salt":"922445847c173e90667a19d90729e1fb","pbkdf2_iterations":500000,"pbkdf2_hash_function":"SHA256","pbkdf2_phase1_key_length":16,"pbkdf2_phase2_key_length":32,"aes_iv":"a57414b88b67f977829cbdca","aes_cipher":"AES-256-GCM","aes_auth_tag":"adeb7dfe53027bdda5824dc524d5e55a","aes_auth_data":""}}')
|
138
|
+
@aes256ecb_user_key = Oj.safe_load('{"encrypted_passphrase":"3wIJtPoC8KO6S7x6LtrN0g==","public_key":"02f87f787bffb30396984cb6b3a9d6830f32d5b656b3e39b0abe4f3b3c35d99323","algorithm":{"pbkdf2_salt":"","pbkdf2_iterations":2048,"pbkdf2_hash_function":"SHA256","pbkdf2_phase1_key_length":16,"pbkdf2_phase2_key_length":32,"aes_iv":null,"aes_cipher":"AES-256-ECB","aes_auth_tag":null,"aes_auth_data":null}}')
|
139
|
+
@pin = "deadbeef"
|
140
|
+
end
|
141
|
+
|
142
|
+
it "aes256ecb_success" do
|
143
|
+
expect(BlockIo::Helper.dynamicExtractKey(@aes256ecb_user_key, @pin).public_key_hex).to eq(BlockIo::Key.from_passphrase("beadbeef").public_key_hex)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "aes256cbc_success" do
|
147
|
+
expect(BlockIo::Helper.dynamicExtractKey(@aes256cbc_user_key, @pin).public_key_hex).to eq(BlockIo::Key.from_passphrase("beadbeef").public_key_hex)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "aes256gcm_success" do
|
151
|
+
expect(BlockIo::Helper.dynamicExtractKey(@aes256gcm_user_key, @pin).public_key_hex).to eq(BlockIo::Key.from_passphrase("beadbeef").public_key_hex)
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
@@ -347,5 +347,25 @@ describe "Client.create_and_sign_transaction" do
|
|
347
347
|
|
348
348
|
end
|
349
349
|
|
350
|
-
|
350
|
+
context "witness_v1_output" do
|
351
|
+
|
352
|
+
before(:each) do
|
353
|
+
|
354
|
+
@blockio = BlockIo::Client.new(:api_key => @api_key, :pin => @insecure_pin_valid)
|
355
|
+
|
356
|
+
end
|
357
|
+
|
358
|
+
it "succeeds_on_witness_v1_output" do
|
359
|
+
|
360
|
+
request = Oj.safe_load(File.open("spec/test-cases/json/prepare_transaction_response_witness_v1_output.json").read)
|
361
|
+
expected_response = Oj.safe_load(File.open("spec/test-cases/json/create_and_sign_transaction_response_witness_v1_output.json").read)
|
362
|
+
|
363
|
+
actual_response = @blockio.create_and_sign_transaction(request)
|
364
|
+
|
365
|
+
expect(actual_response).to eq(expected_response)
|
366
|
+
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
351
370
|
|
371
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
{
|
2
|
+
"tx_type": "basic",
|
3
|
+
"tx_hex": "0100000001784ecc9b864ff9b8a97eaacd138fdf193a5d889735702a4f726d2f87631de45f0100000000ffffffff03204e000000000000225120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433204e000000000000220020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e864339f4c00000000000017a914026b9608a26f40f74644cc60622d1067c3696ac98700000000",
|
4
|
+
"signatures": [
|
5
|
+
{
|
6
|
+
"input_index": 0,
|
7
|
+
"public_key": "02d2cbf77287c1443759abdd35f239e7da2f52c992258653bc8dd577ae63c78628",
|
8
|
+
"signature": "304402206d093e2a14e80e01f3c8eefc76d651d01c3dedbd1f0dabf78ace5b352ca660b602202aac312b5b7f0b8c79ad22e75d2523ee39d9c62a35be4db102b5c8f3f296f662"
|
9
|
+
}
|
10
|
+
]
|
11
|
+
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
{
|
2
|
+
"status": "success",
|
3
|
+
"data": {
|
4
|
+
"network": "BTCTEST",
|
5
|
+
"tx_type": "basic",
|
6
|
+
"inputs": [
|
7
|
+
{
|
8
|
+
"input_index": 0,
|
9
|
+
"previous_txid": "5fe41d63872f6d724f2a703597885d3a19df8f13cdaa7ea9b8f94f869bcc4e78",
|
10
|
+
"previous_output_index": 1,
|
11
|
+
"input_value": "0.00060915",
|
12
|
+
"spending_address": "2MsU2DsvP7okZ2sZGZUvH3rZZuQt4pf75Am"
|
13
|
+
}
|
14
|
+
],
|
15
|
+
"outputs": [
|
16
|
+
{
|
17
|
+
"output_index": 0,
|
18
|
+
"output_category": "user-specified",
|
19
|
+
"output_value": "0.00020000",
|
20
|
+
"receiving_address": "tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"output_index": 1,
|
24
|
+
"output_category": "user-specified",
|
25
|
+
"output_value": "0.00020000",
|
26
|
+
"receiving_address": "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy"
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"output_index": 2,
|
30
|
+
"output_category": "change",
|
31
|
+
"output_value": "0.00019615",
|
32
|
+
"receiving_address": "2MsU2DsvP7okZ2sZGZUvH3rZZuQt4pf75Am"
|
33
|
+
}
|
34
|
+
],
|
35
|
+
"input_address_data": [
|
36
|
+
{
|
37
|
+
"required_signatures": 2,
|
38
|
+
"public_keys": [
|
39
|
+
"021916c1ea9215990263e2862bcecc85397d199a4411c863983176ee3d44e27f7f",
|
40
|
+
"02d2cbf77287c1443759abdd35f239e7da2f52c992258653bc8dd577ae63c78628"
|
41
|
+
],
|
42
|
+
"address": "2MsU2DsvP7okZ2sZGZUvH3rZZuQt4pf75Am",
|
43
|
+
"address_type": "P2WSH-over-P2SH"
|
44
|
+
}
|
45
|
+
],
|
46
|
+
"user_key": {
|
47
|
+
"public_key": "02d2cbf77287c1443759abdd35f239e7da2f52c992258653bc8dd577ae63c78628",
|
48
|
+
"encrypted_passphrase": "jlPuw8CJGTWTb+O4I/IKGWGDdF9G8/MX5meX+IfuLfbb7rRABoSUGYSU2BXxxRqR95K64u8gH46h3zr/NKsj8OFv5gj4JwClM7RN03fvb+3CyXgwy4eYSSpFE6vVsdyoxJ8rshUbpf8tvCerUKC0LhE9d61q7mWYoVAik61WRwc=",
|
49
|
+
"algorithm": {
|
50
|
+
"pbkdf2_salt": "7ccf40ce398f0fb475fe91043f7dce57",
|
51
|
+
"pbkdf2_iterations": 102400,
|
52
|
+
"pbkdf2_hash_function": "SHA256",
|
53
|
+
"pbkdf2_phase1_key_length": 16,
|
54
|
+
"pbkdf2_phase2_key_length": 32,
|
55
|
+
"aes_iv": "7c69a5e81e53ba05213b35bb",
|
56
|
+
"aes_cipher": "AES-256-GCM",
|
57
|
+
"aes_auth_tag": "d19b5e48e068f3b1179a4724b3862650",
|
58
|
+
"aes_auth_data": ""
|
59
|
+
}
|
60
|
+
},
|
61
|
+
"estimated_tx_size": 260,
|
62
|
+
"expected_unsigned_txid": "e1925681c6986df2617d41c90b2bbc32cd01f7df0323ca52417b4a8677b2a160"
|
63
|
+
}
|
64
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: block_io
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Atif Nazir
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -96,80 +96,80 @@ dependencies:
|
|
96
96
|
requirements:
|
97
97
|
- - "~>"
|
98
98
|
- !ruby/object:Gem::Version
|
99
|
-
version:
|
99
|
+
version: '1.0'
|
100
100
|
- - '='
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 0.
|
102
|
+
version: 1.0.0
|
103
103
|
type: :runtime
|
104
104
|
prerelease: false
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
109
|
+
version: '1.0'
|
110
110
|
- - '='
|
111
111
|
- !ruby/object:Gem::Version
|
112
|
-
version: 0.
|
112
|
+
version: 1.0.0
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: http
|
115
115
|
requirement: !ruby/object:Gem::Requirement
|
116
116
|
requirements:
|
117
|
-
- - "~>"
|
118
|
-
- !ruby/object:Gem::Version
|
119
|
-
version: 4.4.1
|
120
117
|
- - ">="
|
121
118
|
- !ruby/object:Gem::Version
|
122
119
|
version: 4.4.1
|
120
|
+
- - "<"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '6.0'
|
123
123
|
type: :runtime
|
124
124
|
prerelease: false
|
125
125
|
version_requirements: !ruby/object:Gem::Requirement
|
126
126
|
requirements:
|
127
|
-
- - "~>"
|
128
|
-
- !ruby/object:Gem::Version
|
129
|
-
version: 4.4.1
|
130
127
|
- - ">="
|
131
128
|
- !ruby/object:Gem::Version
|
132
129
|
version: 4.4.1
|
130
|
+
- - "<"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '6.0'
|
133
133
|
- !ruby/object:Gem::Dependency
|
134
134
|
name: oj
|
135
135
|
requirement: !ruby/object:Gem::Requirement
|
136
136
|
requirements:
|
137
137
|
- - "~>"
|
138
138
|
- !ruby/object:Gem::Version
|
139
|
-
version: '3.
|
140
|
-
- - "
|
139
|
+
version: '3.0'
|
140
|
+
- - "<"
|
141
141
|
- !ruby/object:Gem::Version
|
142
|
-
version: '
|
142
|
+
version: '4.0'
|
143
143
|
type: :runtime
|
144
144
|
prerelease: false
|
145
145
|
version_requirements: !ruby/object:Gem::Requirement
|
146
146
|
requirements:
|
147
147
|
- - "~>"
|
148
148
|
- !ruby/object:Gem::Version
|
149
|
-
version: '3.
|
150
|
-
- - "
|
149
|
+
version: '3.0'
|
150
|
+
- - "<"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
152
|
+
version: '4.0'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: connection_pool
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
|
-
- - "~>"
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: 2.2.5
|
160
157
|
- - ">="
|
161
158
|
- !ruby/object:Gem::Version
|
162
159
|
version: '2.2'
|
160
|
+
- - "<"
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '3.0'
|
163
163
|
type: :runtime
|
164
164
|
prerelease: false
|
165
165
|
version_requirements: !ruby/object:Gem::Requirement
|
166
166
|
requirements:
|
167
|
-
- - "~>"
|
168
|
-
- !ruby/object:Gem::Version
|
169
|
-
version: 2.2.5
|
170
167
|
- - ">="
|
171
168
|
- !ruby/object:Gem::Version
|
172
169
|
version: '2.2'
|
170
|
+
- - "<"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '3.0'
|
173
173
|
description: This Ruby Gem is the official reference client for the Block.io payments
|
174
174
|
API. To use this, you will need the Dogecoin, Bitcoin, or Litecoin API key(s) from
|
175
175
|
Block.io. Go ahead, sign up :)
|
@@ -251,6 +251,7 @@ files:
|
|
251
251
|
- spec/test-cases/json/create_and_sign_transaction_response_sweep_p2wpkh.json
|
252
252
|
- spec/test-cases/json/create_and_sign_transaction_response_sweep_p2wpkh_over_p2sh.json
|
253
253
|
- spec/test-cases/json/create_and_sign_transaction_response_with_blockio_fee_and_expected_unsigned_txid.json
|
254
|
+
- spec/test-cases/json/create_and_sign_transaction_response_witness_v1_output.json
|
254
255
|
- spec/test-cases/json/get_balance_response.json
|
255
256
|
- spec/test-cases/json/prepare_dtrust_transaction_response_P2SH_3of5_195inputs.json
|
256
257
|
- spec/test-cases/json/prepare_dtrust_transaction_response_P2SH_4of5_195inputs.json
|
@@ -284,6 +285,7 @@ files:
|
|
284
285
|
- spec/test-cases/json/prepare_transaction_response_P2WSH-over-P2SH_1of2_253inputs.json
|
285
286
|
- spec/test-cases/json/prepare_transaction_response_P2WSH-over-P2SH_1of2_762inputs.json
|
286
287
|
- spec/test-cases/json/prepare_transaction_response_with_blockio_fee_and_expected_unsigned_txid.json
|
288
|
+
- spec/test-cases/json/prepare_transaction_response_witness_v1_output.json
|
287
289
|
- spec/test-cases/json/summarize_prepared_transaction_response_with_blockio_fee_and_expected_unsigned_txid.json
|
288
290
|
homepage: https://block.io/api/simple/ruby
|
289
291
|
licenses:
|
@@ -297,14 +299,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
297
299
|
requirements:
|
298
300
|
- - ">="
|
299
301
|
- !ruby/object:Gem::Version
|
300
|
-
version: 2.
|
302
|
+
version: 2.6.0
|
301
303
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
302
304
|
requirements:
|
303
305
|
- - ">="
|
304
306
|
- !ruby/object:Gem::Version
|
305
307
|
version: '0'
|
306
308
|
requirements: []
|
307
|
-
rubygems_version: 3.
|
309
|
+
rubygems_version: 3.3.3
|
308
310
|
signing_key:
|
309
311
|
specification_version: 4
|
310
312
|
summary: An easy to use Dogecoin, Bitcoin, Litecoin wallet API by Block.io. Sign up
|
@@ -356,6 +358,7 @@ test_files:
|
|
356
358
|
- spec/test-cases/json/create_and_sign_transaction_response_sweep_p2wpkh.json
|
357
359
|
- spec/test-cases/json/create_and_sign_transaction_response_sweep_p2wpkh_over_p2sh.json
|
358
360
|
- spec/test-cases/json/create_and_sign_transaction_response_with_blockio_fee_and_expected_unsigned_txid.json
|
361
|
+
- spec/test-cases/json/create_and_sign_transaction_response_witness_v1_output.json
|
359
362
|
- spec/test-cases/json/get_balance_response.json
|
360
363
|
- spec/test-cases/json/prepare_dtrust_transaction_response_P2SH_3of5_195inputs.json
|
361
364
|
- spec/test-cases/json/prepare_dtrust_transaction_response_P2SH_4of5_195inputs.json
|
@@ -389,4 +392,5 @@ test_files:
|
|
389
392
|
- spec/test-cases/json/prepare_transaction_response_P2WSH-over-P2SH_1of2_253inputs.json
|
390
393
|
- spec/test-cases/json/prepare_transaction_response_P2WSH-over-P2SH_1of2_762inputs.json
|
391
394
|
- spec/test-cases/json/prepare_transaction_response_with_blockio_fee_and_expected_unsigned_txid.json
|
395
|
+
- spec/test-cases/json/prepare_transaction_response_witness_v1_output.json
|
392
396
|
- spec/test-cases/json/summarize_prepared_transaction_response_with_blockio_fee_and_expected_unsigned_txid.json
|