Class: Fabric::CryptoSuite

Inherits:
Object
  • Object
show all
Defined in:
lib/fabric/crypto_suite.rb

Constant Summary collapse

DEFAULT_KEY_SIZE =
256
DEFAULT_DIGEST_ALGORITHM =
'SHA256'.freeze
DEFAULT_AES_KEY_SIZE =
128
EC_CURVES =
{ 256 => 'prime256v1', 384 => 'secp384r1' }.freeze
CIPHER =
'aes-256-cbc'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ CryptoSuite

Returns a new instance of CryptoSuite.



15
16
17
18
19
20
21
# File 'lib/fabric/crypto_suite.rb', line 15

def initialize(opts = {})
  @key_size = opts[:key_size] || DEFAULT_KEY_SIZE
  @digest_algorithm = opts[:digest_algorithm] || DEFAULT_DIGEST_ALGORITHM
  @digest = OpenSSL::Digest.new digest_algorithm
  @curve = EC_CURVES[key_size]
  @cipher = opts[:cipher] || CIPHER
end

Instance Attribute Details

#cipherObject (readonly)

Returns the value of attribute cipher.



13
14
15
# File 'lib/fabric/crypto_suite.rb', line 13

def cipher
  @cipher
end

#curveObject (readonly)

Returns the value of attribute curve.



13
14
15
# File 'lib/fabric/crypto_suite.rb', line 13

def curve
  @curve
end

#digest(message) ⇒ Object (readonly)

Returns the value of attribute digest.



13
14
15
# File 'lib/fabric/crypto_suite.rb', line 13

def digest
  @digest
end

#digest_algorithmObject (readonly)

Returns the value of attribute digest_algorithm.



13
14
15
# File 'lib/fabric/crypto_suite.rb', line 13

def digest_algorithm
  @digest_algorithm
end

#key_sizeObject (readonly)

Returns the value of attribute key_size.



13
14
15
# File 'lib/fabric/crypto_suite.rb', line 13

def key_size
  @key_size
end

Instance Method Details

#address_from_public_key(public_key) ⇒ Object



84
85
86
87
88
89
# File 'lib/fabric/crypto_suite.rb', line 84

def address_from_public_key(public_key)
  bytes = decode_hex public_key
  address_bytes = keccak256(bytes[1..-1])[-20..-1]

  encode_hex address_bytes
end

#build_shared_key(private_key, public_key) ⇒ Object



91
92
93
94
95
96
97
98
# File 'lib/fabric/crypto_suite.rb', line 91

def build_shared_key(private_key, public_key)
  pkey = pkey_from_private_key private_key
  public_bn = OpenSSL::BN.new public_key, 16
  group = OpenSSL::PKey::EC::Group.new curve
  public_point = OpenSSL::PKey::EC::Point.new group, public_bn

  encode_hex pkey.dh_compute_key(public_point)
end

#decode_hex(string) ⇒ Object



67
68
69
# File 'lib/fabric/crypto_suite.rb', line 67

def decode_hex(string)
  [string].pack('H*')
end

#decrypt(secret, data) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/fabric/crypto_suite.rb', line 110

def decrypt(secret, data)
  return unless data

  encrypted_data = Base64.strict_decode64 data
  aes = OpenSSL::Cipher.new cipher
  aes.decrypt
  aes.key = decode_hex(secret)
  aes.iv = encrypted_data[0..15]
  encrypted_data = encrypted_data[16..-1]

  aes.update(encrypted_data) + aes.final
end

#encode_hex(bytes) ⇒ Object



63
64
65
# File 'lib/fabric/crypto_suite.rb', line 63

def encode_hex(bytes)
  bytes.unpack('H*').first
end

#encrypt(secret, data) ⇒ Object



100
101
102
103
104
105
106
107
108
# File 'lib/fabric/crypto_suite.rb', line 100

def encrypt(secret, data)
  aes = OpenSSL::Cipher.new cipher
  aes.encrypt
  aes.key = decode_hex(secret)
  iv = aes.random_iv
  aes.iv = iv

  Base64.strict_encode64(iv + aes.update(data) + aes.final)
end

#generate_csr(private_key, attrs = []) ⇒ Object



40
41
42
43
44
45
46
47
48
49
# File 'lib/fabric/crypto_suite.rb', line 40

def generate_csr(private_key, attrs = [])
  key = pkey_from_private_key private_key

  req = OpenSSL::X509::Request.new
  req.public_key = key
  req.subject = OpenSSL::X509::Name.new attrs
  req.sign key, @digest

  req
end

#generate_nonce(length = 24) ⇒ Object



51
52
53
# File 'lib/fabric/crypto_suite.rb', line 51

def generate_nonce(length = 24)
  OpenSSL::Random.random_bytes length
end

#generate_private_keyObject



33
34
35
36
37
38
# File 'lib/fabric/crypto_suite.rb', line 33

def generate_private_key
  key = OpenSSL::PKey::EC.new curve
  key.generate_key!

  key.private_key.to_i.to_s(16).downcase
end

#hexdigest(message) ⇒ Object



55
56
57
# File 'lib/fabric/crypto_suite.rb', line 55

def hexdigest(message)
  @digest.hexdigest message
end

#keccak256(bytes) ⇒ Object



71
72
73
# File 'lib/fabric/crypto_suite.rb', line 71

def keccak256(bytes)
  Digest::SHA3.new(256).digest bytes
end

#restore_public_key(private_key) ⇒ Object



75
76
77
78
79
80
81
82
# File 'lib/fabric/crypto_suite.rb', line 75

def restore_public_key(private_key)
  private_bn = OpenSSL::BN.new private_key, 16
  group = OpenSSL::PKey::EC::Group.new curve
  public_bn = group.generator.mul(private_bn).to_bn
  public_bn = OpenSSL::PKey::EC::Point.new(group, public_bn).to_bn

  public_bn.to_s(16).downcase
end

#sign(private_key, message) ⇒ Object



23
24
25
26
27
28
29
30
31
# File 'lib/fabric/crypto_suite.rb', line 23

def sign(private_key, message)
  digest = digest message
  key = pkey_from_private_key private_key
  signature = key.dsa_sign_asn1 digest
  sequence = OpenSSL::ASN1.decode signature
  sequence = prevent_malleability sequence, key.group.order

  sequence.to_der
end