55require 'ecdsa'
66require 'openssl'
77require 'digest'
8+ require 'pbkdf2'
89require 'securerandom'
910require 'base64'
1011
@@ -160,14 +161,20 @@ def public_key
160161 def sign ( data )
161162 # signed the given hexadecimal string
162163
163- nonce = 1 + SecureRandom . random_number ( @group . order - 1 ) # nonce, can be made deterministic TODO
164+ nonce = deterministicGenerateK ( [ data ] . pack ( "H*" ) , @private_key ) # RFC6979
164165
165- signature = ECDSA . sign ( @group , @private_key , [ data ] . pack ( "H*" ) , nonce )
166+ signature = ECDSA . sign ( @group , @private_key , data . to_i ( 16 ) , nonce )
166167
167- # DER encode this, and return it in hex form
168+ # BIP0062 -- use lower S values only
169+ r , s = signature . components
168170
169- return ECDSA ::Format ::SignatureDerString . encode ( signature ) . unpack ( "H*" ) [ 0 ]
171+ over_two = @group . order >> 1 # half of what it was
172+ s = @group . order - s if ( s > over_two )
170173
174+ signature = ECDSA ::Signature . new ( r , s )
175+
176+ # DER encode this, and return it in hex form
177+ return ECDSA ::Format ::SignatureDerString . encode ( signature ) . unpack ( "H*" ) [ 0 ]
171178 end
172179
173180 def self . from_passphrase ( passphrase )
@@ -182,6 +189,60 @@ def self.from_passphrase(passphrase)
182189 return Key . new ( hashed_key )
183190 end
184191
192+ def isPositive ( i )
193+ sig = "!+-" [ i <=> 0 ]
194+
195+ return sig . eql? ( "+" )
196+ end
197+
198+ def deterministicGenerateK ( data , privkey , group = ECDSA ::Group ::Secp256k1 )
199+ # returns a deterministic K -- RFC6979
200+
201+ hash = data . bytes . to_a
202+
203+ x = [ privkey . to_s ( 16 ) ] . pack ( "H*" ) . bytes . to_a
204+
205+ k = [ ]
206+ 32 . times { k . insert ( 0 , 0 ) }
207+
208+ v = [ ]
209+ 32 . times { v . insert ( 0 , 1 ) }
210+
211+ # step D
212+ k = OpenSSL ::HMAC . digest ( OpenSSL ::Digest . new ( 'sha256' ) , k . pack ( "C*" ) , [ ] . concat ( v ) . concat ( [ 0 ] ) . concat ( x ) . concat ( hash ) . pack ( "C*" ) ) . bytes . to_a
213+
214+ # step E
215+ v = OpenSSL ::HMAC . digest ( OpenSSL ::Digest . new ( 'sha256' ) , k . pack ( "C*" ) , v . pack ( "C*" ) ) . bytes . to_a
216+
217+ # puts "E: " + v.pack("C*").unpack("H*")[0]
218+
219+ # step F
220+ k = OpenSSL ::HMAC . digest ( OpenSSL ::Digest . new ( 'sha256' ) , k . pack ( "C*" ) , [ ] . concat ( v ) . concat ( [ 1 ] ) . concat ( x ) . concat ( hash ) . pack ( "C*" ) ) . bytes . to_a
221+
222+ # step G
223+ v = OpenSSL ::HMAC . digest ( OpenSSL ::Digest . new ( 'sha256' ) , k . pack ( "C*" ) , v . pack ( "C*" ) ) . bytes . to_a
224+
225+ # step H2b (Step H1/H2a ignored)
226+ v = OpenSSL ::HMAC . digest ( OpenSSL ::Digest . new ( 'sha256' ) , k . pack ( "C*" ) , v . pack ( "C*" ) ) . bytes . to_a
227+
228+ h2b = v . pack ( "C*" ) . unpack ( "H*" ) [ 0 ]
229+ tNum = h2b . to_i ( 16 )
230+
231+ # step H3
232+ while ( !isPositive ( tNum ) or tNum >= group . order ) do
233+ # k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([0])]), k)
234+ k = OpenSSL ::HMAC . digest ( OpenSSL ::Digest . new ( 'sha256' ) , k . pack ( "C*" ) , [ ] . concat ( v ) . concat ( [ 0 ] ) . pack ( "C*" ) ) . bytes . to_a
235+
236+ # v = crypto.HmacSHA256(v, k)
237+ v = OpenSSL ::HMAC . digest ( OpenSSL ::Digest . new ( 'sha256' ) , k . pack ( "C*" ) , v . pack ( "C*" ) ) . bytes . to_a
238+
239+ # T = BigInteger.fromBuffer(v)
240+ tNum = v . pack ( "C*" ) . unpack ( "H*" ) [ 0 ] . to_i ( 16 )
241+ end
242+
243+ return tNum
244+ end
245+
185246 end
186247
187248 module Helper
@@ -207,9 +268,11 @@ def self.pinToAesKey(secret_pin, iterations = 2048)
207268 # converts the pincode string to PBKDF2
208269 # returns a base64 version of PBKDF2 pincode
209270 salt = ""
210- aes_key_bin = OpenSSL ::PKCS5 . pbkdf2_hmac ( secret_pin , salt , iterations /2 , 16 , OpenSSL ::Digest ::SHA256 . new )
211- aes_key_bin = OpenSSL ::PKCS5 . pbkdf2_hmac ( aes_key_bin . unpack ( "H*" ) [ 0 ] , salt , iterations /2 , 32 , OpenSSL ::Digest ::SHA256 . new )
212-
271+
272+ # pbkdf2-ruby gem uses SHA256 as the default hash function
273+ aes_key_bin = PBKDF2 . new ( :password => secret_pin , :salt => salt , :iterations => iterations /2 , :key_length => 128 /8 ) . value
274+ aes_key_bin = PBKDF2 . new ( :password => aes_key_bin . unpack ( "H*" ) [ 0 ] , :salt => salt , :iterations => iterations /2 , :key_length => 256 /8 ) . value
275+
213276 return Base64 . strict_encode64 ( aes_key_bin ) # the base64 encryption key
214277 end
215278
0 commit comments