/* Derive the 33 subkeys from KEY and store them in SUBKEYS. */ static void serpent_subkeys_generate (serpent_key_t key, serpent_subkeys_t subkeys) { u32 w[8]; /* The `prekey'. */ u32 ws[4]; u32 wt[4]; /* Initialize with key values. */ w[0] = key[0]; w[1] = key[1]; w[2] = key[2]; w[3] = key[3]; w[4] = key[4]; w[5] = key[5]; w[6] = key[6]; w[7] = key[7]; /* Expand to intermediate key using the affine recurrence. */ #define EXPAND_KEY4(wo, r) \ wo[0] = w[(r+0)%8] = \ rol (w[(r+0)%8] ^ w[(r+3)%8] ^ w[(r+5)%8] ^ w[(r+7)%8] ^ PHI ^ (r+0), 11); \ wo[1] = w[(r+1)%8] = \ rol (w[(r+1)%8] ^ w[(r+4)%8] ^ w[(r+6)%8] ^ w[(r+0)%8] ^ PHI ^ (r+1), 11); \ wo[2] = w[(r+2)%8] = \ rol (w[(r+2)%8] ^ w[(r+5)%8] ^ w[(r+7)%8] ^ w[(r+1)%8] ^ PHI ^ (r+2), 11); \ wo[3] = w[(r+3)%8] = \ rol (w[(r+3)%8] ^ w[(r+6)%8] ^ w[(r+0)%8] ^ w[(r+2)%8] ^ PHI ^ (r+3), 11); #define EXPAND_KEY(r) \ EXPAND_KEY4(ws, (r)); \ EXPAND_KEY4(wt, (r + 4)); /* Calculate subkeys via S-Boxes, in bitslice mode. */ EXPAND_KEY (0); SBOX (3, ws, subkeys[0]); SBOX (2, wt, subkeys[1]); EXPAND_KEY (8); SBOX (1, ws, subkeys[2]); SBOX (0, wt, subkeys[3]); EXPAND_KEY (16); SBOX (7, ws, subkeys[4]); SBOX (6, wt, subkeys[5]); EXPAND_KEY (24); SBOX (5, ws, subkeys[6]); SBOX (4, wt, subkeys[7]); EXPAND_KEY (32); SBOX (3, ws, subkeys[8]); SBOX (2, wt, subkeys[9]); EXPAND_KEY (40); SBOX (1, ws, subkeys[10]); SBOX (0, wt, subkeys[11]); EXPAND_KEY (48); SBOX (7, ws, subkeys[12]); SBOX (6, wt, subkeys[13]); EXPAND_KEY (56); SBOX (5, ws, subkeys[14]); SBOX (4, wt, subkeys[15]); EXPAND_KEY (64); SBOX (3, ws, subkeys[16]); SBOX (2, wt, subkeys[17]); EXPAND_KEY (72); SBOX (1, ws, subkeys[18]); SBOX (0, wt, subkeys[19]); EXPAND_KEY (80); SBOX (7, ws, subkeys[20]); SBOX (6, wt, subkeys[21]); EXPAND_KEY (88); SBOX (5, ws, subkeys[22]); SBOX (4, wt, subkeys[23]); EXPAND_KEY (96); SBOX (3, ws, subkeys[24]); SBOX (2, wt, subkeys[25]); EXPAND_KEY (104); SBOX (1, ws, subkeys[26]); SBOX (0, wt, subkeys[27]); EXPAND_KEY (112); SBOX (7, ws, subkeys[28]); SBOX (6, wt, subkeys[29]); EXPAND_KEY (120); SBOX (5, ws, subkeys[30]); SBOX (4, wt, subkeys[31]); EXPAND_KEY4 (ws, 128); SBOX (3, ws, subkeys[32]); wipememory (ws, sizeof (ws)); wipememory (wt, sizeof (wt)); wipememory (w, sizeof (w)); }
static void fpm_rotate(gchar* field, gint len) { /* After we use addnoise (above) we ensure blocks don't look identical * unless all 8 chars in the block are part of the password. This * routine makes us use all three blocks equally rather than fill the * first, then the second, etc. This makes it so none of the blocks * in the password will remain constant from save to save, even if the * password is from 7-20 characters long. Note that passwords from * 21-24 characters start to fill blocks, and so will be constant. */ gint num_blocks; gchar* tmp; gint b, i; g_assert(blocksize>0); num_blocks = len/blocksize; g_assert(len==num_blocks*blocksize); tmp=g_malloc0(len+1); for(b=0;b<num_blocks;b++) { for(i=0;i<blocksize;i++) tmp[b*blocksize+i] = field[i*num_blocks+b]; } memcpy(field, tmp, len); wipememory(tmp, len); g_free(tmp); }
static void encode_seskey( DEK *dek, DEK **seskey, byte *enckey ) { CIPHER_HANDLE hd; byte buf[33]; assert ( dek->keylen <= 32 ); if(!*seskey) { *seskey=xmalloc_clear(sizeof(DEK)); (*seskey)->keylen=dek->keylen; (*seskey)->algo=dek->algo; make_session_key(*seskey); /*log_hexdump( "thekey", c->key, c->keylen );*/ } buf[0] = (*seskey)->algo; memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen ); hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 ); cipher_setkey( hd, dek->key, dek->keylen ); cipher_setiv( hd, NULL, 0 ); cipher_encrypt( hd, buf, buf, (*seskey)->keylen + 1 ); cipher_close( hd ); memcpy( enckey, buf, (*seskey)->keylen + 1 ); wipememory( buf, sizeof buf ); /* burn key */ }
/* Initialize CONTEXT with the key KEY of KEY_LENGTH bits. */ static void serpent_setkey_internal (serpent_context_t *context, const byte *key, unsigned int key_length) { serpent_key_t key_prepared; serpent_key_prepare (key, key_length, key_prepared); serpent_subkeys_generate (key_prepared, context->keys); #ifdef USE_AVX2 context->use_avx2 = 0; if ((_gcry_get_hw_features () & HWF_INTEL_AVX2)) { context->use_avx2 = 1; } #endif #ifdef USE_NEON context->use_neon = 0; if ((_gcry_get_hw_features () & HWF_ARM_NEON)) { context->use_neon = 1; } #endif wipememory (key_prepared, sizeof(key_prepared)); }
static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ) { int i, rc = 0; u32 n; byte buf[1000]; /* this buffer has the plaintext! */ int nbytes; write_header(out, ctb, calc_plaintext( pt ) ); iobuf_put(out, pt->mode ); iobuf_put(out, pt->namelen ); for(i=0; i < pt->namelen; i++ ) iobuf_put(out, pt->name[i] ); rc = write_32(out, pt->timestamp ); if (rc) return rc; n = 0; while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) { rc = iobuf_write (out, buf, nbytes); if (rc) break; n += nbytes; } wipememory(buf,1000); /* burn the buffer */ if( (ctb&0x40) && !pt->len ) iobuf_set_partial_block_mode(out, 0 ); /* turn off partial */ if( pt->len && n != pt->len ) log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n", (ulong)n, (ulong)pt->len ); return rc; }
static void encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey) { gcry_cipher_hd_t hd; byte buf[33]; assert ( dek->keylen <= 32 ); if (!*seskey) { *seskey=xmalloc_clear(sizeof(DEK)); (*seskey)->keylen=dek->keylen; (*seskey)->algo=dek->algo; make_session_key(*seskey); /*log_hexdump( "thekey", c->key, c->keylen );*/ } /* The encrypted session key is prefixed with a one-octet algorithm id. */ buf[0] = (*seskey)->algo; memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen ); /* We only pass already checked values to the following fucntion, thus we consider any failure as fatal. */ if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1)) BUG (); if (gcry_cipher_setkey (hd, dek->key, dek->keylen)) BUG (); gcry_cipher_setiv (hd, NULL, 0); gcry_cipher_encrypt (hd, buf, (*seskey)->keylen + 1, NULL, 0); gcry_cipher_close (hd); memcpy( enckey, buf, (*seskey)->keylen + 1 ); wipememory( buf, sizeof buf ); /* burn key */ }
/* Read data from the system RNG if availavle. */ static void read_system_rng (void (*add)(const void*, size_t, enum random_origins), enum random_origins requester) { BYTE buffer[ SYSTEMRNG_BYTES + 8 ]; int quality = 0; if (!system_rng_available) return; /* Read SYSTEMRNG_BYTES bytes from the system RNG. We don't rely on this for all our randomness requirements (particularly the software RNG) in case it's broken in some way. */ if (hRNGProv) { if (pCryptGenRandom (hRNGProv, SYSTEMRNG_BYTES, buffer)) quality = 80; } else if (pRtlGenRandom) { if ( pRtlGenRandom (buffer, SYSTEMRNG_BYTES)) quality = 50; } if (quality > 0) { if (debug_me) log_debug ("rndw32#read_system_rng: got %d bytes of quality %d\n", SYSTEMRNG_BYTES, quality); (*add) (buffer, SYSTEMRNG_BYTES, requester); wipememory (buffer, SYSTEMRNG_BYTES); } }
/* 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) { 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. */ wipememory (h, h->actual_handle_size); gcry_free (h); }
/* 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; /* 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); xfree ((char*)h - off); }
/* Bulk decryption of complete blocks in CBC mode. This function is only intended for the bulk encryption feature of cipher.c. */ void _gcry_blowfish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, const void *inbuf_arg, size_t nblocks) { BLOWFISH_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; unsigned char savebuf[BLOWFISH_BLOCKSIZE]; int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE; #ifdef USE_AMD64_ASM { if (nblocks >= 4) burn_stack_depth += 5 * sizeof(void*); /* Process data in 4 block chunks. */ while (nblocks >= 4) { _gcry_blowfish_amd64_cbc_dec(ctx, outbuf, inbuf, iv); nblocks -= 4; outbuf += 4 * BLOWFISH_BLOCKSIZE; inbuf += 4 * BLOWFISH_BLOCKSIZE; } /* Use generic code to handle smaller chunks... */ } #elif defined(USE_ARM_ASM) { /* Process data in 2 block chunks. */ while (nblocks >= 2) { _gcry_blowfish_arm_cbc_dec(ctx, outbuf, inbuf, iv); nblocks -= 2; outbuf += 2 * BLOWFISH_BLOCKSIZE; inbuf += 2 * BLOWFISH_BLOCKSIZE; } /* Use generic code to handle smaller chunks... */ } #endif for ( ;nblocks; nblocks-- ) { /* INBUF is needed later and it may be identical to OUTBUF, so store the intermediate result to SAVEBUF. */ do_decrypt_block (ctx, savebuf, inbuf); buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE); inbuf += BLOWFISH_BLOCKSIZE; outbuf += BLOWFISH_BLOCKSIZE; } wipememory(savebuf, sizeof(savebuf)); _gcry_burn_stack(burn_stack_depth); }
void _gcry_burn_stack (int bytes) { char buf[64]; wipememory (buf, sizeof buf); bytes -= sizeof buf; if (bytes > 0) _gcry_burn_stack (bytes); }
static void burn_stack (int bytes) { char buf[128]; wipememory(buf,sizeof buf); bytes -= sizeof buf; if (bytes > 0) burn_stack (bytes); }
void fpm_crypt_set_password(gchar *password) { gchar *prehash = ""; byte *hash; new_salt = get_new_salt(cipher->salt_len); hash = g_malloc(cipher->hash_len); if(cipher_algo == AES256) { fpm_pkcs5_pbkdf2((guchar *)password, strlen(password), new_salt, cipher->salt_len, hash, cipher->hash_len, PBKDF2_ITERATIONS); } else { prehash = g_strdup_printf("%s%s", new_salt, password); md5(prehash, hash); } fpm_setkey(new_context, hash, cipher->hash_len); if (cipher_algo == BLOWFISH) wipememory(prehash, strlen(prehash)); wipememory(hash, cipher->hash_len); g_free(hash); }
void fpm_crypt_init(gchar* password) { gchar *prehash1 = "", *prehash2 = ""; byte *hash_1, *hash_2; old_context = g_malloc(cipher->contextsize); new_context = g_malloc(cipher->contextsize); hash_1 = g_malloc(cipher->hash_len); hash_2 = g_malloc(cipher->hash_len); if(cipher_algo == AES256) { fpm_pkcs5_pbkdf2((guchar *)password, strlen(password), old_salt, cipher->salt_len, hash_1, cipher->hash_len, PBKDF2_ITERATIONS); fpm_pkcs5_pbkdf2((guchar *)password, strlen(password), new_salt, cipher->salt_len, hash_2, cipher->hash_len, PBKDF2_ITERATIONS); } else { prehash1 = g_strdup_printf("%s%s", old_salt, password); prehash2 = g_strdup_printf("%s%s", new_salt, password); md5(prehash1, hash_1); md5(prehash2, hash_2); } fpm_setkey(old_context, hash_1, cipher->hash_len); fpm_setkey(new_context, hash_2, cipher->hash_len); wipememory(hash_1, cipher->hash_len); wipememory(hash_2, cipher->hash_len); g_free(hash_1); g_free(hash_2); if (cipher_algo == BLOWFISH) { wipememory(prehash1, strlen(prehash1)); wipememory(prehash2, strlen(prehash2)); g_free(prehash1); g_free(prehash2); } }
void _gcry_mpi_free_limb_space( mpi_ptr_t a, unsigned int nlimbs) { if (a) { size_t len = nlimbs * sizeof(mpi_limb_t); /* If we have information on the number of allocated limbs, we better wipe that space out. This is a failsafe feature if secure memory has been disabled or was not properly implemented in user provided allocation functions. */ if (len) wipememory (a, len); xfree(a); } }
static gcry_err_code_t do_arcfour_setkey (void *context, const byte *key, unsigned int keylen) { static int initialized; static const char* selftest_failed; int i, j; byte karr[256]; ARCFOUR_context *ctx = (ARCFOUR_context *) context; if (!initialized ) { initialized = 1; selftest_failed = selftest(); if( selftest_failed ) log_error ("ARCFOUR selftest failed (%s)\n", selftest_failed ); } if( selftest_failed ) return GPG_ERR_SELFTEST_FAILED; if( keylen < 40/8 ) /* we want at least 40 bits */ return GPG_ERR_INV_KEYLEN; ctx->idx_i = ctx->idx_j = 0; for (i=0; i < 256; i++ ) ctx->sbox[i] = i; for (i=j=0; i < 256; i++,j++ ) { if (j >= keylen) j = 0; karr[i] = key[j]; } for (i=j=0; i < 256; i++ ) { int t; j = (j + ctx->sbox[i] + karr[i]) & 255; t = ctx->sbox[i]; ctx->sbox[i] = ctx->sbox[j]; ctx->sbox[j] = t; } wipememory( karr, sizeof(karr) ); return GPG_ERR_NO_ERROR; }
/* Create a new session key and append it as a tuple to the memory buffer MB. The EncFS daemon takes a passphrase from stdin and internally mangles it by means of some KDF from OpenSSL. We want to store a binary key but we need to make sure that certain characters are not used because the EncFS utility reads it from stdin and obviously acts on some of the characters. This we replace CR (in case of an MSDOS version of EncFS), LF (the delimiter used by EncFS) and Nul (because it is unlikely to work). We use 32 bytes (256 bit) because that is sufficient for the largest cipher (AES-256) and in addition gives enough margin for a possible entropy degradation by the KDF. */ gpg_error_t be_encfs_create_new_keys (membuf_t *mb) { char *buffer; int i, j; /* Allocate a buffer of 32 bytes plus 8 spare bytes we may need to replace the unwanted values. */ buffer = xtrymalloc_secure (32+8); if (!buffer) return gpg_error_from_syserror (); /* Randomize the buffer. STRONG random should be enough as it is a good compromise between security and performance. The anticipated usage of this tool is the quite often creation of new containers and thus this should not deplete the system's entropy tool too much. */ gcry_randomize (buffer, 32+8, GCRY_STRONG_RANDOM); for (i=j=0; i < 32; i++) { if (buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == 0 ) { /* Replace. */ if (j == 8) { /* Need to get more random. */ gcry_randomize (buffer+32, 8, GCRY_STRONG_RANDOM); j = 0; } buffer[i] = buffer[32+j]; j++; } } /* Store the key. */ append_tuple (mb, KEYBLOB_TAG_ENCKEY, buffer, 32); /* Free the temporary buffer. */ wipememory (buffer, 32+8); /* A failsafe extra wiping. */ xfree (buffer); return 0; }
static void fpm_unrotate(gchar* field, gint len) { gint num_blocks; gchar* tmp; gint b, i; g_assert(blocksize>0); num_blocks = len/blocksize; g_assert(len==num_blocks*blocksize); tmp=g_malloc0(len+1); for(b=0;b<num_blocks;b++) { for(i=0;i<blocksize;i++) tmp[i*num_blocks+b] = field[b*blocksize+i]; } memcpy(field, tmp, len); wipememory(tmp, len); g_free(tmp); }
gchar* fpm_encrypt_field_var( void* context, gchar* plaintext) { gint num_blocks, len; gchar* cipher_field; gchar* plain_field; num_blocks = (strlen(plaintext)/(blocksize-1))+1; len = num_blocks*blocksize; plain_field = g_malloc0(len+1); strncpy(plain_field, plaintext, len); cipher_field = g_malloc0((len*2)+1); fpm_encrypt_field(context, cipher_field, plain_field, num_blocks*blocksize); wipememory(plain_field, len); g_free(plain_field); return(cipher_field); }
static void salsa20_setiv (void *context, const byte *iv, unsigned int ivlen) { SALSA20_context_t *ctx = (SALSA20_context_t *)context; byte tmp[SALSA20_IV_SIZE]; if (iv && ivlen != SALSA20_IV_SIZE) log_info ("WARNING: salsa20_setiv: bad ivlen=%u\n", ivlen); if (!iv || ivlen != SALSA20_IV_SIZE) memset (tmp, 0, sizeof(tmp)); else memcpy (tmp, iv, SALSA20_IV_SIZE); ctx->ivsetup (ctx, tmp); /* Reset the unused pad bytes counter. */ ctx->unused = 0; wipememory (tmp, sizeof(tmp)); }
/**************** * Release resource of the given SEXP object. */ void gcry_sexp_release( gcry_sexp_t sexp ) { if (sexp) { if (gcry_is_secure (sexp)) { /* Extra paranoid wiping. */ const byte *p = sexp->d; int type; while ( (type = *p) != ST_STOP ) { p++; switch ( type ) { case ST_OPEN: break; case ST_CLOSE: break; case ST_DATA: { DATALEN n; memcpy ( &n, p, sizeof n ); p += sizeof n; p += n; } break; default: break; } } wipememory (sexp->d, p - sexp->d); } gcry_free ( sexp ); } }
/* Bulk encryption of complete blocks in CTR mode. This function is only intended for the bulk encryption feature of cipher.c. CTR is expected to be of size BLOWFISH_BLOCKSIZE. */ void _gcry_blowfish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, const void *inbuf_arg, size_t nblocks) { BLOWFISH_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; unsigned char tmpbuf[BLOWFISH_BLOCKSIZE]; int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE; int i; #ifdef USE_AMD64_ASM { if (nblocks >= 4) burn_stack_depth += 5 * sizeof(void*); /* Process data in 4 block chunks. */ while (nblocks >= 4) { _gcry_blowfish_amd64_ctr_enc(ctx, outbuf, inbuf, ctr); nblocks -= 4; outbuf += 4 * BLOWFISH_BLOCKSIZE; inbuf += 4 * BLOWFISH_BLOCKSIZE; } /* Use generic code to handle smaller chunks... */ /* TODO: use caching instead? */ } #elif defined(USE_ARM_ASM) { /* Process data in 2 block chunks. */ while (nblocks >= 2) { _gcry_blowfish_arm_ctr_enc(ctx, outbuf, inbuf, ctr); nblocks -= 2; outbuf += 2 * BLOWFISH_BLOCKSIZE; inbuf += 2 * BLOWFISH_BLOCKSIZE; } /* Use generic code to handle smaller chunks... */ /* TODO: use caching instead? */ } #endif for ( ;nblocks; nblocks-- ) { /* Encrypt the counter. */ do_encrypt_block(ctx, tmpbuf, ctr); /* XOR the input with the encrypted counter and store in output. */ buf_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE); outbuf += BLOWFISH_BLOCKSIZE; inbuf += BLOWFISH_BLOCKSIZE; /* Increment the counter. */ for (i = BLOWFISH_BLOCKSIZE; i > 0; i--) { ctr[i-1]++; if (ctr[i-1]) break; } } wipememory(tmpbuf, sizeof(tmpbuf)); _gcry_burn_stack(burn_stack_depth); }
/* Include the implementation of map_spwq_error. */ MAP_SPWQ_ERROR_IMPL static void preset_passphrase (const char *keygrip) { int rc; char *line; /* FIXME: Use secure memory. */ char passphrase[500]; char *passphrase_esc; if (!opt_passphrase) { rc = read (0, passphrase, sizeof (passphrase) - 1); if (rc < 0) { log_error ("reading passphrase failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); return; } passphrase[rc] = '\0'; line = strchr (passphrase, '\n'); if (line) { if (line > passphrase && line[-1] == '\r') line--; *line = '\0'; } /* FIXME: How to handle empty passwords? */ } { const char *s = opt_passphrase ? opt_passphrase : passphrase; passphrase_esc = bin2hex (s, strlen (s), NULL); } if (!passphrase_esc) { log_error ("can not escape string: %s\n", gpg_strerror (gpg_error_from_syserror ())); return; } rc = asprintf (&line, "PRESET_PASSPHRASE %s -1 %s\n", keygrip, passphrase_esc); wipememory (passphrase_esc, strlen (passphrase_esc)); xfree (passphrase_esc); if (rc < 0) { log_error ("caching passphrase failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); return; } if (!opt_passphrase) wipememory (passphrase, sizeof (passphrase)); rc = map_spwq_error (simple_query (line)); if (rc) { log_error ("caching passphrase failed: %s\n", gpg_strerror (rc)); return; } wipememory (line, strlen (line)); xfree (line); }
/* Bulk decryption of complete blocks in CBC mode. This function is only intended for the bulk encryption feature of cipher.c. */ void _gcry_camellia_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, const void *inbuf_arg, size_t nblocks) { CAMELLIA_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; unsigned char savebuf[CAMELLIA_BLOCK_SIZE]; int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size; #ifdef USE_AESNI_AVX2 if (ctx->use_aesni_avx2) { int did_use_aesni_avx2 = 0; /* Process data in 32 block chunks. */ while (nblocks >= 32) { _gcry_camellia_aesni_avx2_cbc_dec(ctx, outbuf, inbuf, iv); nblocks -= 32; outbuf += 32 * CAMELLIA_BLOCK_SIZE; inbuf += 32 * CAMELLIA_BLOCK_SIZE; did_use_aesni_avx2 = 1; } if (did_use_aesni_avx2) { int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + 2 * sizeof(void *) + ASM_EXTRA_STACK;; if (burn_stack_depth < avx2_burn_stack_depth) burn_stack_depth = avx2_burn_stack_depth; } /* Use generic code to handle smaller chunks... */ } #endif #ifdef USE_AESNI_AVX if (ctx->use_aesni_avx) { int did_use_aesni_avx = 0; /* Process data in 16 block chunks. */ while (nblocks >= 16) { _gcry_camellia_aesni_avx_cbc_dec(ctx, outbuf, inbuf, iv); nblocks -= 16; outbuf += 16 * CAMELLIA_BLOCK_SIZE; inbuf += 16 * CAMELLIA_BLOCK_SIZE; did_use_aesni_avx = 1; } if (did_use_aesni_avx) { int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *) + ASM_EXTRA_STACK; if (burn_stack_depth < avx_burn_stack_depth) burn_stack_depth = avx_burn_stack_depth; } /* Use generic code to handle smaller chunks... */ } #endif for ( ;nblocks; nblocks-- ) { /* INBUF is needed later and it may be identical to OUTBUF, so store the intermediate result to SAVEBUF. */ Camellia_DecryptBlock(ctx->keybitlength, inbuf, ctx->keytable, savebuf); buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); inbuf += CAMELLIA_BLOCK_SIZE; outbuf += CAMELLIA_BLOCK_SIZE; } wipememory(savebuf, sizeof(savebuf)); _gcry_burn_stack(burn_stack_depth); }
/* Bulk encryption of complete blocks in CTR mode. This function is only intended for the bulk encryption feature of cipher.c. CTR is expected to be of size CAMELLIA_BLOCK_SIZE. */ void _gcry_camellia_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, const void *inbuf_arg, size_t nblocks) { CAMELLIA_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; unsigned char tmpbuf[CAMELLIA_BLOCK_SIZE]; int burn_stack_depth = CAMELLIA_encrypt_stack_burn_size; int i; #ifdef USE_AESNI_AVX2 if (ctx->use_aesni_avx2) { int did_use_aesni_avx2 = 0; /* Process data in 32 block chunks. */ while (nblocks >= 32) { _gcry_camellia_aesni_avx2_ctr_enc(ctx, outbuf, inbuf, ctr); nblocks -= 32; outbuf += 32 * CAMELLIA_BLOCK_SIZE; inbuf += 32 * CAMELLIA_BLOCK_SIZE; did_use_aesni_avx2 = 1; } if (did_use_aesni_avx2) { int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + 2 * sizeof(void *) + ASM_EXTRA_STACK; if (burn_stack_depth < avx2_burn_stack_depth) burn_stack_depth = avx2_burn_stack_depth; } /* Use generic code to handle smaller chunks... */ /* TODO: use caching instead? */ } #endif #ifdef USE_AESNI_AVX if (ctx->use_aesni_avx) { int did_use_aesni_avx = 0; /* Process data in 16 block chunks. */ while (nblocks >= 16) { _gcry_camellia_aesni_avx_ctr_enc(ctx, outbuf, inbuf, ctr); nblocks -= 16; outbuf += 16 * CAMELLIA_BLOCK_SIZE; inbuf += 16 * CAMELLIA_BLOCK_SIZE; did_use_aesni_avx = 1; } if (did_use_aesni_avx) { int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *) + ASM_EXTRA_STACK; if (burn_stack_depth < avx_burn_stack_depth) burn_stack_depth = avx_burn_stack_depth; } /* Use generic code to handle smaller chunks... */ /* TODO: use caching instead? */ } #endif for ( ;nblocks; nblocks-- ) { /* Encrypt the counter. */ Camellia_EncryptBlock(ctx->keybitlength, ctr, ctx->keytable, tmpbuf); /* XOR the input with the encrypted counter and store in output. */ buf_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE); outbuf += CAMELLIA_BLOCK_SIZE; inbuf += CAMELLIA_BLOCK_SIZE; /* Increment the counter. */ for (i = CAMELLIA_BLOCK_SIZE; i > 0; i--) { ctr[i-1]++; if (ctr[i-1]) break; } } wipememory(tmpbuf, sizeof(tmpbuf)); _gcry_burn_stack(burn_stack_depth); }
/* Return the secret key as an S-Exp in RESULT after locating it using the GRIP. Stores NULL at RESULT if the operation shall be diverted to a token; in this case an allocated S-expression with the shadow_info part from the file is stored at SHADOW_INFO. CACHE_MODE defines now the cache shall be used. DESC_TEXT may be set to present a custom description for the pinentry. LOOKUP_TTL is an optional function to convey a TTL to the cache manager; we do not simply pass the TTL value because the value is only needed if an unprotect action was needed and looking up the TTL may have some overhead (e.g. scanning the sshcontrol file). */ gpg_error_t agent_key_from_file (ctrl_t ctrl, const char *desc_text, const unsigned char *grip, unsigned char **shadow_info, cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, gcry_sexp_t *result) { int rc; unsigned char *buf; size_t len, buflen, erroff; gcry_sexp_t s_skey; int got_shadow_info = 0; *result = NULL; if (shadow_info) *shadow_info = NULL; rc = read_key_file (grip, &s_skey); if (rc) return rc; /* For use with the protection functions we also need the key as an canonical encoded S-expression in a buffer. Create this buffer now. */ rc = make_canon_sexp (s_skey, &buf, &len); if (rc) return rc; switch (agent_private_key_type (buf)) { case PRIVATE_KEY_CLEAR: break; /* no unprotection needed */ case PRIVATE_KEY_PROTECTED: { char *desc_text_final; char *comment = NULL; /* Note, that we will take the comment as a C string for display purposes; i.e. all stuff beyond a Nul character is ignored. */ { gcry_sexp_t comment_sexp; comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0); if (comment_sexp) comment = gcry_sexp_nth_string (comment_sexp, 1); gcry_sexp_release (comment_sexp); } desc_text_final = NULL; if (desc_text) rc = modify_description (desc_text, comment? comment:"", s_skey, &desc_text_final); gcry_free (comment); if (!rc) { rc = unprotect (ctrl, desc_text_final, &buf, grip, cache_mode, lookup_ttl); if (rc) log_error ("failed to unprotect the secret key: %s\n", gpg_strerror (rc)); } xfree (desc_text_final); } break; case PRIVATE_KEY_SHADOWED: if (shadow_info) { const unsigned char *s; size_t n; rc = agent_get_shadow_info (buf, &s); if (!rc) { n = gcry_sexp_canon_len (s, 0, NULL,NULL); assert (n); *shadow_info = xtrymalloc (n); if (!*shadow_info) rc = out_of_core (); else { memcpy (*shadow_info, s, n); rc = 0; got_shadow_info = 1; } } if (rc) log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc)); } else rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY); break; default: log_error ("invalid private key format\n"); rc = gpg_error (GPG_ERR_BAD_SECKEY); break; } gcry_sexp_release (s_skey); s_skey = NULL; if (rc || got_shadow_info) { xfree (buf); return rc; } buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL); rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen); wipememory (buf, buflen); xfree (buf); if (rc) { log_error ("failed to build S-Exp (off=%u): %s\n", (unsigned int)erroff, gpg_strerror (rc)); return rc; } *result = s_skey; return 0; }
/* 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; }
/* Bulk decryption of complete blocks in CBC mode. This function is only intended for the bulk encryption feature of cipher.c. */ void _gcry_serpent_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, const void *inbuf_arg, size_t nblocks) { serpent_context_t *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; unsigned char savebuf[sizeof(serpent_block_t)]; int burn_stack_depth = 2 * sizeof (serpent_block_t); #ifdef USE_AVX2 if (ctx->use_avx2) { int did_use_avx2 = 0; /* Process data in 16 block chunks. */ while (nblocks >= 16) { _gcry_serpent_avx2_cbc_dec(ctx, outbuf, inbuf, iv); nblocks -= 16; outbuf += 16 * sizeof(serpent_block_t); inbuf += 16 * sizeof(serpent_block_t); did_use_avx2 = 1; } if (did_use_avx2) { /* serpent-avx2 assembly code does not use stack */ if (nblocks == 0) burn_stack_depth = 0; } /* Use generic/sse2 code to handle smaller chunks... */ } #endif #ifdef USE_SSE2 { int did_use_sse2 = 0; /* Process data in 8 block chunks. */ while (nblocks >= 8) { _gcry_serpent_sse2_cbc_dec(ctx, outbuf, inbuf, iv); nblocks -= 8; outbuf += 8 * sizeof(serpent_block_t); inbuf += 8 * sizeof(serpent_block_t); did_use_sse2 = 1; } if (did_use_sse2) { /* serpent-sse2 assembly code does not use stack */ if (nblocks == 0) burn_stack_depth = 0; } /* Use generic code to handle smaller chunks... */ } #endif #ifdef USE_NEON if (ctx->use_neon) { int did_use_neon = 0; /* Process data in 8 block chunks. */ while (nblocks >= 8) { _gcry_serpent_neon_cbc_dec(ctx, outbuf, inbuf, iv); nblocks -= 8; outbuf += 8 * sizeof(serpent_block_t); inbuf += 8 * sizeof(serpent_block_t); did_use_neon = 1; } if (did_use_neon) { /* serpent-neon assembly code does not use stack */ if (nblocks == 0) burn_stack_depth = 0; } /* Use generic code to handle smaller chunks... */ } #endif for ( ;nblocks; nblocks-- ) { /* INBUF is needed later and it may be identical to OUTBUF, so store the intermediate result to SAVEBUF. */ serpent_decrypt_internal (ctx, inbuf, savebuf); buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, sizeof(serpent_block_t)); inbuf += sizeof(serpent_block_t); outbuf += sizeof(serpent_block_t); } wipememory(savebuf, sizeof(savebuf)); _gcry_burn_stack(burn_stack_depth); }
/**************** * Encrypt the file with the given userids (or ask if none * is supplied). */ int encode_crypt( const char *filename, STRLIST remusr, int use_symkey ) { IOBUF inp = NULL, out = NULL; PACKET pkt; PKT_plaintext *pt = NULL; DEK *symkey_dek = NULL; STRING2KEY *symkey_s2k = NULL; int rc = 0, rc2 = 0; u32 filesize; cipher_filter_context_t cfx; armor_filter_context_t afx; compress_filter_context_t zfx; text_filter_context_t tfx; progress_filter_context_t pfx; PK_LIST pk_list,work_list; int do_compress = opt.compress_algo && !RFC1991; memset( &cfx, 0, sizeof cfx); memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); memset( &tfx, 0, sizeof tfx); init_packet(&pkt); if(use_symkey && (rc=setup_symkey(&symkey_s2k,&symkey_dek))) return rc; if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) ) return rc; if(PGP2) { for(work_list=pk_list; work_list; work_list=work_list->next) if(!(is_RSA(work_list->pk->pubkey_algo) && nbits_from_pk(work_list->pk)<=2048)) { log_info(_("you can only encrypt to RSA keys of 2048 bits or " "less in --pgp2 mode\n")); compliance_failure(); break; } } /* prepare iobufs */ inp = iobuf_open(filename); if (inp) iobuf_ioctl (inp,3,1,NULL); /* disable fd caching */ if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; errno = EPERM; } if( !inp ) { log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]", strerror(errno) ); rc = G10ERR_OPEN_FILE; goto leave; } else if( opt.verbose ) log_info(_("reading from `%s'\n"), filename? filename: "[stdin]"); handle_progress (&pfx, inp, filename); if( opt.textmode ) iobuf_push_filter( inp, text_filter, &tfx ); if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) goto leave; if( opt.armor ) iobuf_push_filter( out, armor_filter, &afx ); /* create a session key */ cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek); if( !opt.def_cipher_algo ) { /* try to get it from the prefs */ cfx.dek->algo = select_algo_from_prefs(pk_list,PREFTYPE_SYM,-1,NULL); /* The only way select_algo_from_prefs can fail here is when mixing v3 and v4 keys, as v4 keys have an implicit preference entry for 3DES, and the pk_list cannot be empty. In this case, use 3DES anyway as it's the safest choice - perhaps the v3 key is being used in an OpenPGP implementation and we know that the implementation behind any v4 key can handle 3DES. */ if( cfx.dek->algo == -1 ) { cfx.dek->algo = CIPHER_ALGO_3DES; if( PGP2 ) { log_info(_("unable to use the IDEA cipher for all of the keys " "you are encrypting to.\n")); compliance_failure(); } } } else { if(!opt.expert && select_algo_from_prefs(pk_list,PREFTYPE_SYM, opt.def_cipher_algo,NULL)!=opt.def_cipher_algo) log_info(_("WARNING: forcing symmetric cipher %s (%d)" " violates recipient preferences\n"), cipher_algo_to_string(opt.def_cipher_algo), opt.def_cipher_algo); cfx.dek->algo = opt.def_cipher_algo; } cfx.dek->use_mdc=use_mdc(pk_list,cfx.dek->algo); /* Only do the is-file-already-compressed check if we are using a MDC. This forces compressed files to be re-compressed if we do not have a MDC to give some protection against chosen ciphertext attacks. */ if (do_compress && cfx.dek->use_mdc && is_file_compressed(filename, &rc2) ) { if (opt.verbose) log_info(_("`%s' already compressed\n"), filename); do_compress = 0; } if (rc2) { rc = rc2; goto leave; } make_session_key( cfx.dek ); if( DBG_CIPHER ) log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen ); rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out ); if( rc ) goto leave; /* We put the passphrase (if any) after any public keys as this seems to be the most useful on the recipient side - there is no point in prompting a user for a passphrase if they have the secret key needed to decrypt. */ if(use_symkey && (rc=write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out))) goto leave; if (!opt.no_literal) { /* setup the inner packet */ if( filename || opt.set_filename ) { char *s = make_basename( opt.set_filename ? opt.set_filename : filename, iobuf_get_real_fname( inp ) ); pt = xmalloc( sizeof *pt + strlen(s) - 1 ); pt->namelen = strlen(s); memcpy(pt->name, s, pt->namelen ); xfree(s); } else { /* no filename */ pt = xmalloc( sizeof *pt - 1 ); pt->namelen = 0; } } if (!iobuf_is_pipe_filename (filename) && *filename && !opt.textmode ) { off_t tmpsize; int overflow; if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) && !overflow ) log_info(_("WARNING: `%s' is an empty file\n"), filename ); /* We can't encode the length of very large files because OpenPGP uses only 32 bit for file sizes. So if the the size of a file is larger than 2^32 minus some bytes for packet headers, we switch to partial length encoding. */ if (tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) ) filesize = tmpsize; else filesize = 0; } else filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { pt->timestamp = make_timestamp(); pt->mode = opt.textmode ? 't' : 'b'; pt->len = filesize; pt->new_ctb = !pt->len && !RFC1991; pt->buf = inp; pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0; } else cfx.datalen = filesize && !do_compress ? filesize : 0; /* register the cipher filter */ iobuf_push_filter( out, cipher_filter, &cfx ); /* register the compress filter */ if( do_compress ) { int compr_algo = opt.compress_algo; if(compr_algo==-1) { if((compr_algo= select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1) compr_algo=DEFAULT_COMPRESS_ALGO; /* Theoretically impossible to get here since uncompressed is implicit. */ } else if(!opt.expert && select_algo_from_prefs(pk_list,PREFTYPE_ZIP, compr_algo,NULL)!=compr_algo) log_info(_("WARNING: forcing compression algorithm %s (%d)" " violates recipient preferences\n"), compress_algo_to_string(compr_algo),compr_algo); /* algo 0 means no compression */ if( compr_algo ) { if (cfx.dek && cfx.dek->use_mdc) zfx.new_ctb = 1; push_compress_filter(out,&zfx,compr_algo); } } /* do the work */ if (!opt.no_literal) { if( (rc = build_packet( out, &pkt )) ) log_error("build_packet failed: %s\n", g10_errstr(rc) ); } else { /* user requested not to create a literal packet, so we copy the plain data */ byte copy_buffer[4096]; int bytes_copied; while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1) if (iobuf_write(out, copy_buffer, bytes_copied) == -1) { rc = G10ERR_WRITE_FILE; log_error("copying input to output failed: %s\n", g10_errstr(rc) ); break; } wipememory(copy_buffer, 4096); /* burn buffer */ } /* finish the stuff */ leave: iobuf_close(inp); if( rc ) iobuf_cancel(out); else { iobuf_close(out); /* fixme: check returncode */ write_status( STATUS_END_ENCRYPTION ); } if( pt ) pt->buf = NULL; free_packet(&pkt); xfree(cfx.dek); xfree(symkey_dek); xfree(symkey_s2k); release_pk_list( pk_list ); return rc; }
/* We don't want to use use_seskey yet because older gnupg versions can't handle it, and there isn't really any point unless we're making a message that can be decrypted by a public key or passphrase. */ static int encode_simple( const char *filename, int mode, int use_seskey ) { IOBUF inp, out; PACKET pkt; PKT_plaintext *pt = NULL; STRING2KEY *s2k = NULL; byte enckey[33]; int rc = 0; int seskeylen = 0; u32 filesize; cipher_filter_context_t cfx; armor_filter_context_t afx; compress_filter_context_t zfx; text_filter_context_t tfx; progress_filter_context_t pfx; int do_compress = !RFC1991 && default_compress_algo(); memset( &cfx, 0, sizeof cfx); memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); memset( &tfx, 0, sizeof tfx); init_packet(&pkt); /* prepare iobufs */ inp = iobuf_open(filename); if (inp) iobuf_ioctl (inp,3,1,NULL); /* disable fd caching */ if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; errno = EPERM; } if( !inp ) { log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]", strerror(errno) ); return G10ERR_OPEN_FILE; } handle_progress (&pfx, inp, filename); if( opt.textmode ) iobuf_push_filter( inp, text_filter, &tfx ); /* Due the the fact that we use don't use an IV to encrypt the session key we can't use the new mode with RFC1991 because it has no S2K salt. RFC1991 always uses simple S2K. */ if ( RFC1991 && use_seskey ) use_seskey = 0; cfx.dek = NULL; if( mode ) { s2k = xmalloc_clear( sizeof *s2k ); s2k->mode = RFC1991? 0:opt.s2k_mode; s2k->hash_algo=S2K_DIGEST_ALGO; cfx.dek = passphrase_to_dek( NULL, 0, default_cipher_algo(), s2k, 2, NULL, NULL); if( !cfx.dek || !cfx.dek->keylen ) { rc = G10ERR_PASSPHRASE; xfree(cfx.dek); xfree(s2k); iobuf_close(inp); log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) ); return rc; } if (use_seskey && s2k->mode != 1 && s2k->mode != 3) { use_seskey = 0; log_info (_("can't use a symmetric ESK packet " "due to the S2K mode\n")); } if ( use_seskey ) { DEK *dek = NULL; seskeylen = cipher_get_keylen( default_cipher_algo() ) / 8; encode_seskey( cfx.dek, &dek, enckey ); xfree( cfx.dek ); cfx.dek = dek; } if(opt.verbose) log_info(_("using cipher %s\n"), cipher_algo_to_string(cfx.dek->algo)); cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo); } if (do_compress && cfx.dek && cfx.dek->use_mdc && is_file_compressed(filename, &rc)) { if (opt.verbose) log_info(_("`%s' already compressed\n"), filename); do_compress = 0; } if( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) { iobuf_cancel(inp); xfree(cfx.dek); xfree(s2k); return rc; } if( opt.armor ) iobuf_push_filter( out, armor_filter, &afx ); if( s2k && !RFC1991 ) { PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc + seskeylen + 1 ); enc->version = 4; enc->cipher_algo = cfx.dek->algo; enc->s2k = *s2k; if ( use_seskey && seskeylen ) { enc->seskeylen = seskeylen + 1; /* algo id */ memcpy( enc->seskey, enckey, seskeylen + 1 ); } pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if( (rc = build_packet( out, &pkt )) ) log_error("build symkey packet failed: %s\n", g10_errstr(rc) ); xfree(enc); } if (!opt.no_literal) pt=setup_plaintext_name(filename,inp); /* Note that PGP 5 has problems decrypting symmetrically encrypted data if the file length is in the inner packet. It works when only partial length headers are use. In the past, we always used partial body length here, but since PGP 2, PGP 6, and PGP 7 need the file length, and nobody should be using PGP 5 nowadays anyway, this is now set to the file length. Note also that this only applies to the RFC-1991 style symmetric messages, and not the RFC-2440 style. PGP 6 and 7 work with either partial length or fixed length with the new style messages. */ if ( !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode ) { off_t tmpsize; int overflow; if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) && !overflow ) log_info(_("WARNING: `%s' is an empty file\n"), filename ); /* We can't encode the length of very large files because OpenPGP uses only 32 bit for file sizes. So if the the size of a file is larger than 2^32 minus some bytes for packet headers, we switch to partial length encoding. */ if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) ) filesize = tmpsize; else filesize = 0; } else filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { pt->timestamp = make_timestamp(); pt->mode = opt.textmode? 't' : 'b'; pt->len = filesize; pt->new_ctb = !pt->len && !RFC1991; pt->buf = inp; pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0; } else { cfx.datalen = filesize && !do_compress ? filesize : 0; pkt.pkttype = 0; pkt.pkt.generic = NULL; } /* register the cipher filter */ if( mode ) iobuf_push_filter( out, cipher_filter, &cfx ); /* register the compress filter */ if( do_compress ) { if (cfx.dek && cfx.dek->use_mdc) zfx.new_ctb = 1; push_compress_filter(out,&zfx,default_compress_algo()); } /* do the work */ if (!opt.no_literal) { if( (rc = build_packet( out, &pkt )) ) log_error("build_packet failed: %s\n", g10_errstr(rc) ); } else { /* user requested not to create a literal packet, * so we copy the plain data */ byte copy_buffer[4096]; int bytes_copied; while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1) if (iobuf_write(out, copy_buffer, bytes_copied) == -1) { rc = G10ERR_WRITE_FILE; log_error("copying input to output failed: %s\n", g10_errstr(rc) ); break; } wipememory(copy_buffer, 4096); /* burn buffer */ } /* finish the stuff */ iobuf_close(inp); if (rc) iobuf_cancel(out); else { iobuf_close(out); /* fixme: check returncode */ if (mode) write_status( STATUS_END_ENCRYPTION ); } if (pt) pt->buf = NULL; free_packet(&pkt); xfree(cfx.dek); xfree(s2k); return rc; }