Esempio n. 1
0
gcry_err_code_t
_gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c,
                          unsigned char *outbuf, size_t outbuflen,
                          const unsigned char *inbuf, size_t inbuflen)
{
  unsigned char *ivp;
  gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
  size_t blocksize = c->spec->blocksize;
  size_t blocksize_x_2 = blocksize + blocksize;
  unsigned int burn, nburn;

  /* Tell compiler that we require a cipher with a 64bit or 128 bit block
   * length, to allow better optimization of this function.  */
  if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
    return GPG_ERR_INV_LENGTH;

  if (outbuflen < inbuflen)
    return GPG_ERR_BUFFER_TOO_SHORT;

  if ( inbuflen <= c->unused )
    {
      /* Short enough to be encoded by the remaining XOR mask. */
      /* XOR the input with the IV and store input into IV. */
      ivp = c->u_iv.iv + blocksize - c->unused;
      buf_xor_2dst(outbuf, ivp, inbuf, inbuflen);
      c->unused -= inbuflen;
      return 0;
    }

  burn = 0;

  if ( c->unused )
    {
      /* XOR the input with the IV and store input into IV */
      inbuflen -= c->unused;
      ivp = c->u_iv.iv + blocksize - c->unused;
      buf_xor_2dst(outbuf, ivp, inbuf, c->unused);
      outbuf += c->unused;
      inbuf += c->unused;
      c->unused = 0;
    }

  /* Now we can process complete blocks.  We use a loop as long as we
     have at least 2 blocks and use conditions for the rest.  This
     also allows to use a bulk encryption function if available.  */
  if (inbuflen >= blocksize_x_2 && c->bulk.cfb_enc)
    {
      size_t nblocks = inbuflen / blocksize;
      c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
      outbuf += nblocks * blocksize;
      inbuf  += nblocks * blocksize;
      inbuflen -= nblocks * blocksize;
    }
  else
    {
      while ( inbuflen >= blocksize_x_2 )
        {
          /* Encrypt the IV. */
          nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
          burn = nburn > burn ? nburn : burn;
          /* XOR the input with the IV and store input into IV.  */
          buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
          outbuf += blocksize;
          inbuf += blocksize;
          inbuflen -= blocksize;
        }
    }

  if ( inbuflen >= blocksize )
    {
      /* Save the current IV and then encrypt the IV. */
      buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
      nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
      burn = nburn > burn ? nburn : burn;
      /* XOR the input with the IV and store input into IV */
      buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
      outbuf += blocksize;
      inbuf += blocksize;
      inbuflen -= blocksize;
    }
  if ( inbuflen )
    {
      /* Save the current IV and then encrypt the IV. */
      buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
      nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
      burn = nburn > burn ? nburn : burn;
      c->unused = blocksize;
      /* Apply the XOR. */
      c->unused -= inbuflen;
      buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, inbuflen);
      outbuf += inbuflen;
      inbuf += inbuflen;
      inbuflen = 0;
    }

  if (burn > 0)
    _gcry_burn_stack (burn + 4 * sizeof(void *));

  return 0;
}
Esempio n. 2
0
/* Run the self-tests for <block cipher>-CFB-<block size>, tests bulk CFB
   decryption.  Returns NULL on success. */
const char *
_gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey_func,
			   gcry_cipher_encrypt_t encrypt_one,
			   gcry_cipher_bulk_cfb_dec_t bulk_cfb_dec,
			   const int nblocks, const int blocksize,
			   const int context_size)
{
  int i, offs;
  unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem;
  unsigned int ctx_aligned_size, memsize;

  // blad3master: change alignment to MSVC specific
  __declspec(align(16)) static const unsigned char key[16] = {
      0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33
    };

  /* Allocate buffers, align first two elements to 16 bytes and latter to
     block size.  */
  ctx_aligned_size = context_size + 15;
  ctx_aligned_size -= ctx_aligned_size & 0xf;

  memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;

  mem = xtrycalloc (1, memsize);
  if (!mem)
    return "failed to allocate memory";

  offs = (16 - ((uintptr_t)mem & 15)) & 15;
  ctx = (void*)(mem + offs);
  iv = ctx + ctx_aligned_size;
  iv2 = iv + blocksize;
  plaintext = iv2 + blocksize;
  plaintext2 = plaintext + nblocks * blocksize;
  ciphertext = plaintext2 + nblocks * blocksize;

  /* Initialize ctx */
  setkey_func (ctx, key, sizeof(key));

  /* Test single block code path */
  memset(iv, 0xd3, blocksize);
  memset(iv2, 0xd3, blocksize);
  for (i = 0; i < blocksize; i++)
    plaintext[i] = i;

  /* CFB manually.  */
  encrypt_one (ctx, ciphertext, iv);
  buf_xor_2dst (iv, ciphertext, plaintext, blocksize);

  /* CFB decrypt.  */
  bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, 1);
  if (memcmp(plaintext2, plaintext, blocksize))
    {
      xfree(mem);
#ifdef HAVE_SYSLOG
      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
              "%s-CFB-%d test failed (plaintext mismatch)", cipher,
	      blocksize * 8);
#endif
      return "selftest for CFB failed - see syslog for details";
    }

  if (memcmp(iv2, iv, blocksize))
    {
      xfree(mem);
#ifdef HAVE_SYSLOG
      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
              "%s-CFB-%d test failed (IV mismatch)", cipher, blocksize * 8);
#endif
      return "selftest for CFB failed - see syslog for details";
    }

  /* Test parallelized code paths */
  memset(iv, 0xe6, blocksize);
  memset(iv2, 0xe6, blocksize);

  for (i = 0; i < nblocks * blocksize; i++)
    plaintext[i] = i;

  /* Create CFB ciphertext manually.  */
  for (i = 0; i < nblocks * blocksize; i+=blocksize)
    {
      encrypt_one (ctx, &ciphertext[i], iv);
      buf_xor_2dst (iv, &ciphertext[i], &plaintext[i], blocksize);
    }

  /* Decrypt using bulk CBC and compare result.  */
  bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, nblocks);

  if (memcmp(plaintext2, plaintext, nblocks * blocksize))
    {
      xfree(mem);
#ifdef HAVE_SYSLOG
      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
              "%s-CFB-%d test failed (plaintext mismatch, parallel path)",
              cipher, blocksize * 8);
#endif
      return "selftest for CFB failed - see syslog for details";
    }
  if (memcmp(iv2, iv, blocksize))
    {
      xfree(mem);
#ifdef HAVE_SYSLOG
      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
              "%s-CFB-%d test failed (IV mismatch, parallel path)", cipher,
	      blocksize * 8);
#endif
      return "selftest for CFB failed - see syslog for details";
    }

  xfree(mem);
  return NULL;
}