summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>1999-09-18 10:17:18 +0000
committerWerner Koch <wk@gnupg.org>1999-09-18 10:17:18 +0000
commita1934b9e7193801ab58529064c02edb1ee2aa57e (patch)
treec8e096d0806c4d43738ea83e40e554ae31c726f2
parent3cc20e7cad424e807921ee52b30db262febca6ff (diff)
downloadlibgcrypt-a1934b9e7193801ab58529064c02edb1ee2aa57e.tar.gz
See ChangeLog: Sat Sep 18 12:16:08 CEST 1999 Werner Koch
-rw-r--r--cipher/Makefile.am5
-rw-r--r--cipher/cipher.c1
-rw-r--r--cipher/rndw32.c265
-rw-r--r--src/gcrypt.h30
-rw-r--r--src/mdapi.c25
-rw-r--r--src/symapi.c181
6 files changed, 458 insertions, 49 deletions
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 3d9a5cb9..e68ee19f 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -99,4 +99,9 @@ rndlinux: $(srcdir)/rndlinux.c
rndegd: $(srcdir)/rndegd.c
$(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndegd $(srcdir)/rndegd.c
+# We need to have a better system for selection which modules
+# to compile. For now this works.
+rndw32: $(srcdir)/rndw32.c
+ echo "#!/bin/sh" >rndw32
+ echo "Not usable as a module" >>rndw32
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 990671fc..7224ab69 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -362,6 +362,7 @@ cipher_open( int algo, int mode, int secure )
if( algo == CIPHER_ALGO_DUMMY )
hd->mode = CIPHER_MODE_DUMMY;
else if( mode == CIPHER_MODE_AUTO_CFB ) {
+ #warning Remove this code and the AUTO:CFB macro.
if( algo >= 100 )
hd->mode = CIPHER_MODE_CFB;
else
diff --git a/cipher/rndw32.c b/cipher/rndw32.c
new file mode 100644
index 00000000..032d666a
--- /dev/null
+++ b/cipher/rndw32.c
@@ -0,0 +1,265 @@
+/* rndw32.c - interface to the Winseed DLL
+ * Copyright (C) 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <windows.h>
+
+#include "types.h"
+#include "util.h"
+#include "dynload.h"
+
+
+#ifdef IS_MODULE
+ #define _(a) (a)
+#else
+ #include "i18n.h"
+#endif
+
+
+#define WIN32_SLOW_SEEDER 0
+#define WIN32_FAST_SEEDER 1
+
+#define PCP_SUCCESS 0
+#define PCP_NULL_POINTER 1
+#define PCP_SEEDER_FAILED 2
+#define PCP_SEEDER_NO_MEM 3
+#define PCP_SEEDER_TOO_SMALL 4
+#define PCP_DLL_LOAD_FAILED 5
+#define PCP_UNKNOWN_PLATFORM 6
+#define PCP_ERROR_VERSION 7
+#define PCP_DLL_FUNC 8
+#define PCP_UNKNOWN_SEEDER_TYPE 9
+
+typedef void *WIN32_SEEDER;
+
+static WIN32_SEEDER (WINAPI *create_instance)( byte type, unsigned int *reason);
+static void (WINAPI *delete_instance)( WIN32_SEEDER that );
+static unsigned int (WINAPI *get_internal_seed_size)( WIN32_SEEDER that );
+static void (WINAPI *set_internal_seed_size)( WIN32_SEEDER that,
+ unsigned int new_size);
+static unsigned int (WINAPI *get_expected_seed_size)( WIN32_SEEDER that);
+static unsigned int (WINAPI *get_seed)( WIN32_SEEDER that, byte *buffer,
+ unsigned int *desired_length);
+
+static WIN32_SEEDER slow_seeder, fast_seeder;
+static byte *entropy_buffer;
+static size_t entropy_buffer_size;
+
+static char *entropy_dll;
+
+/****************
+ * Load and initialize the winseed DLL
+ * NOTE: winseed is not part of the GnuPG distribution. It should be available
+ * at the GNU crypto FTP server site.
+ * We do not load the DLL on demand to have a better control over the
+ * location of the library.
+ */
+static void
+load_and_init_winseed( void )
+{
+ int hInstance;
+ void *addr;
+ unsigned int reason = 0;
+ unsigned int n1, n2;
+ const char *dllname = entropy_dll? entropy_dll : "c:/gnupg/entropy.dll";
+
+ hInstance = LoadLibrary( dllname );
+ if( !hInstance )
+ goto failure;
+ if( !(addr = GetProcAddress( hInstance, "WS_create_instance" )) )
+ goto failure;
+ create_instance = addr;
+ if( !(addr = GetProcAddress( hInstance, "WS_delete_instance" )) )
+ goto failure;
+ delete_instance = addr;
+ if( !(addr = GetProcAddress( hInstance, "WS_get_internal_seed_size" )) )
+ goto failure;
+ get_internal_seed_size = addr;
+ if( !(addr = GetProcAddress( hInstance, "WS_set_internal_seed_size" )) )
+ goto failure;
+ set_internal_seed_size = addr;
+ if( !(addr = GetProcAddress( hInstance, "WS_get_expected_seed_size" )) )
+ goto failure;
+ get_expected_seed_size = addr;
+ if( !(addr = GetProcAddress( hInstance, "WS_get_seed" )) )
+ goto failure;
+ get_seed = addr;
+
+ /* we have all the functions - init the system */
+ slow_seeder = create_instance( WIN32_SLOW_SEEDER, &reason);
+ if( !slow_seeder ) {
+ g10_log_fatal("error creating winseed slow seeder: rc=%u\n", reason );
+ goto failure;
+ }
+ fast_seeder = create_instance( WIN32_FAST_SEEDER, &reason);
+ if( !fast_seeder ) {
+ g10_log_fatal("error creating winseed fast seeder: rc=%u\n", reason );
+ goto failure;
+ }
+ g10_log_info("slow and fast seeders created.\n");
+ n1 = get_internal_seed_size( slow_seeder );
+ g10_log_info("slow buffer size=%u\n", n1);
+ n2 = get_internal_seed_size( fast_seeder );
+ g10_log_info("fast buffer size=%u\n", n2);
+
+ entropy_buffer_size = n1 > n2? n1: n2;
+ entropy_buffer = m_alloc( entropy_buffer_size );
+ g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );
+
+ return;
+
+ failure:
+ g10_log_fatal("error loading winseed DLL `%s'\n", dllname );
+}
+
+
+
+
+
+/* Note: we always use the highest level.
+ * TO boost the performance we may want to add some
+ * additional code for level 1
+ */
+static int
+gather_random( void (*add)(const void*, size_t, int), int requester,
+ size_t length, int level )
+{
+ unsigned int result;
+ unsigned int nbytes;
+
+ if( !slow_seeder )
+ load_and_init_winseed();
+
+ /* Our estimation on how much entropy we should use is very vague.
+ * Winseed delivers some amount of entropy on each slow poll and
+ * we add it to our random pool. Depending on the required quality
+ * level we adjust the requested length so that for higer quality
+ * we make sure to add more entropy to our pool. However, as we don't
+ * like to waste any entropy collected by winseed, we always add
+ * at least everything we got from winseed.
+ */
+ if( level > 1 )
+ length *= 100;
+ else if( level > 0 )
+ length *= 10;
+
+ for(;;) {
+ nbytes = entropy_buffer_size;
+ result = get_seed( slow_seeder, entropy_buffer, &nbytes);
+ if( result ) {
+ g10_log_fatal("rndw32: get_seed(slow) failed: rc=%u\n", result);
+ return -1; /* actually never reached */
+ }
+ g10_log_info("rndw32: slow poll level %d, need %u, got %u\n",
+ level, (unsigned int)length, (unsigned int)nbytes );
+ (*add)( entropy_buffer, nbytes, requester );
+ if( length <= nbytes )
+ return 0; /* okay */
+ length -= nbytes;
+ g10_log_info("rndw32: need more\n");
+ }
+}
+
+static int
+gather_random_fast( void (*add)(const void*, size_t, int), int requester )
+{
+ unsigned int result;
+ unsigned int nbytes;
+
+ if( !fast_seeder )
+ load_and_init_winseed();
+
+ /* winseed delivers a constant ammount of entropy for a fast
+ * poll. We can simply use this and add it to the pool; no need
+ * a loop like it is used in the slow poll */
+ nbytes = entropy_buffer_size;
+ result = get_seed( fast_seeder, entropy_buffer, &nbytes);
+ if( result ) {
+ g10_log_fatal("rndw32: get_seed(fast) failed: rc=%u\n", result);
+ return -1; /* actually never reached */
+ }
+ /*g10_log_info("rndw32: fast poll got %u\n", (unsigned int)nbytes );*/
+ (*add)( entropy_buffer, nbytes, requester );
+ return 0;
+}
+
+
+
+#ifndef IS_MODULE
+static
+#endif
+const char * const gnupgext_version = "RNDW32 ($Revision$)";
+
+static struct {
+ int class;
+ int version;
+ void *func;
+} func_table[] = {
+ { 40, 1, gather_random },
+ { 41, 1, gather_random_fast },
+};
+
+
+#ifndef IS_MODULE
+static
+#endif
+void *
+gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
+{
+ void *ret;
+ int i = *sequence;
+
+ do {
+ if ( i >= DIM(func_table) || i < 0 ) {
+ return NULL;
+ }
+ *class = func_table[i].class;
+ *vers = func_table[i].version;
+ ret = func_table[i].func;
+ i++;
+ } while ( what && what != *class );
+
+ *sequence = i;
+ return ret;
+}
+
+#ifdef USE_STATIC_RNDW32
+void
+rndw32_set_dll_name( const char *name )
+{
+ entropy_dll = m_strdup( name );
+}
+#endif
+
+#ifndef IS_MODULE
+void
+rndw32_constructor(void)
+{
+ register_internal_cipher_extension( gnupgext_version,
+ gnupgext_enum_func );
+}
+#endif
+
diff --git a/src/gcrypt.h b/src/gcrypt.h
index 5172be62..cb4cb43f 100644
--- a/src/gcrypt.h
+++ b/src/gcrypt.h
@@ -61,6 +61,9 @@ enum gcry_ctl_cmds {
GCRYCTL_CFB_SYNC = 3,
GCRYCTL_RESET = 4, /* e.g. for MDs */
GCRYCTL_FINALIZE = 5,
+ GCRYCTL_GET_KEYLEN = 6,
+ GCRYCTL_GET_BLKLEN = 7,
+ GCRYCTL_TEST_ALGO = 8,
};
int gcry_control( enum gcry_ctl_cmds, ... );
@@ -181,20 +184,20 @@ enum gcry_cipher_flags {
#if 0 /* not yet done */
int gcry_string_to_cipher_algo( const char *string );
-const char * gcry_cipher_algo_to_string( int algo );
int gcry_check_cipher_algo( int algo );
-unsigned gcry_cipher_get_keylen( int algo );
-unsigned gcry_cipher_get_blocksize( int algo );
#endif
-int gcry_cipher_open( GCRY_CIPHER_HD *rhd, int algo, int mode, unsigned flags);
+GCRY_CIPHER_HD r gcry_cipher_open( int algo, int mode, unsigned flags);
void gcry_cipher_close( GCRY_CIPHER_HD h );
int gcry_cipher_ctl( GCRY_CIPHER_HD h, int cmd, byte *buffer, size_t buflen);
+int gcry_cipher_info( GCRY_CIPHER_HD h, int what, void *buffer, size_t *nbytes);
+int gcry_cipher_algo_info( int algo, int what, void *buffer, size_t *nbytes);
+const char *gcry_cipher_algo_name( int algo );
int gcry_cipher_encrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize,
- byte *in, size_t inlen );
+ const byte *in, size_t inlen );
int gcry_cipher_decrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize,
- byte *in, size_t inlen );
+ const byte *in, size_t inlen );
/* some handy macros */
@@ -205,6 +208,13 @@ int gcry_cipher_decrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize,
#define gcry_cipher_sync(h) gcry_cipher_ctl( (h), GCRYCTL_CFB_SYNC, \
NULL, 0 )
+#define gcry_cipher_get_algo_keylen(a) \
+ gcry_cipher_algo_info( (a), GCRYCTL_GET_KEYLEN, NULL, NULL );
+#define gcry_cipher_get_algo_blklen(a) \
+ gcry_cipher_algo_info( (a), GCRYCTL_GET_BLKLEN, NULL, NULL );
+#define gcry_cipher_test_algo(a) \
+ gcry_cipher_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL );
+
/*********************************************
******* asymmetric cipher functions *******
@@ -236,16 +246,16 @@ enum gcry_md_flags {
};
-int gcry_md_open( GCRY_MD_HD *ret_hd, int algo, unsigned flags );
+GCRY_MD_HD gcry_md_open( int algo, unsigned flags );
void gcry_md_close( GCRY_MD_HD hd );
int gcry_md_enable( GCRY_MD_HD hd, int algo );
GCRY_MD_HD gcry_md_copy( GCRY_MD_HD hd );
int gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen);
void gcry_md_write( GCRY_MD_HD hd, const byte *buffer, size_t length);
byte *gcry_md_read( GCRY_MD_HD hd, int algo );
-int gcry_md_algo( GCRY_MD_HD hd );
-size_t gcry_md_dlen( int algo );
-int gcry_md_get( GCRY_MD_HD hd, int algo, byte *buffer, int buflen );
+int gcry_md_get_algo( GCRY_MD_HD hd );
+int gcry_md_get_dlen( int algo );
+/*??int gcry_md_get( GCRY_MD_HD hd, int algo, byte *buffer, int buflen );*/
/*****************************************
diff --git a/src/mdapi.c b/src/mdapi.c
index a0bbc648..5fd2eb61 100644
--- a/src/mdapi.c
+++ b/src/mdapi.c
@@ -31,16 +31,13 @@
#include "memory.h"
-int
-gcry_md_open( GCRY_MD_HD *ret_hd, int algo, unsigned flags )
+GCRY_MD_HD
+gcry_md_open( GCRY_MD_HD *ret_hd, int algo, unsigned int flags )
{
- GCRY_MD_HD hd;
-
/* fixme: check that algo is available and that only valid
* flag values are used */
hd = md_open( algo, (flags & GCRY_MD_FLAG_SECURE) );
- *ret_hd = hd;
- return 0;
+ return hd;
}
void
@@ -68,8 +65,6 @@ gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen)
{
if( cmd == GCRYCTL_FINALIZE )
md_final( hd );
- else if( cmd == GCRYCTL_FINALIZE )
- md_final( hd );
else
return GCRYERR_INV_OP;
return 0;
@@ -93,16 +88,17 @@ gcry_md_read( GCRY_MD_HD hd, int algo )
}
int
-gcry_md_algo( GCRY_MD_HD hd )
+gcry_md_get_algo( GCRY_MD_HD hd )
{
- return md_get_algo( hd );
+ return md_get_algo( hd ); /* fixme: we need error handling */
}
/****************
* Return the length of the digest in bytes.
+ * This function will return 0 in case of errors.
*/
-size_t
-gcry_md_dlen( int algo )
+unsigned int
+gcry_md_get_algo_dlen( int algo )
{
/* we do some very quick checks here */
switch( algo )
@@ -110,7 +106,10 @@ gcry_md_dlen( int algo )
case GCRY_MD_MD5: return 16;
case GCRY_MD_SHA1:
case GCRY_MD_RMD160: return 20;
- default: return 0; /* fixme: pass it to a lookup function */
+ default:
+ /* fixme: pass it to a lookup function */
+ set_lasterr( GCRYERR_INV_ALGO );
+ return -1;
}
}
diff --git a/src/symapi.c b/src/symapi.c
index e2aca4e2..5cd21775 100644
--- a/src/symapi.c
+++ b/src/symapi.c
@@ -49,48 +49,60 @@ struct gcry_cipher_context {
};
-int
-gcry_cipher_open( GCRY_CIPHER_HD *ret_hd, int algo, int mode, unsigned flags )
+GCRY_CIPHER_HD
+gcry_cipher_open( int algo, int mode, unsigned flags )
{
GCRY_CIPHER_HD h;
/* check whether the algo is available */
- if( check_cipher_algo( algo ) )
- return set_lasterr( GCRYERR_INV_ALGO );
+ if( check_cipher_algo( algo ) ) {
+ set_lasterr( GCRYERR_INV_ALGO );
+ return NULL;
+ }
/* check flags */
- if( (flags & ~(GCRY_CIPHER_SECURE|GCRY_CIPHER_ENABLE_SYNC)) )
- return set_lasterr( GCRYERR_INV_ARG );
+ if( (flags & ~(GCRY_CIPHER_SECURE|GCRY_CIPHER_ENABLE_SYNC)) ) {
+ set_lasterr( GCRYERR_INV_ARG );
+ return NULL;
+ }
/* map mode to internal mode */
switch( mode ) {
- case GCRY_CIPHER_MODE_NONE: mode = CIPHER_MODE_DUMMY; break;
- case GCRY_CIPHER_MODE_ECB: mode = CIPHER_MODE_ECB; break;
+ case GCRY_CIPHER_MODE_NONE:
+ mode = CIPHER_MODE_DUMMY;
+ break;
+ case GCRY_CIPHER_MODE_ECB:
+ mode = CIPHER_MODE_ECB;
+ break;
case GCRY_CIPHER_MODE_CFB:
mode = (flags & GCRY_CIPHER_ENABLE_SYNC) ? CIPHER_MODE_PHILS_CFB
: CIPHER_MODE_CFB;
break;
- case GCRY_CIPHER_MODE_CBC: mode = CIPHER_MODE_CBC; break;
+ case GCRY_CIPHER_MODE_CBC: mode = CIPHER_MODE_CBC;
+ break;
default:
- return set_lasterr( GCRYERR_INV_ALGO );
+ set_lasterr( GCRYERR_INV_ALGO );
+ return NULL;
}
/* FIXME: issue a warning when CIPHER_MODE_NONE is used */
/* allocate the handle */
h = m_lib_alloc_clear( sizeof *h );
- if( !h )
- return set_lasterr( GCRYERR_NOMEM );
+ if( !h ) {
+ set_lasterr( GCRYERR_NOMEM );
+ return NULL;
+ }
h->magic = CONTEXT_MAGIC;
h->mode = mode;
h->hd = cipher_open( algo, mode, (flags & GCRY_CIPHER_SECURE) );
if( !h ) {
m_lib_free( h );
- return set_lasterr( GCRYERR_INTERNAL );
+ set_lasterr( GCRYERR_INTERNAL );
+ return NULL;
}
- *ret_hd = h;
- return 0;
+ return h;
}
@@ -126,26 +138,143 @@ int gcry_cipher_ctl( GCRY_CIPHER_HD h, int cmd, byte *buffer, size_t buflen)
}
+/****************
+ * Return information about the cipher handle.
+ * -1 is returned on error and gcry_errno() may be used to get more information
+ * about the error.
+ */
+int
+gcry_cipher_info( GCRY_CIPHER_HD h, int cmd, byte *buffer, size_t *nbytes)
+{
+ switch( cmd ) {
+ default:
+ set_lasterr( GCRYERR_INV_OP );
+ return -1;
+ }
+ return 0;
+}
+
+/****************
+ * Return information about the given cipher algorithm
+ * WHAT select the kind of information returned:
+ * GCRYCTL_GET_KEYLEN:
+ * Return the length of the key, if the algorithm
+ * supports multiple key length, the maximum supported value
+ * is returnd. The length is return as number of octets.
+ * buffer and nbytes must be zero.
+ * GCRYCTL_GET_BLKLEN:
+ * Return the blocklength of the algorithm counted in octets.
+ * buffer and nbytes must be zero.
+ * GCRYCTL_TEST_ALGO:
+ * Returns 0 when the specified algorithm is available for use.
+ * buffer and nbytes must be zero.
+ *
+ * On error the value -1 is returned and the error reason may be
+ * retrieved by gcry_errno().
+ * Note: Because this function is in most caes used to return an
+ * integer value, we can make it easier for the caller to just look at
+ * the return value. The caller will in all cases consult the value
+ * and thereby detecting whether a error occured or not (i.e. while checking
+ * the block size)
+ */
+int
+gcry_cipher_algo_info( int algo, int what, void *buffer, size_t *nbytes)
+{
+ switch( what ) {
+ case GCRYCTL_GET_KEYLEN:
+ if( buffer || nbytes ) {
+ set_lasterr( GCRYERR_INV_ARG );
+ return -1;
+ }
+ BUG(); /* FIXME: implement this */
+ break;
+
+ case GCRYCTL_GET_BLKLEN:
+ if( buffer || nbytes ) {
+ set_lasterr( GCRYERR_INV_ARG );
+ return -1;
+ }
+ ui = cipher_get_blocksize( algo );
+ if( ui > 0 && ui < 10000 )
+ return (int)ui;
+ /* the only reason is an invalid algo or a strange blocksize */
+ set_lasterr( GCRYERR_INV_ALGO );
+ return -1;
+
+ case GCRYCTL_TEST_ALGO:
+ if( buffer || nbytes ) {
+ set_lasterr( GCRYERR_INV_ARG );
+ return -1;
+ }
+ if( check_cipher_algo( algo ) ) {
+ set_lasterr( GCRYERR_INV_ALGO );
+ return -1;
+ }
+ return 0;
+
+
+ default:
+ set_lasterr( GCRYERR_INV_OP );
+ return -1;
+ }
+ return 0;
+}
+
+
+/****************
+ * This function simply returns the name of the algorithm or soem constant
+ * string when there is no algo. It will never return NULL.
+ */
+const char *
+gcry_cipher_algo_name( int algo )
+{
+ return cipher_algo_to_string( algo );
+}
+
+
+/****************
+ * Encrypt IN and write it to OUT. If IN is NULL, in-place encryption has
+ * been requested,
+ */
int
gcry_cipher_encrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize,
- byte *in, size_t inlen )
+ const byte *in, size_t inlen )
{
- if( outsize < inlen )
- return set_lasterr( GCRYERR_TOO_SHORT );
- /* fixme: check that the inlength is a multipe of the blocksize
- * if a blockoriented mode is used, or modify cipher_encrypt to
- * return an error in this case */
- cipher_encrypt( h->hd, out, in, inlen );
+ 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 performace */
+ cipher_encrypt( h->hd, out, out, outsize );
+ }
+ else {
+ if( outsize < inlen )
+ return set_lasterr( GCRYERR_TOO_SHORT );
+ /* fixme: check that the inlength is a multipe of the blocksize
+ * if a blockoriented mode is used, or modify cipher_encrypt to
+ * return an error in this case */
+ cipher_encrypt( h->hd, out, in, inlen );
+ }
return 0;
}
int
gcry_cipher_decrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize,
- byte *in, size_t inlen )
+ const byte *in, size_t inlen )
{
- if( outsize < inlen )
- return set_lasterr( GCRYERR_TOO_SHORT );
- cipher_decrypt( h->hd, out, in, inlen );
+ 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 performace */
+ cipher_decrypt( h->hd, out, out, outsize );
+ }
+ else {
+ if( outsize < inlen )
+ return set_lasterr( GCRYERR_TOO_SHORT );
+ /* fixme: check that the inlength is a multipe of the blocksize
+ * if a blockoriented mode is used, or modify cipher_encrypt to
+ * return an error in this case */
+ cipher_decrypt( h->hd, out, in, inlen );
+ }
return 0;
}