gpgme не может зашифровать на 64-битном Debian

Я столкнулся с проблемой, которая вызывает у меня проблемы с трассировкой gpgme. Я воспроизвел его с помощью простой тестовой программы (начиная с другого простого примера, который я нашел), которую я вставил ниже. Это работает в 32-битной системе на основе Debian, но не работает в 64-битной. В частности, в 64-битном случае я могу успешно читать и дешифровать (не показано в примере), но я получаю довольно загадочную ошибку в шифровании:

$ ./test2 C37DBF71 Ciao!
version=1.2.0
Protocol name: OpenPGP
file=/usr/bin/gpg, home=(null)
Error in encrypting data. Error 1: General error (Unspecified source)

Версия libgpgme также показана выше.

Это вывод unameПросто чтобы показать вам, что я работаю в 64-битной системе:

$ uname -a
Linux spagan-laptop 3.2.0-39-generic #62-Ubuntu SMP Thu Feb 28 00:28:53 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

Да, первое, что я сделал, это попытался убедиться, что я определяю _FILE_OFFSET_BITS=64; также я проверил, что off_t фактически имеет размер 8. Вот как я его компилирую:

gcc -m64 -D_FILE_OFFSET_BITS=64 -g test2.c -lgpgme -L/usr/lib/x86_64-linux-gnu -lgpg-error -o test2

и, наконец, вот тестовая программа:

#include <gpgme.h>   /* gpgme             */
#include <stdio.h>   /* printf            */
#include <unistd.h>  /* write             */
#include <errno.h>   /* errno             */
#include <locale.h>  /* locale support    */
#include <string.h>  /* string support    */
#include <stdlib.h>  /* memory management */

#define SIZE 1024

int main(int argc, char **argv)
{
  if (argc < 2) {
    printf("ERROR. Usage: %s key message\n", argv[0]);
    return -1;
  }

  char *m_key = argv[1];
  char *pSource = argv[2];
  char *pDest = malloc(65536);

  char *p;
  char buf[SIZE];
  size_t read_bytes;
  int tmp;
  gpgme_ctx_t ceofcontext;
  gpgme_error_t err;
  gpgme_data_t data;

  gpgme_engine_info_t enginfo;

  /* The function `gpgme_check_version' must be called before any other
   * function in the library, because it initializes the thread support
   * subsystem in GPGME. (from the info page) */
  setlocale (LC_ALL, "");
  p = (char *) gpgme_check_version(NULL);
  printf("version=%s\n",p);
  /* set locale, because tests do also */
  gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));

  /* check for OpenPGP support */
  err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
  if(err != GPG_ERR_NO_ERROR) return 1;

  p = (char *) gpgme_get_protocol_name(GPGME_PROTOCOL_OpenPGP);
  printf("Protocol name: %s\n",p);

  /* get engine information */
  err = gpgme_get_engine_info(&enginfo);
  if(err != GPG_ERR_NO_ERROR) return 2;
  printf("file=%s, home=%s\n",enginfo->file_name,enginfo->home_dir);

  /* create our own context */
  err = gpgme_new(&ceofcontext);
  if(err != GPG_ERR_NO_ERROR) return 3;

  /* set protocol to use in our context */
  err = gpgme_set_protocol(ceofcontext,GPGME_PROTOCOL_OpenPGP);
  if(err != GPG_ERR_NO_ERROR) return 4;

  /* set engine info in our context; I changed it for ceof like this:

   err = gpgme_ctx_set_engine_info (ceofcontext, GPGME_PROTOCOL_OpenPGP,
               "/usr/bin/gpg","/home/user/nico/.ceof/gpg/");

           but I'll use standard values for this example: */

  err = gpgme_ctx_set_engine_info (ceofcontext, GPGME_PROTOCOL_OpenPGP,
                               enginfo->file_name,enginfo->home_dir);
  if(err != GPG_ERR_NO_ERROR) return 5;

  /* do ascii armor data, so output is readable in console */
  gpgme_set_armor(ceofcontext, 1);

  gpgme_data_t source;
  gpgme_data_t dest;

  //get key to encrypt, get the first key
  gpgme_key_t key[2];
  err = gpgme_op_keylist_start(ceofcontext, m_key, 0);
  err = gpgme_op_keylist_next (ceofcontext, key);
  if (err) {
    printf("Key not found in current key-ring: %s\n", m_key);
    return 1;
  }
  key[1] = 0; //set to NULL the second entry

  //point to source buffer
  err = gpgme_data_new_from_mem(&source, pSource, strlen(pSource), 0);  
  if (err != GPG_ERR_NO_ERROR) {
    printf("Error in reading data to encrypt. Error %d: %s (%s)\n",
       gpgme_err_code(err), gpgme_strerror(err), gpgme_strsource(err));
    return 2;
  }

  //create dest buffer
  err = gpgme_data_new(&dest);
  if (err != GPG_ERR_NO_ERROR) {
    printf("Error in creating output data buffer to encrypt. Error %d: %s (%s)\n",
       gpgme_err_code(err), gpgme_strerror(err), gpgme_strsource(err));
    return 3;
  }

  //encrypt text
  gpgme_encrypt_flags_t flags;
  flags = GPGME_ENCRYPT_NO_ENCRYPT_TO; //only specified recipient, no defaults please
  err = gpgme_op_encrypt(ceofcontext, key, flags, source, dest);
  if (err != GPG_ERR_NO_ERROR) {
    printf("Error in encrypting data. Error %d: %s (%s)\n",
       gpgme_err_code(err), gpgme_strerror(err), gpgme_strsource(err));
    return 4;    
  }

  //retrieve result
  printf("Result: \n%s\n", pDest);

  //release key and buffers
  gpgme_key_release(key[0]);  
  gpgme_data_release(dest);
  gpgme_data_release(source);
  free(pDest);

  /* free context */
  gpgme_release(ceofcontext);

  return 0;
}

