class NetPGP::SecretKey

Secret key

Attributes

check_hash[RW]
encrypted[RW]
hash_algorithm[RW]
iv[RW]
mpi[RW]
parent[RW]
passphrase[RW]
public_key[RW]
raw_subpackets[RW]
string_to_key_specifier[RW]
string_to_key_usage[RW]
subkeys[RW]
symmetric_key_algorithm[RW]
userids[RW]

Public Class Methods

from_native(sk, encrypted=false) click to toggle source
# File lib/netpgp/highlevel/secretkey.rb, line 230
def self.from_native(sk, encrypted=false)
  seckey = SecretKey.new
  seckey.public_key = PublicKey::from_native(sk[:pubkey])
  seckey.string_to_key_usage = LibNetPGP::enum_value(sk[:s2k_usage])
  seckey.string_to_key_specifier = LibNetPGP::enum_value(sk[:s2k_specifier])
  seckey.symmetric_key_algorithm = LibNetPGP::enum_value(sk[:alg])
  seckey.hash_algorithm = LibNetPGP::enum_value(sk[:hash_alg]) || HashAlgorithm::SHA1
  seckey.iv = sk[:iv].to_ptr.read_bytes(sk[:iv].size)
  if not sk[:checkhash].null?
    seckey.check_hash = sk[:checkhash].read_bytes(LibNetPGP::PGP_CHECKHASH_SIZE)
  end
  seckey.mpi = NetPGP::mpis_from_native(sk[:pubkey][:alg], sk)
  seckey.encrypted = encrypted
  seckey
end
generate(passphrase, options={}) click to toggle source
# File lib/netpgp/highlevel/secretkey.rb, line 204
def self.generate(passphrase, options={})
  valid_options = [:key_length, :public_key_algorithm, :algorithm_params,
                   :hash_algorithm, :symmetric_key_algorithm]
  for option in options.keys
    raise if not valid_options.include?(option)
  end

  key_length = options[:key_length] || 4096
  pkalg = options[:public_key_algorithm] || PublicKeyAlgorithm::RSA
  pkalg_params = options[:algorithm_params] || {e: 65537}
  hashalg = options[:hash_algorithm] || HashAlgorithm::SHA1
  skalg = options[:symmetric_key_algorithm] || SymmetricKeyAlgorithm::CAST5
  hashalg_s = HashAlgorithm::to_s(hashalg)
  skalg_s = SymmetricKeyAlgorithm::to_s(skalg)

  native_key = nil
  begin
    native_key = LibNetPGP::pgp_rsa_new_key(key_length, pkalg_params[:e], hashalg_s, skalg_s)
    key = SecretKey::from_native(native_key[:key][:seckey])
    key.passphrase = passphrase
    key
  ensure
    LibNetPGP::pgp_keydata_free(native_key) if native_key
  end
end
new() click to toggle source
# File lib/netpgp/highlevel/secretkey.rb, line 30
def initialize
  @public_key = nil
  @string_to_key_usage = nil
  @string_to_key_specifier = nil
  @symmetric_key_algorithm = nil
  @hash_algorithm = nil
  @iv = nil
  @check_hash = nil
  @mpi = {}
  @userids = []
  @parent = nil
  @subkeys = []
  @raw_subpackets = []
  @encrypted = false
  @passphrase = ''
end

Public Instance Methods

add_subkey(subkey) click to toggle source
# File lib/netpgp/highlevel/secretkey.rb, line 197
def add_subkey(subkey)
  raise if subkey.subkeys.any?
  subkey.parent = self
  subkey.userids = @userids
  @subkeys.push(subkey)
end
clearsign(data, armored=true, options={}) click to toggle source

