diff --git a/NEWS b/NEWS index 162212cf..92a96732 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ Noteworthy changes in version 1.10.1 (unreleased) gpgme_op_encrypt_sign_ext_start NEW. GPGME_ENCRYPT_WANT_ADDRESS NEW. gpgme_import_result_t EXTENDED: New field 'skipped_v3_keys'. + gpgme_decrypt_result_t EXTENDED: New field 'symkey_algo'. cpp: Key::locate NEW. cpp: Data::toString NEW. cpp: ImportResult::numV3KeysSkipped NEW. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index f5efec67..5a09ea0a 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -5399,6 +5399,13 @@ You must not try to access this member of the struct unless or @code{gpgme_get_ctx_flag (ctx, "export-session-key")} returns true (non-empty string). +@item char *symkey_algo +@since{1.11.0} + +A string with the symmetric encryption algorithm and mode using the +format ".". Note that old non-MDC encryption mode of +OpenPGP is given as "PGPCFB". + @end table @end deftp diff --git a/src/conversion.c b/src/conversion.c index 5b84f672..4bfd3d3e 100644 --- a/src/conversion.c +++ b/src/conversion.c @@ -575,3 +575,49 @@ _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol) return algo; } + + +/* Return a string with a cipher algorithm. */ +const char * +_gpgme_cipher_algo_name (int algo, gpgme_protocol_t protocol) +{ + if (protocol == GPGME_PROTOCOL_OPENPGP) + { + /* The algo is given according to OpenPGP specs. */ + switch (algo) + { + case 1: return "IDEA"; + case 2: return "3DES"; + case 3: return "CAST5"; + case 4: return "BLOWFISH"; + case 7: return "AES"; + case 8: return "AES192"; + case 9: return "AES256"; + case 10: return "TWOFISH"; + case 11: return "CAMELLIA128"; + case 12: return "CAMELLIA192"; + case 13: return "CAMELLIA256"; + } + } + + return "Unknown"; +} + + +/* Return a string with the cipher mode. */ +const char * +_gpgme_cipher_mode_name (int algo, gpgme_protocol_t protocol) +{ + if (protocol == GPGME_PROTOCOL_OPENPGP) + { + /* The algo is given according to OpenPGP specs. */ + switch (algo) + { + case 0: return "CFB"; + case 1: return "EAX"; + case 2: return "OCB"; + } + } + + return "Unknown"; +} diff --git a/src/decrypt.c b/src/decrypt.c index 8c2cd4d7..e4de6e41 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -69,14 +69,10 @@ release_op_data (void *hook) op_data_t opd = (op_data_t) hook; gpgme_recipient_t recipient = opd->result.recipients; - if (opd->result.unsupported_algorithm) - free (opd->result.unsupported_algorithm); - - if (opd->result.file_name) - free (opd->result.file_name); - - if (opd->result.session_key) - free (opd->result.session_key); + free (opd->result.unsupported_algorithm); + free (opd->result.file_name); + free (opd->result.session_key); + free (opd->result.symkey_algo); while (recipient) { @@ -104,6 +100,17 @@ gpgme_op_decrypt_result (gpgme_ctx_t ctx) return NULL; } + /* Make sure that SYMKEY_ALGO has a value. */ + if (!opd->result.symkey_algo) + { + opd->result.symkey_algo = strdup ("?.?"); + if (!opd->result.symkey_algo) + { + TRACE_SUC0 ("result=(null)"); + return NULL; + } + } + if (_gpgme_debug_trace ()) { gpgme_recipient_t rcp; @@ -263,6 +270,49 @@ parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol) } +/* Parse the ARGS of a + * DECRYPTION_INFO [] + * status. Returns 0 on success and updates the OPD. + */ +static gpgme_error_t +parse_decryption_info (char *args, op_data_t opd, gpgme_protocol_t protocol) +{ + char *field[3]; + int nfields; + char *args2; + int mdc, mode; + const char *algostr, *modestr; + + if (!args) + return trace_gpg_error (GPG_ERR_INV_ENGINE); + + args2 = strdup (args); /* Split modifies the input string. */ + nfields = _gpgme_split_fields (args2, field, DIM (field)); + if (nfields < 2) + { + free (args2); + return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required arg missing. */ + } + + mdc = atoi (field[0]); + algostr = _gpgme_cipher_algo_name (atoi (field[1]), protocol); + mode = nfields < 3? 0 : atoi (field[2]); + modestr = _gpgme_cipher_mode_name (mode, protocol); + + free (args2); + + free (opd->result.symkey_algo); + if (!mode && mdc != 2) + opd->result.symkey_algo = _gpgme_strconcat (algostr, ".PGPCFB", NULL); + else + opd->result.symkey_algo = _gpgme_strconcat (algostr, ".", modestr, NULL); + if (!opd->result.symkey_algo) + return gpg_error_from_syserror (); + + return 0; +} + + gpgme_error_t _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args) @@ -303,7 +353,9 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, break; case GPGME_STATUS_DECRYPTION_INFO: - /* Fixme: Provide a way to return the used symmetric algorithm. */ + err = parse_decryption_info (args, opd, ctx->protocol); + if (err) + return err; break; case GPGME_STATUS_DECRYPTION_OKAY: diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 860e0931..202859c3 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1368,6 +1368,10 @@ struct _gpgme_op_decrypt_result /* A textual representation of the session key used to decrypt the * message, if available */ char *session_key; + + /* A string with the symmetric encryption algorithm and mode using + * the format ".". */ + char *symkey_algo; }; typedef struct _gpgme_op_decrypt_result *gpgme_decrypt_result_t; diff --git a/src/util.h b/src/util.h index b4043ed1..da929eb4 100644 --- a/src/util.h +++ b/src/util.h @@ -165,10 +165,11 @@ time_t _gpgme_parse_timestamp (const char *timestamp, char **endp); * on error or missing timestamp. */ unsigned long _gpgme_parse_timestamp_ul (const char *timestamp); -gpgme_error_t _gpgme_map_gnupg_error (char *err); - int _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol); +const char *_gpgme_cipher_algo_name (int algo, gpgme_protocol_t protocol); +const char *_gpgme_cipher_mode_name (int algo, gpgme_protocol_t protocol); + /*-- b64dec.c --*/ diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index a2e82a0e..8eb6ba09 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -59,6 +59,7 @@ print_result (gpgme_decrypt_result_t result) nonnull(result->unsupported_algorithm)); if (result->session_key) printf ("Session key: %s\n", result->session_key); + printf ("Symmetric algorithm: %s\n", result->symkey_algo); for (recp = result->recipients; recp && recp->next; recp = recp->next) {