Using passphrase callback in ruby gpgme
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
how to bypass pinentry (passphrase screen) while decrypting a file using gpgme
I am unable to bypass the passphrase or pinentry screen, but I used gpg-agent
options like default-cache-ttl
to set the cache time. So that from the second attempt, the pinentry is going to retrieve the cached passphrase and will reset the timer on defaul-cache-ttl
.
There is one more called max-cache-ttl
option, even after the successfull retrieval of cached passphrase and reset of default-cache-ttl, this option doesn't change its timer and expires the cached passphrase after the set timeout.
For ex: If I set both of them for 10hrs (i.e., 36000sec), if I call the decrypt after 5hrs, default is going to reset its timer and now we have 10more hours. But the max is going to expire after the initial 10hours and thus removes the cached passphrase after 10hours.
One more problem I found is, session issue with gpg-agent. i.e., if I open a new session and try to decrypt, it doesn't happen and errors out that gpg-agent is not available for this session. I wrote some shell script and put it on bashrc so that it starts as soon as a new session is started
Why does GPGME / GnuPG use pinentry for password input?
GnuPG starting with 2.1 removed the most critical private key functionality into the gpg-agent
, to reduce the attack surface on the most intimate secrets -- the private keys.
Such a callback would not only expose the passphrase to the application you're writing (which probably means an even larger attack surface than GnuPG would be), but also GnuPG gets aware of the passphrase.
If you really need to control entry of the passphrase from your application, you have several choices.
Implementing Pinentry
The information flow would then be: your application calls GnuPG through GPGME, GnuPG requests some private key operation from gpg-agent
, which again asks your application for the passphrase. Be aware this will only work if you also started the gpg-agent
with appropriate pinentry configuration (you might have to start another instance, separate from the one already running on your system).
gpg-preset-passphrase
The most important use case of passing the passphrase directly is in headless daemons, where no humans waits for entering the passphrase. GnuPG also brings a small utility gpg-preset-passphrase
(on Debian and derivatives, it is installed as /usr/lib/gnupg2/gpg-preset-passphrase
), which also can be used to precache the passphrase (so it is not queried for a configurable time).
Pinentry Loopback
With GnuPG 2.1, another option was added: in gpg-agent
, you can allow pinentry loopback with the allow-loopback-pinentry
option. An additional parameter pinentry-mode
set to loopback
in GnuPG/GPGME should allow you to handle passphrase interaction using passphrase_cb
again.
But: consider this exposes the passphrase not both your application and GnuPG, and might prove to be a (possibly minor but existing and maybe unnecessary) security risk. Also, GnuPG 2.1 is not yet widely spread, which might be a problem if you do not control the environment.
Related Topics
What's Wrong with the Square and Rectangle Inheritance
Ruby on Rails - Activerecord::Relation Count Method Is Wrong
Detect Similar Sounding Words in Ruby
Cron Is Running in Home Directory Instead of File Directory
Ruby Optionparser Empty Switch "-" Behavior
Markdown to Plain Text in Ruby
How to Define a Simple Global Variable in an Rspec Test That Can Be Accesed by Helper Functions
Transliteration with Iconv in Ruby
Installing Ncurses for Ruby on Windows
Ruby How to Merge Two CSV Files with Slightly Different Headers
Rotate Bits Right Operation in Ruby
Ruby -- Capitalize First Letter of Every Sentence in a Paragraph
How to Call a Method That Is a Hash Value
How to Refactor Openssl Pkcs5_Keyivgen in Ruby
When to Use Keyword Arguments Aka Named Parameters in Ruby