Cleartext signs data using this secret key. This is a shortcut for {#sign}.

Note: {#passphrase} must be set to the correct passphrase prior to this call. If no passphrase is required, it should be set to ''.

@param data [String] the data to be signed. @param armored [Boolean] whether the output should be ASCII armored. @param options [Hash] less-often used options that override defaults.

* :from [Time] (defaults to Time.now) - signature creation time
* :duration [Integer] (defaults to 0) - signature duration/expiration
* :hash_algorithm [{NetPGP::HashAlgorithm}] (defaults to SHA1) -
  hash algorithm to use

@return [String] the signed data, or nil on error.

# File lib/netpgp/highlevel/secretkey.rb, line 150
def clearsign(data, armored=true, options={})
  options[:cleartext] = true
  sign(data, armored, options)
end
decrypt(data, armored=true) click to toggle source

Decrypts data using this secret key.

Note: {#passphrase} must be set to the correct passphrase prior to this call. If no passphrase is required, it should be set to '' (not nil).

@param data [String] the encrypted data to be decrypted. @param armored [Boolean] whether the encrypted data is ASCII armored.

# File lib/netpgp/highlevel/secretkey.rb, line 64
def decrypt(data, armored=true)
  begin
    rd, wr = IO.pipe
    wr.write(@passphrase + "\n")
    native_keyring_ptr = LibC::calloc(1, LibNetPGP::PGPKeyring.size)
    native_keyring = LibNetPGP::PGPKeyring.new(native_keyring_ptr)
    NetPGP::keys_to_native_keyring([self], native_keyring)
    pgpio = create_pgpio
    data_ptr = FFI::MemoryPointer.new(:uint8, data.bytesize)
    data_ptr.write_bytes(data)
    passfp = LibC::fdopen(rd.to_i, 'r')
    mem_ptr = LibNetPGP::pgp_decrypt_buf(pgpio, data_ptr, data_ptr.size,
                                         native_keyring, nil,
                                         armored ? 1 : 0, 0, passfp, 1, nil)
    return nil if mem_ptr.null?
    mem = LibNetPGP::PGPMemory.new(mem_ptr)
    mem[:buf].read_bytes(mem[:length])
  ensure
    rd.close
    wr.close
  end
end
decrypted_seckey() click to toggle source
# File lib/netpgp/highlevel/secretkey.rb, line 283
def decrypted_seckey
  if encrypted?
    native_ptr = LibC::calloc(1, LibNetPGP::PGPKey.size)
    native = LibNetPGP::PGPKey.new(native_ptr)
    native_auto = FFI::AutoPointer.new(native_ptr, LibNetPGP::PGPKey.method(:release))
    to_native_key(native)
    rd, wr = IO.pipe
    wr.write(@passphrase + "\n")
    wr.close
    passfp = LibC::fdopen(rd.to_i, 'r')
    decrypted = LibNetPGP::pgp_decrypt_seckey(native, passfp)
    rd.close
    LibC::fclose(passfp)
    return nil if not decrypted or decrypted.null?
    LibNetPGP::PGPSecKey.new(decrypted)
  else
    native_ptr = LibC::calloc(1, LibNetPGP::PGPSecKey.size)
    native = LibNetPGP::PGPSecKey.new(native_ptr)
    to_native(native)
    native
  end
end
detached_sign(infile, sigfile=nil, armored=true, options={}) click to toggle source

Creates a detached signature of a file.

Note: {#passphrase} must be set to the correct passphrase prior to this call. If no passphrase is required, it should be set to ''.

@param infile [String] the path to the input file for which a

signature will be created.

@param sigfile [String] the path to the signature file that will

be created.

This can be nil, in which case the filename will be the infile
parameter with '.asc' appended.

@param armored [Boolean] whether the output should be ASCII armored. @param options [Hash] less-often used options that override defaults.

* :from [Time] (defaults to Time.now) - signature creation time
* :duration [Integer] (defaults to 0) - signature duration/expiration
* :hash_algorithm [{NetPGP::HashAlgorithm}] (defaults to SHA1) -
  hash algorithm to use

@return [Boolean] whether the signing was successful.

# File lib/netpgp/highlevel/secretkey.rb, line 175
def detached_sign(infile, sigfile=nil, armored=true, options={})
  valid_options = [:from, :duration, :hash_algorithm]
  for option in options.keys
    raise if not valid_options.include?(option)
  end

  armored = armored ? 1 : 0
  from = options[:from] || Time.now
  duration = options[:duration] || 0
  hashalg = options[:hash_algorithm] || HashAlgorithm::SHA1

  hashname = HashAlgorithm::to_s(hashalg)
  from = from.to_i

  pgpio = create_pgpio
  # Note: pgp_sign_detached calls pgp_seckey_free for us
  seckey = decrypted_seckey
  return false if not seckey
  ret = LibNetPGP::pgp_sign_detached(pgpio, infile, sigfile, seckey, hashname, from, duration, armored, 1)
  return ret == 1
end
encrypted?() click to toggle source

Checks if a key is encrypted. An encrypted key requires a passphrase for signing/decrypting/etc and will have nil values for key material/mpis.

@return [Boolean]

# File lib/netpgp/highlevel/secretkey.rb, line 52
def encrypted?
  @encrypted
end
sign(data, armored=true, options={}) click to toggle source

Signs data using this secret key.

Note: {#passphrase} must be set to the correct passphrase prior to this call. If no passphrase is required, it should be set to ''.

@param data [String] the data to be signed. @param armored [Boolean] whether the output should be ASCII armored. @param options [Hash] less-often used options that override defaults.

* :from [Time] (defaults to Time.now) - signature creation time
* :duration [Numeric] (defaults to 0) - signature duration/expiration
* :hash_algorithm [NetPGP::HashAlgorithm] (defaults to SHA1) -
  hash algorithm to use
* :cleartext [Boolean] (defaults to false) - whether this should be
  a cleartext/clearsign signature, which includes the original
  data in cleartext in the same document.

@return [String] the signed data, or nil on error.

# File lib/netpgp/highlevel/secretkey.rb, line 103
def sign(data, armored=true, options={})
  valid_options = [:from, :duration, :hash_algorithm, :cleartext]
  for option in options.keys
    raise if not valid_options.include?(option)
  end

  armored = armored ? 1 : 0
  from = options[:from] || Time.now
  duration = options[:duration] || 0
  hashalg = options[:hash_algorithm] || HashAlgorithm::SHA1
  cleartext = options[:cleartext] ? 1 : 0

  from = from.to_i
  hashname = HashAlgorithm::to_s(hashalg)

  pgpio = create_pgpio
  data_buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
  data_buf.write_bytes(data)
  seckey = decrypted_seckey
  return nil if not seckey
  memory = nil
  begin
    memory_ptr = LibNetPGP::pgp_sign_buf(pgpio, data_buf, data_buf.size, seckey, from, duration, hashname, armored, cleartext)
    return nil if not memory_ptr or memory_ptr.null?
    memory = LibNetPGP::PGPMemory.new(memory_ptr)
    signed_data = memory[:buf].read_bytes(memory[:length])
    signed_data
  ensure
    LibNetPGP::pgp_memory_free(memory) if memory
    LibNetPGP::pgp_seckey_free(seckey) if seckey
  end
end
to_native(native) click to toggle source
# File lib/netpgp/highlevel/secretkey.rb, line 246
def to_native(native)
  @public_key.to_native(native[:pubkey])
  native[:s2k_usage] = @string_to_key_usage
  native[:s2k_specifier] = @string_to_key_specifier
  native[:alg] = @symmetric_key_algorithm
  native[:hash_alg] = @hash_algorithm
  # zero IV, then copy
  native[:iv].to_ptr.write_bytes("\x00" * native[:iv].size)
  native[:iv].to_ptr.write_bytes(@iv) if @iv
  NetPGP::mpis_to_native(PublicKeyAlgorithm::to_native(@public_key.public_key_algorithm), @mpi, native)
  # note: this has to come after mpis_to_native because that frees ptrs
  if @check_hash
    native[:checkhash] = LibC::calloc(1, LibNetPGP::PGP_CHECKHASH_SIZE)
    native[:checkhash].write_bytes(@check_hash)
  end
end
to_native_key(native_key) click to toggle source
# File lib/netpgp/highlevel/secretkey.rb, line 263
def to_native_key(native_key)
  raise if not native_key[:packets].null?
  native_key[:type] = :PGP_PTAG_CT_SECRET_KEY
  native_key[:sigid] = @public_key.key_id
  to_native(native_key[:key][:seckey])
  if not @parent
    @userids.each {|userid|
      LibNetPGP::dynarray_append_item(native_key, 'uid', :string, userid)
    }
  end
  @raw_subpackets.each {|bytes|
    packet = LibNetPGP::PGPSubPacket.new
    length = bytes.bytesize
    packet[:length] = length
    packet[:raw] = LibC::calloc(1, length)
    packet[:raw].write_bytes(bytes)
    LibNetPGP::dynarray_append_item(native_key, 'packet', LibNetPGP::PGPSubPacket, packet)
  }
end

Private Instance Methods

create_pgpio() click to toggle source
# File lib/netpgp/highlevel/secretkey.rb, line 307
def create_pgpio
  pgpio = LibNetPGP::PGPIO.new
  pgpio[:outs] = LibC::fdopen($stdout.to_i, 'w')
  pgpio[:errs] = LibC::fdopen($stderr.to_i, 'w')
  pgpio[:res] = pgpio[:errs]
  pgpio
end