Using passphrase callback in ruby gpgme - ruby

I am using ruby gpgme gem (1.0.8). My passphrase callback isn't called:
def passfunc(*args)
fd = args.last
io = IO.for_fd(fd, 'w')
io.puts "mypassphrase"
io.flush
end
opts = {
:passphrase_callback => method(:passfunc)
}
GPGME.decrypt(input,output, opts)
Does someone have working example of passphrase callback?

Sample of callback you can find in the following working example. It signs a file in detached mode, i.e., the signature file is separated from the original file. It uses the default keyring at ~/.gnupg or something like that. To use a different directory for your keyring, set the environment variable ENV["GNUPGHOME"]="" before call GPGME::sign().
#!/usr/bin/ruby
require 'rubygems'
require 'gpgme'
puts "Signing #{ARGV[0]}"
input = File.open(ARGV[0],'r')
PASSWD = "abc"
def passfunc(hook, uid_hint, passphrase_info, prev_was_bad, fd)
puts("Passphrase for #{uid_hint}: ")
io = IO.for_fd(fd, 'w')
io.write(PASSWD+"\n")
io.flush
end
output = File.open(ARGV[0]+'.asc','w')
sign = GPGME::sign(input, {
:passphrase_callback => method(:passfunc),
:mode => GPGME::SIG_MODE_DETACH
})
output.write(sign)
output.close
input.close

Here's another working example for you that doesn't use a detached signature. To test this, simply change 'user#host.name' to the identifier of your key and do this: GPG.decrypt(GPG.encrypt('some text', :armor => true))
require 'gpgme'
require 'highline/import'
module GPG
ENCRYPT_KEY = 'user#host.com'
#gpg = GPGME::Crypto.new
class << self
def decrypt(encrypted_data, options = {})
options = { :passphrase_callback => self.method(:passfunc) }.merge(options)
#gpg.decrypt(encrypted_data, options).read
end
def encrypt(data_to_encrypt, options = {})
options = { :passphrase_callback => self.method(:passfunc), :armor => true }.merge(options)
#gpg.encrypt(data_to_encrypt, options).read
end
private
def get_passphrase
ask("Enter passphrase for #{ENCRYPT_KEY}: ") { |q| q.echo = '*' }
end
def passfunc(hook, uid_hint, passphrase_info, prev_was_bad, fd)
begin
system('stty -echo')
io = IO.for_fd(fd, 'w')
io.puts(get_passphrase)
io.flush
ensure
(0 ... $_.length).each do |i| $_[i] = ?0 end if $_
system('stty echo')
end
$stderr.puts
end
end
end
Cheers!,
--
Carl

It is important to note that as of GnuPG 2.0 (and in 1.4 when the use-agent option is used) pinentry is used for passphrase collection. This means that the gpgme passphrase callback will not be invoked. This is described here and an example of usage can be found in the gpgme-tool example.

Related

ruby-snmp: how to automatically convert response to its proper type?

In ruby I read some SNMP registers. Response is an array of objects.
Is there a nice way to convert each object to the proper type avoiding the case..when in the following code? It looks strange that it must be converted manually as the type is already known:
require 'snmp'
HOST = '127.0.0.1'.freeze
registers = ['sysContact.0', 'sysUpTime.0',
'upsIdentManufacturer.0', 'upsIdentModel.0', 'upsIdentName.0']
params_array = {}
SNMP::Manager.open(host: HOST) do |manager|
manager.load_module('UPS-MIB')
response = manager.get(registers)
response.each_varbind do |vb|
##################################
# change from here...
value = nil
case vb.value.asn1_type
when 'OCTET STRING' # <==========
value = vb.value
when 'INTEGER' # <==========
value = vb.value.to_i
when 'TimeTicks' # <==========
value = vb.value.to_s
else
puts "Type '#{vb.value.asn1_type}' not recognized!"
exit(1)
end
params_array[vb.name.to_s] = value
# ... to here
##################################
# with something like
# params_array[vb.name.to_s] = vb.value._to_its_proper_type_
end
end
pp params_array
Looking at the code in the gem repo, it doesn't look like like there is a method for this. I suppose you could try to monkey patch it, but not sure if it's worth the trouble.
If you don't like the switch syntax, you could just use a hash lookup like this:
require 'snmp'
HOST = '127.0.0.1'.freeze
TYPE_VALUES = {
'OCTET STRING' => :to_s,
'INTEGER' => :to_i,
'TimeTicks' => :to_s
}.freeze
registers = ['sysContact.0', 'sysUpTime.0',
'upsIdentManufacturer.0', 'upsIdentModel.0', 'upsIdentName.0']
params_array = {}
SNMP::Manager.open(host: HOST) do |manager|
manager.load_module('UPS-MIB')
response = manager.get(registers)
response.each_varbind do |vb|
if method = TYPE_VALUES[vb.value.ans1_type]
params_array[vb.name.to_s] = vb.value.send(method)
else
puts "Type '#{vb.value.asn1_type}' not recognized!"
exit(1)
end
end
end
pp params_array

