static ssize_t enc_read(io_private_t *f, void *d, size_t l) { f->buffer_crypt->offset[1] = l; f->buffer_crypt->offset[2] = 0; while (true) { if (f->buffer_crypt->offset[0] >= f->buffer_crypt->offset[1]) { memcpy(d + f->buffer_crypt->offset[2], f->buffer_crypt->stream, f->buffer_crypt->offset[1]); f->buffer_crypt->offset[0] -= f->buffer_crypt->offset[1]; uint8_t *x = gcry_calloc_secure(f->buffer_crypt->block, sizeof( uint8_t )); if (!x) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, f->buffer_crypt->block * sizeof( uint8_t )); memcpy(x, f->buffer_crypt->stream + f->buffer_crypt->offset[1], f->buffer_crypt->offset[0]); memset(f->buffer_crypt->stream, 0x00, f->buffer_crypt->block); memcpy(f->buffer_crypt->stream, x, f->buffer_crypt->offset[0]); gcry_free(x); return l; } memcpy(d + f->buffer_crypt->offset[2], f->buffer_crypt->stream, f->buffer_crypt->offset[0]); f->buffer_crypt->offset[2] += f->buffer_crypt->offset[0]; f->buffer_crypt->offset[1] -= f->buffer_crypt->offset[0]; f->buffer_crypt->offset[0] = 0; ssize_t e = EXIT_SUCCESS; if ((e = ecc_read(f, f->buffer_crypt->stream, f->buffer_crypt->block)) < 0) return e; #if !defined(__DEBUG__) || defined(__DEBUG_WITH_ENCRYPTION__) gcry_cipher_decrypt(f->cipher_handle, f->buffer_crypt->stream, f->buffer_crypt->block, NULL, 0); #endif f->buffer_crypt->offset[0] = f->buffer_crypt->block; } }
extern IO_HANDLE io_dummy_handle(void) { io_private_t *io_ptr = gcry_calloc_secure(1, sizeof( io_private_t )); io_ptr->fd = -IO_DUMMY_FD; return io_ptr; }
extern void execute(crypto_t *c) { if (!c || c->status != STATUS_INIT) return; pthread_t *t = gcry_calloc_secure(1, sizeof( pthread_t )); pthread_attr_t a; pthread_attr_init(&a); pthread_attr_setdetachstate(&a, PTHREAD_CREATE_JOINABLE); pthread_create(t, &a, c->process, c); c->thread = t; pthread_attr_destroy(&a); return; }
extern version_e is_encrypted_aux(bool b, const char *n, char **c, char **h, char **m) { struct stat s; stat(n, &s); if (S_ISDIR(s.st_mode)) return VERSION_UNKNOWN; int64_t f = open(n, O_RDONLY | F_RDLCK | O_BINARY, S_IRUSR | S_IWUSR); if (f < 0) return VERSION_UNKNOWN; uint64_t head[3] = { 0x0 }; if ((read(f, head, sizeof head)) < 0) return close(f) , VERSION_UNKNOWN; if (head[0] != htonll(HEADER_0) && head[1] != htonll(HEADER_1)) return close(f) , VERSION_UNKNOWN; version_e version = check_version(ntohll(head[2])); if (b) { if (version >= VERSION_2015_10) { /* skips past ECC length byte */ uint8_t b; read(f, &b, sizeof b); } uint8_t l; read(f, &l, sizeof l); char *a = gcry_calloc_secure(l + sizeof( char ), sizeof( char )); read(f, a, l); char *s = strchr(a, '/'); *s = '\0'; s++; char *d = strrchr(s, '/'); if (d) { *d = '\0'; d++; } else d = "CBC"; if (*c) *c = strdup(a); if (*h) *h = strdup(s); if (*m) *m = strdup(d); gcry_free(a); } close(f); return version; }
extern IO_HANDLE io_open(const char *n, int f, mode_t m) { #ifndef _WIN32 int64_t fd = open(n, f, m); #else int64_t fd = open(n, f); #endif if (fd < 0) return NULL; io_private_t *io_ptr = gcry_calloc_secure(1, sizeof( io_private_t )); io_ptr->fd = fd; io_ptr->eof = EOF_NO; return io_ptr; }
gboolean gkm_data_asn1_write_mpi (GNode *asn, gcry_mpi_t mpi) { gcry_error_t gcry; gsize len; guchar *buf; g_return_val_if_fail (asn, FALSE); g_return_val_if_fail (mpi, FALSE); /* Get the size */ gcry = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &len, mpi); g_return_val_if_fail (gcry == 0, FALSE); g_return_val_if_fail (len > 0, FALSE); buf = gcry_calloc_secure (len, 1); gcry = gcry_mpi_print (GCRYMPI_FMT_STD, buf, len, &len, mpi); g_return_val_if_fail (gcry == 0, FALSE); return egg_asn1x_set_integer_as_raw (asn, buf, len, gcry_free); }
/* Unprotect the canconical encoded S-expression key in KEYBUF. GRIP should be the hex encoded keygrip of that key to be used with the caching mechanism. DESC_TEXT may be set to override the default description used for the pinentry. If LOOKUP_TTL is given this function is used to lookup the default ttl. */ static int unprotect (ctrl_t ctrl, const char *desc_text, unsigned char **keybuf, const unsigned char *grip, cache_mode_t cache_mode, lookup_ttl_t lookup_ttl) { struct pin_entry_info_s *pi; struct try_unprotect_arg_s arg; int rc; unsigned char *result; size_t resultlen; char hexgrip[40+1]; bin2hex (grip, 20, hexgrip); /* First try to get it from the cache - if there is none or we can't unprotect it, we fall back to ask the user */ if (cache_mode != CACHE_MODE_IGNORE) { void *cache_marker; const char *pw; retry: pw = agent_get_cache (hexgrip, cache_mode, &cache_marker); if (pw) { rc = agent_unprotect (*keybuf, pw, NULL, &result, &resultlen); agent_unlock_cache_entry (&cache_marker); if (!rc) { xfree (*keybuf); *keybuf = result; return 0; } rc = 0; } /* If the pinentry is currently in use, we wait up to 60 seconds for it to close and check the cache again. This solves a common situation where several requests for unprotecting a key have been made but the user is still entering the passphrase for the first request. Because all requests to agent_askpin are serialized they would then pop up one after the other to request the passphrase - despite that the user has already entered it and is then available in the cache. This implementation is not race free but in the worst case the user has to enter the passphrase only once more. */ if (pinentry_active_p (ctrl, 0)) { /* Active - wait */ if (!pinentry_active_p (ctrl, 60)) { /* We need to give the other thread a chance to actually put it into the cache. */ pth_sleep (1); goto retry; } /* Timeout - better call pinentry now the plain way. */ } } pi = gcry_calloc_secure (1, sizeof (*pi) + 100); if (!pi) return gpg_error_from_syserror (); pi->max_length = 100; pi->min_digits = 0; /* we want a real passphrase */ pi->max_digits = 16; pi->max_tries = 3; pi->check_cb = try_unprotect_cb; arg.ctrl = ctrl; arg.protected_key = *keybuf; arg.unprotected_key = NULL; arg.change_required = 0; pi->check_cb_arg = &arg; rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi); if (!rc) { assert (arg.unprotected_key); if (arg.change_required) { size_t canlen, erroff; gcry_sexp_t s_skey; assert (arg.unprotected_key); canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL); rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)arg.unprotected_key, canlen); if (rc) { log_error ("failed to build S-Exp (off=%u): %s\n", (unsigned int)erroff, gpg_strerror (rc)); wipememory (arg.unprotected_key, canlen); xfree (arg.unprotected_key); xfree (pi); return rc; } rc = agent_protect_and_store (ctrl, s_skey); gcry_sexp_release (s_skey); if (rc) { log_error ("changing the passphrase failed: %s\n", gpg_strerror (rc)); wipememory (arg.unprotected_key, canlen); xfree (arg.unprotected_key); xfree (pi); return rc; } } else agent_put_cache (hexgrip, cache_mode, pi->pin, lookup_ttl? lookup_ttl (hexgrip) : 0); xfree (*keybuf); *keybuf = arg.unprotected_key; } xfree (pi); return rc; }
/* Callback used to ask for the PIN which should be set into BUF. The buf has been allocated by the caller and is of size MAXBUF which includes the terminating null. The function should return an UTF-8 string with the passphrase, the buffer may optionally be padded with arbitrary characters. INFO gets displayed as part of a generic string. However if the first character of INFO is a vertical bar all up to the next verical bar are considered flags and only everything after the second vertical bar gets displayed as the full prompt. Flags: 'N' = New PIN, this requests a second prompt to repeat the PIN. If the PIN is not correctly repeated it starts from all over. 'A' = The PIN is an Admin PIN, SO-PIN or alike. 'P' = The PIN is a PUK (Personal Unblocking Key). 'R' = The PIN is a Reset Code. Example: "|AN|Please enter the new security officer's PIN" The text "Please ..." will get displayed and the flags 'A' and 'N' are considered. */ static int getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) { struct pin_entry_info_s *pi; int rc; ctrl_t ctrl = opaque; const char *ends, *s; int any_flags = 0; int newpin = 0; int resetcode = 0; int is_puk = 0; const char *again_text = NULL; const char *prompt = "PIN"; if (buf && maxbuf < 2) return gpg_error (GPG_ERR_INV_VALUE); /* Parse the flags. */ if (info && *info =='|' && (ends=strchr (info+1, '|'))) { for (s=info+1; s < ends; s++) { if (*s == 'A') prompt = _("Admin PIN"); else if (*s == 'P') { /* TRANSLATORS: A PUK is the Personal Unblocking Code used to unblock a PIN. */ prompt = _("PUK"); is_puk = 1; } else if (*s == 'N') newpin = 1; else if (*s == 'R') { prompt = _("Reset Code"); resetcode = 1; } } info = ends+1; any_flags = 1; } else if (info && *info == '|') log_debug ("pin_cb called without proper PIN info hack\n"); /* If BUF has been passed as NULL, we are in pinpad mode: The callback opens the popup and immediatley returns. */ if (!buf) { if (maxbuf == 0) /* Close the pinentry. */ { agent_popup_message_stop (ctrl); rc = 0; } else if (maxbuf == 1) /* Open the pinentry. */ { if (info) { char *desc; if ( asprintf (&desc, _("%s%%0A%%0AUse the reader's pinpad for input."), info) < 0 ) rc = gpg_error_from_syserror (); else { rc = agent_popup_message_start (ctrl, desc, NULL); xfree (desc); } } else rc = agent_popup_message_start (ctrl, NULL, NULL); } else rc = gpg_error (GPG_ERR_INV_VALUE); return rc; } /* FIXME: keep PI and TRIES in OPAQUE. Frankly this is a whole mess because we should call the card's verify function from the pinentry check pin CB. */ again: pi = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10); if (!pi) return gpg_error_from_syserror (); pi->max_length = maxbuf-1; pi->min_digits = 0; /* we want a real passphrase */ pi->max_digits = 16; pi->max_tries = 3; if (any_flags) { rc = agent_askpin (ctrl, info, prompt, again_text, pi, NULL, 0); again_text = NULL; if (!rc && newpin) { struct pin_entry_info_s *pi2; pi2 = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10); if (!pi2) { rc = gpg_error_from_syserror (); xfree (pi); return rc; } pi2->max_length = maxbuf-1; pi2->min_digits = 0; pi2->max_digits = 16; pi2->max_tries = 1; rc = agent_askpin (ctrl, (resetcode? _("Repeat this Reset Code"): is_puk? _("Repeat this PUK"): _("Repeat this PIN")), prompt, NULL, pi2, NULL, 0); if (!rc && strcmp (pi->pin, pi2->pin)) { again_text = (resetcode? N_("Reset Code not correctly repeated; try again"): is_puk? N_("PUK not correctly repeated; try again"): N_("PIN not correctly repeated; try again")); xfree (pi2); xfree (pi); goto again; } xfree (pi2); } } else { char *desc; if ( asprintf (&desc, _("Please enter the PIN%s%s%s to unlock the card"), info? " (`":"", info? info:"", info? "')":"") < 0) desc = NULL; rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi, NULL, 0); xfree (desc); } if (!rc) { strncpy (buf, pi->pin, maxbuf-1); buf[maxbuf-1] = 0; } xfree (pi); return rc; }
extern void io_encryption_init(IO_HANDLE ptr, enum gcry_cipher_algos c, enum gcry_md_algos h, enum gcry_cipher_modes m, const uint8_t *k, size_t l, io_extra_t x) { io_private_t *io_ptr = ptr; if (!io_ptr || io_ptr->fd < 0) return errno = EBADF , (void)NULL; /* * start setting up the encryption buffer */ if (!(io_ptr->buffer_crypt = gcry_malloc_secure(sizeof( buffer_t )))) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, sizeof( buffer_t )); gcry_md_open(&io_ptr->hash_handle, h, GCRY_MD_FLAG_SECURE); gcry_cipher_open(&io_ptr->cipher_handle, c, m, GCRY_CIPHER_SECURE); /* * generate a hash of the supplied key data */ size_t hash_length = gcry_md_get_algo_dlen(h); uint8_t *hash = gcry_malloc_secure(hash_length); if (!hash) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, hash_length); gcry_md_hash_buffer(gcry_md_get_algo(io_ptr->hash_handle), hash, k, l); /* * set the key as the hash of supplied data */ size_t key_length = gcry_cipher_get_algo_keylen(c); uint8_t *key = gcry_calloc_secure(key_length, sizeof( byte_t )); if (!key) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, key_length); memcpy(key, hash, key_length < hash_length ? key_length : hash_length); gcry_cipher_setkey(io_ptr->cipher_handle, key, key_length); /* here is where it blows-up on Windows 8, using AES */ gcry_free(key); /* * the 2011.* versions (incorrectly) used key length instead of block * length; versions after 2014.06 randomly generate the IV instead */ io_ptr->buffer_crypt->block = gcry_cipher_get_algo_blklen(c); uint8_t *iv = gcry_calloc_secure(x.x_iv == IV_BROKEN ? key_length : io_ptr->buffer_crypt->block, sizeof( byte_t )); if (!iv) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, io_ptr->buffer_crypt->block); if (x.x_iv == IV_RANDOM) { if (x.x_encrypt) { gcry_create_nonce(iv, io_ptr->buffer_crypt->block); io_write(ptr, iv, io_ptr->buffer_crypt->block); } else io_read(ptr, iv, io_ptr->buffer_crypt->block); } else { uint8_t *iv_hash = gcry_malloc_secure(hash_length); if (!iv_hash) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, hash_length); /* * set the IV as the hash of the hash */ gcry_md_hash_buffer(gcry_md_get_algo(io_ptr->hash_handle), iv_hash, hash, hash_length); memcpy(iv, iv_hash, io_ptr->buffer_crypt->block < hash_length ? io_ptr->buffer_crypt->block : hash_length); gcry_free(iv_hash); } gcry_free(hash); if (m == GCRY_CIPHER_MODE_CTR) gcry_cipher_setctr(io_ptr->cipher_handle, iv, io_ptr->buffer_crypt->block); else gcry_cipher_setiv(io_ptr->cipher_handle, iv, io_ptr->buffer_crypt->block); gcry_free(iv); /* * set the rest of the buffer */ if (!(io_ptr->buffer_crypt->stream = gcry_malloc_secure(io_ptr->buffer_crypt->block))) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, io_ptr->buffer_crypt->block); /* * when encrypting/writing data: * 0: length of data buffered so far (in stream) * 1: length of data processed (from d) * when decrypting/reading data: * 0: length of available data in input buffer (stream) * 1: available space in read buffer (d) * 2: next available memory location for data (from d) */ for (unsigned i = 0; i < OFFSET_SLOTS; i++) io_ptr->buffer_crypt->offset[i] = 0; io_ptr->cipher_init = true; io_ptr->hash_init = true; io_ptr->operation = IO_ENCRYPT; return; }
extern IO_HANDLE io_use_stdout(void) { io_private_t *io_ptr = gcry_calloc_secure(1, sizeof( io_private_t )); io_ptr->fd = STDOUT_FILENO; return io_ptr; }
/* 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); }
/* 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); }
/* Unprotect the canconical encoded S-expression key in KEYBUF. GRIP should be the hex encoded keygrip of that key to be used with the caching mechanism. DESC_TEXT may be set to override the default description used for the pinentry. If LOOKUP_TTL is given this function is used to lookup the default ttl. If R_PASSPHRASE is not NULL, the function succeeded and the key was protected the used passphrase (entered or from the cache) is stored there; if not NULL will be stored. The caller needs to free the returned passphrase. */ static int unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, unsigned char **keybuf, const unsigned char *grip, cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, char **r_passphrase) { struct pin_entry_info_s *pi; struct try_unprotect_arg_s arg; int rc; unsigned char *result; size_t resultlen; char hexgrip[40+1]; if (r_passphrase) *r_passphrase = NULL; bin2hex (grip, 20, hexgrip); /* Initially try to get it using a cache nonce. */ if (cache_nonce) { char *pw; pw = agent_get_cache (cache_nonce, CACHE_MODE_NONCE); if (pw) { rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen); if (!rc) { if (r_passphrase) *r_passphrase = pw; else xfree (pw); xfree (*keybuf); *keybuf = result; return 0; } xfree (pw); } } /* First try to get it from the cache - if there is none or we can't unprotect it, we fall back to ask the user */ if (cache_mode != CACHE_MODE_IGNORE) { char *pw; retry: pw = agent_get_cache (hexgrip, cache_mode); if (pw) { rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen); if (!rc) { if (cache_mode == CACHE_MODE_NORMAL) agent_store_cache_hit (hexgrip); if (r_passphrase) *r_passphrase = pw; else xfree (pw); xfree (*keybuf); *keybuf = result; return 0; } xfree (pw); rc = 0; } else if (cache_mode == CACHE_MODE_NORMAL) { /* The standard use of GPG keys is to have a signing and an encryption subkey. Commonly both use the same passphrase. We try to help the user to enter the passphrase only once by silently trying the last correctly entered passphrase. Checking one additional passphrase should be acceptable; despite the S2K introduced delays. The assumed workflow is: 1. Read encrypted message in a MUA and thus enter a passphrase for the encryption subkey. 2. Reply to that mail with an encrypted and signed mail, thus entering the passphrase for the signing subkey. We can often avoid the passphrase entry in the second step. We do this only in normal mode, so not to interfere with unrelated cache entries. */ pw = agent_get_cache (NULL, cache_mode); if (pw) { rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen); if (!rc) { if (r_passphrase) *r_passphrase = pw; else xfree (pw); xfree (*keybuf); *keybuf = result; return 0; } xfree (pw); rc = 0; } } /* If the pinentry is currently in use, we wait up to 60 seconds for it to close and check the cache again. This solves a common situation where several requests for unprotecting a key have been made but the user is still entering the passphrase for the first request. Because all requests to agent_askpin are serialized they would then pop up one after the other to request the passphrase - despite that the user has already entered it and is then available in the cache. This implementation is not race free but in the worst case the user has to enter the passphrase only once more. */ if (pinentry_active_p (ctrl, 0)) { /* Active - wait */ if (!pinentry_active_p (ctrl, 60)) { /* We need to give the other thread a chance to actually put it into the cache. */ npth_sleep (1); goto retry; } /* Timeout - better call pinentry now the plain way. */ } } pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1); if (!pi) return gpg_error_from_syserror (); pi->max_length = MAX_PASSPHRASE_LEN + 1; pi->min_digits = 0; /* we want a real passphrase */ pi->max_digits = 16; pi->max_tries = 3; pi->check_cb = try_unprotect_cb; arg.ctrl = ctrl; arg.protected_key = *keybuf; arg.unprotected_key = NULL; arg.change_required = 0; pi->check_cb_arg = &arg; rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi, hexgrip, cache_mode); if (!rc) { assert (arg.unprotected_key); if (arg.change_required) { /* The callback told as that the user should change their passphrase. Present the dialog to do. */ size_t canlen, erroff; gcry_sexp_t s_skey; assert (arg.unprotected_key); canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL); rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)arg.unprotected_key, canlen); if (rc) { log_error ("failed to build S-Exp (off=%u): %s\n", (unsigned int)erroff, gpg_strerror (rc)); wipememory (arg.unprotected_key, canlen); xfree (arg.unprotected_key); xfree (pi); return rc; } rc = agent_protect_and_store (ctrl, s_skey, NULL); gcry_sexp_release (s_skey); if (rc) { log_error ("changing the passphrase failed: %s\n", gpg_strerror (rc)); wipememory (arg.unprotected_key, canlen); xfree (arg.unprotected_key); xfree (pi); return rc; } } else { /* Passphrase is fine. */ agent_put_cache (hexgrip, cache_mode, pi->pin, lookup_ttl? lookup_ttl (hexgrip) : 0); agent_store_cache_hit (hexgrip); if (r_passphrase && *pi->pin) *r_passphrase = xtrystrdup (pi->pin); } xfree (*keybuf); *keybuf = arg.unprotected_key; } xfree (pi); return rc; }
int main (int argc, char **argv) { /* Parse arguments */ if(opt_parse("usage: %s < filename > [options]", options, argv) == 0) { opt_help(0, NULL); } /* Read in password */ char *pass = NULL; size_t passLen = 0; ssize_t passRead; char *fileName; printf("Password: "******"libgcrypt version mismatch\n", stderr); exit (2); } gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN); gcry_control(GCRYCTL_INIT_SECMEM, 131072, 0); gcry_control(GCRYCTL_RESUME_SECMEM_WARN); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); /* Key Generation */ char key[16] = ""; size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER); const char *salt = "NaCl"; size_t saltLen = sizeof(salt); unsigned long iterations = 4096; gpg_error_t errStatus; errStatus = gcry_kdf_derive(pass, passLen, GCRY_KDF_PBKDF2, GCRY_MD_SHA512, salt, saltLen, iterations, keyLength, key); /* Cipher Setup */ // printf("Key: %X\n", key); puts(key); const char* IV = "5844"; // const int IV = 5844; const char *name = "aes128"; int algorithm = gcry_cipher_map_name(name); size_t blockLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER); gcry_cipher_hd_t hand; gcry_cipher_open(&hand, algorithm, GCRY_CIPHER_MODE_CBC, 0); gcry_cipher_setkey(hand, key, keyLength); gcry_cipher_setiv(hand, IV, blockLength); char *buffer; long len; size_t macLen = 0; /* If the local flag is set then we encrypt the file locally instead of sending it over the network Otherwise we send the file over the network */ if (local == 1) { /* Open the file for reading and then copy to a buffer */ FILE *ifp = fopen(argv[1], "rb"); if(ifp == 0) { printf("%s", "Could not open file"); return 1; } // Lets figure out how big the file is fseek(ifp, 0L, SEEK_END); len = ftell(ifp); rewind(ifp); // Allocate secure RAM for the buffer buffer = gcry_calloc_secure(len, sizeof(char)); // Copy the input file to the buffer fread(buffer, 1, len, ifp); // Since we're running locally, the name of the output file is the same as the argument // without the .gt fileName = argv[1]; size_t inLen = strlen(fileName); // End the filename by replacing the "." with a NULL char fileName[inLen-3] = '\0'; fclose(ifp); } else { /* Retrieve file from remote computer Open a socket and listen for communication */ int sock; int localSock; struct sockaddr_in inPort; inPort.sin_family = AF_INET; inPort.sin_addr.s_addr = INADDR_ANY; inPort.sin_port = htons(port); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { printf("%s", "Could not open socket"); exit(1); } bind(sock, (struct sockaddr *) &inPort, sizeof(inPort)); listen(sock, 0); printf("%s", "Waiting for connection...\n"); // Accepting the connection localSock = accept(sock, NULL, NULL); printf("%s", "Inbound file...\n"); // Allocate some memory for the buffer // len+(160(len%16)) is so that the memory we allocate is divisible // by the blocklength, which is 16 len = 4096L; buffer = gcry_calloc_secure(len+(16-(len%16)), sizeof(char)); long dataRead = 0L; int keepReading = 1; // Let's figure out how much data we're getting // If I were to do this part over, I would instead open two connections // from techrypt- where the first connection sends the // amount of data to be transmitted in the second connection while (keepReading) { dataRead = recv(localSock, buffer, len, MSG_PEEK); if (dataRead == len) { len = len * 2; sleep(.5); buffer = gcry_realloc(buffer, len); keepReading = 1; } else { keepReading = 0; } } // How much data did we read? len = dataRead; // Now lets actually store it in the buffer dataRead = recv(localSock, buffer, len, 0); // Output file name is the command line argument fileName = argv[1]; close(sock); /* Setup the HMAC */ gcry_md_hd_t macHand; macLen = gcry_md_get_algo_dlen(GCRY_MD_SHA512); char *mac = gcry_calloc_secure(macLen, sizeof(char)); gcry_md_open(&macHand, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC); gcry_md_setkey(macHand, key, keyLength); // Generate the HMAC for the message we received // Since we know there's a MAC of size macLen at the end // we will only generate the hash based on the first // len-macLen bytes gcry_md_write(macHand, buffer, len-macLen); mac = gcry_md_read(macHand, 0); /* Strip HMAC from buffer */ char *exMac = buffer+(len-macLen); /* Check HMAC against our HMAC */ // I think this may be exploitable with a strategically placed NULL // The use of memcmp could fix this...if I have time I will replace and check if(strncmp(mac, exMac, macLen) != 0) { exit(62); } } /* Decrypt the buffer */ gcry_cipher_decrypt(hand, buffer, len, NULL, 0); /* Reverse padding algorithm Strip the amount of bytes from the end of the file determined by the contents of the last byte This is why using PKCS7 was so useful */ char *padPtr = buffer+len-macLen-1; int writeLen = len-macLen-(*padPtr); /* Write the buffer to a file */ FILE *ofp = fopen(fileName, "wb"); fwrite(buffer, 1, writeLen, ofp); fclose(ofp); return 0; }