int
sc_cipher_decrypt (sc_cipher_hd_t h, void *out, size_t outsize,
                   const void *in, size_t inlen, int* outlen, int last)
{
    TInt err( KErrNone );

    if (last && !outlen)
        err = KErrArgument;
    else if (! in)
        /* Caller requested in-place encryption. */
        /* Actullay cipher_encrypt() does not need to know about it, but
         * we may chnage this to get better performance. */
        err = cipher_decrypt (h, (byte*)out, (byte*)out, outsize, outlen, last);
    else if (inlen == 0)
        return err;
    else if (outsize < inlen)
        err = KErrArgument;
    else if (((h->mode == SC_CIPHER_MODE_ECB)
              || ((h->mode == SC_CIPHER_MODE_CBC)
                  && (! ((h->flags & SC_CIPHER_CBC_CTS)
                         && (inlen > h->blocksize)))))
             && (inlen % h->blocksize))
        err = KErrArgument;
    else
        err = cipher_decrypt (h, (byte*)out, (byte*)in, inlen, outlen, last);

    return err;
}
Beispiel #2
0
static int do_decryption(const char *algo_name)
{
	int fd_plain, fd_cipher;
	u8 data[PAGE_SIZE];
	u32 file_size;
	int retv;

	if (open_plain_cipher_files(&fd_plain, &fd_cipher) < 0) {
		printf("Cannot open files!\n");
		return -1;
	}
	file_size = get_file_size(fd_cipher);

	if (prepare_cipher_algo(algo_name) < 0) {
		printf("prepare_cipher_algo failed !\n");
		return -1;
	}

	if (prepare_cipher_key(default_key, KEY_LENGTH) < 0) {
		printf("prepare_cipher_key failed !\n");
		return -1;
	}

	while (file_size > PAGE_SIZE) {
		if ((retv = read(fd_cipher, data, PAGE_SIZE)) != PAGE_SIZE) {
			printf("Read data failed [%d].\n", retv);
			return -1;
		}
		print_u8_array("Cipher Text", data, PAGE_SIZE);
		if (cipher_decrypt(data, PAGE_SIZE) < 0) {
			printf("cipher_decrypt failed !\n");
			return -1;
		}
		print_u8_array("Plain Text", data, PAGE_SIZE);
		if ((retv = write(fd_plain, data, PAGE_SIZE)) != PAGE_SIZE) {
			printf("Write data failed [%d].\n", retv);
			return -1;
		}
		file_size -= PAGE_SIZE;
	}
	if ((retv = read(fd_cipher, data, file_size)) != file_size) {
		printf("Read data failed [%d].\n", retv);
		return -1;
	}
	print_u8_array("Cipher Text", data, file_size);
	if (cipher_decrypt(data, file_size) < 0) {
		printf("cipher_decrypt failed !\n");
		return -1;
	}
	print_u8_array("Plain Text", data, file_size);
	if ((retv = write(fd_plain, data, file_size)) != file_size) {
		printf("Write data failed [%d].\n", retv);
		return -1;
	}

	close_plain_cipher_files(fd_plain, fd_cipher);

	return 0;
}
Beispiel #3
0
gcry_error_t
gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
		     const void *in, size_t inlen)
{
  gcry_err_code_t err;

  if (!in) /* Caller requested in-place encryption. */
    err = cipher_decrypt (h, out, outsize, out, outsize);
  else
    err = cipher_decrypt (h, out, outsize, in, inlen);

  return gcry_error (err);
}
Beispiel #4
0
static
ssize_t xdecrypt(struct master_config* config, struct cipher_context* context, const char* in, size_t ilength, char* out) {
    char* tmp;
    char* signature;
    ssize_t olength, i;

    if (ilength < config->digest_size) {
        return -1;
    }

    tmp = alloca(ilength - config->digest_size);
    signature = alloca(config->digest_size);

    olength = cipher_decrypt(context, in, ilength - config->digest_size, tmp);
    if (olength < config->cipher_size) {
        fprintf(stderr, "invalid packet. %d\n", (int)olength);
        return -1;
    }

    digest_sign(config->digest, tmp, olength, signature);
    if (memcmp(signature, in + ilength - config->digest_size, config->digest_size) != 0) {
        /*fprintf(stderr, "signature mistmatch\n");*/
        return -1;
    }
    memcpy(out, tmp + config->cipher_size, olength - config->cipher_size);
    return olength - config->cipher_size;
}
Beispiel #5
0
gcry_err_code_t
_gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
                      const void *in, size_t inlen)
{
  if (!in) /* Caller requested in-place encryption. */
    {
      in = out;
      inlen = outsize;
    }

  return cipher_decrypt (h, out, outsize, in, inlen);
}
Beispiel #6
0
int
main(int argc, char **argv)
{
    int encode=0;
    CIPHER_HANDLE hd;
    char buf[4096];
    int n, size=4096;
    int algo;

#ifdef HAVE_DOSISH_SYSTEM
    setmode( fileno(stdin), O_BINARY );
    setmode( fileno(stdout), O_BINARY );
#endif

    i18n_init();
    if( argc > 1 && !strcmp(argv[1], "-e") ) {
	encode++;
	argc--; argv++;
    }
    else if( argc > 1 && !strcmp(argv[1], "-E") ) {
	encode++;
	argc--; argv++;
	size = 10;
    }
    else if( argc > 1 && !strcmp(argv[1], "-d") ) {
	argc--; argv++;
    }
    else if( argc > 1 && !strcmp(argv[1], "-D") ) {
	argc--; argv++;
	size = 10;
    }
    if( argc != 3 )
	my_usage();
    argc--; argv++;
    algo = string_to_cipher_algo( *argv );
    argc--; argv++;

    hd = cipher_open( algo, CIPHER_MODE_CFB, 0 );
    cipher_setkey( hd, *argv, strlen(*argv) );
    cipher_setiv( hd, NULL, 0 );
    while( (n = fread( buf, 1, size, stdin )) > 0 ) {
	if( encode )
	    cipher_encrypt( hd, buf, buf, n );
	else
	    cipher_decrypt( hd, buf, buf, n );
	if( fwrite( buf, 1, n, stdout) != n )
	    log_fatal("write error\n");
    }
    cipher_close(hd);
    return 0;
}
Beispiel #7
0
gcry_error_t
gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
		     const void *in, size_t inlen)
{
  gcry_err_code_t err = GPG_ERR_NO_ERROR;

  if (! in)
    /* Caller requested in-place encryption. */
    /* Actullay cipher_encrypt() does not need to know about it, but
     * we may chnage this to get better performance. */
    err = cipher_decrypt (h, out, out, outsize);
  else if (outsize < inlen)
    err = GPG_ERR_TOO_SHORT;
  else if (((h->mode == GCRY_CIPHER_MODE_ECB)
	    || ((h->mode == GCRY_CIPHER_MODE_CBC)
		&& (! ((h->flags & GCRY_CIPHER_CBC_CTS)
		       && (inlen > h->cipher->blocksize)))))
	   && (inlen % h->cipher->blocksize) != 0)
    err = GPG_ERR_INV_ARG;
  else
    err = cipher_decrypt (h, out, in, inlen);

  return gcry_error (err);
}
Beispiel #8
0
/**
 * Test CBC decryption
 *
 * @v cipher			Cipher algorithm
 * @v key			Key
 * @v key_len			Length of key
 * @v iv			Initialisation vector
 * @v ciphertext		Ciphertext data
 * @v expected_plaintext	Expected plaintext data
 * @v len			Length of data
 * @ret ok			Plaintext is as expected
 */
