Class: BitPay::KeyUtils

Inherits:
Object
  • Object
show all
Defined in:
lib/bitpay/key_utils.rb

Class Method Summary collapse

Class Method Details

.create_key(pem) ⇒ Object



39
40
41
# File 'lib/bitpay/key_utils.rb', line 39

def create_key pem
  OpenSSL::PKey::EC.new(pem)
end

.create_new_keyObject



43
44
45
46
47
# File 'lib/bitpay/key_utils.rb', line 43

def create_new_key
  key = OpenSSL::PKey::EC.new("secp256k1")
  key.generate_key
  key
end

.generate_pemObject



32
33
34
35
36
37
# File 'lib/bitpay/key_utils.rb', line 32

def generate_pem
  key = OpenSSL::PKey::EC.new("secp256k1")
  key.generate_key
  write_pem_file(key)
  key.to_pem
end

.generate_sin_from_pem(pem = nil) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/bitpay/key_utils.rb', line 80

def generate_sin_from_pem(pem = nil)
  #http://blog.bitpay.com/2014/07/01/bitauth-for-decentralized-authentication.html
  #https://en.bitcoin.it/wiki/Identity_protocol_v1

  # NOTE:  All Digests are calculated against the binary representation, 
  # hence the requirement to use [].pack("H*") to convert to binary for each step
  
  #Generate Private Key
  key = pem.nil? ? get_local_pem_file : OpenSSL::PKey::EC.new(pem)
  key.public_key.group.point_conversion_form = :compressed
  public_key = key.public_key.to_bn.to_s(2)
  step_one = Digest::SHA256.hexdigest(public_key)
  step_two = Digest::RMD160.hexdigest([step_one].pack("H*")) 
  step_three = "0F02" + step_two
  step_four_a = Digest::SHA256.hexdigest([step_three].pack("H*"))
  step_four = Digest::SHA256.hexdigest([step_four_a].pack("H*"))
  step_five = step_four[0..7]
  step_six = step_three + step_five
  encode_base58(step_six)
end

.get_local_pem_fileObject

Gets private key from ENV variable or local FS



55
56
57
# File 'lib/bitpay/key_utils.rb', line 55

def get_local_pem_file
  ENV['BITPAY_PEM'] || File.read(PRIVATE_KEY_PATH) || (raise BitPayError, MISSING_KEY)
end

.get_private_key(key) ⇒ Object



59
60
61
# File 'lib/bitpay/key_utils.rb', line 59

def get_private_key key
  key.private_key.to_int.to_s(16)
end

.get_private_key_from_pem(pem) ⇒ Object

Raises:



68
69
70
71
72
# File 'lib/bitpay/key_utils.rb', line 68

def get_private_key_from_pem pem
  raise BitPayError, MISSING_KEY unless pem
  key = OpenSSL::PKey::EC.new(pem)
  get_private_key key
end

.get_public_key(key) ⇒ Object



63
64
65
66
# File 'lib/bitpay/key_utils.rb', line 63

def get_public_key key 
  key.public_key.group.point_conversion_form = :compressed
  key.public_key.to_bn.to_s(16).downcase
end

.get_public_key_from_pem(pem) ⇒ Object

Raises:



74
75
76
77
78
# File 'lib/bitpay/key_utils.rb', line 74

def get_public_key_from_pem pem
  raise BitPayError, MISSING_KEY unless pem
  key = OpenSSL::PKey::EC.new(pem)
  get_public_key key
end

.nonceObject



17
18
19
# File 'lib/bitpay/key_utils.rb', line 17

def nonce
  Time.now.utc.strftime('%Y%m%d%H%M%S%L')
end

.retrieve_or_generate_pemObject

Generates a new private key and writes to local FS



23
24
25
26
27
28
29
30
# File 'lib/bitpay/key_utils.rb', line 23

def retrieve_or_generate_pem
  begin
    pem = get_local_pem_file
  rescue
    pem = generate_pem
  end
  pem
end

.sign(message, privkey) ⇒ Object

Generate ECDSA signature

This is the last method that requires the ecdsa gem, which we would like to replace


105
106
107
108
109
110
111
112
113
114
# File 'lib/bitpay/key_utils.rb', line 105

def sign(message, privkey)
  group = ECDSA::Group::Secp256k1
  digest = Digest::SHA256.digest(message)
  signature = nil
  while signature.nil?
    temp_key = 1 + SecureRandom.random_number(group.order - 1)
    signature = ECDSA.sign(group, privkey.to_i(16), digest, temp_key)
    return ECDSA::Format::SignatureDerString.encode(signature).unpack("H*").first
  end
end

.write_pem_file(key) ⇒ Object



49
50
51
52
# File 'lib/bitpay/key_utils.rb', line 49

def write_pem_file key
  FileUtils.mkdir_p(BITPAY_CREDENTIALS_DIR)
  File.open(PRIVATE_KEY_PATH, 'w') { |file| file.write(key.to_pem) }
end