| /* cipher.c - cipher dispatcher |
| * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 |
| * 2005, 2007, 2008, 2010 Free Software Foundation, Inc. |
| * |
| * This file is part of Libgcrypt. |
| * |
| * Libgcrypt is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU Lesser general Public License as |
| * published by the Free Software Foundation; either version 2.1 of |
| * the License, or (at your option) any later version. |
| * |
| * Libgcrypt is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this program; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <config.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| #include "g10lib.h" |
| #include "cipher.h" |
| #include "ath.h" |
| |
| #define MAX_BLOCKSIZE 16 |
| #define TABLE_SIZE 14 |
| #define CTX_MAGIC_NORMAL 0x24091964 |
| #define CTX_MAGIC_SECURE 0x46919042 |
| |
| #undef NEED_16BYTE_ALIGNED_CONTEXT |
| #if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__) |
| #define NEED_16BYTE_ALIGNED_CONTEXT 1 |
| #endif |
| |
| /* A dummy extraspec so that we do not need to tests the extraspec |
| field from the module specification against NULL and instead |
| directly test the respective fields of extraspecs. */ |
| static cipher_extra_spec_t dummy_extra_spec; |
| |
| /* This is the list of the default ciphers, which are included in |
| libgcrypt. */ |
| static struct cipher_table_entry |
| { |
| gcry_cipher_spec_t *cipher; |
| cipher_extra_spec_t *extraspec; |
| unsigned int algorithm; |
| int fips_allowed; |
| } cipher_table[] = |
| { |
| #if USE_BLOWFISH |
| { &_gcry_cipher_spec_blowfish, |
| &dummy_extra_spec, GCRY_CIPHER_BLOWFISH }, |
| #endif |
| #if USE_DES |
| { &_gcry_cipher_spec_des, |
| &dummy_extra_spec, GCRY_CIPHER_DES }, |
| { &_gcry_cipher_spec_tripledes, |
| &_gcry_cipher_extraspec_tripledes, GCRY_CIPHER_3DES, 1 }, |
| #endif |
| #if USE_ARCFOUR |
| { &_gcry_cipher_spec_arcfour, |
| &dummy_extra_spec, GCRY_CIPHER_ARCFOUR }, |
| #endif |
| #if USE_CAST5 |
| { &_gcry_cipher_spec_cast5, |
| &dummy_extra_spec, GCRY_CIPHER_CAST5 }, |
| #endif |
| #if USE_AES |
| { &_gcry_cipher_spec_aes, |
| &_gcry_cipher_extraspec_aes, GCRY_CIPHER_AES, 1 }, |
| { &_gcry_cipher_spec_aes192, |
| &_gcry_cipher_extraspec_aes192, GCRY_CIPHER_AES192, 1 }, |
| { &_gcry_cipher_spec_aes256, |
| &_gcry_cipher_extraspec_aes256, GCRY_CIPHER_AES256, 1 }, |
| #endif |
| #if USE_TWOFISH |
| { &_gcry_cipher_spec_twofish, |
| &dummy_extra_spec, GCRY_CIPHER_TWOFISH }, |
| { &_gcry_cipher_spec_twofish128, |
| &dummy_extra_spec, GCRY_CIPHER_TWOFISH128 }, |
| #endif |
| #if USE_SERPENT |
| { &_gcry_cipher_spec_serpent128, |
| &dummy_extra_spec, GCRY_CIPHER_SERPENT128 }, |
| { &_gcry_cipher_spec_serpent192, |
| &dummy_extra_spec, GCRY_CIPHER_SERPENT192 }, |
| { &_gcry_cipher_spec_serpent256, |
| &dummy_extra_spec, GCRY_CIPHER_SERPENT256 }, |
| #endif |
| #if USE_RFC2268 |
| { &_gcry_cipher_spec_rfc2268_40, |
| &dummy_extra_spec, GCRY_CIPHER_RFC2268_40 }, |
| #endif |
| #if USE_SEED |
| { &_gcry_cipher_spec_seed, |
| &dummy_extra_spec, GCRY_CIPHER_SEED }, |
| #endif |
| #if USE_CAMELLIA |
| { &_gcry_cipher_spec_camellia128, |
| &dummy_extra_spec, GCRY_CIPHER_CAMELLIA128 }, |
| { &_gcry_cipher_spec_camellia192, |
| &dummy_extra_spec, GCRY_CIPHER_CAMELLIA192 }, |
| { &_gcry_cipher_spec_camellia256, |
| &dummy_extra_spec, GCRY_CIPHER_CAMELLIA256 }, |
| #endif |
| { NULL } |
| }; |
| |
| /* List of registered ciphers. */ |
| static gcry_module_t ciphers_registered; |
| |
| /* This is the lock protecting CIPHERS_REGISTERED. */ |
| static ath_mutex_t ciphers_registered_lock = ATH_MUTEX_INITIALIZER; |
| |
| /* Flag to check wether the default ciphers have already been |
| registered. */ |
| static int default_ciphers_registered; |
| |
| /* Convenient macro for registering the default ciphers. */ |
| #define REGISTER_DEFAULT_CIPHERS \ |
| do \ |
| { \ |
| ath_mutex_lock (&ciphers_registered_lock); \ |
| if (! default_ciphers_registered) \ |
| { \ |
| cipher_register_default (); \ |
| default_ciphers_registered = 1; \ |
| } \ |
| ath_mutex_unlock (&ciphers_registered_lock); \ |
| } \ |
| while (0) |
| |
| |
| /* A VIA processor with the Padlock engine requires an alignment of |
| most data on a 16 byte boundary. Because we trick out the compiler |
| while allocating the context, the align attribute as used in |
| rijndael.c does not work on its own. Thus we need to make sure |
| that the entire context structure is a aligned on that boundary. |
| We achieve this by defining a new type and use that instead of our |
| usual alignment type. */ |
| typedef union |
| { |
| PROPERLY_ALIGNED_TYPE foo; |
| #ifdef NEED_16BYTE_ALIGNED_CONTEXT |
| char bar[16] __attribute__ ((aligned (16))); |
| #endif |
| char c[1]; |
| } cipher_context_alignment_t; |
| |
| |
| /* The handle structure. */ |
| struct gcry_cipher_handle |
| { |
| int magic; |
| size_t actual_handle_size; /* Allocated size of this handle. */ |
| size_t handle_offset; /* Offset to the malloced block. */ |
| gcry_cipher_spec_t *cipher; |
| cipher_extra_spec_t *extraspec; |
| gcry_module_t module; |
| |
| /* The algorithm id. This is a hack required because the module |
| interface does not easily allow to retrieve this value. */ |
| int algo; |
| |
| /* A structure with function pointers for bulk operations. Due to |
| limitations of the module system (we don't want to change the |
| API) we need to keep these function pointers here. The cipher |
| open function intializes them and the actual encryption routines |
| use them if they are not NULL. */ |
| struct { |
| void (*cfb_enc)(void *context, unsigned char *iv, |
| void *outbuf_arg, const void *inbuf_arg, |
| unsigned int nblocks); |
| void (*cfb_dec)(void *context, unsigned char *iv, |
| void *outbuf_arg, const void *inbuf_arg, |
| unsigned int nblocks); |
| void (*cbc_enc)(void *context, unsigned char *iv, |
| void *outbuf_arg, const void *inbuf_arg, |
| unsigned int nblocks, int cbc_mac); |
| void (*cbc_dec)(void *context, unsigned char *iv, |
| void *outbuf_arg, const void *inbuf_arg, |
| unsigned int nblocks); |
| } bulk; |
| |
| |
| int mode; |
| unsigned int flags; |
| |
| struct { |
| unsigned int key:1; /* Set to 1 if a key has been set. */ |
| unsigned int iv:1; /* Set to 1 if a IV has been set. */ |
| } marks; |
| |
| /* The initialization vector. To help code optimization we make |
| sure that it is aligned on an unsigned long and u32 boundary. */ |
| union { |
| unsigned long dummy_iv; |
| u32 dummy_u32_iv; |
| unsigned char iv[MAX_BLOCKSIZE]; |
| } u_iv; |
| |
| unsigned char lastiv[MAX_BLOCKSIZE]; |
| int unused; /* Number of unused bytes in the IV. */ |
| |
| unsigned char ctr[MAX_BLOCKSIZE]; /* For Counter (CTR) mode. */ |
| |
| |
| /* What follows are two contexts of the cipher in use. The first |
| one needs to be aligned well enough for the cipher operation |
| whereas the second one is a copy created by cipher_setkey and |
| used by cipher_reset. That second copy has no need for proper |
| aligment because it is only accessed by memcpy. */ |
| cipher_context_alignment_t context; |
| }; |
| |
| |
| |
| /* These dummy functions are used in case a cipher implementation |
| refuses to provide it's own functions. */ |
| |
| static gcry_err_code_t |
| dummy_setkey (void *c, const unsigned char *key, unsigned int keylen) |
| { |
| (void)c; |
| (void)key; |
| (void)keylen; |
| return GPG_ERR_NO_ERROR; |
| } |
| |
| static void |
| dummy_encrypt_block (void *c, |
| unsigned char *outbuf, const unsigned char *inbuf) |
| { |
| (void)c; |
| (void)outbuf; |
| (void)inbuf; |
| BUG(); |
| } |
| |
| static void |
| dummy_decrypt_block (void *c, |
| unsigned char *outbuf, const unsigned char *inbuf) |
| { |
| (void)c; |
| (void)outbuf; |
| (void)inbuf; |
| BUG(); |
| } |
| |
| static void |
| dummy_encrypt_stream (void *c, |
| unsigned char *outbuf, const unsigned char *inbuf, |
| unsigned int n) |
| { |
| (void)c; |
| (void)outbuf; |
| (void)inbuf; |
| (void)n; |
| BUG(); |
| } |
| |
| static void |
| dummy_decrypt_stream (void *c, |
| unsigned char *outbuf, const unsigned char *inbuf, |
| unsigned int n) |
| { |
| (void)c; |
| (void)outbuf; |
| (void)inbuf; |
| (void)n; |
| BUG(); |
| } |
| |
| |
| /* Internal function. Register all the ciphers included in |
| CIPHER_TABLE. Note, that this function gets only used by the macro |
| REGISTER_DEFAULT_CIPHERS which protects it using a mutex. */ |
| static void |
| cipher_register_default (void) |
| { |
| gcry_err_code_t err = GPG_ERR_NO_ERROR; |
| int i; |
| |
| for (i = 0; !err && cipher_table[i].cipher; i++) |
| { |
| if (! cipher_table[i].cipher->setkey) |
| cipher_table[i].cipher->setkey = dummy_setkey; |
| if (! cipher_table[i].cipher->encrypt) |
| cipher_table[i].cipher->encrypt = dummy_encrypt_block; |
| if (! cipher_table[i].cipher->decrypt) |
| cipher_table[i].cipher->decrypt = dummy_decrypt_block; |
| if (! cipher_table[i].cipher->stencrypt) |
| cipher_table[i].cipher->stencrypt = dummy_encrypt_stream; |
| if (! cipher_table[i].cipher->stdecrypt) |
| cipher_table[i].cipher->stdecrypt = dummy_decrypt_stream; |
| |
| if ( fips_mode () && !cipher_table[i].fips_allowed ) |
| continue; |
| |
| err = _gcry_module_add (&ciphers_registered, |
| cipher_table[i].algorithm, |
| (void *) cipher_table[i].cipher, |
| (void *) cipher_table[i].extraspec, |
| NULL); |
| } |
| |
| if (err) |
| BUG (); |
| } |
| |
| /* Internal callback function. Used via _gcry_module_lookup. */ |
| static int |
| gcry_cipher_lookup_func_name (void *spec, void *data) |
| { |
| gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; |
| char *name = (char *) data; |
| const char **aliases = cipher->aliases; |
| int i, ret = ! stricmp (name, cipher->name); |
| |
| if (aliases) |
| for (i = 0; aliases[i] && (! ret); i++) |
| ret = ! stricmp (name, aliases[i]); |
| |
| return ret; |
| } |
| |
| /* Internal callback function. Used via _gcry_module_lookup. */ |
| static int |
| gcry_cipher_lookup_func_oid (void *spec, void *data) |
| { |
| gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; |
| char *oid = (char *) data; |
| gcry_cipher_oid_spec_t *oid_specs = cipher->oids; |
| int ret = 0, i; |
| |
| if (oid_specs) |
| for (i = 0; oid_specs[i].oid && (! ret); i++) |
| if (! stricmp (oid, oid_specs[i].oid)) |
| ret = 1; |
| |
| return ret; |
| } |
| |
| /* Internal function. Lookup a cipher entry by it's name. */ |
| static gcry_module_t |
| gcry_cipher_lookup_name (const char *name) |
| { |
| gcry_module_t cipher; |
| |
| cipher = _gcry_module_lookup (ciphers_registered, (void *) name, |
| gcry_cipher_lookup_func_name); |
| |
| return cipher; |
| } |
| |
| /* Internal function. Lookup a cipher entry by it's oid. */ |
| static gcry_module_t |
| gcry_cipher_lookup_oid (const char *oid) |
| { |
| gcry_module_t cipher; |
| |
| cipher = _gcry_module_lookup (ciphers_registered, (void *) oid, |
| gcry_cipher_lookup_func_oid); |
| |
| return cipher; |
| } |
| |
| /* Register a new cipher module whose specification can be found in |
| CIPHER. On success, a new algorithm ID is stored in ALGORITHM_ID |
| and a pointer representhing this module is stored in MODULE. */ |
| gcry_error_t |
| _gcry_cipher_register (gcry_cipher_spec_t *cipher, |
| cipher_extra_spec_t *extraspec, |
| int *algorithm_id, |
| gcry_module_t *module) |
| { |
| gcry_err_code_t err = 0; |
| gcry_module_t mod; |
| |
| /* We do not support module loading in fips mode. */ |
| if (fips_mode ()) |
| return gpg_error (GPG_ERR_NOT_SUPPORTED); |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| err = _gcry_module_add (&ciphers_registered, 0, |
| (void *)cipher, |
| (void *)(extraspec? extraspec : &dummy_extra_spec), |
| &mod); |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| if (! err) |
| { |
| *module = mod; |
| *algorithm_id = mod->mod_id; |
| } |
| |
| return gcry_error (err); |
| } |
| |
| /* Unregister the cipher identified by MODULE, which must have been |
| registered with gcry_cipher_register. */ |
| void |
| gcry_cipher_unregister (gcry_module_t module) |
| { |
| ath_mutex_lock (&ciphers_registered_lock); |
| _gcry_module_release (module); |
| ath_mutex_unlock (&ciphers_registered_lock); |
| } |
| |
| /* Locate the OID in the oid table and return the index or -1 when not |
| found. An opitonal "oid." or "OID." prefix in OID is ignored, the |
| OID is expected to be in standard IETF dotted notation. The |
| internal algorithm number is returned in ALGORITHM unless it |
| ispassed as NULL. A pointer to the specification of the module |
| implementing this algorithm is return in OID_SPEC unless passed as |
| NULL.*/ |
| static int |
| search_oid (const char *oid, int *algorithm, gcry_cipher_oid_spec_t *oid_spec) |
| { |
| gcry_module_t module; |
| int ret = 0; |
| |
| if (oid && ((! strncmp (oid, "oid.", 4)) |
| || (! strncmp (oid, "OID.", 4)))) |
| oid += 4; |
| |
| module = gcry_cipher_lookup_oid (oid); |
| if (module) |
| { |
| gcry_cipher_spec_t *cipher = module->spec; |
| int i; |
| |
| for (i = 0; cipher->oids[i].oid && !ret; i++) |
| if (! stricmp (oid, cipher->oids[i].oid)) |
| { |
| if (algorithm) |
| *algorithm = module->mod_id; |
| if (oid_spec) |
| *oid_spec = cipher->oids[i]; |
| ret = 1; |
| } |
| _gcry_module_release (module); |
| } |
| |
| return ret; |
| } |
| |
| /* Map STRING to the cipher algorithm identifier. Returns the |
| algorithm ID of the cipher for the given name or 0 if the name is |
| not known. It is valid to pass NULL for STRING which results in a |
| return value of 0. */ |
| int |
| gcry_cipher_map_name (const char *string) |
| { |
| gcry_module_t cipher; |
| int ret, algorithm = 0; |
| |
| if (! string) |
| return 0; |
| |
| REGISTER_DEFAULT_CIPHERS; |
| |
| /* If the string starts with a digit (optionally prefixed with |
| either "OID." or "oid."), we first look into our table of ASN.1 |
| object identifiers to figure out the algorithm */ |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| |
| ret = search_oid (string, &algorithm, NULL); |
| if (! ret) |
| { |
| cipher = gcry_cipher_lookup_name (string); |
| if (cipher) |
| { |
| algorithm = cipher->mod_id; |
| _gcry_module_release (cipher); |
| } |
| } |
| |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| return algorithm; |
| } |
| |
| |
| /* Given a STRING with an OID in dotted decimal notation, this |
| function returns the cipher mode (GCRY_CIPHER_MODE_*) associated |
| with that OID or 0 if no mode is known. Passing NULL for string |
| yields a return value of 0. */ |
| int |
| gcry_cipher_mode_from_oid (const char *string) |
| { |
| gcry_cipher_oid_spec_t oid_spec; |
| int ret = 0, mode = 0; |
| |
| if (!string) |
| return 0; |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| ret = search_oid (string, NULL, &oid_spec); |
| if (ret) |
| mode = oid_spec.mode; |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| return mode; |
| } |
| |
| |
| /* Map the cipher algorithm whose ID is contained in ALGORITHM to a |
| string representation of the algorithm name. For unknown algorithm |
| IDs this function returns "?". */ |
| static const char * |
| cipher_algo_to_string (int algorithm) |
| { |
| gcry_module_t cipher; |
| const char *name; |
| |
| REGISTER_DEFAULT_CIPHERS; |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); |
| if (cipher) |
| { |
| name = ((gcry_cipher_spec_t *) cipher->spec)->name; |
| _gcry_module_release (cipher); |
| } |
| else |
| name = "?"; |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| return name; |
| } |
| |
| /* Map the cipher algorithm identifier ALGORITHM to a string |
| representing this algorithm. This string is the default name as |
| used by Libgcrypt. An pointer to an empty string is returned for |
| an unknown algorithm. NULL is never returned. */ |
| const char * |
| gcry_cipher_algo_name (int algorithm) |
| { |
| return cipher_algo_to_string (algorithm); |
| } |
| |
| |
| /* Flag the cipher algorithm with the identifier ALGORITHM as |
| disabled. There is no error return, the function does nothing for |
| unknown algorithms. Disabled algorithms are vitually not available |
| in Libgcrypt. */ |
| static void |
| disable_cipher_algo (int algorithm) |
| { |
| gcry_module_t cipher; |
| |
| REGISTER_DEFAULT_CIPHERS; |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); |
| if (cipher) |
| { |
| if (! (cipher->flags & FLAG_MODULE_DISABLED)) |
| cipher->flags |= FLAG_MODULE_DISABLED; |
| _gcry_module_release (cipher); |
| } |
| ath_mutex_unlock (&ciphers_registered_lock); |
| } |
| |
| |
| /* Return 0 if the cipher algorithm with identifier ALGORITHM is |
| available. Returns a basic error code value if it is not |
| available. */ |
| static gcry_err_code_t |
| check_cipher_algo (int algorithm) |
| { |
| gcry_err_code_t err = GPG_ERR_NO_ERROR; |
| gcry_module_t cipher; |
| |
| REGISTER_DEFAULT_CIPHERS; |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); |
| if (cipher) |
| { |
| if (cipher->flags & FLAG_MODULE_DISABLED) |
| err = GPG_ERR_CIPHER_ALGO; |
| _gcry_module_release (cipher); |
| } |
| else |
| err = GPG_ERR_CIPHER_ALGO; |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| return err; |
| } |
| |
| |
| /* Return the standard length of the key for the cipher algorithm with |
| the identifier ALGORITHM. This function expects a valid algorithm |
| and will abort if the algorithm is not available or the length of |
| the key is not known. */ |
| static unsigned int |
| cipher_get_keylen (int algorithm) |
| { |
| gcry_module_t cipher; |
| unsigned len = 0; |
| |
| REGISTER_DEFAULT_CIPHERS; |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); |
| if (cipher) |
| { |
| len = ((gcry_cipher_spec_t *) cipher->spec)->keylen; |
| if (!len) |
| log_bug ("cipher %d w/o key length\n", algorithm); |
| _gcry_module_release (cipher); |
| } |
| else |
| log_bug ("cipher %d not found\n", algorithm); |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| return len; |
| } |
| |
| /* Return the block length of the cipher algorithm with the identifier |
| ALGORITHM. This function expects a valid algorithm and will abort |
| if the algorithm is not available or the length of the key is not |
| known. */ |
| static unsigned int |
| cipher_get_blocksize (int algorithm) |
| { |
| gcry_module_t cipher; |
| unsigned len = 0; |
| |
| REGISTER_DEFAULT_CIPHERS; |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); |
| if (cipher) |
| { |
| len = ((gcry_cipher_spec_t *) cipher->spec)->blocksize; |
| if (! len) |
| log_bug ("cipher %d w/o blocksize\n", algorithm); |
| _gcry_module_release (cipher); |
| } |
| else |
| log_bug ("cipher %d not found\n", algorithm); |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| return len; |
| } |
| |
| |
| /* |
| Open a cipher handle for use with cipher algorithm ALGORITHM, using |
| the cipher mode MODE (one of the GCRY_CIPHER_MODE_*) and return a |
| handle in HANDLE. Put NULL into HANDLE and return an error code if |
| something goes wrong. FLAGS may be used to modify the |
| operation. The defined flags are: |
| |
| GCRY_CIPHER_SECURE: allocate all internal buffers in secure memory. |
| GCRY_CIPHER_ENABLE_SYNC: Enable the sync operation as used in OpenPGP. |
| GCRY_CIPHER_CBC_CTS: Enable CTS mode. |
| GCRY_CIPHER_CBC_MAC: Enable MAC mode. |
| |
| Values for these flags may be combined using OR. |
| */ |
| gcry_error_t |
| gcry_cipher_open (gcry_cipher_hd_t *handle, |
| int algo, int mode, unsigned int flags) |
| { |
| int secure = (flags & GCRY_CIPHER_SECURE); |
| gcry_cipher_spec_t *cipher = NULL; |
| cipher_extra_spec_t *extraspec = NULL; |
| gcry_module_t module = NULL; |
| gcry_cipher_hd_t h = NULL; |
| gcry_err_code_t err = 0; |
| |
| /* If the application missed to call the random poll function, we do |
| it here to ensure that it is used once in a while. */ |
| _gcry_fast_random_poll (); |
| |
| REGISTER_DEFAULT_CIPHERS; |
| |
| /* Fetch the according module and check wether the cipher is marked |
| available for use. */ |
| ath_mutex_lock (&ciphers_registered_lock); |
| module = _gcry_module_lookup_id (ciphers_registered, algo); |
| if (module) |
| { |
| /* Found module. */ |
| |
| if (module->flags & FLAG_MODULE_DISABLED) |
| { |
| /* Not available for use. */ |
| err = GPG_ERR_CIPHER_ALGO; |
| _gcry_module_release (module); |
| } |
| else |
| { |
| cipher = (gcry_cipher_spec_t *) module->spec; |
| extraspec = module->extraspec; |
| } |
| } |
| else |
| err = GPG_ERR_CIPHER_ALGO; |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| /* check flags */ |
| if ((! err) |
| && ((flags & ~(0 |
| | GCRY_CIPHER_SECURE |
| | GCRY_CIPHER_ENABLE_SYNC |
| | GCRY_CIPHER_CBC_CTS |
| | GCRY_CIPHER_CBC_MAC)) |
| || (flags & GCRY_CIPHER_CBC_CTS & GCRY_CIPHER_CBC_MAC))) |
| err = GPG_ERR_CIPHER_ALGO; |
| |
| /* check that a valid mode has been requested */ |
| if (! err) |
| switch (mode) |
| { |
| case GCRY_CIPHER_MODE_ECB: |
| case GCRY_CIPHER_MODE_CBC: |
| case GCRY_CIPHER_MODE_CFB: |
| case GCRY_CIPHER_MODE_OFB: |
| case GCRY_CIPHER_MODE_CTR: |
| case GCRY_CIPHER_MODE_AESWRAP: |
| if ((cipher->encrypt == dummy_encrypt_block) |
| || (cipher->decrypt == dummy_decrypt_block)) |
| err = GPG_ERR_INV_CIPHER_MODE; |
| break; |
| |
| case GCRY_CIPHER_MODE_STREAM: |
| if ((cipher->stencrypt == dummy_encrypt_stream) |
| || (cipher->stdecrypt == dummy_decrypt_stream)) |
| err = GPG_ERR_INV_CIPHER_MODE; |
| break; |
| |
| case GCRY_CIPHER_MODE_NONE: |
| /* This mode may be used for debugging. It copies the main |
| text verbatim to the ciphertext. We do not allow this in |
| fips mode or if no debug flag has been set. */ |
| if (fips_mode () || !_gcry_get_debug_flag (0)) |
| err = GPG_ERR_INV_CIPHER_MODE; |
| break; |
| |
| default: |
| err = GPG_ERR_INV_CIPHER_MODE; |
| } |
| |
| /* Perform selftest here and mark this with a flag in cipher_table? |
| No, we should not do this as it takes too long. Further it does |
| not make sense to exclude algorithms with failing selftests at |
| runtime: If a selftest fails there is something seriously wrong |
| with the system and thus we better die immediately. */ |
| |
| if (! err) |
| { |
| size_t size = (sizeof (*h) |
| + 2 * cipher->contextsize |
| - sizeof (cipher_context_alignment_t) |
| #ifdef NEED_16BYTE_ALIGNED_CONTEXT |
| + 15 /* Space for leading alignment gap. */ |
| #endif /*NEED_16BYTE_ALIGNED_CONTEXT*/ |
| ); |
| |
| if (secure) |
| h = gcry_calloc_secure (1, size); |
| else |
| h = gcry_calloc (1, size); |
| |
| if (! h) |
| err = gpg_err_code_from_errno (errno); |
| else |
| { |
| size_t off = 0; |
| |
| #ifdef NEED_16BYTE_ALIGNED_CONTEXT |
| if ( ((unsigned long)h & 0x0f) ) |
| { |
| /* The malloced block is not aligned on a 16 byte |
| boundary. Correct for this. */ |
| off = 16 - ((unsigned long)h & 0x0f); |
| h = (void*)((char*)h + off); |
| } |
| #endif /*NEED_16BYTE_ALIGNED_CONTEXT*/ |
| |
| h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; |
| h->actual_handle_size = size - off; |
| h->handle_offset = off; |
| h->cipher = cipher; |
| h->extraspec = extraspec; |
| h->module = module; |
| h->algo = algo; |
| h->mode = mode; |
| h->flags = flags; |
| |
| /* Setup bulk encryption routines. */ |
| switch (algo) |
| { |
| #ifdef USE_AES |
| case GCRY_CIPHER_AES128: |
| case GCRY_CIPHER_AES192: |
| case GCRY_CIPHER_AES256: |
| h->bulk.cfb_enc = _gcry_aes_cfb_enc; |
| h->bulk.cfb_dec = _gcry_aes_cfb_dec; |
| h->bulk.cbc_enc = _gcry_aes_cbc_enc; |
| h->bulk.cbc_dec = _gcry_aes_cbc_dec; |
| break; |
| #endif /*USE_AES*/ |
| |
| default: |
| break; |
| } |
| } |
| } |
| |
| /* Done. */ |
| |
| if (err) |
| { |
| if (module) |
| { |
| /* Release module. */ |
| ath_mutex_lock (&ciphers_registered_lock); |
| _gcry_module_release (module); |
| ath_mutex_unlock (&ciphers_registered_lock); |
| } |
| } |
| |
| *handle = err ? NULL : h; |
| |
| return gcry_error (err); |
| } |
| |
| |
| /* Release all resources associated with the cipher handle H. H may be |
| NULL in which case this is a no-operation. */ |
| void |
| gcry_cipher_close (gcry_cipher_hd_t h) |
| { |
| size_t off; |
| |
| if (!h) |
| return; |
| |
| if ((h->magic != CTX_MAGIC_SECURE) |
| && (h->magic != CTX_MAGIC_NORMAL)) |
| _gcry_fatal_error(GPG_ERR_INTERNAL, |
| "gcry_cipher_close: already closed/invalid handle"); |
| else |
| h->magic = 0; |
| |
| /* Release module. */ |
| ath_mutex_lock (&ciphers_registered_lock); |
| _gcry_module_release (h->module); |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| /* We always want to wipe out the memory even when the context has |
| been allocated in secure memory. The user might have disabled |
| secure memory or is using his own implementation which does not |
| do the wiping. To accomplish this we need to keep track of the |
| actual size of this structure because we have no way to known |
| how large the allocated area was when using a standard malloc. */ |
| off = h->handle_offset; |
| wipememory (h, h->actual_handle_size); |
| |
| gcry_free ((char*)h - off); |
| } |
| |
| |
| /* Set the key to be used for the encryption context C to KEY with |
| length KEYLEN. The length should match the required length. */ |
| static gcry_error_t |
| cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned int keylen) |
| { |
| gcry_err_code_t ret; |
| |
| ret = (*c->cipher->setkey) (&c->context.c, key, keylen); |
| if (!ret) |
| { |
| /* Duplicate initial context. */ |
| memcpy ((void *) ((char *) &c->context.c + c->cipher->contextsize), |
| (void *) &c->context.c, |
| c->cipher->contextsize); |
| c->marks.key = 1; |
| } |
| else |
| c->marks.key = 0; |
| |
| return gcry_error (ret); |
| } |
| |
| |
| /* Set the IV to be used for the encryption context C to IV with |
| length IVLEN. The length should match the required length. */ |
| static void |
| cipher_setiv( gcry_cipher_hd_t c, const byte *iv, unsigned ivlen ) |
| { |
| memset (c->u_iv.iv, 0, c->cipher->blocksize); |
| if (iv) |
| { |
| if (ivlen != c->cipher->blocksize) |
| { |
| log_info ("WARNING: cipher_setiv: ivlen=%u blklen=%u\n", |
| ivlen, (unsigned int)c->cipher->blocksize); |
| fips_signal_error ("IV length does not match blocklength"); |
| } |
| if (ivlen > c->cipher->blocksize) |
| ivlen = c->cipher->blocksize; |
| memcpy (c->u_iv.iv, iv, ivlen); |
| c->marks.iv = 1; |
| } |
| else |
| c->marks.iv = 0; |
| |
| c->unused = 0; |
| } |
| |
| |
| /* Reset the cipher context to the initial context. This is basically |
| the same as an release followed by a new. */ |
| static void |
| cipher_reset (gcry_cipher_hd_t c) |
| { |
| memcpy (&c->context.c, |
| (char *) &c->context.c + c->cipher->contextsize, |
| c->cipher->contextsize); |
| memset (&c->marks, 0, sizeof c->marks); |
| memset (c->u_iv.iv, 0, c->cipher->blocksize); |
| memset (c->lastiv, 0, c->cipher->blocksize); |
| memset (c->ctr, 0, c->cipher->blocksize); |
| } |
| |
| |
| static void |
| do_ecb_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, |
| unsigned int nblocks ) |
| { |
| unsigned int n; |
| |
| for (n=0; n < nblocks; n++ ) |
| { |
| c->cipher->encrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf ); |
| inbuf += c->cipher->blocksize; |
| outbuf += c->cipher->blocksize; |
| } |
| } |
| |
| static void |
| do_ecb_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, |
| unsigned int nblocks ) |
| { |
| unsigned int n; |
| |
| for (n=0; n < nblocks; n++ ) |
| { |
| c->cipher->decrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf ); |
| inbuf += c->cipher->blocksize; |
| outbuf += c->cipher->blocksize; |
| } |
| } |
| |
| |
| static void |
| do_cbc_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, |
| const unsigned char *inbuf, unsigned int nbytes ) |
| { |
| unsigned int n; |
| unsigned char *ivp; |
| int i; |
| size_t blocksize = c->cipher->blocksize; |
| unsigned nblocks = nbytes / blocksize; |
| |
| if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) |
| { |
| if ((nbytes % blocksize) == 0) |
| nblocks--; |
| } |
| |
| if (c->bulk.cbc_enc) |
| { |
| c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, |
| (c->flags & GCRY_CIPHER_CBC_MAC)); |
| inbuf += nblocks * blocksize; |
| if (!(c->flags & GCRY_CIPHER_CBC_MAC)) |
| outbuf += nblocks * blocksize; |
| } |
| else |
| { |
| for (n=0; n < nblocks; n++ ) |
| { |
| for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) |
| outbuf[i] = inbuf[i] ^ *ivp++; |
| c->cipher->encrypt ( &c->context.c, outbuf, outbuf ); |
| memcpy (c->u_iv.iv, outbuf, blocksize ); |
| inbuf += blocksize; |
| if (!(c->flags & GCRY_CIPHER_CBC_MAC)) |
| outbuf += blocksize; |
| } |
| } |
| |
| if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) |
| { |
| /* We have to be careful here, since outbuf might be equal to |
| inbuf. */ |
| int restbytes; |
| unsigned char b; |
| |
| if ((nbytes % blocksize) == 0) |
| restbytes = blocksize; |
| else |
| restbytes = nbytes % blocksize; |
| |
| outbuf -= blocksize; |
| for (ivp = c->u_iv.iv, i = 0; i < restbytes; i++) |
| { |
| b = inbuf[i]; |
| outbuf[blocksize + i] = outbuf[i]; |
| outbuf[i] = b ^ *ivp++; |
| } |
| for (; i < blocksize; i++) |
| outbuf[i] = 0 ^ *ivp++; |
| |
| c->cipher->encrypt (&c->context.c, outbuf, outbuf); |
| memcpy (c->u_iv.iv, outbuf, blocksize); |
| } |
| } |
| |
| |
| static void |
| do_cbc_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, |
| const unsigned char *inbuf, unsigned int nbytes) |
| { |
| unsigned int n; |
| unsigned char *ivp; |
| int i; |
| size_t blocksize = c->cipher->blocksize; |
| unsigned int nblocks = nbytes / blocksize; |
| |
| if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) |
| { |
| nblocks--; |
| if ((nbytes % blocksize) == 0) |
| nblocks--; |
| memcpy (c->lastiv, c->u_iv.iv, blocksize); |
| } |
| |
| if (c->bulk.cbc_dec) |
| { |
| c->bulk.cbc_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); |
| inbuf += nblocks * blocksize; |
| outbuf += nblocks * blocksize; |
| } |
| else |
| { |
| for (n=0; n < nblocks; n++ ) |
| { |
| /* Because outbuf and inbuf might be the same, we have to |
| * save the original ciphertext block. We use LASTIV for |
| * this here because it is not used otherwise. */ |
| memcpy (c->lastiv, inbuf, blocksize); |
| c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); |
| for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) |
| outbuf[i] ^= *ivp++; |
| memcpy(c->u_iv.iv, c->lastiv, blocksize ); |
| inbuf += c->cipher->blocksize; |
| outbuf += c->cipher->blocksize; |
| } |
| } |
| |
| if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) |
| { |
| int restbytes; |
| |
| if ((nbytes % blocksize) == 0) |
| restbytes = blocksize; |
| else |
| restbytes = nbytes % blocksize; |
| |
| memcpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ |
| memcpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */ |
| |
| c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); |
| for (ivp=c->u_iv.iv,i=0; i < restbytes; i++ ) |
| outbuf[i] ^= *ivp++; |
| |
| memcpy(outbuf + blocksize, outbuf, restbytes); |
| for(i=restbytes; i < blocksize; i++) |
| c->u_iv.iv[i] = outbuf[i]; |
| c->cipher->decrypt (&c->context.c, outbuf, c->u_iv.iv); |
| for(ivp=c->lastiv,i=0; i < blocksize; i++ ) |
| outbuf[i] ^= *ivp++; |
| /* c->lastiv is now really lastlastiv, does this matter? */ |
| } |
| } |
| |
| |
| static void |
| do_cfb_encrypt( gcry_cipher_hd_t c, unsigned char *outbuf, |
| const unsigned char *inbuf, unsigned int nbytes ) |
| { |
| unsigned char *ivp; |
| size_t blocksize = c->cipher->blocksize; |
| size_t blocksize_x_2 = blocksize + blocksize; |
| |
| if ( nbytes <= c->unused ) |
| { |
| /* Short enough to be encoded by the remaining XOR mask. */ |
| /* XOR the input with the IV and store input into IV. */ |
| for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused; |
| nbytes; |
| nbytes--, c->unused-- ) |
| *outbuf++ = (*ivp++ ^= *inbuf++); |
| return; |
| } |
| |
| if ( c->unused ) |
| { |
| /* XOR the input with the IV and store input into IV */ |
| nbytes -= c->unused; |
| for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) |
| *outbuf++ = (*ivp++ ^= *inbuf++); |
| } |
| |
| /* Now we can process complete blocks. We use a loop as long as we |
| have at least 2 blocks and use conditions for the rest. This |
| also allows to use a bulk encryption function if available. */ |
| if (nbytes >= blocksize_x_2 && c->bulk.cfb_enc) |
| { |
| unsigned int nblocks = nbytes / blocksize; |
| c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); |
| outbuf += nblocks * blocksize; |
| inbuf += nblocks * blocksize; |
| nbytes -= nblocks * blocksize; |
| } |
| else |
| { |
| while ( nbytes >= blocksize_x_2 ) |
| { |
| int i; |
| /* Encrypt the IV. */ |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| /* XOR the input with the IV and store input into IV. */ |
| for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) |
| *outbuf++ = (*ivp++ ^= *inbuf++); |
| nbytes -= blocksize; |
| } |
| } |
| |
| if ( nbytes >= blocksize ) |
| { |
| int i; |
| /* Save the current IV and then encrypt the IV. */ |
| memcpy( c->lastiv, c->u_iv.iv, blocksize ); |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| /* XOR the input with the IV and store input into IV */ |
| for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) |
| *outbuf++ = (*ivp++ ^= *inbuf++); |
| nbytes -= blocksize; |
| } |
| if ( nbytes ) |
| { |
| /* Save the current IV and then encrypt the IV. */ |
| memcpy( c->lastiv, c->u_iv.iv, blocksize ); |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| c->unused = blocksize; |
| /* Apply the XOR. */ |
| c->unused -= nbytes; |
| for(ivp=c->u_iv.iv; nbytes; nbytes-- ) |
| *outbuf++ = (*ivp++ ^= *inbuf++); |
| } |
| } |
| |
| |
| static void |
| do_cfb_decrypt( gcry_cipher_hd_t c, unsigned char *outbuf, |
| const unsigned char *inbuf, unsigned int nbytes ) |
| { |
| unsigned char *ivp; |
| unsigned long temp; |
| int i; |
| size_t blocksize = c->cipher->blocksize; |
| size_t blocksize_x_2 = blocksize + blocksize; |
| |
| if (nbytes <= c->unused) |
| { |
| /* Short enough to be encoded by the remaining XOR mask. */ |
| /* XOR the input with the IV and store input into IV. */ |
| for (ivp=c->u_iv.iv+blocksize - c->unused; |
| nbytes; |
| nbytes--, c->unused--) |
| { |
| temp = *inbuf++; |
| *outbuf++ = *ivp ^ temp; |
| *ivp++ = temp; |
| } |
| return; |
| } |
| |
| if (c->unused) |
| { |
| /* XOR the input with the IV and store input into IV. */ |
| nbytes -= c->unused; |
| for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) |
| { |
| temp = *inbuf++; |
| *outbuf++ = *ivp ^ temp; |
| *ivp++ = temp; |
| } |
| } |
| |
| /* Now we can process complete blocks. We use a loop as long as we |
| have at least 2 blocks and use conditions for the rest. This |
| also allows to use a bulk encryption function if available. */ |
| if (nbytes >= blocksize_x_2 && c->bulk.cfb_dec) |
| { |
| unsigned int nblocks = nbytes / blocksize; |
| c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); |
| outbuf += nblocks * blocksize; |
| inbuf += nblocks * blocksize; |
| nbytes -= nblocks * blocksize; |
| } |
| else |
| { |
| while (nbytes >= blocksize_x_2 ) |
| { |
| /* Encrypt the IV. */ |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| /* XOR the input with the IV and store input into IV. */ |
| for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) |
| { |
| temp = *inbuf++; |
| *outbuf++ = *ivp ^ temp; |
| *ivp++ = temp; |
| } |
| nbytes -= blocksize; |
| } |
| } |
| |
| if (nbytes >= blocksize ) |
| { |
| /* Save the current IV and then encrypt the IV. */ |
| memcpy ( c->lastiv, c->u_iv.iv, blocksize); |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| /* XOR the input with the IV and store input into IV */ |
| for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) |
| { |
| temp = *inbuf++; |
| *outbuf++ = *ivp ^ temp; |
| *ivp++ = temp; |
| } |
| nbytes -= blocksize; |
| } |
| |
| if (nbytes) |
| { |
| /* Save the current IV and then encrypt the IV. */ |
| memcpy ( c->lastiv, c->u_iv.iv, blocksize ); |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| c->unused = blocksize; |
| /* Apply the XOR. */ |
| c->unused -= nbytes; |
| for (ivp=c->u_iv.iv; nbytes; nbytes-- ) |
| { |
| temp = *inbuf++; |
| *outbuf++ = *ivp ^ temp; |
| *ivp++ = temp; |
| } |
| } |
| } |
| |
| |
| static void |
| do_ofb_encrypt( gcry_cipher_hd_t c, |
| byte *outbuf, const byte *inbuf, unsigned nbytes ) |
| { |
| byte *ivp; |
| size_t blocksize = c->cipher->blocksize; |
| |
| if ( nbytes <= c->unused ) |
| { |
| /* Short enough to be encoded by the remaining XOR mask. */ |
| /* XOR the input with the IV */ |
| for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused; |
| nbytes; |
| nbytes--, c->unused-- ) |
| *outbuf++ = (*ivp++ ^ *inbuf++); |
| return; |
| } |
| |
| if( c->unused ) |
| { |
| nbytes -= c->unused; |
| for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) |
| *outbuf++ = (*ivp++ ^ *inbuf++); |
| } |
| |
| /* Now we can process complete blocks. */ |
| while ( nbytes >= blocksize ) |
| { |
| int i; |
| /* Encrypt the IV (and save the current one). */ |
| memcpy( c->lastiv, c->u_iv.iv, blocksize ); |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| |
| for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) |
| *outbuf++ = (*ivp++ ^ *inbuf++); |
| nbytes -= blocksize; |
| } |
| if ( nbytes ) |
| { /* process the remaining bytes */ |
| memcpy( c->lastiv, c->u_iv.iv, blocksize ); |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| c->unused = blocksize; |
| c->unused -= nbytes; |
| for(ivp=c->u_iv.iv; nbytes; nbytes-- ) |
| *outbuf++ = (*ivp++ ^ *inbuf++); |
| } |
| } |
| |
| static void |
| do_ofb_decrypt( gcry_cipher_hd_t c, |
| byte *outbuf, const byte *inbuf, unsigned int nbytes ) |
| { |
| byte *ivp; |
| size_t blocksize = c->cipher->blocksize; |
| |
| if( nbytes <= c->unused ) |
| { |
| /* Short enough to be encoded by the remaining XOR mask. */ |
| for (ivp=c->u_iv.iv+blocksize - c->unused; nbytes; nbytes--,c->unused--) |
| *outbuf++ = *ivp++ ^ *inbuf++; |
| return; |
| } |
| |
| if ( c->unused ) |
| { |
| nbytes -= c->unused; |
| for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) |
| *outbuf++ = *ivp++ ^ *inbuf++; |
| } |
| |
| /* Now we can process complete blocks. */ |
| while ( nbytes >= blocksize ) |
| { |
| int i; |
| /* Encrypt the IV (and save the current one). */ |
| memcpy( c->lastiv, c->u_iv.iv, blocksize ); |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) |
| *outbuf++ = *ivp++ ^ *inbuf++; |
| nbytes -= blocksize; |
| } |
| if ( nbytes ) |
| { /* Process the remaining bytes. */ |
| /* Encrypt the IV (and save the current one). */ |
| memcpy( c->lastiv, c->u_iv.iv, blocksize ); |
| c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); |
| c->unused = blocksize; |
| c->unused -= nbytes; |
| for (ivp=c->u_iv.iv; nbytes; nbytes-- ) |
| *outbuf++ = *ivp++ ^ *inbuf++; |
| } |
| } |
| |
| |
| static void |
| do_ctr_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, |
| unsigned int nbytes ) |
| { |
| unsigned int n; |
| byte tmp[MAX_BLOCKSIZE]; |
| int i; |
| |
| for(n=0; n < nbytes; n++) |
| { |
| if ((n % c->cipher->blocksize) == 0) |
| { |
| c->cipher->encrypt (&c->context.c, tmp, c->ctr); |
| |
| for (i = c->cipher->blocksize; i > 0; i--) |
| { |
| c->ctr[i-1]++; |
| if (c->ctr[i-1] != 0) |
| break; |
| } |
| } |
| |
| /* XOR input with encrypted counter and store in output. */ |
| outbuf[n] = inbuf[n] ^ tmp[n % c->cipher->blocksize]; |
| } |
| } |
| |
| static void |
| do_ctr_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, |
| unsigned int nbytes ) |
| { |
| do_ctr_encrypt (c, outbuf, inbuf, nbytes); |
| } |
| |
| |
| /* Perform the AES-Wrap algorithm as specified by RFC3394. We |
| implement this as a mode usable with any cipher algorithm of |
| blocksize 128. */ |
| static gcry_err_code_t |
| do_aeswrap_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, |
| const byte *inbuf, unsigned int inbuflen ) |
| { |
| int j, x; |
| unsigned int n, i; |
| unsigned char *r, *a, *b; |
| unsigned char t[8]; |
| |
| #if MAX_BLOCKSIZE < 8 |
| #error Invalid block size |
| #endif |
| /* We require a cipher with a 128 bit block length. */ |
| if (c->cipher->blocksize != 16) |
| return GPG_ERR_INV_LENGTH; |
| |
| /* The output buffer must be able to hold the input data plus one |
| additional block. */ |
| if (outbuflen < inbuflen + 8) |
| return GPG_ERR_BUFFER_TOO_SHORT; |
| /* Input data must be multiple of 64 bits. */ |
| if (inbuflen % 8) |
| return GPG_ERR_INV_ARG; |
| |
| n = inbuflen / 8; |
| |
| /* We need at least two 64 bit blocks. */ |
| if (n < 2) |
| return GPG_ERR_INV_ARG; |
| |
| r = outbuf; |
| a = outbuf; /* We store A directly in OUTBUF. */ |
| b = c->ctr; /* B is also used to concatenate stuff. */ |
| |
| /* If an IV has been set we use that IV as the Alternative Initial |
| Value; if it has not been set we use the standard value. */ |
| if (c->marks.iv) |
| memcpy (a, c->u_iv.iv, 8); |
| else |
| memset (a, 0xa6, 8); |
| |
| /* Copy the inbuf to the outbuf. */ |
| memmove (r+8, inbuf, inbuflen); |
| |
| memset (t, 0, sizeof t); /* t := 0. */ |
| |
| for (j = 0; j <= 5; j++) |
| { |
| for (i = 1; i <= n; i++) |
| { |
| /* B := AES_k( A | R[i] ) */ |
| memcpy (b, a, 8); |
| memcpy (b+8, r+i*8, 8); |
| c->cipher->encrypt (&c->context.c, b, b); |
| /* t := t + 1 */ |
| for (x = 7; x >= 0; x--) |
| { |
| t[x]++; |
| if (t[x]) |
| break; |
| } |
| /* A := MSB_64(B) ^ t */ |
| for (x=0; x < 8; x++) |
| a[x] = b[x] ^ t[x]; |
| /* R[i] := LSB_64(B) */ |
| memcpy (r+i*8, b+8, 8); |
| } |
| } |
| |
| return 0; |
| } |
| |
| /* Perform the AES-Unwrap algorithm as specified by RFC3394. We |
| implement this as a mode usable with any cipher algorithm of |
| blocksize 128. */ |
| static gcry_err_code_t |
| do_aeswrap_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, |
| const byte *inbuf, unsigned int inbuflen) |
| { |
| int j, x; |
| unsigned int n, i; |
| unsigned char *r, *a, *b; |
| unsigned char t[8]; |
| |
| #if MAX_BLOCKSIZE < 8 |
| #error Invalid block size |
| #endif |
| /* We require a cipher with a 128 bit block length. */ |
| if (c->cipher->blocksize != 16) |
| return GPG_ERR_INV_LENGTH; |
| |
| /* The output buffer must be able to hold the input data minus one |
| additional block. Fixme: The caller has more restrictive checks |
| - we may want to fix them for this mode. */ |
| if (outbuflen + 8 < inbuflen) |
| return GPG_ERR_BUFFER_TOO_SHORT; |
| /* Input data must be multiple of 64 bits. */ |
| if (inbuflen % 8) |
| return GPG_ERR_INV_ARG; |
| |
| n = inbuflen / 8; |
| |
| /* We need at least three 64 bit blocks. */ |
| if (n < 3) |
| return GPG_ERR_INV_ARG; |
| |
| r = outbuf; |
| a = c->lastiv; /* We use c->LASTIV as buffer for A. */ |
| b = c->ctr; /* B is also used to concatenate stuff. */ |
| |
| /* Copy the inbuf to the outbuf and save A. */ |
| memcpy (a, inbuf, 8); |
| memmove (r, inbuf+8, inbuflen-8); |
| n--; /* Reduce to actual number of data blocks. */ |
| |
| /* t := 6 * n */ |
| i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */ |
| for (x=0; x < 8 && x < sizeof (i); x++) |
| t[7-x] = i >> (8*x); |
| for (; x < 8; x++) |
| t[7-x] = 0; |
| |
| for (j = 5; j >= 0; j--) |
| { |
| for (i = n; i >= 1; i--) |
| { |
| /* B := AES_k^1( (A ^ t)| R[i] ) */ |
| for (x = 0; x < 8; x++) |
| b[x] = a[x] ^ t[x]; |
| memcpy (b+8, r+(i-1)*8, 8); |
| c->cipher->decrypt (&c->context.c, b, b); |
| /* t := t - 1 */ |
| for (x = 7; x >= 0; x--) |
| { |
| t[x]--; |
| if (t[x] != 0xff) |
| break; |
| } |
| /* A := MSB_64(B) */ |
| memcpy (a, b, 8); |
| /* R[i] := LSB_64(B) */ |
| memcpy (r+(i-1)*8, b+8, 8); |
| } |
| } |
| |
| /* If an IV has been set we compare against this Alternative Initial |
| Value; if it has not been set we compare against the standard IV. */ |
| if (c->marks.iv) |
| j = memcmp (a, c->u_iv.iv, 8); |
| else |
| { |
| for (j=0, x=0; x < 8; x++) |
| if (a[x] != 0xa6) |
| { |
| j=1; |
| break; |
| } |
| } |
| return j? GPG_ERR_CHECKSUM : 0; |
| } |
| |
| |
| /**************** |
| * Encrypt INBUF to OUTBUF with the mode selected at open. |
| * inbuf and outbuf may overlap or be the same. |
| * Depending on the mode some contraints apply to NBYTES. |
| */ |
| static gcry_err_code_t |
| cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, |
| const byte *inbuf, unsigned int nbytes) |
| { |
| gcry_err_code_t rc = GPG_ERR_NO_ERROR; |
| |
| switch( c->mode ) { |
| case GCRY_CIPHER_MODE_ECB: |
| if (!(nbytes%c->cipher->blocksize)) |
| do_ecb_encrypt(c, outbuf, inbuf, nbytes/c->cipher->blocksize ); |
| else |
| rc = GPG_ERR_INV_ARG; |
| break; |
| case GCRY_CIPHER_MODE_CBC: |
| if (!(nbytes%c->cipher->blocksize) |
| || (nbytes > c->cipher->blocksize |
| && (c->flags & GCRY_CIPHER_CBC_CTS))) |
| do_cbc_encrypt(c, outbuf, inbuf, nbytes ); |
| else |
| rc = GPG_ERR_INV_ARG; |
| break; |
| case GCRY_CIPHER_MODE_CFB: |
| do_cfb_encrypt(c, outbuf, inbuf, nbytes ); |
| break; |
| case GCRY_CIPHER_MODE_OFB: |
| do_ofb_encrypt(c, outbuf, inbuf, nbytes ); |
| break; |
| case GCRY_CIPHER_MODE_CTR: |
| do_ctr_encrypt(c, outbuf, inbuf, nbytes ); |
| break; |
| case GCRY_CIPHER_MODE_STREAM: |
| c->cipher->stencrypt ( &c->context.c, |
| outbuf, (byte*)/*arggg*/inbuf, nbytes ); |
| break; |
| case GCRY_CIPHER_MODE_NONE: |
| if (fips_mode () || !_gcry_get_debug_flag (0)) |
| { |
| fips_signal_error ("cipher mode NONE used"); |
| rc = GPG_ERR_INV_CIPHER_MODE; |
| } |
| else |
| { |
| if ( inbuf != outbuf ) |
| memmove (outbuf, inbuf, nbytes); |
| } |
| break; |
| default: |
| log_fatal("cipher_encrypt: invalid mode %d\n", c->mode ); |
| rc = GPG_ERR_INV_CIPHER_MODE; |
| break; |
| } |
| return rc; |
| } |
| |
| |
| /**************** |
| * Encrypt IN and write it to OUT. If IN is NULL, in-place encryption has |
| * been requested. |
| */ |
| gcry_error_t |
| gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, |
| const void *in, size_t inlen) |
| { |
| gcry_err_code_t err; |
| |
| if (h->mode == GCRY_CIPHER_MODE_AESWRAP) |
| { |
| /* Hack to implement AESWRAP without touching the other modes. |
| The actual function has been taken from the current |
| development version which does all error checking in each |
| mode function. */ |
| if (!in) |
| err = do_aeswrap_encrypt (h, out, outsize, out, outsize); |
| else |
| err = do_aeswrap_encrypt (h, out, outsize, in, inlen); |
| } |
| else if (!in) |
| { |
| /* Caller requested in-place encryption. */ |
| /* Actually cipher_encrypt() does not need to know about it, but |
| * we may change it in the future to get better performance. */ |
| err = cipher_encrypt (h, out, out, outsize); |
| } |
| else if (outsize < ((h->flags & GCRY_CIPHER_CBC_MAC) ? |
| h->cipher->blocksize : inlen)) |
| err = GPG_ERR_TOO_SHORT; |
| else if ((h->mode == GCRY_CIPHER_MODE_ECB |
| || (h->mode == GCRY_CIPHER_MODE_CBC |
| && (! ((h->flags & GCRY_CIPHER_CBC_CTS) |
| && (inlen > h->cipher->blocksize))))) |
| && (inlen % h->cipher->blocksize)) |
| err = GPG_ERR_INV_ARG; |
| else |
| err = cipher_encrypt (h, out, in, inlen); |
| |
| if (err && out) |
| memset (out, 0x42, outsize); /* Failsafe: Make sure that the |
| plaintext will never make it into |
| OUT. */ |
| |
| return gcry_error (err); |
| } |
| |
| |
| |
| /**************** |
| * Decrypt INBUF to OUTBUF with the mode selected at open. |
| * inbuf and outbuf may overlap or be the same. |
| * Depending on the mode some some contraints apply to NBYTES. |
| */ |
| static gcry_err_code_t |
| cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, |
| unsigned int nbytes) |
| { |
| gcry_err_code_t rc = GPG_ERR_NO_ERROR; |
| |
| switch( c->mode ) { |
| case GCRY_CIPHER_MODE_ECB: |
| if (!(nbytes%c->cipher->blocksize)) |
| do_ecb_decrypt(c, outbuf, inbuf, nbytes/c->cipher->blocksize ); |
| else |
| rc = GPG_ERR_INV_ARG; |
| break; |
| case GCRY_CIPHER_MODE_CBC: |
| if (!(nbytes%c->cipher->blocksize) |
| || (nbytes > c->cipher->blocksize |
| && (c->flags & GCRY_CIPHER_CBC_CTS))) |
| do_cbc_decrypt(c, outbuf, inbuf, nbytes ); |
| else |
| rc = GPG_ERR_INV_ARG; |
| break; |
| case GCRY_CIPHER_MODE_CFB: |
| do_cfb_decrypt(c, outbuf, inbuf, nbytes ); |
| break; |
| case GCRY_CIPHER_MODE_OFB: |
| do_ofb_decrypt(c, outbuf, inbuf, nbytes ); |
| break; |
| case GCRY_CIPHER_MODE_CTR: |
| do_ctr_decrypt(c, outbuf, inbuf, nbytes ); |
| break; |
| case GCRY_CIPHER_MODE_STREAM: |
| c->cipher->stdecrypt ( &c->context.c, |
| outbuf, (byte*)/*arggg*/inbuf, nbytes ); |
| break; |
| case GCRY_CIPHER_MODE_NONE: |
| if (fips_mode () || !_gcry_get_debug_flag (0)) |
| { |
| fips_signal_error ("cipher mode NONE used"); |
| rc = GPG_ERR_INV_CIPHER_MODE; |
| } |
| else |
| { |
| if (inbuf != outbuf) |
| memmove (outbuf, inbuf, nbytes); |
| } |
| break; |
| default: |
| log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode ); |
| rc = GPG_ERR_INV_CIPHER_MODE; |
| break; |
| } |
| return rc; |
| } |
| |
| |
| gcry_error_t |
| gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize, |
| const void *in, size_t inlen) |
| { |
| gcry_err_code_t err = 0; |
| |
| if (h->mode == GCRY_CIPHER_MODE_AESWRAP) |
| { |
| /* Hack to implement AESWRAP without touching the other modes. |
| The actual function has been taken from the current |
| development version which does all error checking in each |
| mode function. */ |
| if (!in) |
| err = do_aeswrap_decrypt (h, out, outsize, out, outsize); |
| else |
| err = do_aeswrap_decrypt (h, out, outsize, in, inlen); |
| } |
| else if (!in) |
| { |
| /* Caller requested in-place encryption. */ |
| /* Actually cipher_encrypt() does not need to know about it, but |
| * we may change it in the future to get better performance. */ |
| err = cipher_decrypt (h, out, out, outsize); |
| } |
| else if (outsize < inlen) |
| err = GPG_ERR_TOO_SHORT; |
| else if (((h->mode == GCRY_CIPHER_MODE_ECB) |
| || ((h->mode == GCRY_CIPHER_MODE_CBC) |
| && (! ((h->flags & GCRY_CIPHER_CBC_CTS) |
| && (inlen > h->cipher->blocksize))))) |
| && (inlen % h->cipher->blocksize) != 0) |
| err = GPG_ERR_INV_ARG; |
| else |
| err = cipher_decrypt (h, out, in, inlen); |
| |
| return gcry_error (err); |
| } |
| |
| |
| |
| /**************** |
| * Used for PGP's somewhat strange CFB mode. Only works if |
| * the corresponding flag is set. |
| */ |
| static void |
| cipher_sync (gcry_cipher_hd_t c) |
| { |
| if ((c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused) |
| { |
| memmove (c->u_iv.iv + c->unused, |
| c->u_iv.iv, c->cipher->blocksize - c->unused); |
| memcpy (c->u_iv.iv, |
| c->lastiv + c->cipher->blocksize - c->unused, c->unused); |
| c->unused = 0; |
| } |
| } |
| |
| |
| gcry_error_t |
| _gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) |
| { |
| return cipher_setkey (hd, (void*)key, keylen); |
| } |
| |
| |
| gcry_error_t |
| _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) |
| { |
| cipher_setiv (hd, iv, ivlen); |
| return 0; |
| } |
| |
| /* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of |
| block size length, or (NULL,0) to set the CTR to the all-zero |
| block. */ |
| gpg_error_t |
| _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) |
| { |
| if (ctr && ctrlen == hd->cipher->blocksize) |
| memcpy (hd->ctr, ctr, hd->cipher->blocksize); |
| else if (!ctr || !ctrlen) |
| memset (hd->ctr, 0, hd->cipher->blocksize); |
| else |
| return gpg_error (GPG_ERR_INV_ARG); |
| return 0; |
| } |
| |
| |
| gcry_error_t |
| gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) |
| { |
| gcry_err_code_t rc = GPG_ERR_NO_ERROR; |
| |
| switch (cmd) |
| { |
| case GCRYCTL_SET_KEY: /* Deprecated; use gcry_cipher_setkey. */ |
| rc = cipher_setkey( h, buffer, buflen ); |
| break; |
| |
| case GCRYCTL_SET_IV: /* Deprecated; use gcry_cipher_setiv. */ |
| cipher_setiv( h, buffer, buflen ); |
| break; |
| |
| case GCRYCTL_RESET: |
| cipher_reset (h); |
| break; |
| |
| case GCRYCTL_CFB_SYNC: |
| cipher_sync( h ); |
| break; |
| |
| case GCRYCTL_SET_CBC_CTS: |
| if (buflen) |
| if (h->flags & GCRY_CIPHER_CBC_MAC) |
| rc = GPG_ERR_INV_FLAG; |
| else |
| h->flags |= GCRY_CIPHER_CBC_CTS; |
| else |
| h->flags &= ~GCRY_CIPHER_CBC_CTS; |
| break; |
| |
| case GCRYCTL_SET_CBC_MAC: |
| if (buflen) |
| if (h->flags & GCRY_CIPHER_CBC_CTS) |
| rc = GPG_ERR_INV_FLAG; |
| else |
| h->flags |= GCRY_CIPHER_CBC_MAC; |
| else |
| h->flags &= ~GCRY_CIPHER_CBC_MAC; |
| break; |
| |
| case GCRYCTL_DISABLE_ALGO: |
| /* This command expects NULL for H and BUFFER to point to an |
| integer with the algo number. */ |
| if( h || !buffer || buflen != sizeof(int) ) |
| return gcry_error (GPG_ERR_CIPHER_ALGO); |
| disable_cipher_algo( *(int*)buffer ); |
| break; |
| |
| case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr. */ |
| if (buffer && buflen == h->cipher->blocksize) |
| memcpy (h->ctr, buffer, h->cipher->blocksize); |
| else if (buffer == NULL || buflen == 0) |
| memset (h->ctr, 0, h->cipher->blocksize); |
| else |
| rc = GPG_ERR_INV_ARG; |
| break; |
| |
| case 61: /* Disable weak key detection (private). */ |
| if (h->extraspec->set_extra_info) |
| rc = h->extraspec->set_extra_info |
| (&h->context.c, CIPHER_INFO_NO_WEAK_KEY, NULL, 0); |
| else |
| rc = GPG_ERR_NOT_SUPPORTED; |
| break; |
| |
| case 62: /* Return current input vector (private). */ |
| /* This is the input block as used in CFB and OFB mode which has |
| initially been set as IV. The returned format is: |
| 1 byte Actual length of the block in bytes. |
| n byte The block. |
| If the provided buffer is too short, an error is returned. */ |
| if (buflen < (1 + h->cipher->blocksize)) |
| rc = GPG_ERR_TOO_SHORT; |
| else |
| { |
| unsigned char *ivp; |
| unsigned char *dst = buffer; |
| int n = h->unused; |
| |
| if (!n) |
| n = h->cipher->blocksize; |
| gcry_assert (n <= h->cipher->blocksize); |
| *dst++ = n; |
| ivp = h->u_iv.iv + h->cipher->blocksize - n; |
| while (n--) |
| *dst++ = *ivp++; |
| } |
| break; |
| |
| default: |
| rc = GPG_ERR_INV_OP; |
| } |
| |
| return gcry_error (rc); |
| } |
| |
| |
| /* Return information about the cipher handle H. CMD is the kind of |
| information requested. BUFFER and NBYTES are reserved for now. |
| |
| There are no values for CMD yet defined. |
| |
| The fucntion always returns GPG_ERR_INV_OP. |
| |
| */ |
| gcry_error_t |
| gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes) |
| { |
| gcry_err_code_t err = GPG_ERR_NO_ERROR; |
| |
| (void)h; |
| (void)buffer; |
| (void)nbytes; |
| |
| switch (cmd) |
| { |
| default: |
| err = GPG_ERR_INV_OP; |
| } |
| |
| return gcry_error (err); |
| } |
| |
| /* Return information about the given cipher algorithm ALGO. |
| |
| WHAT select the kind of information returned: |
| |
| GCRYCTL_GET_KEYLEN: |
| Return the length of the key. If the algorithm ALGO |
| supports multiple key lengths, the maximum supported key length |
| is returned. The key length is returned as number of octets. |
| BUFFER and NBYTES must be zero. |
| |
| GCRYCTL_GET_BLKLEN: |
| Return the blocklength of the algorithm ALGO counted in octets. |
| BUFFER and NBYTES must be zero. |
| |
| GCRYCTL_TEST_ALGO: |
| Returns 0 if the specified algorithm ALGO is available for use. |
| BUFFER and NBYTES must be zero. |
| |
| Note: Because this function is in most cases used to return an |
| integer value, we can make it easier for the caller to just look at |
| the return value. The caller will in all cases consult the value |
| and thereby detecting whether a error occured or not (i.e. while |
| checking the block size) |
| */ |
| gcry_error_t |
| gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes) |
| { |
| gcry_err_code_t err = GPG_ERR_NO_ERROR; |
| unsigned int ui; |
| |
| switch (what) |
| { |
| case GCRYCTL_GET_KEYLEN: |
| if (buffer || (! nbytes)) |
| err = GPG_ERR_CIPHER_ALGO; |
| else |
| { |
| ui = cipher_get_keylen (algo); |
| if ((ui > 0) && (ui <= 512)) |
| *nbytes = (size_t) ui / 8; |
| else |
| /* The only reason is an invalid algo or a strange |
| blocksize. */ |
| err = GPG_ERR_CIPHER_ALGO; |
| } |
| break; |
| |
| case GCRYCTL_GET_BLKLEN: |
| if (buffer || (! nbytes)) |
| err = GPG_ERR_CIPHER_ALGO; |
| else |
| { |
| ui = cipher_get_blocksize (algo); |
| if ((ui > 0) && (ui < 10000)) |
| *nbytes = ui; |
| else |
| /* The only reason is an invalid algo or a strange |
| blocksize. */ |
| err = GPG_ERR_CIPHER_ALGO; |
| } |
| break; |
| |
| case GCRYCTL_TEST_ALGO: |
| if (buffer || nbytes) |
| err = GPG_ERR_INV_ARG; |
| else |
| err = check_cipher_algo (algo); |
| break; |
| |
| default: |
| err = GPG_ERR_INV_OP; |
| } |
| |
| return gcry_error (err); |
| } |
| |
| |
| /* This function returns length of the key for algorithm ALGO. If the |
| algorithm supports multiple key lengths, the maximum supported key |
| length is returned. On error 0 is returned. The key length is |
| returned as number of octets. |
| |
| This is a convenience functions which should be preferred over |
| gcry_cipher_algo_info because it allows for proper type |
| checking. */ |
| size_t |
| gcry_cipher_get_algo_keylen (int algo) |
| { |
| size_t n; |
| |
| if (gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &n)) |
| n = 0; |
| return n; |
| } |
| |
| /* This functions returns the blocklength of the algorithm ALGO |
| counted in octets. On error 0 is returned. |
| |
| This is a convenience functions which should be preferred over |
| gcry_cipher_algo_info because it allows for proper type |
| checking. */ |
| size_t |
| gcry_cipher_get_algo_blklen (int algo) |
| { |
| size_t n; |
| |
| if (gcry_cipher_algo_info( algo, GCRYCTL_GET_BLKLEN, NULL, &n)) |
| n = 0; |
| return n; |
| } |
| |
| /* Explicitly initialize this module. */ |
| gcry_err_code_t |
| _gcry_cipher_init (void) |
| { |
| gcry_err_code_t err = GPG_ERR_NO_ERROR; |
| |
| REGISTER_DEFAULT_CIPHERS; |
| |
| return err; |
| } |
| |
| /* Get a list consisting of the IDs of the loaded cipher modules. If |
| LIST is zero, write the number of loaded cipher modules to |
| LIST_LENGTH and return. If LIST is non-zero, the first |
| *LIST_LENGTH algorithm IDs are stored in LIST, which must be of |
| according size. In case there are less cipher modules than |
| *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ |
| gcry_error_t |
| gcry_cipher_list (int *list, int *list_length) |
| { |
| gcry_err_code_t err = GPG_ERR_NO_ERROR; |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| err = _gcry_module_list (ciphers_registered, list, list_length); |
| ath_mutex_unlock (&ciphers_registered_lock); |
| |
| return err; |
| } |
| |
| |
| /* Run the selftests for cipher algorithm ALGO with optional reporting |
| function REPORT. */ |
| gpg_error_t |
| _gcry_cipher_selftest (int algo, int extended, selftest_report_func_t report) |
| { |
| gcry_module_t module = NULL; |
| cipher_extra_spec_t *extraspec = NULL; |
| gcry_err_code_t ec = 0; |
| |
| REGISTER_DEFAULT_CIPHERS; |
| |
| ath_mutex_lock (&ciphers_registered_lock); |
| module = _gcry_module_lookup_id (ciphers_registered, algo); |
| if (module && !(module->flags & FLAG_MODULE_DISABLED)) |
| extraspec = module->extraspec; |
| ath_mutex_unlock (&ciphers_registered_lock); |
| if (extraspec && extraspec->selftest) |
| ec = extraspec->selftest (algo, extended, report); |
| else |
| { |
| ec = GPG_ERR_CIPHER_ALGO; |
| if (report) |
| report ("cipher", algo, "module", |
| module && !(module->flags & FLAG_MODULE_DISABLED)? |
| "no selftest available" : |
| module? "algorithm disabled" : "algorithm not found"); |
| } |
| |
| if (module) |
| { |
| ath_mutex_lock (&ciphers_registered_lock); |
| _gcry_module_release (module); |
| ath_mutex_unlock (&ciphers_registered_lock); |
| } |
| return gpg_error (ec); |
| } |