Digesting value in YAML file into MD5 hash

I have a YAML file containing usernames and passwords.
Overview of YAML:
users:
test:
password: test
test2:
password: test2
I want to encrypt the password value into an MD5 hash using Digest::MD5 for example:
user:
Lost Bam:
password: testtesttest #<=I want to overwrite this password with a MD5 hash
In Digest is there a way to encrypt a hash value? If so how do I implement this into a YAML file?
md5.rb Source:
require 'yaml'
require 'digest'
private
def load_file
File.exist?('info.yml') ? YAML.load_file('info.yml') : {users: {}}
end
def read_file
File.read('info.yml')
end
def save_file( hash )
File.open('info.yml', 'w') { |f| f.write(hash.to_yaml)}
end
def add_user
hash = load_file
hash["users"][prompt('Enter username:')] =
{ "password" => prompt('Enter password:') }
puts "Encrypt information?"
information = gets.chomp
case input
when /yes/i
# hash = Digest::MD5.digest(["password"]'value')<-Doesn't work
#
#This is where I want to be able to encrypt the
#value of the password key that was entered by the user
#
# save_file( hash )
else
puts "Add another?"#Not completed yet
end
save_file( hash )
end
main.rb Source:
require_relative 'md5.rb'
def main
puts <<-END.gsub(/^\s*>/, '')
>
>To load information type "L" to quit system type "Q"
>
END
input = gets.chomp.upcase
case input
when "L"
add_user
when "Q"
exit_system
else
exit_lock
end
end
def exit_system
puts "Exiting..."
exit
end
def exit_lock
puts "Locked out, please contact system administrator"
exit
end
def restart
puts "Encrypt more?"
input = gets.chomp
if input =~ /yes/i
return true
else
exit_system
end
end
def prompt( message )
puts message
gets.chomp
end
main
You can use Digest::MD5:
require 'digest'
Digest::MD5.digest('value')
http://ruby-doc.org/stdlib-2.1.0/libdoc/digest/rdoc/Digest.html

Zlib data error while opening file in Ruby - works when a string is specified

I wrote this bit of code that reverses XOR-based encryption in Ruby. The chipertext is XORed with 'key' and the output is passed to Zlib.deflate.
require 'zlib'
def bin_to_hex(s)
s.unpack('H*').first
end
def hex(s)
s.scan(/../).map { |x| x.hex }.pack('c*')
end
chipertext = "Encrypted data"
key = "Some encryption key"
puts hex((bin_to_hex(Zlib::Inflate.inflate(code)).to_i(16) ^ ((bin_to_hex(key) * (bin_to_hex(Zlib::Inflate.inflate(chipertext)).length/bin_to_hex(key).length)) + bin_to_hex(key)[0, bin_to_hex(Zlib::Inflate.inflate(chipertext)).length%bin_to_hex(key).length]).to_i(16)).to_s(16))
The code runs perfectly when I specify chipertext as a string, in the example above. But when I use code like chipertext = File.open(ARGV[0], 'rb') { |f| f.read }, I get a inflate: incorrect header check (Zlib::DataError).
How can I prevent this from happening?