Большое спасибо за любую помощь, которую вы могли бы дать мне! Я еще не нашел ничего полезного, чтобы помочь мне отладить это..

1 ответ

В приведенном примере значение pDest никогда не устанавливается.

Для того, чтобы получить значение gpgme_data_t объект destиспользовать gpgme_data_release_and_get_mem,

пример:

#include <gpgme.h>   /* gpgme             */
#include <stdio.h>   /* printf            */
#include <unistd.h>  /* write             */
#include <errno.h>   /* errno             */
#include <locale.h>  /* locale support    */
#include <string.h>  /* string support    */
#include <stdlib.h>  /* memory management */

#define SIZE 1024

int main(int argc, char **argv)
{
  if (argc < 2) {
    printf("ERROR. Usage: %s key message\n", argv[0]);
    return -1;
  }

  char *m_key = argv[1];
  char *pSource = argv[2];

  char *p;
  size_t read_bytes;
  gpgme_ctx_t ceofcontext;
  gpgme_error_t err;

  gpgme_engine_info_t enginfo;

  /* The function `gpgme_check_version' must be called before any other
   * function in the library, because it initializes the thread support
   * subsystem in GPGME. (from the info page) */
  setlocale (LC_ALL, "");
  p = (char *) gpgme_check_version(NULL);
  printf("version=%s\n",p);
  /* set locale, because tests do also */
  gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));

  /* check for OpenPGP support */
  err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
  if(err != GPG_ERR_NO_ERROR) return 1;

  p = (char *) gpgme_get_protocol_name(GPGME_PROTOCOL_OpenPGP);
  printf("Protocol name: %s\n",p);

  /* get engine information */
  err = gpgme_get_engine_info(&enginfo);
  if(err != GPG_ERR_NO_ERROR) return 2;
  printf("file=%s, home=%s\n",enginfo->file_name,enginfo->home_dir);

  /* create our own context */
  err = gpgme_new(&ceofcontext);
  if(err != GPG_ERR_NO_ERROR) return 3;

  /* set protocol to use in our context */
  err = gpgme_set_protocol(ceofcontext,GPGME_PROTOCOL_OpenPGP);
  if(err != GPG_ERR_NO_ERROR) return 4;

  /* set engine info in our context; I changed it for ceof like this:

   err = gpgme_ctx_set_engine_info (ceofcontext, GPGME_PROTOCOL_OpenPGP,
               "/usr/bin/gpg","/home/user/nico/.ceof/gpg/");

           but I'll use standard values for this example: */

  err = gpgme_ctx_set_engine_info (ceofcontext, GPGME_PROTOCOL_OpenPGP,
                               enginfo->file_name,enginfo->home_dir);
  if(err != GPG_ERR_NO_ERROR) return 5;

  /* do ascii armor data, so output is readable in console */
  gpgme_set_armor(ceofcontext, 1);

  gpgme_data_t source;
  gpgme_data_t dest;

  //get key to encrypt, get the first key
  gpgme_key_t key[2];
  err = gpgme_op_keylist_start(ceofcontext, m_key, 0);
  err = gpgme_op_keylist_next (ceofcontext, key);
  if (err) {
    printf("Key not found in current key-ring: %s\n", m_key);
    return 1;
  }
  key[1] = 0; //set to NULL the second entry

  //point to source buffer
  err = gpgme_data_new_from_mem(&source, pSource, strlen(pSource), 0);  
  if (err != GPG_ERR_NO_ERROR) {
    printf("Error in reading data to encrypt. Error %d: %s (%s)\n",
       gpgme_err_code(err), gpgme_strerror(err), gpgme_strsource(err));
    return 2;
  }

  //create dest buffer
  err = gpgme_data_new(&dest);
  if (err != GPG_ERR_NO_ERROR) {
    printf("Error in creating output data buffer to encrypt. Error %d: %s (%s)\n",
       gpgme_err_code(err), gpgme_strerror(err), gpgme_strsource(err));
    return 3;
  }

  //encrypt text
  gpgme_encrypt_flags_t flags;
  flags = GPGME_ENCRYPT_NO_ENCRYPT_TO; //only specified recipient, no defaults please
  err = gpgme_op_encrypt(ceofcontext, key, flags, source, dest);
  if (err != GPG_ERR_NO_ERROR) {
    printf("Error in encrypting data. Error %d: %s (%s)\n",
       gpgme_err_code(err), gpgme_strerror(err), gpgme_strsource(err));
    return 4;    
  }

  p = gpgme_data_release_and_get_mem(dest, &read_bytes);

  p[read_bytes] = 0;

  //retrieve result
  printf("Result: \n%s\n", p);

  //release key and buffers
  gpgme_key_release(key[0]);
  gpgme_data_release(source);

  /* free context */
  gpgme_release(ceofcontext);

  return 0;
}

Составлено с gcc -Wall -m64 -D_FILE_OFFSET_BITS=64 -g test2.c -lgpgme -lgpg-error -o test2

Результаты в:

version=1.4.2
Protocol name: OpenPGP
file=/usr/bin/gpg, home=(null)
Result: 
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1

hQIMA33UcjHVsYaXARAAh1txbI4bSsterGLf2d1AhrjQaugDfqaqSX32itxPKv1K
<SNIP>
EHlJTb0rVRvnTGjp5yLMy/hlw4hEtTh7HA==
=LRyw
-----END PGP MESSAGE-----
Другие вопросы по тегам