int cbc_test_decrypt ( struct cipher_algorithm *cipher, const void *key,
		       size_t key_len, const void *iv, const void *ciphertext,
		       const void *expected_plaintext, size_t len ) {
	uint8_t ctx[cipher->ctxsize];
	uint8_t plaintext[len];
	int rc;

	/* Initialise cipher */
	rc = cipher_setkey ( cipher, ctx, key, key_len );
	assert ( rc == 0 );
	cipher_setiv ( cipher, ctx, iv );

	/* Perform encryption */
	cipher_decrypt ( cipher, ctx, ciphertext, plaintext, len );

	/* Verify result */
	return ( memcmp ( plaintext, expected_plaintext, len ) == 0 );
}
Beispiel #9
0
/**
 * Unwrap a key or other data using AES Key Wrap (RFC 3394)
 *
 * @v kek	Key Encryption Key, 16 bytes
 * @v src	Data to decrypt
 * @v nblk	Number of 8-byte blocks in @e plaintext key
 * @ret dest	Decrypted data (8 bytes shorter than input)
 * @ret rc	Zero on success, nonzero on IV mismatch
 *
 * The algorithm is implemented such that @a src and @a dest may point
 * to the same buffer.
 */
int aes_unwrap ( const void *kek, const void *src, void *dest, int nblk )
{
	u8 A[8], B[16];
	u8 *R;
	int i, j;
	void *aes_ctx = malloc ( AES_CTX_SIZE );

	if ( ! aes_ctx )
		return -1;

	cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 );

	/* Set up */
	memcpy ( A, src, 8 );
	memmove ( dest, src + 8, nblk * 8 );

	/* Unwrap */
	for ( j = 5; j >= 0; j-- ) {
		R = dest + ( nblk - 1 ) * 8;
		for ( i = nblk; i >= 1; i-- ) {
			memcpy ( B, A, 8 );
			memcpy ( B + 8, R, 8 );
			B[7] ^= ( nblk * j ) + i;
			cipher_decrypt ( &aes_algorithm, aes_ctx, B, B, 16 );
			memcpy ( A, B, 8 );
			memcpy ( R, B + 8, 8 );
			R -= 8;
		}
	}

	free ( aes_ctx );

	/* Check IV */
	for ( i = 0; i < 8; i++ ) {
		if ( A[i] != 0xA6 )
			return -1;
	}

	return 0;
}
Beispiel #10
0
static int auto_test(char * algo_name)
{
	u8 plain[TEXT_LENGTH] = {0};
	u8 cipher[TEXT_LENGTH] = {0};
	u8 temp[TEXT_LENGTH] = {0};
	u32 key_len = sizeof(default_key);
	u32 text_bytes = sizeof(plain);
	u8 in[]="The quick brown fox jumps over the lazy dog";
	u8 correctsha[]={0x2f,0xd4,0xe1,0xc6,0x7a,0x2d,0x28,0xfc,0xed,0x84,0x9e,0xe1,0xbb,0x76,0xe7,0x39,0x1b,0x93,0xeb,0x12,'\0'};
	u8 correctmd5[]={0x9e,0x10,0x7d,0x9d,0x37,0x2b,0xb6,0x82,0x6b,0xd8,0x1d,0x35,0x42,0xa4,0x19,0xd6,'\0'};
	u8 out[21];

	if (prepare_cipher_algo(algo_name) < 0) {
		printf("prepare_cipher_algo failed !\n");
		return -1;
	}

	if (prepare_cipher_key(default_key, key_len) < 0) {
		printf("prepare_cipher_key failed !\n");
		return -1;
	}

	set_plain_text(plain, sizeof(plain) - 4);
	memcpy(cipher, plain, sizeof(plain));
	printf("== Before encryption ==");
	print_u8_array("Plain Text", plain, sizeof(plain));
	print_u8_array("Cipher Text", cipher, sizeof(cipher));
	if (cipher_encrypt(plain, text_bytes) < 0) {
		printf("cipher_encrypt failed !\n");
		return -1;
	}
	printf("\n== After encrytion ==");
	memcpy(temp, cipher, sizeof(temp));
	memcpy(cipher, plain, sizeof(cipher));
	memcpy(plain, temp, sizeof(plain));
	print_u8_array("Plain Text", plain, sizeof(plain));
	print_u8_array("Cipher Text", cipher, sizeof(cipher));
	printf("\n== Before decryption ==");
	print_u8_array("Plain Text", plain, sizeof(plain));
	print_u8_array("Cipher Text", cipher, sizeof(cipher));
	if (cipher_decrypt(cipher, text_bytes) < 0) {
		printf("cipher_decrypt failed !\n");
		return -1;
	}
	printf("\n== After decrytion ==");
	print_u8_array("Plain Text", plain, sizeof(plain));
	print_u8_array("Cipher Text", cipher, sizeof(cipher));

	printf("\n== TEST SHA1&MD5 ==\n");
	printf("in= %s\n",in);
	if(auto_sha(in,out) != 0){
		printf("SHA1 driver failed!\n");
	}
	out[20]='\0';
	if(strcmp((const char*)out,(const char*)correctsha) == 0){
		printf("SHA1 CORRECT!\n");
	}else{
		printf("SHA1 ERROR; The correct should be 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\n");
	}

	if(auto_md5(in,out) != 0){
		printf("MD5 driver failed!\n");
	}
	out[16]='\0';
	if(strcmp((const char*)out,(const char*)correctmd5) == 0){
		printf("MD5 CORRECT!\n");
	}else{
		printf("MD5 ERROR; The correct should be 9e107d9d372bb6826bd81d3542a419d6\n");
	}
	return 0;
}
Beispiel #11
0
int main(int argc, char **argv)
{
  int c;
  SshCryptoStatus cs;
  SshCipher cipher;
  Boolean all_ciphers = FALSE, speed_test = FALSE, quiet = FALSE;
  unsigned char *iv = NULL, *key = NULL;
  size_t iv_len = 0, key_len = 0;
  char *cipher_name = NULL, *cipher_names, *hlp, *passphrase = NULL;
  Boolean encrypt_mode = TRUE;
  char *input_file = NULL, *output_file = NULL;
  FILE *fin, *fout;
  Boolean r = TRUE;

  if (strchr(argv[0], '/'))
    av0 = strrchr(argv[0], '/') + 1;
  else
    av0 = argv[0];

  if (strcasecmp(av0, "ssh-encrypt") == 0)
    encrypt_mode = TRUE;
  else if (strcasecmp(av0, "ssh-decrypt") == 0)
    encrypt_mode = FALSE;

  if (ssh_crypto_library_initialize() != SSH_CRYPTO_OK)
    {
      fprintf(stderr, "Can't initialize the cryptographic provider.\n");
      exit(1);
    }
  while ((c = ssh_getopt(argc, argv, "thd:ac:i:k:EDp:", NULL)) != -1)
    {
      switch (c)
        {
        case 'd':
          ssh_debug_set_level_string(ssh_optarg);
          break;
        case 't':
          speed_test = TRUE;
          break;
        case 'a':
          all_ciphers = TRUE;
          break;
        case 'c':
          cipher_name = ssh_xstrdup(ssh_optarg);
          break;
        case 'q':
          quiet = TRUE;
          break;
        case 'i':
          if (iv)
            {
              fprintf(stderr,
                      "%s: No multiple initialization vectors allowed.\n",
                      av0);
              usage();
              exit(-1);
            }
          if (! hex_string_to_data(ssh_optarg, &iv, &iv_len))
            {
              fprintf(stderr, "%s: Bad IV string.\n", av0); 
              exit(-1);
            }
          break;
        case 'k':
          if (key)
            {
              fprintf(stderr, "%s: No multiple keys allowed.\n", av0);
              usage();
              exit(-1);
            }
          if (! hex_string_to_data(ssh_optarg, &key, &key_len))
            {
              fprintf(stderr, "%s: Bad KEY string.\n", av0); 
              exit(-1);
            }
          break;
        case 'p':
          if (passphrase)
            {
              fprintf(stderr, "%s: No multiple passphrases allowed.\n", av0);
              usage();
              exit(-1);
            }
          passphrase = ssh_optarg;
          break;
        case 'E':
          encrypt_mode = TRUE;
          break;
        case 'D':
          encrypt_mode = FALSE;
          break;
        case 'h':
          help_info();
          usage();
          exit(0);
          /*NOTREACHED*/
        default:
          usage();
          exit(-1);
          /*NOTREACHED*/
        }
    }
  argc -= ssh_optind;
  argv += ssh_optind;
  if (speed_test && (argc > 0))
    {
      fprintf(stderr, "%s: Extra parameters.\n", av0);
      usage();
      exit(-1);
      /*NOTREACHED*/
    }
  if (argc > 2)
    {
      fprintf(stderr, "%s: Extra parameters.\n", av0);
      usage();
      exit(-1);
      /*NOTREACHED*/
    }
  if (argc > 1)
    output_file = ssh_xstrdup(argv[1]);
  if (argc > 0)
    input_file = ssh_xstrdup(argv[0]);
  if ((cipher_name != NULL) && all_ciphers)
    {
      fprintf(stderr, "%s: -c and -a can't be used together.\n", av0);
      usage();
      exit(-1);
      /*NOTREACHED*/
    }
  if (all_ciphers && !speed_test)
    {
      fprintf(stderr, "%s: -a can only be used with -t.\n", av0);
      usage();
      exit(-1);
      /*NOTREACHED*/
    }
  if ((cipher_name != NULL) && strchr(cipher_name, ',') && !speed_test)
    {
      fprintf(stderr, "%s: Multiple ciphers only be used with -t.\n", av0);
      usage();
      exit(-1);
      /*NOTREACHED*/
    }
  if (cipher_name == NULL)
    {
      if (speed_test)
        {
          all_ciphers = TRUE; /* Assume `all' if test mode with no ciphers. */
        }
      else
        {
          fprintf(stderr, "Missing -c flag.\n");
          usage();
          exit(-1);
          /*NOTREACHED*/
        }
    }
  if (passphrase && key)
    {
      fprintf(stderr, "%s: Can't use both passphrase and hex key.\n", av0);
      usage();
      exit(-1);
      /*NOTREACHED*/
    }
  if (!key && !passphrase && !speed_test)
    {
      ssh_warning("%s: No key!  Empty passphrase assumed.", av0);
      passphrase = "";
      /*NOTREACHED*/
    }
  if (speed_test)
    {
      fprintf(stderr, "Performing speed tests\n");
      if (all_ciphers)
        {
          cipher_names = ssh_cipher_get_supported();
        }
      else
        {
          /* Steal allocated cipher_name */
          cipher_names = cipher_name;
          cipher_name = NULL;
        }
      hlp = cipher_names;
      while ((cipher_name = ssh_name_list_get_name(hlp)) != NULL)
        {
          hlp += strlen(cipher_name);
          if (*hlp == ',')
            hlp++;
          cipher_speed_test(cipher_name,
                            passphrase,
                            key, key_len,
                            iv, iv_len,
                            encrypt_mode);
          ssh_xfree(cipher_name);

          if (strlen(hlp) == 0)
            break;
        }
      ssh_xfree(cipher_names);
    }
  else
    {
      if (passphrase)
        cs = ssh_cipher_allocate_with_passphrase(cipher_name,
                                                 passphrase,
                                                 encrypt_mode,
                                                 &cipher);
      else
        cs = ssh_cipher_allocate(cipher_name,
                                 key,
                                 key_len,
                                 encrypt_mode,
                                 &cipher);
      if (cs != SSH_CRYPTO_OK)
        {
          switch (cs)
            {
            case SSH_CRYPTO_UNSUPPORTED:
              fprintf(stderr, "%s: Unsupported cipher \"%s\".\n", av0, 
                      cipher_name);
              usage();
              exit(-1);
            case SSH_CRYPTO_KEY_TOO_SHORT:
              fprintf(stderr, "%s: Key too short for \"%s\".\n", av0, 
                      cipher_name);
              usage();
              exit(-1);
            default:
              fprintf(stderr, "%s: Cipher allocate failed.\n", av0);
              exit(-1);
            }
          /*NOTREACHED*/
        }
      if (iv != NULL)
        {
          if (ssh_cipher_get_iv_length(ssh_cipher_name(cipher)) == iv_len)
            ssh_cipher_set_iv(cipher, iv);
          else
            {
              fprintf(stderr, "%s: Weird IV length.\n", av0);
              exit(-1);
            }
        }
      if (input_file != NULL)
        {
          fin = fopen(input_file, "r");
          if (fin == NULL)
            {
              fprintf(stderr, "%s: Cannot open input file \"%s\".\n", 
                      av0, input_file);
              exit(-1);
            }
        }
      else
        {
          fin = stdin;
        }
      if (output_file != NULL)
        {
          struct stat st;
          if (stat(output_file, &st) >= 0)
            {
              fprintf(stderr, "%s: Output file \"%s\" exists.\n", av0, 
                      output_file);
              exit(-1);
            }
          fout = fopen(output_file, "w");
          if (fout == NULL)
            {    
              fprintf(stderr, "%s: Cannot open output file \"%s\".\n", 
                      av0, output_file);
              exit(-1);
            }
        }
      else
        {
          fout = stdout;
        }
      if (encrypt_mode)
        r = cipher_encrypt(cipher, fin, fout);
      else
        r = cipher_decrypt(cipher, fin, fout);
      if (input_file)
        fclose(fin);
      if (output_file)
        {
          fclose(fout);
          if (! r)
            (void)unlink(output_file);
        }
      ssh_cipher_free(cipher);
      ssh_xfree(cipher_name);
    }

  ssh_xfree(input_file);
  ssh_xfree(output_file);
  ssh_xfree(key);
  ssh_xfree(iv);

  ssh_crypto_library_uninitialize();
  ssh_util_uninit();
  return((r == TRUE) ? 0 : -1);
}
Beispiel #12
0
err_status_t
cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) {
  const cipher_test_case_t *test_case = test_data;
  cipher_t *c;
  err_status_t status;
  uint8_t buffer[SELF_TEST_BUF_OCTETS];
  uint8_t buffer2[SELF_TEST_BUF_OCTETS];
  unsigned int len;
  int i, j, case_num = 0;

  debug_print(mod_cipher, "running self-test for cipher %s", 
	      ct->description);
  
  /*
   * check to make sure that we have at least one test case, and
   * return an error if we don't - we need to be paranoid here
   */
  if (test_case == NULL)
    return err_status_cant_check;

  /*
   * loop over all test cases, perform known-answer tests of both the
   * encryption and decryption functions
   */  
  while (test_case != NULL) {

    /* allocate cipher */
    status = cipher_type_alloc(ct, &c, test_case->key_length_octets);
    if (status)
      return status;
    
    /*
     * test the encrypt function 
     */
    debug_print(mod_cipher, "testing encryption", NULL);    
    
    /* initialize cipher */
    status = cipher_init(c, test_case->key, direction_encrypt);
    if (status) {
      cipher_dealloc(c);
      return status;
    }
    
    /* copy plaintext into test buffer */
    if (test_case->ciphertext_length_octets > SELF_TEST_BUF_OCTETS) {
      cipher_dealloc(c);    
      return err_status_bad_param;
    }
    for (i=0; i < test_case->plaintext_length_octets; i++)
      buffer[i] = test_case->plaintext[i];

    debug_print(mod_cipher, "plaintext:    %s",
	     octet_string_hex_string(buffer,
				     test_case->plaintext_length_octets));

    /* set the initialization vector */
    status = cipher_set_iv(c, test_case->idx);
    if (status) {
      cipher_dealloc(c);
      return status;
    } 
    
    /* encrypt */
    len = test_case->plaintext_length_octets;
    status = cipher_encrypt(c, buffer, &len);
    if (status) {
      cipher_dealloc(c);
      return status;
    }
    
    debug_print(mod_cipher, "ciphertext:   %s",
	     octet_string_hex_string(buffer,
				     test_case->ciphertext_length_octets));

    /* compare the resulting ciphertext with that in the test case */
    if (len != (unsigned int)test_case->ciphertext_length_octets)
      return err_status_algo_fail;
    status = err_status_ok;
    for (i=0; i < test_case->ciphertext_length_octets; i++)
      if (buffer[i] != test_case->ciphertext[i]) {
	status = err_status_algo_fail;
	debug_print(mod_cipher, "test case %d failed", case_num);
	debug_print(mod_cipher, "(failure at byte %d)", i);
	break;
      }
    if (status) {

      debug_print(mod_cipher, "c computed: %s",
	     octet_string_hex_string(buffer,
		  2*test_case->plaintext_length_octets));
      debug_print(mod_cipher, "c expected: %s",
		  octet_string_hex_string(test_case->ciphertext,
			  2*test_case->plaintext_length_octets));

      cipher_dealloc(c);
      return err_status_algo_fail;
    }

    /*
     * test the decrypt function
     */
    debug_print(mod_cipher, "testing decryption", NULL);    

    /* re-initialize cipher for decryption */
    status = cipher_init(c, test_case->key, direction_decrypt);
    if (status) {
      cipher_dealloc(c);
      return status;
    }

    /* copy ciphertext into test buffer */
    if (test_case->ciphertext_length_octets > SELF_TEST_BUF_OCTETS) {
      cipher_dealloc(c);    
      return err_status_bad_param;
    }
    for (i=0; i < test_case->ciphertext_length_octets; i++)
      buffer[i] = test_case->ciphertext[i];

    debug_print(mod_cipher, "ciphertext:    %s",
		octet_string_hex_string(buffer,
					test_case->plaintext_length_octets));

    /* set the initialization vector */
    status = cipher_set_iv(c, test_case->idx);
    if (status) {
      cipher_dealloc(c);
      return status;
    } 
    
    /* decrypt */
    len = test_case->ciphertext_length_octets;
    status = cipher_decrypt(c, buffer, &len);
    if (status) {
      cipher_dealloc(c);
      return status;
    }
    
    debug_print(mod_cipher, "plaintext:   %s",
	     octet_string_hex_string(buffer,
				     test_case->plaintext_length_octets));

    /* compare the resulting plaintext with that in the test case */
    if (len != (unsigned int)test_case->plaintext_length_octets)
      return err_status_algo_fail;
    status = err_status_ok;
    for (i=0; i < test_case->plaintext_length_octets; i++)
      if (buffer[i] != test_case->plaintext[i]) {
	status = err_status_algo_fail;
	debug_print(mod_cipher, "test case %d failed", case_num);
	debug_print(mod_cipher, "(failure at byte %d)", i);
      }
    if (status) {

      debug_print(mod_cipher, "p computed: %s",
	     octet_string_hex_string(buffer,
		  2*test_case->plaintext_length_octets));
      debug_print(mod_cipher, "p expected: %s",
		  octet_string_hex_string(test_case->plaintext,
			  2*test_case->plaintext_length_octets));

      cipher_dealloc(c);
      return err_status_algo_fail;
    }

    /* deallocate the cipher */
    status = cipher_dealloc(c);
    if (status)
      return status;
    
    /* 
     * the cipher passed the test case, so move on to the next test
     * case in the list; if NULL, we'l proceed to the next test
     */   
    test_case = test_case->next_test_case;
    ++case_num;
  }
  
  /* now run some random invertibility tests */

  /* allocate cipher, using paramaters from the first test case */
  test_case = test_data;
  status = cipher_type_alloc(ct, &c, test_case->key_length_octets);
  if (status)
      return status;
  
  rand_source_init();
  
  for (j=0; j < NUM_RAND_TESTS; j++) {
    unsigned length;
    int plaintext_len;
    uint8_t key[MAX_KEY_LEN];
    uint8_t  iv[MAX_KEY_LEN];

    /* choose a length at random (leaving room for IV and padding) */
    length = rand() % (SELF_TEST_BUF_OCTETS - 64);
    debug_print(mod_cipher, "random plaintext length %d\n", length);
    status = rand_source_get_octet_string(buffer, length);
    if (status) return status;

    debug_print(mod_cipher, "plaintext:    %s",
		octet_string_hex_string(buffer, length));

    /* copy plaintext into second buffer */
    for (i=0; (unsigned int)i < length; i++)
      buffer2[i] = buffer[i];
    
    /* choose a key at random */
    if (test_case->key_length_octets > MAX_KEY_LEN)
      return err_status_cant_check;
    status = rand_source_get_octet_string(key, test_case->key_length_octets);
    if (status) return status;

   /* chose a random initialization vector */
    status = rand_source_get_octet_string(iv, MAX_KEY_LEN);
    if (status) return status;
        
    /* initialize cipher */
    status = cipher_init(c, key, direction_encrypt);
    if (status) {
      cipher_dealloc(c);
      return status;
    }

    /* set initialization vector */
    status = cipher_set_iv(c, test_case->idx);
    if (status) {
      cipher_dealloc(c);
      return status;
    } 

    /* encrypt buffer with cipher */
    plaintext_len = length;
    status = cipher_encrypt(c, buffer, &length);
    if (status) {
      cipher_dealloc(c);
      return status;
    }
    debug_print(mod_cipher, "ciphertext:   %s",
		octet_string_hex_string(buffer, length));

    /* 
     * re-initialize cipher for decryption, re-set the iv, then
     * decrypt the ciphertext
     */
    status = cipher_init(c, key, direction_decrypt);
    if (status) {
      cipher_dealloc(c);
      return status;
    }
    status = cipher_set_iv(c, test_case->idx);
    if (status) {
      cipher_dealloc(c);
      return status;
    } 
    status = cipher_decrypt(c, buffer, &length);
    if (status) {
      cipher_dealloc(c);
      return status;
    }    

    debug_print(mod_cipher, "plaintext[2]: %s",
		octet_string_hex_string(buffer, length));    

    /* compare the resulting plaintext with the original one */
    if (length != (unsigned int)plaintext_len)
      return err_status_algo_fail;
    status = err_status_ok;
    for (i=0; i < plaintext_len; i++)
      if (buffer[i] != buffer2[i]) {
	status = err_status_algo_fail;
	debug_print(mod_cipher, "random test case %d failed", case_num);
	debug_print(mod_cipher, "(failure at byte %d)", i);
      }
    if (status) {
      cipher_dealloc(c);
      return err_status_algo_fail;
    }
        
  }

  status = cipher_dealloc(c);
  if (status)
    return status;

  return err_status_ok;
}