ruby-gpgme icon indicating copy to clipboard operation
ruby-gpgme copied to clipboard

Unable to import key

Open apanzerj opened this issue 12 years ago • 24 comments

I'm unable to import a key file. I'm using ruby 1.9.3-p448

running:

require "gpgme"

begin
  key = GPGME::Key.import(File.open("private.key"), {:password => "redacted"})

rescue GPGME::Error => g
  puts g.inspect
  puts g.message
  puts g.code
  puts g.source
end

Output

#<GPGME::Error: GPGME::Error>
Inappropriate ioctl for device
32870
7

I have gpg, MacGPGTools and gpg-agent installed on my system. Am I missing something?

apanzerj avatar Jul 25 '13 17:07 apanzerj

I have the same error when I try:

ctx = GPGME::Ctx.new

Was these a solution for this error?

yoshie902a avatar Jan 16 '14 20:01 yoshie902a

Because ruby-gpgme is a wrapper for the C code, the errors are sometimes obtuse and not immediately helpful.

How was the key exported, as in, was it a GPGME export? Or is it from somewhere else? For example, OpenSSL keys can't be imported because the key formats are different.

dansketcher avatar Jan 17 '14 00:01 dansketcher

Update: I reinstalled pgpme with brew and after that the "Inappropriate ioctl for device" device error was gone. However, I ran into getting a empty string with, so I added decrypted.seek(0) per the other fix request. Is this still the most appropriate way to decrypt the file?

require 'rubygems' require 'gpgme'

encrypted_data = GPGME::Data.new(File.open("list.csv.pgp")) key = GPGME::Data.new(File.open("key.gpg"))

ctx = GPGME::Ctx.new :password=> thepassword' ctx.import_keys key

decrypted = ctx.decrypt encrypted_data decrypted.seek(0)

File.write('list.csv', decrypted.read)

yoshie902a avatar Jan 17 '14 01:01 yoshie902a

Yeah, using the GPGME::Ctx classes is fine, and if that works for you, then no problem.

I tend to use keys in the keychain, so rather than importing the keys I specify the recipient when performing crypto functions. Here's a roundtrip example, and note that I wrote this for a console, the conf.echo = false line is to stop IRB complaining when echoing binary data, and is not required for production code

conf.echo = false # Stop IRB echoing everything, which errors with binary data

class PassphraseCallback
  def initialize(passphrase)
    @passphrase = passphrase
  end

  def call(*args)
    fd = args.last
    io = IO.for_fd(fd, 'w')
    io.puts(@passphrase)
    io.flush
  end
end

# recipients can be found using $ gpg --list-keys --homedir ./keychain_location
# pub   2048R/A1B2C3D4 2014-01-17
# Use that line to substitute your own. 2048R is the key length and type (RSA in this case)

# If you want to substitute a non-default keychain into the engine do this:
# home_dir = Rails.root.join('keychain_location').to_s
# GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, '/usr/local/bin/gpg', home_dir)
# Note GPG executable location will change across platforms


crypto = GPGME::Crypto.new
options = {:recipients => 'A1B2C3D4'}

plaintext = GPGME::Data.new(File.open(Rails.root.join('Gemfile')))

data = crypto.encrypt plaintext, options

f = File.open(Rails.root.join('Gemfile.gpg'), 'wb')
bytes_written = f.write(data)
f.close

puts bytes_written




crypto = GPGME::Crypto.new
options = {:recipients => 'A1B2C3D4', :passphrase_callback => PassphraseCallback.new('my_passphrase')}

cipthertext = GPGME::Data.new(File.open(Rails.root.join('Gemfile.gpg')))

data = crypto.decrypt cipthertext, options
puts data

dansketcher avatar Jan 17 '14 01:01 dansketcher

Hello there,

Ran into this problem today. It looks like it's something to do with the bundling/installing process of the gpgme gem and how it connects to the system gpg install. If you have gpg/gpgme installed natively on your system, everything works, but if not, you'll hit this error.

If you're seeing this error:

  • uninstall the gem or remove it from your bundle,
  • install gpg/gpgme natively (i.e., brew install gpg)
  • rebundle/install the gpgme gem

At least, that's what worked for me.

jeffreytheobald avatar Mar 26 '14 05:03 jeffreytheobald

I know the issue is not related to heroku stack.. but just wondering if someone can help me.

The very same problem happens on new Heroku Cedar14 stack... whenever I try to do something like: GPGME::Key.import(File.open("private.key")) I get the "Inappropriate ioctl for device" error.

Same does not happen on Heroku Cedar.

Also had the same problem locally, but reinstalling gpg and the gem solved the issue.

Not sure what to do from here..

