gpg-rs / gpgme

GPGme bindings for Rust

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

gpgme::encrypt produces "Bad file descriptor" error

cyphar opened this issue · comments

If you try to encrypt some data with gpgme::encrypt I always seem to get the following error:

thread 'main' panicked at 'encrypt: Error { source: Some("GPGME"), code: 32779, description: "Bad file descriptor" }', src/libcore/result.rs:906:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Here's a minimal snippet of Rust code which will reproduce this.

extern crate gpgme;

fn main() {
    // Get a gpgme context.
    let mut gpg_context = gpgme::Context::from_protocol(gpgme::Protocol::OpenPgp).expect("new context");
    gpg_context.set_armor(true);
    //gpg_context.set_offline(true);

    // Find the keyids that we are looking for.
    let recipient_key = gpg_context.find_key("cyphar@cyphar.com").expect("finding key");

    // Encrypt some text. in_data is filled from somewhere else.
    let mut in_data = String::from("Hello, world!").into_bytes();
    let (mut plain, mut cipher) = (Vec::new(), Vec::new());

    plain.append(&mut in_data);
    //std::mem::drop(in_data);

    // Encrypt the body.
    gpg_context.encrypt_with_flags(Some(&recipient_key), &mut plain, &mut cipher, gpgme::EncryptFlags::empty()).expect("encrypt");
    println!("ciphertext: {}", String::from_utf8(cipher).unwrap());
}

I've double checked that the equivalent Assam commands operate correctly:

% echo "Hello, world" > in ; gpgme-tool 3<in 4>out
OK GPGME-Tool 1.9.0 ready
ARMOR true
OK
RECIPIENT cyphar@cyphar.com
S RECIPIENT 6FA1B3E3F9A18CDCBE6A2CF54A7BE7BF70DE9B9F
OK
OUTPUT FD=4
OK
INPUT FD=3
OK
ENCRYPT
S PROGRESS -&11 0x3f 0 0
S PROGRESS -&11 0x3f 13 0
OK
% cat out
-----BEGIN PGP MESSAGE-----

hQIMA+hUAzv9on82ARAApJZIinIMeOQAtbhDIQzSe+UqmU68atpQuR1TzZQfSjbl
kVAoHz0BuDxRWVmlJ6180QArXQWynm/3OuJtS96tM6Mt5xsf5AHzr7vlAL+XikJG
YsZEFhaHZLit3cpI2gT3do/OG9nf/Ill+zEoeOVS6KAaR4FNLKBYzEg85oAWW7Ds
lL45jgLShMo8vo6gNF778rXk32ZNgwyeRJvQ1sRZLSVVLmiaAoBbEFKgphJmq+lL
vwuxh7zL1cE3eckcWEqyozQRU7FGi/j4LmEv3vHJIIDgCLylvneUX7hsaQgttFT/
O5Ak959gocmghd3yhjjRV9K55I70F5XFEeC0wNa1ri4oD+l8wQie4IZd6eUazGtH
lanlznnw7Ft9R7+Qi6T10HYm6vONS1dDy38zOP6ESujsKEqDv1AgO/BouBGu5oaL
59kfSgsWnbvTMBgWNmgS9MWA9rOxOET5YsWHjBzki51cgc31KT7Q72XHPtBuIC+p
iPyOM2U1xHO54lvKOAGH9GIpnencH/dOwhcrS0Hie+Jv81+U+a3UGgMk51hdsAWq
GV8KMXWMqlE2auYoSEn2UayTyYiZuJfMe6Sj82WxygWBdMIdGjbWpDbIL7ogzSa3
TJugkhWEpnvZPTAH3kbZUxTCejVv/1hOtY8/4385z+bc/YJ/PNC9lwFHN1VLzLfS
SAF+u4VIgQKDEhkPnRLsh6vsHfBQlhCvWFmkIuoNM962YW2c80jCJlYo82sYh9Wr
ztXfpn/3nZvpbPjUAWOxaWBYhF+BbNVQbg==
=VVre
-----END PGP MESSAGE-----

And here is the gpgme-error information about the error code:

% gpg-error 32779
32779 = (0, 32779) = (GPG_ERR_SOURCE_UNKNOWN, GPG_ERR_EBADF) = (Unspecified source, Bad file descriptor)

This is caused by passing in a mutable reference to plain. The mutable reference is turned into a write-only Data wrapper by IntoData while gpgme expects a readable object. This can be fixed by passing an immutable reference to plain or by passing plain directly:
gpg_context.encrypt(Some(&recipient_key), &plain, &mut cipher).expect("encrypt"); or
gpg_context.encrypt(Some(&recipient_key), plain, &mut cipher).expect("encrypt");

Okay, I believe this documentation example should be updated since that's what I based my code off of. Would you like a PR to update that?