block_io 3.0.0 → 3.0.4

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: c7a878068a7ce224442ab3544657e2fb5de30dc68c43b00fd443c7c8ea35a61a
4
- data.tar.gz: '09ad2302125ca6d86427637023439ffac4f8c1e7d6f477d098aeb6955d0f3be2'
3
+ metadata.gz: eed2e36f43cdd4162187d87cc37d1a7262cf3bb49c74dd0ee5fa419287700805
4
+ data.tar.gz: c8841cd420bd57b9c29b8617aaf39f26d2e8a7050d432c2a0cc9b35bf3b0d602
5
5
  SHA512:
6
- metadata.gz: bb922e78d5c23c2e64b8259a688189eab1c20e654fa63389cc919d28a68030a0650101df2a32aecafbabb6ff639552e2698def07cd405638f0aea6bed32e7995
7
- data.tar.gz: 940ff69d78033e939b150af65fc89944a8fd99a4296bab9c8314b5988508e2d093ec1e6c1295df37ebcbac4d31110fc70e3749d02a58da25585039594b872de6
6
+ metadata.gz: 54d0ba740aa4cfbe535ae9a3c57f42d72f70422840609634c2810e9d2f491d53281fbb8afd6739da7e13d9329bfd0234e8b82e50b649f419dc963ae1dd465660
7
+ data.tar.gz: 60275bf0b7acffcdc354c095e557b34f1815aa5819e000384ef182f9439287188d9fd660951aa195b329a1cb0959a58b9ef8a397ba6f533625733a094124c240
data/.travis.yml CHANGED
@@ -1,9 +1,9 @@
1
1
  language: ruby
2
2
  os:
3
3
  - linux
4
+ dist:
5
+ - bionic
4
6
  rvm:
5
- - 2.4
6
- - 2.5
7
7
  - 2.6
8
8
  - 2.7
9
9
  - 3.0
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 -v=3.0.0
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.4.0'
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", "~> 0.7.0", "= 0.7.0"
26
- spec.add_runtime_dependency "http", "~> 4.4.1", ">= 4.4.1"
27
- spec.add_runtime_dependency "oj", "~> 3.11", ">= 3.11"
28
- spec.add_runtime_dependency "connection_pool", "~> 2.2.5", ">= 2.2"
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
@@ -2,7 +2,7 @@
2
2
  network: "BTC"
3
3
  address_version: "00"
4
4
  p2sh_version: "05"
5
- bech32_hrp: 'bc'
5
+ bech32_hrp: "bc"
6
6
  privkey_version: "80"
7
7
  extended_privkey_version: "0488ade4"
8
8
  extended_pubkey_version: "0488b21e"
@@ -2,7 +2,7 @@
2
2
  network: "BTCTEST"
3
3
  address_version: "6f"
4
4
  p2sh_version: "c4"
5
- bech32_hrp: 'tb'
5
+ bech32_hrp: "tb"
6
6
  privkey_version: "ef"
7
7
  extended_privkey_version: "04358394"
8
8
  extended_pubkey_version: "043587cf"
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Bitcoin::ChainParams
2
2
  network: "LTC"
3
3
  address_version: "30"
4
- p2sh_version: "05"
5
- bech32_hrp: 'ltc'
4
+ p2sh_version: "50"
5
+ bech32_hrp: "ltc"
6
6
  privkey_version: "b0"
7
7
  extended_privkey_version: "019d9cfe"
8
8
  extended_pubkey_version: "019da462"
@@ -2,7 +2,7 @@
2
2
  network: "LTCTEST"
3
3
  address_version: "6f"
4
4
  p2sh_version: "3a"
5
- bech32_hrp: 'tltc'
5
+ bech32_hrp: "tltc"
6
6
  privkey_version: "ef"
7
7
  extended_privkey_version: "0436f6e1"
8
8
  extended_pubkey_version: "0436ef7d"
@@ -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
- @encryption_key = Helper.pinToAesKey(args[:pin] || "") if args.key?(:pin)
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 @encryption_key or @keys.size > 0
135
-
136
- key = Helper.extractKey(encrypted_key['encrypted_passphrase'], @encryption_key)
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.load(File.open("#{__dir__}/chainparams/#{name}.yml"))
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
- s = GROUP.order - s if s > (GROUP.order / 2)
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
@@ -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
- 1024,
181
- 128/8,
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
- 1024,
189
- 256/8,
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
- [aes.update(data) << aes.final].pack("m0")
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
@@ -1,3 +1,3 @@
1
1
  module BlockIo
2
- VERSION = "3.0.0"
2
+ VERSION = "3.0.4"
3
3
  end
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
- it "deadbeef" do
10
- expect(BlockIo::Helper.pinToAesKey("deadbeef", false)).to eq([["b87ddac3d84865782a0edbc21b5786d56795dd52bab0fe49270b3726372a83fe"].pack("H*")].pack("m0"))
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.encrypt" do
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.decrypt" do
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
- end
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.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-05-26 00:00:00.000000000 Z
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: 0.7.0
99
+ version: '1.0'
100
100
  - - '='
101
101
  - !ruby/object:Gem::Version
102
- version: 0.7.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: 0.7.0
109
+ version: '1.0'
110
110
  - - '='
111
111
  - !ruby/object:Gem::Version
112
- version: 0.7.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.11'
140
- - - ">="
139
+ version: '3.0'
140
+ - - "<"
141
141
  - !ruby/object:Gem::Version
142
- version: '3.11'
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.11'
150
- - - ">="
149
+ version: '3.0'
150
+ - - "<"
151
151
  - !ruby/object:Gem::Version
152
- version: '3.11'
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.4.0
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.2.15
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