andrehjr avatar Jan 06 '15 12:01 andrehjr

+1 on having this issue with Cedar14

@andrehjr Were you able to solve it?

recurrence avatar Feb 10 '15 20:02 recurrence

@recurrence not yet.. we also tried different implementations, but new priorities came up..

One idea that one of the members of my team brought up was to use: https://github.com/ddollar/heroku-buildpack-apt and install gpgme from there instead...

If you try that and if it works, please let me know :)

andrehjr avatar Feb 11 '15 12:02 andrehjr

I tried a custom built gpgme and it also failed.

I ended up using shell commands :)

recurrence avatar Feb 11 '15 23:02 recurrence

I don't know much about Heroku, but if it is sort of chroot, perhaps it might be failing in GPGME's use of ttyname_r: http://article.gmane.org/gmane.comp.encryption.gpg.devel/10777 https://lists.archlinux.org/pipermail/arch-projects/2011-October/001953.html

ueno avatar Feb 12 '15 03:02 ueno

maybe the first step would be to isolate the problem between the gem and GPGME C library. since the library has a test case of --import, you can run it with:

$ gem install -i tmpdir gpgme -- --disable-clean
$ cd tmpdir/gems/gpgme-2.0.8/ext/gpgme/tmp/.../ports/gpgme/1.5.3/gpgme-1.5.3
$ make check

ueno avatar Feb 13 '15 03:02 ueno

Just tried make check on Heroku. Here's the output: https://gist.github.com/vovayartsev/a466aa82320b84f32b13

vovayartsev avatar Mar 28 '15 20:03 vovayartsev

I'm having this problem as well. I can confirm that it breaks in Cedar-14, but works perfectly fine in Cedar-10.

My current guess is that the version of GPGME installed by ruby-gpgme needs to be changed here. Perhaps the versions of libassuan or libgpg-error need to be changed, too; I don't actually know what they do. :)

Does this sound like an avenue worth exploring?

slepkin avatar Jun 02 '15 04:06 slepkin

A correction: Circle CI has GPGME installed on their VMs, so I'm no longer confident that Ubuntu 12.04 is compatible with this gem (without reinstalling gpgme). I edited the above to reflect this.

slepkin avatar Jun 02 '15 20:06 slepkin

2.0.10 gem might fix the issue, as it contains gpgme 1.6.0, which has a fix to the ttyname_r error handling: http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gpgme.git;a=commit;h=028a0ef3336c5180797fb247448683195376c007

ueno avatar Aug 27 '15 01:08 ueno

:+1: @ueno, upgrading to 2.0.10 on Heroku fixed the issue for me.

jorgevaldivia avatar Sep 09 '15 19:09 jorgevaldivia

Since this issue is still open ....

Is it intended that GPGME::Key.import() can be used to import public keys from a public key server? If so, are there undocumented configurations necessary?

lhagemann avatar Mar 02 '17 15:03 lhagemann

I barely remember, but ruby-gpgme doesn't seem to export the gpgme_op_import_keys C function which imports keys from a keyserver. Could you open a separate issue if you need that feature?

ueno avatar Mar 07 '17 15:03 ueno

@dansketcher Your comment was really helpful for my implementation and cleaner. I wished the GPGME github page provided clear example like that.

thanks and Great work

adet4ever avatar Nov 28 '18 20:11 adet4ever

I'd completely forgotten I'd written this :) Now integrated into the Readme! https://github.com/ueno/ruby-gpgme#round-trip-example-using-keychain-keys

dansketcher avatar Nov 29 '18 00:11 dansketcher

Trying to do some decryption today however, I keep getting the password GUI prompt to enter the passphrase. Is there any way to bypass the password prompt

adet4ever avatar Dec 05 '18 20:12 adet4ever

Use GPGME 1.4, or a dummy pinentry program per https://github.com/ueno/ruby-gpgme/pull/126 or see the note on the pinentry loopback in the same PR

dansketcher avatar Dec 05 '18 22:12 dansketcher

@adet4ever Setting the pinentry_mode to the following resolved the password prompt from showing up anytime I wanted to perform a crypt operation.

crypto = GPGME::Crypto.new(pinentry_mode: GPGME::PINENTRY_MODE_LOOPBACK)

joshuamcginnis avatar Dec 05 '18 23:12 joshuamcginnis

Leaving a comment here for future readers around the Inappropriate ioctl for device issue. For me it was source 5, code 32870, following closely the example. Using the above line in combination with the example PassphraseCallback made the issue go away. For clarity :

crypto = GPGME::Crypto.new(pinentry_mode: GPGME::PINENTRY_MODE_LOOPBACK)

dvkch avatar Aug 25 '20 16:08 dvkch