/* 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); }
/* 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); }
/* 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; }
/* 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); }
/* 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); }
/* Take the pool lock. */ static void lock_pool (void) { int err; err = ath_mutex_lock (&pool_lock); if (err) log_fatal ("failed to acquire the pool lock: %s\n", strerror (err)); pool_is_locked = 1; }
/* * Return a pointer to a randomized buffer of LEVEL and NBYTES length. * Caller must free the buffer. */ static byte * get_random_bytes ( size_t nbytes, int level, int secure) { byte *buf, *p; int err; /* First a hack toavoid the strong random using our regression test suite. */ if (quick_test && level > 1) level = 1; /* Make sure the requested level is in range. */ MASK_LEVEL(level); /* Lock the pool. */ err = ath_mutex_lock (&pool_lock); if (err) log_fatal ("failed to acquire the pool lock: %s\n", strerror (err)); pool_is_locked = 1; /* Keep some statistics. */ if (level >= 2) { rndstats.getbytes2 += nbytes; rndstats.ngetbytes2++; } else { rndstats.getbytes1 += nbytes; rndstats.ngetbytes1++; } /* Allocate the return buffer. */ buf = secure && secure_alloc ? gcry_xmalloc_secure( nbytes ) : gcry_xmalloc( nbytes ); /* Fill that buffer with random. */ for (p = buf; nbytes > 0; ) { size_t n; n = nbytes > POOLSIZE? POOLSIZE : nbytes; read_pool( p, n, level ); nbytes -= n; p += n; } /* Release the pool lock. */ pool_is_locked = 0; err = ath_mutex_unlock (&pool_lock); if (err) log_fatal ("failed to release the pool lock: %s\n", strerror (err)); /* Return the buffer. */ return buf; }
/* Acquire the system_rng_lock. */ static void lock_rng (void) { int my_errno; my_errno = ath_mutex_lock (&system_rng_lock); if (my_errno) log_fatal ("failed to acquire the System RNG lock: %s\n", strerror (my_errno)); system_rng_is_locked = 1; }
/* 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; }
/* Public function to fill the buffer with LENGTH bytes of cryptographically strong random bytes. level 0 is not very strong, 1 is strong enough for most usage, 2 is good for key generation stuff but may be very slow. */ void gcry_randomize (void *buffer, size_t length, enum gcry_random_level level) { byte *p; int err; /* Make sure we are initialized. */ if (!is_initialized) initialize (); /* Handle our hack used for regression tests of Libgcrypt. */ if( quick_test && level > 1 ) level = 1; /* Make sure the level is okay. */ MASK_LEVEL(level); /* Acquire the pool lock. */ err = ath_mutex_lock (&pool_lock); if (err) log_fatal ("failed to acquire the pool lock: %s\n", strerror (err)); pool_is_locked = 1; /* Update the statistics. */ if (level >= 2) { rndstats.getbytes2 += length; rndstats.ngetbytes2++; } else { rndstats.getbytes1 += length; rndstats.ngetbytes1++; } /* Read the random into the provided buffer. */ for (p = buffer; length > 0;) { size_t n; n = length > POOLSIZE? POOLSIZE : length; read_pool (p, n, level); length -= n; p += n; } /* Release the pool lock. */ pool_is_locked = 0; err = ath_mutex_unlock (&pool_lock); if (err) log_fatal ("failed to release the pool lock: %s\n", strerror (err)); }
/* 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); }
/* 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; }
static void lock_fsm (void) { gpg_error_t err; err = ath_mutex_lock (&fsm_lock); if (err) { log_info ("FATAL: failed to acquire the FSM lock in libgrypt: %s\n", strerror (err)); #ifdef HAVE_SYSLOG syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " "acquiring FSM lock failed: %s - abort", strerror (err)); #endif /*HAVE_SYSLOG*/ abort (); } }
/* Map the cipher algorithm identifier ALGORITHM to a string representing this algorithm. This string is the default name as used by Libgcrypt. NULL is returned for an unknown algorithm. */ static const char * cipher_algo_to_string (int algorithm) { gcry_module_t cipher; const char *name = NULL; 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); } ath_mutex_unlock (&ciphers_registered_lock); return name; }
/* 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, int *algorithm_id, gcry_module_t *module) { gcry_err_code_t err = 0; gcry_module_t mod; ath_mutex_lock (&ciphers_registered_lock); err = _gcry_module_add (&ciphers_registered, 0, (void *) cipher, &mod); ath_mutex_unlock (&ciphers_registered_lock); if (! err) { *module = mod; *algorithm_id = mod->mod_id; } return gcry_error (err); }
/* Return the block length of the cipher algorithm with the identifier ALGORITHM. This function return 0 for an invalid algorithm. */ 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); } ath_mutex_unlock (&ciphers_registered_lock); return len; }
/* The fast random pool function as called at some places in libgcrypt. This is merely a wrapper to make sure that this module is initalized and to look the pool. Note, that this function is a NOP unless a random function has been used or _gcry_initialize (1) has been used. We use this hack so that the internal use of this function in cipher_open and md_open won't start filling up the radnom pool, even if no random will be required by the process. */ void _gcry_fast_random_poll (void) { int err; if (!is_initialized) return; err = ath_mutex_lock (&pool_lock); if (err) log_fatal ("failed to acquire the pool lock: %s\n", strerror (err)); pool_is_locked = 1; do_fast_random_poll (); pool_is_locked = 0; err = ath_mutex_unlock (&pool_lock); if (err) log_fatal ("failed to acquire the pool lock: %s\n", strerror (err)); }
/* 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; }
/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */ void gcry_create_nonce (void *buffer, size_t length) { static unsigned char nonce_buffer[20+8]; static int nonce_buffer_initialized = 0; static volatile pid_t my_pid; /* The volatile is there to make sure the compiler does not optimize the code away in case the getpid function is badly attributed. */ volatile pid_t apid; unsigned char *p; size_t n; int err; /* First check whether we shall use the FIPS nonce generator. This is only done in FIPS mode, in all other modes, we use our own nonce generator which is seeded by the RNG actual in use. */ if (fips_mode ()) { _gcry_rngfips_create_nonce (buffer, length); return; } /* This is the nonce generator, which formerly lived in random-csprng.c. It is now used by all RNG types except when in FIPS mode (not that this means it is also used if the FIPS RNG has been selected but we are not in fips mode). */ /* Make sure we are initialized. */ _gcry_random_initialize (1); /* Acquire the nonce buffer lock. */ err = ath_mutex_lock (&nonce_buffer_lock); if (err) log_fatal ("failed to acquire the nonce buffer lock: %s\n", strerror (err)); apid = getpid (); /* The first time initialize our buffer. */ if (!nonce_buffer_initialized) { time_t atime = time (NULL); pid_t xpid = apid; my_pid = apid; if ((sizeof apid + sizeof atime) > sizeof nonce_buffer) BUG (); /* Initialize the first 20 bytes with a reasonable value so that a failure of gcry_randomize won't affect us too much. Don't care about the uninitialized remaining bytes. */ p = nonce_buffer; memcpy (p, &xpid, sizeof xpid); p += sizeof xpid; memcpy (p, &atime, sizeof atime); /* Initialize the never changing private part of 64 bits. */ gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); nonce_buffer_initialized = 1; } else if ( my_pid != apid ) { /* We forked. Need to reseed the buffer - doing this for the private part should be sufficient. */ do_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); /* Update the pid so that we won't run into here again and again. */ my_pid = apid; } /* Create the nonce by hashing the entire buffer, returning the hash and updating the first 20 bytes of the buffer with this hash. */ for (p = buffer; length > 0; length -= n, p += n) { _gcry_sha1_hash_buffer (nonce_buffer, nonce_buffer, sizeof nonce_buffer); n = length > 20? 20 : length; memcpy (p, nonce_buffer, n); } /* Release the nonce buffer lock. */ err = ath_mutex_unlock (&nonce_buffer_lock); if (err) log_fatal ("failed to release the nonce buffer lock: %s\n", strerror (err)); }
void _gcry_update_random_seed_file() { unsigned long *sp, *dp; int fd, i; int err; if ( !seed_file_name || !is_initialized || !pool_filled ) return; if ( !allow_seed_file_update ) { log_info(_("note: random_seed file not updated\n")); return; } err = ath_mutex_lock (&pool_lock); if (err) log_fatal ("failed to acquire the pool lock: %s\n", strerror (err)); pool_is_locked = 1; /* copy the entropy pool to a scratch pool and mix both of them */ for (i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) { *dp = *sp + ADD_VALUE; } mix_pool(rndpool); rndstats.mixrnd++; mix_pool(keypool); rndstats.mixkey++; #ifdef HAVE_DOSISH_SYSTEM fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR ); #else fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR ); #endif if (fd == -1 ) log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) ); else { do { i = write (fd, keypool, POOLSIZE ); } while( i == -1 && errno == EINTR ); if (i != POOLSIZE) log_info (_("can't write `%s': %s\n"), seed_file_name, strerror(errno) ); if (close(fd)) log_info(_("can't close `%s': %s\n"), seed_file_name, strerror(errno) ); } pool_is_locked = 0; err = ath_mutex_unlock (&pool_lock); if (err) log_fatal ("failed to release the pool lock: %s\n", strerror (err)); }
/* 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; 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; } 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_CTR: 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: /* FIXME: issue a warning when this mode is used */ break; default: err = GPG_ERR_INV_CIPHER_MODE; } /* ? FIXME: perform selftest here and mark this with a flag in cipher_table ? */ if (! err) { size_t size = (sizeof (*h) + 2 * cipher->contextsize - sizeof (PROPERLY_ALIGNED_TYPE)); if (secure) h = gcry_calloc_secure (1, size); else h = gcry_calloc (1, size); if (! h) err = gpg_err_code_from_errno (errno); else { h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; h->actual_handle_size = size; h->cipher = cipher; h->module = module; h->mode = mode; h->flags = flags; } } /* 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); }
/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */ void gcry_create_nonce (void *buffer, size_t length) { static unsigned char nonce_buffer[20+8]; static int nonce_buffer_initialized = 0; static volatile pid_t my_pid; /* The volatile is there to make sure the compiler does not optimize the code away in case the getpid function is badly attributed. */ volatile pid_t apid; unsigned char *p; size_t n; int err; /* Make sure we are initialized. */ if (!is_initialized) initialize (); /* Acquire the nonce buffer lock. */ err = ath_mutex_lock (&nonce_buffer_lock); if (err) log_fatal ("failed to acquire the nonce buffer lock: %s\n", strerror (err)); apid = getpid (); /* The first time intialize our buffer. */ if (!nonce_buffer_initialized) { time_t atime = time (NULL); pid_t xpid = apid; my_pid = apid; if ((sizeof apid + sizeof atime) > sizeof nonce_buffer) BUG (); /* Initialize the first 20 bytes with a reasonable value so that a failure of gcry_randomize won't affect us too much. Don't care about the uninitialized remaining bytes. */ p = nonce_buffer; memcpy (p, &xpid, sizeof xpid); p += sizeof xpid; memcpy (p, &atime, sizeof atime); /* Initialize the never changing private part of 64 bits. */ gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); nonce_buffer_initialized = 1; } else if ( my_pid != apid ) { /* We forked. Need to reseed the buffer - doing this for the private part should be sufficient. */ gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); /* Update the pid so that we won't run into here again and again. */ my_pid = apid; } /* Create the nonce by hashing the entire buffer, returning the hash and updating the first 20 bytes of the buffer with this hash. */ for (p = buffer; length > 0; length -= n, p += n) { _gcry_sha1_hash_buffer ((char*)nonce_buffer, (char*)nonce_buffer, sizeof nonce_buffer); n = length > 20? 20 : length; memcpy (p, nonce_buffer, n); } /* Release the nonce buffer lock. */ err = ath_mutex_unlock (&nonce_buffer_lock); if (err) log_fatal ("failed to release the nonce buffer lock: %s\n", strerror (err)); }
/* 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 whether 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; } 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_syserror (); 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; h->bulk.ctr_enc = _gcry_aes_ctr_enc; break; #endif /*USE_AES*/ #ifdef USE_BLOWFISH case GCRY_CIPHER_BLOWFISH: h->bulk.cfb_dec = _gcry_blowfish_cfb_dec; h->bulk.cbc_dec = _gcry_blowfish_cbc_dec; h->bulk.ctr_enc = _gcry_blowfish_ctr_enc; break; #endif /*USE_BLOWFISH*/ #ifdef USE_CAST5 case GCRY_CIPHER_CAST5: h->bulk.cfb_dec = _gcry_cast5_cfb_dec; h->bulk.cbc_dec = _gcry_cast5_cbc_dec; h->bulk.ctr_enc = _gcry_cast5_ctr_enc; break; #endif /*USE_CAMELLIA*/ #ifdef USE_CAMELLIA case GCRY_CIPHER_CAMELLIA128: case GCRY_CIPHER_CAMELLIA192: case GCRY_CIPHER_CAMELLIA256: h->bulk.cbc_dec = _gcry_camellia_cbc_dec; h->bulk.cfb_dec = _gcry_camellia_cfb_dec; h->bulk.ctr_enc = _gcry_camellia_ctr_enc; break; #endif /*USE_CAMELLIA*/ #ifdef USE_SERPENT case GCRY_CIPHER_SERPENT128: case GCRY_CIPHER_SERPENT192: case GCRY_CIPHER_SERPENT256: h->bulk.cbc_dec = _gcry_serpent_cbc_dec; h->bulk.cfb_dec = _gcry_serpent_cfb_dec; h->bulk.ctr_enc = _gcry_serpent_ctr_enc; break; #endif /*USE_SERPENT*/ #ifdef USE_TWOFISH case GCRY_CIPHER_TWOFISH: case GCRY_CIPHER_TWOFISH128: h->bulk.cbc_dec = _gcry_twofish_cbc_dec; h->bulk.cfb_dec = _gcry_twofish_cfb_dec; h->bulk.ctr_enc = _gcry_twofish_ctr_enc; break; #endif /*USE_TWOFISH*/ 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); }