md5 Hash in a puppet custom function

Currently I want to create an md5 hash from an argument. Then I want to write the hash into a file (the path is another argument).
That is the custom function:
module Puppet::Parser::Functions
newfunction(:write_line_to_file) do |args|
require 'md5'
filename = args[0]
str = MD5.new(lookupvar(args[1])).to_s
File.open(filename, 'a') {|fd| fd.puts str }
end
end
And the call in the puppet manifest:
write_line_to_file('/tmp/some_hash', "Hello world!")
The result I get is a file and the content is not the hash but the original string. (In the example Hello World!)
I know that this custom function has no practical use. I just want to understand how the md5 hash works.
---UPD---
new Function (it works properly):
require 'digest'
module Puppet::Parser::Functions
newfunction(:lxwrite_line_to_file) do |args|
filename = args[0]
str = Digest::MD5.hexdigest args[1]
File.open(filename, 'w') {|fd| fd.puts str }
end
end
Which ruby you are using?
In Ruby 2.0+ there is a Digest module (documentation here) - why you don't use it instead?.
You can use any hash, available in Digest, like this:
Digest::MD5.digest '123'
=> " ,\xB9b\xACY\a[\x96K\a\x15-#Kp"
or use hexdigest if you prefer hex representation
Digest::MD5.hexdigest '123'
=> "202cb962ac59075b964b07152d234b70"
There are also other hash-functions available there:
Digest::SHA2.hexdigest '123'
=> "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"

Ruby Options parser not reading command line options

Im trying to use the Ruby builtin options parser
I have this file
File parser.rb
#!/usr/bin/env ruby
require 'optparse'
require 'pp'
class parser
def initialize(args)
#options = Hash.new()
#op = OptionParser.new do |opts|
#options[:verbose] = false
opts.on('-v', '--verbose', 'Output more information') do
#options[:verbose] = true
end
#options[:quick] = false
opts.on( '-q', '--quick', 'Perform the task quickly' ) do
#options[:quick] = true
end
#options[:logfile] = nil
opts.on( '-l', '--logfile FILE', 'Write log to FILE' ) do|file|
#options[:logfile] = file
end
opts.on( '-h', '--help', 'Display this screen' ) do
puts opts
exit
end
#options[:sID] = "-1"
opts.on('-sID', '--senderID', 'Sender ID used by device') do |sID|
#options[:sID] = sID
end
#options[:rID] = "-1"
opts.on('-rID', '--receiverID', 'Receiver ID used by device') do |rID|
#options[:rID] = rID
end
#op.parse!
#op
end
def getOptionsHash
#options
end
then Im trying to use this class in the file below
#!/usr/bin/env ruby
# Setup Bundler
require 'rubygems'
require 'bundler/setup'
require_relative 'parser'
#Variables in the options hash in parser.rb
op = Parser.new(ARGV)
pp op.getOptionsHash()
when I run this on the command line without args it uses default values:
./push_test.rb
I get the following output:
{:verbose=>false,
:quick=>false,
:logfile=>nil,
:sID=>"-1",
:rID=>"-1",
}
when I run this on the command line with args:
./push_test.rb -sID "33"
I get the following output:
{:verbose=>false,
:quick=>false,
:logfile=>nil,
:sID=>"ID",
:rID=>"-1",
}
Why is the sID not being set to 33?
Can anyone help please?Ive tried to figure this out but cant make any headway
Seems the short switch has to be a single character -s
./push_test.rb -sID "33"
outputs:
{:verbose=>false, :quick=>false, :logfile=>nil, :sID=>"ID", :rID=>"-1" }
because everything after -s to the first white space will be assigned to :sID, in your case its the word "ID" that follows "-s", hence you are getting :sID =>"ID"
./push_test.rb -s "33" will do the trick.
From the OptParser docs:
Short style switch:: Specifies short style switch which takes a
mandatory, optional or no argument. It's a string of the following
form:
"-xMANDATORY"
"-x[OPTIONAL]"
"-x"
So at specifying switch -sID you define switch -s with argument named ID - something different than you were probably expecting.

Resources