/* Update the message digest with the contents of INBUF with length INLEN. */ static void sha256_write (void *context, byte *inbuf, size_t inlen) { SHA256_CONTEXT *hd = context; if (hd->count == 64) { /* flush the buffer */ transform (hd, hd->buf); _gcry_burn_stack (74*4+32); hd->count = 0; hd->nblocks++; } if (!inbuf) return; if (hd->count) { for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; sha256_write (hd, NULL, 0); if (!inlen) return; } while (inlen >= 64) { transform (hd, inbuf); hd->count = 0; hd->nblocks++; inlen -= 64; inbuf += 64; } _gcry_burn_stack (74*4+32); for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; }
/* The routine updates the message-digest context to * account for the presence of each of the characters inBuf[0..inLen-1] * in the message whose digest is being computed. */ void texpdf_MD5_write (MD5_CONTEXT *hd, const unsigned char *inbuf, unsigned long inlen) { if (hd->count == 64) { /* flush the buffer */ transform(hd, hd->buf); _gcry_burn_stack(80+6*sizeof(void*)); hd->count = 0; hd->nblocks++; } if (!inbuf) return; if (hd->count) { for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; texpdf_MD5_write(hd, NULL, 0); if (!inlen) return; } _gcry_burn_stack(80+6*sizeof(void*)); while (inlen >= 64) { transform(hd, inbuf); hd->count = 0; hd->nblocks++; inlen -= 64; inbuf += 64; } for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; }
/* Update the message digest with the contents * of INBUF with length INLEN. */ static void sha512_write (void *context, byte *inbuf, size_t inlen) { SHA512_CONTEXT *hd = context; if (hd->count == 128) { /* flush the buffer */ transform (hd, hd->buf); _gcry_burn_stack (768); hd->count = 0; hd->nblocks++; } if (!inbuf) return; if (hd->count) { for (; inlen && hd->count < 128; inlen--) hd->buf[hd->count++] = *inbuf++; sha512_write (context, NULL, 0); if (!inlen) return; } while (inlen >= 128) { transform (hd, inbuf); hd->count = 0; hd->nblocks++; inlen -= 128; inbuf += 128; } _gcry_burn_stack (768); for (; inlen && hd->count < 128; inlen--) hd->buf[hd->count++] = *inbuf++; }
/* Update the message digest with the contents * of INBUF with length INLEN. */ static void rmd160_write( void *context, byte *inbuf, size_t inlen) { RMD160_CONTEXT *hd = context; if( hd->count == 64 ) /* flush the buffer */ { transform( hd, hd->buf ); _gcry_burn_stack (108+5*sizeof(void*)); hd->count = 0; hd->nblocks++; } if( !inbuf ) return; if( hd->count ) { for( ; inlen && hd->count < 64; inlen-- ) hd->buf[hd->count++] = *inbuf++; rmd160_write( hd, NULL, 0 ); if( !inlen ) return; } while( inlen >= 64 ) { transform( hd, inbuf ); hd->count = 0; hd->nblocks++; inlen -= 64; inbuf += 64; } _gcry_burn_stack (108+5*sizeof(void*)); for( ; inlen && hd->count < 64; inlen-- ) hd->buf[hd->count++] = *inbuf++; }
/* Common function to write a chunk of data to the transform function of a hash algorithm. Note that the use of the term "block" does not imply a fixed size block. Note that we explicitly allow to use this function after the context has been finalized; the result does not have any meaning but writing after finalize is sometimes helpful to mitigate timing attacks. */ void _gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen) { const unsigned char *inbuf = inbuf_arg; gcry_md_block_ctx_t *hd = context; unsigned int stack_burn = 0; const unsigned int blocksize = hd->blocksize; size_t inblocks; if (sizeof(hd->buf) < blocksize) BUG(); if (!hd->bwrite) return; if (hd->count == blocksize) /* Flush the buffer. */ { stack_burn = hd->bwrite (hd, hd->buf, 1); _gcry_burn_stack (stack_burn); stack_burn = 0; hd->count = 0; if (!++hd->nblocks) hd->nblocks_high++; } if (!inbuf) return; if (hd->count) { for (; inlen && hd->count < blocksize; inlen--) hd->buf[hd->count++] = *inbuf++; _gcry_md_block_write (hd, NULL, 0); if (!inlen) return; } if (inlen >= blocksize) { inblocks = inlen / blocksize; stack_burn = hd->bwrite (hd, inbuf, inblocks); hd->count = 0; hd->nblocks_high += (hd->nblocks + inblocks < inblocks); hd->nblocks += inblocks; inlen -= inblocks * blocksize; inbuf += inblocks * blocksize; } _gcry_burn_stack (stack_burn); for (; inlen && hd->count < blocksize; inlen--) hd->buf[hd->count++] = *inbuf++; }
/* Initialize CTX with the key KEY of KEY_LENGTH bytes. */ static gcry_err_code_t serpent_setkey (void *ctx, const byte *key, unsigned int key_length) { serpent_context_t *context = ctx; static const char *serpent_test_ret; static int serpent_init_done; gcry_err_code_t ret = GPG_ERR_NO_ERROR; if (! serpent_init_done) { /* Execute a self-test the first time, Serpent is used. */ serpent_test_ret = serpent_test (); if (serpent_test_ret) log_error ("Serpent test failure: %s\n", serpent_test_ret); serpent_init_done = 1; } if (serpent_test_ret) ret = GPG_ERR_SELFTEST_FAILED; else { serpent_setkey_internal (context, key, key_length); _gcry_burn_stack (sizeof (serpent_key_t)); } return ret; }
static gcry_err_code_t do_ecb_crypt (gcry_cipher_hd_t c, unsigned char *outbuf, size_t outbuflen, const unsigned char *inbuf, size_t inbuflen, gcry_cipher_encrypt_t crypt_fn) { unsigned int blocksize = c->spec->blocksize; size_t n, nblocks; unsigned int burn, nburn; if (outbuflen < inbuflen) return GPG_ERR_BUFFER_TOO_SHORT; if ((inbuflen % blocksize)) return GPG_ERR_INV_LENGTH; nblocks = inbuflen / blocksize; burn = 0; for (n=0; n < nblocks; n++ ) { nburn = crypt_fn (&c->context.c, outbuf, inbuf); burn = nburn > burn ? nburn : burn; inbuf += blocksize; outbuf += blocksize; } if (burn > 0) _gcry_burn_stack (burn + 4 * sizeof(void *)); return 0; }
static void twofish_encrypt (void *context, byte *out, const byte *in) { TWOFISH_context *ctx = context; do_twofish_encrypt (ctx, out, in); _gcry_burn_stack (24+3*sizeof (void*)); }
/* Common function to write a chunk of data to the transform function of a hash algorithm. Note that the use of the term "block" does not imply a fixed size block. */ void _gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen) { const unsigned char *inbuf = inbuf_arg; gcry_md_block_ctx_t *hd = context; unsigned int stack_burn = 0; if (sizeof(hd->buf) < hd->blocksize) BUG(); if (hd->buf == NULL || hd->bwrite == NULL) return; if (hd->count == hd->blocksize) /* Flush the buffer. */ { stack_burn = hd->bwrite (hd, hd->buf); _gcry_burn_stack (stack_burn); stack_burn = 0; hd->count = 0; if (!++hd->nblocks) hd->nblocks_high++; } if (!inbuf) return; if (hd->count) { for (; inlen && hd->count < hd->blocksize; inlen--) hd->buf[hd->count++] = *inbuf++; _gcry_md_block_write (hd, NULL, 0); if (!inlen) return; } while (inlen >= hd->blocksize) { stack_burn = hd->bwrite (hd, inbuf); hd->count = 0; if (!++hd->nblocks) hd->nblocks_high++; inlen -= hd->blocksize; inbuf += hd->blocksize; } _gcry_burn_stack (stack_burn); for (; inlen && hd->count < hd->blocksize; inlen--) hd->buf[hd->count++] = *inbuf++; }
static void _gcry_burn_stack (int bytes) { char buf[64]; memset(buf, 0, sizeof buf); bytes -= sizeof buf; if (bytes > 0) _gcry_burn_stack(bytes); }
static gcry_err_code_t arcfour_setkey ( void *context, const byte *key, unsigned int keylen ) { ARCFOUR_context *ctx = (ARCFOUR_context *) context; gcry_err_code_t rc = do_arcfour_setkey (ctx, key, keylen ); _gcry_burn_stack (300); return rc; }
static gcry_err_code_t twofish_setkey (void *context, const byte *key, unsigned int keylen) { TWOFISH_context *ctx = context; int rc = do_twofish_setkey (ctx, key, keylen); _gcry_burn_stack (23+6*sizeof(void*)); return rc; }
static void encrypt_stream (void *context, byte *outbuf, const byte *inbuf, size_t length) { ARCFOUR_context *ctx = (ARCFOUR_context *) context; do_encrypt_stream (ctx, outbuf, inbuf, length ); _gcry_burn_stack (64); }
static gcry_err_code_t salsa20_setkey (void *context, const byte *key, unsigned int keylen) { SALSA20_context_t *ctx = (SALSA20_context_t *)context; gcry_err_code_t rc = salsa20_do_setkey (ctx, key, keylen); _gcry_burn_stack (300/* FIXME*/); 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_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); }
static void serpent_encrypt (void *ctx, byte *buffer_out, const byte *buffer_in) { serpent_context_t *context = ctx; serpent_encrypt_internal (context, (const u32 *) buffer_in, (u32 *) buffer_out); _gcry_burn_stack (2 * sizeof (serpent_block_t)); }
/* 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); _gcry_burn_stack (272 * sizeof (u32)); }
void _gcry_burn_stack (int bytes) { char buf[64]; wipememory (buf, sizeof buf); bytes -= sizeof buf; if (bytes > 0) _gcry_burn_stack (bytes); }
void texpdf_MD5_final (unsigned char *outbuf, MD5_CONTEXT *hd) { unsigned long t, msb, lsb; unsigned char *p; texpdf_MD5_write(hd, NULL, 0); /* flush */ t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; msb = t >> 26; /* add the count */ t = lsb; if ((lsb += hd->count) < t) msb++; /* multiply by 8 to make a bit count */ t = lsb; lsb <<= 3; msb <<= 3; msb |= t >> 29; if (hd->count < 56) { /* enough room */ hd->buf[hd->count++] = 0x80; /* pad */ while (hd->count < 56) hd->buf[hd->count++] = 0; /* pad */ } else { /* need one extra block */ hd->buf[hd->count++] = 0x80; /* pad character */ while (hd->count < 64) hd->buf[hd->count++] = 0; texpdf_MD5_write(hd, NULL, 0); /* flush */ memset(hd->buf, 0, 56); /* fill next block with zeroes */ } /* append the 64 bit count */ hd->buf[56] = lsb & 0xff; hd->buf[57] = (lsb >> 8) & 0xff; hd->buf[58] = (lsb >> 16) & 0xff; hd->buf[59] = (lsb >> 24) & 0xff; hd->buf[60] = msb & 0xff; hd->buf[61] = (msb >> 8) & 0xff; hd->buf[62] = (msb >> 16) & 0xff; hd->buf[63] = (msb >> 24) & 0xff; transform(hd, hd->buf); _gcry_burn_stack(80+6*sizeof(void*)); p = outbuf; /* p = hd->buf; */ #ifdef WORDS_BIGENDIAN #define X(a) do { *p++ = hd->a; *p++ = hd->a >> 8; \ *p++ = hd->a >> 16; *p++ = hd->a >> 24; } while (0) #else /* little endian */ #define X(a) do { *(uint32_t *)p = (*hd).a ; p += sizeof(uint32_t); } while (0) #endif X(A); X(B); X(C); X(D); #undef X }
/* Update the message digest with the contents * of INBUF with length INLEN. */ static void sha1_write( void *context, const void *inbuf_arg, size_t inlen) { const unsigned char *inbuf = inbuf_arg; SHA1_CONTEXT *hd = context; size_t nblocks; if (hd->count == 64) /* Flush the buffer. */ { TRANSFORM( hd, hd->buf, 1 ); _gcry_burn_stack (88+4*sizeof(void*)); hd->count = 0; hd->nblocks++; } if (!inbuf) return; if (hd->count) { for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; sha1_write (hd, NULL, 0); if (!inlen) return; } nblocks = inlen / 64; if (nblocks) { TRANSFORM (hd, inbuf, nblocks); hd->count = 0; hd->nblocks += nblocks; inlen -= nblocks * 64; inbuf += nblocks * 64; } _gcry_burn_stack (88+4*sizeof(void*)); /* Save remaining bytes. */ for (; inlen && hd->count < 64; inlen--) hd->buf[hd->count++] = *inbuf++; }
static void rmd160_final( void *context ) { RMD160_CONTEXT *hd = context; u32 t, msb, lsb; byte *p; unsigned int burn; _gcry_md_block_write(hd, NULL, 0); /* flush */; t = hd->bctx.nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; msb = t >> 26; /* add the count */ t = lsb; if( (lsb += hd->bctx.count) < t ) msb++; /* multiply by 8 to make a bit count */ t = lsb; lsb <<= 3; msb <<= 3; msb |= t >> 29; if( hd->bctx.count < 56 ) /* enough room */ { hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */ while( hd->bctx.count < 56 ) hd->bctx.buf[hd->bctx.count++] = 0; /* pad */ } else /* need one extra block */ { hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */ while( hd->bctx.count < 64 ) hd->bctx.buf[hd->bctx.count++] = 0; _gcry_md_block_write(hd, NULL, 0); /* flush */; memset(hd->bctx.buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ buf_put_le32(hd->bctx.buf + 56, lsb); buf_put_le32(hd->bctx.buf + 60, msb); burn = transform( hd, hd->bctx.buf ); _gcry_burn_stack (burn); p = hd->bctx.buf; #define X(a) do { *(u32*)p = le_bswap32(hd->h##a) ; p += 4; } while(0) X(0); X(1); X(2); X(3); X(4); #undef X }
static gcry_err_code_t camellia_setkey(void *c, const byte *key, unsigned keylen) { CAMELLIA_context *ctx=c; static int initialized=0; static const char *selftest_failed=NULL; #if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) unsigned int hwf = _gcry_get_hw_features (); #endif if(keylen!=16 && keylen!=24 && keylen!=32) return GPG_ERR_INV_KEYLEN; if(!initialized) { initialized=1; selftest_failed=selftest(); if(selftest_failed) log_error("%s\n",selftest_failed); } if(selftest_failed) return GPG_ERR_SELFTEST_FAILED; #ifdef USE_AESNI_AVX ctx->use_aesni_avx = (hwf & HWF_INTEL_AESNI) && (hwf & HWF_INTEL_AVX); #endif #ifdef USE_AESNI_AVX2 ctx->use_aesni_avx2 = (hwf & HWF_INTEL_AESNI) && (hwf & HWF_INTEL_AVX2); #endif ctx->keybitlength=keylen*8; if (0) { } #ifdef USE_AESNI_AVX else if (ctx->use_aesni_avx) _gcry_camellia_aesni_avx_keygen(ctx, key, keylen); else #endif { Camellia_Ekeygen(ctx->keybitlength,key,ctx->keytable); _gcry_burn_stack ((19+34+34)*sizeof(u32)+2*sizeof(void*) /* camellia_setup256 */ +(4+32)*sizeof(u32)+2*sizeof(void*) /* camellia_setup192 */ +0+sizeof(int)+2*sizeof(void*) /* Camellia_Ekeygen */ +3*2*sizeof(void*) /* Function calls. */ ); } return 0; }
/* Bulk decryption of complete blocks in CFB mode. This function is only intended for the bulk encryption feature of cipher.c. */ void _gcry_blowfish_cfb_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; 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_cfb_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_cfb_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-- ) { do_encrypt_block(ctx, iv, iv); buf_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE); outbuf += BLOWFISH_BLOCKSIZE; inbuf += BLOWFISH_BLOCKSIZE; } _gcry_burn_stack(burn_stack_depth); }
/* The routine updates the message-digest context to * account for the presence of each of the characters inBuf[0..inLen-1] * in the message whose digest is being computed. */ static void md5_write( void *context, const void *inbuf_arg , size_t inlen) { const unsigned char *inbuf = inbuf_arg; MD5_CONTEXT *hd = context; if( hd->count == 64 ) /* flush the buffer */ { transform( hd, hd->buf ); _gcry_burn_stack (80+6*sizeof(void*)); hd->count = 0; hd->nblocks++; } if( !inbuf ) return; if( hd->count ) { for( ; inlen && hd->count < 64; inlen-- ) hd->buf[hd->count++] = *inbuf++; md5_write( hd, NULL, 0 ); if( !inlen ) return; } _gcry_burn_stack (80+6*sizeof(void*)); while( inlen >= 64 ) { transform( hd, inbuf ); hd->count = 0; hd->nblocks++; inlen -= 64; inbuf += 64; } for( ; inlen && hd->count < 64; inlen-- ) hd->buf[hd->count++] = *inbuf++; }
gcry_err_code_t _gcry_cipher_cfb8_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, size_t outbuflen, const unsigned char *inbuf, size_t inbuflen) { gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; size_t blocksize = c->spec->blocksize; unsigned int burn, nburn; unsigned char appendee; if (outbuflen < inbuflen) return GPG_ERR_BUFFER_TOO_SHORT; burn = 0; while (inbuflen > 0) { int i; /* Encrypt the IV. */ nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; /* inbuf might == outbuf, make sure we keep the value so we can append it later */ appendee = inbuf[0]; outbuf[0] = inbuf[0] ^ c->lastiv[0]; /* Bitshift iv by 8 bit to the left */ for (i = 0; i < blocksize-1; i++) c->u_iv.iv[i] = c->u_iv.iv[i+1]; c->u_iv.iv[blocksize-1] = appendee; outbuf += 1; inbuf += 1; inbuflen -= 1; } if (burn > 0) _gcry_burn_stack (burn + 4 * sizeof(void *)); return 0; }
static void salsa20_encrypt_stream (void *context, byte *outbuf, const byte *inbuf, unsigned int length) { SALSA20_context_t *ctx = (SALSA20_context_t *)context; if (length) { salsa20_do_encrypt_stream (ctx, outbuf, inbuf, length); _gcry_burn_stack (/* salsa20_do_encrypt_stream: */ 2*sizeof (void*) + 3*sizeof (void*) + sizeof (unsigned int) /* salsa20_core: */ + 2*sizeof (void*) + 2*sizeof (void*) + 64 + sizeof (unsigned int) + sizeof (u32) ); } }
static void md4_final( void *context ) { MD4_CONTEXT *hd = context; u32 t, msb, lsb; byte *p; md4_write(hd, NULL, 0); /* flush */; t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; msb = t >> 26; /* add the count */ t = lsb; if( (lsb += hd->count) < t ) msb++; /* multiply by 8 to make a bit count */ t = lsb; lsb <<= 3; msb <<= 3; msb |= t >> 29; if( hd->count < 56 ) /* enough room */ { hd->buf[hd->count++] = 0x80; /* pad */ while( hd->count < 56 ) hd->buf[hd->count++] = 0; /* pad */ } else /* need one extra block */ { hd->buf[hd->count++] = 0x80; /* pad character */ while( hd->count < 64 ) hd->buf[hd->count++] = 0; md4_write(hd, NULL, 0); /* flush */; memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ hd->buf[56] = lsb ; hd->buf[57] = lsb >> 8; hd->buf[58] = lsb >> 16; hd->buf[59] = lsb >> 24; hd->buf[60] = msb ; hd->buf[61] = msb >> 8; hd->buf[62] = msb >> 16; hd->buf[63] = msb >> 24; transform( hd, hd->buf ); _gcry_burn_stack (80+6*sizeof(void*)); p = hd->buf; #ifdef WORDS_BIGENDIAN #define X(a) do { *p++ = hd->a ; *p++ = hd->a >> 8; \ *p++ = hd->a >> 16; *p++ = hd->a >> 24; } while(0) #else /* little endian */ #define X(a) do { *(u32*)p = (*hd).a ; p += 4; } while(0) #endif X(A); X(B); X(C); X(D); #undef X }
/* 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); }
/* The routine finally terminates the computation and returns the digest. The handle is prepared for a new cycle, but adding bytes to the handle will the destroy the returned buffer. Returns: 32 bytes with the message the digest. */ static void sha256_final(void *context) { SHA256_CONTEXT *hd = context; u32 t, msb, lsb; byte *p; sha256_write (hd, NULL, 0); /* flush */; t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; msb = t >> 26; /* add the count */ t = lsb; if ((lsb += hd->count) < t) msb++; /* multiply by 8 to make a bit count */ t = lsb; lsb <<= 3; msb <<= 3; msb |= t >> 29; if (hd->count < 56) { /* enough room */ hd->buf[hd->count++] = 0x80; /* pad */ while (hd->count < 56) hd->buf[hd->count++] = 0; /* pad */ } else { /* need one extra block */ hd->buf[hd->count++] = 0x80; /* pad character */ while (hd->count < 64) hd->buf[hd->count++] = 0; sha256_write (hd, NULL, 0); /* flush */; memset (hd->buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ hd->buf[56] = msb >> 24; hd->buf[57] = msb >> 16; hd->buf[58] = msb >> 8; hd->buf[59] = msb; hd->buf[60] = lsb >> 24; hd->buf[61] = lsb >> 16; hd->buf[62] = lsb >> 8; hd->buf[63] = lsb; transform (hd, hd->buf); _gcry_burn_stack (74*4+32); p = hd->buf; #ifdef WORDS_BIGENDIAN #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0) #else /* little endian */ #define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0) #endif X(0); X(1); X(2); X(3); X(4); X(5); X(6); X(7); #undef X }
/* Bulk decryption of complete blocks in CFB mode. This function is only intended for the bulk encryption feature of cipher.c. */ void _gcry_camellia_cfb_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; 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_cfb_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_cfb_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-- ) { Camellia_EncryptBlock(ctx->keybitlength, iv, ctx->keytable, iv); buf_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); outbuf += CAMELLIA_BLOCK_SIZE; inbuf += CAMELLIA_BLOCK_SIZE; } _gcry_burn_stack(burn_stack_depth); }