class Eth::Key::Encrypter

The Eth::Key::Encrypter class to handle PBKDF2-SHA-256 encryption.

def self.perform(key, password, options = {})

Returns:
  • (JSON) - formatted with encrypted key (cyphertext) and [other identifying data](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition#pbkdf2-sha-256)

Options Hash: (**options)
  • :block_size (Integer) -- for scrypt, defaults to 1
  • :parallelization (Integer) -- parallelization factor for scrypt, defaults to 8
  • :iv (String) -- 128-bit initialisation vector for the cipher
  • :salt (String) -- passed to PBKDF
  • :iterations (String) -- number of iterations for the hash function
  • :id (String) -- uuid given to the secret key
  • :kdf (String) -- key derivation function defaults to pbkdf2

Parameters:
  • options (Hash) -- the options to encrypt with
  • key (Eth::Key) -- representing a secret key-pair used for encryption
def self.perform(key, password, options = {})
  new(key, options).perform(password)
end

def block_size

def block_size
  options[:block_size] || 1
end

def cipher

def cipher
  @cipher ||= OpenSSL::Cipher.new(cipher_name).tap do |cipher|
    cipher.encrypt
    cipher.iv = iv
    cipher.key = derived_key[0, (key_length / 2)]
  end
end

def cipher_name

def cipher_name
  "aes-128-ctr"
end

def data

Returns:
  • (Hash) - the encrypted keystore data.
def data
  # default to pbkdf2
  kdfparams = if kdf == "scrypt"
      {
        dklen: 32,
        n: iterations,
        p: parallelization,
        r: block_size,
        salt: Util.bin_to_hex(salt),
      }
    else
      {
        c: iterations,
        dklen: 32,
        prf: prf,
        salt: Util.bin_to_hex(salt),
      }
    end
  {
    crypto: {
      cipher: cipher_name,
      cipherparams: {
        iv: Util.bin_to_hex(iv),
      },
      ciphertext: Util.bin_to_hex(encrypted_key),
      kdf: kdf,
      kdfparams: kdfparams,
      mac: Util.bin_to_hex(mac),
    },
    id: id,
    version: 3,
  }
end

def derive_key(password)

def derive_key(password)
  if kdf == "scrypt"
    @derived_key = SCrypt::Engine.scrypt(password, salt, iterations, block_size, parallelization, key_length)
  else
    @derived_key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, digest)
  end
end

def digest

def digest
  @digest ||= OpenSSL::Digest.new digest_name
end

def digest_name

def digest_name
  "sha256"
end

def encrypt

def encrypt
  @encrypted_key = cipher.update(Util.hex_to_bin key.private_hex) + cipher.final
end

def id

def id
  @id ||= options[:id] || SecureRandom.uuid
end

def initialize(key, options = {})

Options Hash: (**options)
  • :block_size (Integer) -- for scrypt, defaults to 1
  • :parallelization (Integer) -- parallelization factor for scrypt, defaults to 8
  • :iv (String) -- 128-bit initialisation vector for the cipher
  • :salt (String) -- passed to PBKDF
  • :iterations (String) -- number of iterations for the hash function
  • :id (String) -- uuid given to the secret key
  • :kdf (String) -- key derivation function defaults to pbkdf2

Parameters:
  • options (Hash) -- the options to encrypt with
  • key (Eth::Key) -- representing a secret key-pair used for encryption
def initialize(key, options = {})
  @key = key
  @options = options
  # the key derivation functions default to pbkdf2 if no option is specified
  # however, if an option is given then it must be either pbkdf2 or scrypt
  if kdf != "scrypt" && kdf != "pbkdf2"
    raise EncrypterError, "Unsupported key derivation function: #{kdf}!"
  end
end

def iterations

def iterations
  options[:iterations] || 262_144
end

def iv

def iv
  @iv ||= if options[:iv]
      Util.hex_to_bin options[:iv]
    else
      SecureRandom.random_bytes(iv_length)
    end
end

def iv_length

def iv_length
  16
end

def kdf

def kdf
  options[:kdf] || "pbkdf2"
end

def key_length

def key_length
  32
end

def mac

def mac
  Util.keccak256(derived_key[(key_length / 2), key_length] + encrypted_key)
end

def parallelization

def parallelization
  options[:parallelization] || 8
end

def perform(password)

Returns:
  • (String) - a json-formatted keystore string.

Parameters:
  • password (String) -- a secret key used for encryption
def perform(password)
  derive_key password
  encrypt
  data.to_json
end

def prf

def prf
  "hmac-#{digest_name}"
end

def salt

def salt
  @salt ||= if options[:salt]
      Util.hex_to_bin options[:salt]
    else
      SecureRandom.random_bytes(salt_length)
    end
end

def salt_length

def salt_length
  32
end