summaryrefslogtreecommitdiffstats
path: root/cipher/cipher.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>1999-10-26 14:14:37 +0200
committerWerner Koch <wk@gnupg.org>1999-10-26 14:14:37 +0200
commitcf70ca8d68eb836b952f2c234f064b1afc205962 (patch)
treeaa33afbc79efd1f8538e5286b13d900321a8f14b /cipher/cipher.c
parentChanged the way it works - now needs an extra program to to most tasks. (diff)
downloadgnupg2-cf70ca8d68eb836b952f2c234f064b1afc205962.tar.xz
gnupg2-cf70ca8d68eb836b952f2c234f064b1afc205962.zip
See ChangeLog: Tue Oct 26 14:10:21 CEST 1999 Werner Koch
Diffstat (limited to 'cipher/cipher.c')
-rw-r--r--cipher/cipher.c366
1 files changed, 287 insertions, 79 deletions
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 7224ab69d..277dd13f0 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -24,6 +24,8 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
+
+#include "g10lib.h"
#include "util.h"
#include "errors.h"
#include "cipher.h"
@@ -32,9 +34,10 @@
#include "cast5.h"
#include "dynload.h"
-
#define MAX_BLOCKSIZE 16
#define TABLE_SIZE 10
+#define CTX_MAGIC_NORMAL 0x24091964
+#define CTX_MAGIC_SECURE 0x46919042
struct cipher_table_s {
const char *name;
@@ -50,10 +53,11 @@ struct cipher_table_s {
static struct cipher_table_s cipher_table[TABLE_SIZE];
static int disabled_algos[TABLE_SIZE];
-
-struct cipher_handle_s {
+struct gcry_cipher_handle {
+ int magic;
int algo;
int mode;
+ unsigned int flags;
size_t blocksize;
byte iv[MAX_BLOCKSIZE]; /* (this should be ulong aligned) */
byte lastiv[MAX_BLOCKSIZE];
@@ -209,16 +213,13 @@ load_cipher_modules(void)
}
-
-
-
-
-
/****************
- * Map a string to the cipher algo
+ * Map a string to the cipher algo.
+ * Returns: The algo ID of the cipher for the gioven name or
+ * 0 if the name is not known.
*/
int
-string_to_cipher_algo( const char *string )
+gcry_cipher_map_name( const char *string )
{
int i;
const char *s;
@@ -234,7 +235,7 @@ string_to_cipher_algo( const char *string )
/****************
* Map a cipher algo to a string
*/
-const char *
+static const char *
cipher_algo_to_string( int algo )
{
int i;
@@ -247,8 +248,20 @@ cipher_algo_to_string( int algo )
return NULL;
}
+/****************
+ * This function simply returns the name of the algorithm or some constant
+ * string when there is no algo. It will never return NULL.
+ */
+const char *
+gcry_cipher_algo_name( int algo )
+{
+ const char *s = cipher_algo_to_string( algo );
+ return s? s: "";
+}
-void
+
+
+static void
disable_cipher_algo( int algo )
{
int i;
@@ -266,7 +279,7 @@ disable_cipher_algo( int algo )
/****************
* Return 0 if the cipher algo is available
*/
-int
+static int
check_cipher_algo( int algo )
{
int i;
@@ -285,7 +298,7 @@ check_cipher_algo( int algo )
}
-unsigned
+static unsigned
cipher_get_keylen( int algo )
{
int i;
@@ -305,7 +318,7 @@ cipher_get_keylen( int algo )
return 0;
}
-unsigned
+static unsigned
cipher_get_blocksize( int algo )
{
int i;
@@ -328,70 +341,98 @@ cipher_get_blocksize( int algo )
/****************
* Open a cipher handle for use with algorithm ALGO, in mode MODE
- * and put it into secure memory if SECURE is true.
+ * and return the handle. Return NULL and set the internal error variable
+ * if something goes wrong.
*/
-CIPHER_HANDLE
-cipher_open( int algo, int mode, int secure )
+
+GCRY_CIPHER_HD
+gcry_cipher_open( int algo, int mode, unsigned int flags )
{
- CIPHER_HANDLE hd;
- int i;
+ GCRY_CIPHER_HD h;
+ int idx;
+ int secure = (flags & GCRY_CIPHER_SECURE);
fast_random_poll();
- do {
- for(i=0; cipher_table[i].name; i++ )
- if( cipher_table[i].algo == algo )
- break;
- } while( !cipher_table[i].name && load_cipher_modules() );
- if( !cipher_table[i].name ) {
- log_fatal("cipher_open: algorithm %d not available\n", algo );
+
+ /* check whether the algo is available */
+ if( check_cipher_algo( algo ) ) {
+ set_lasterr( GCRYERR_INV_ALGO );
return NULL;
}
- /* ? perform selftest here and mark this with a flag in cipher_table ? */
+ /* check flags */
+ if( (flags & ~(GCRY_CIPHER_SECURE|GCRY_CIPHER_ENABLE_SYNC)) ) {
+ set_lasterr( GCRYERR_INV_ARG );
+ return NULL;
+ }
+
+ /* get the table index of the algo */
+ for(idx=0; cipher_table[idx].name; idx++ )
+ if( cipher_table[idx].algo == algo )
+ break;
+ if( !cipher_table[idx].name )
+ BUG(); /* check_cipher_algo() should have loaded the algo */
- hd = secure ? m_alloc_secure_clear( sizeof *hd
- + cipher_table[i].contextsize
- - sizeof(PROPERLY_ALIGNED_TYPE) )
- : m_alloc_clear( sizeof *hd + cipher_table[i].contextsize
- - sizeof(PROPERLY_ALIGNED_TYPE) );
- hd->algo = algo;
- hd->blocksize = cipher_table[i].blocksize;
- hd->setkey = cipher_table[i].setkey;
- hd->encrypt = cipher_table[i].encrypt;
- hd->decrypt = cipher_table[i].decrypt;
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
- hd->mode = CIPHER_MODE_PHILS_CFB;
+ mode = GCRY_CIPHER_MODE_NONE; /* force this mode for dummy algo */
+
+ /* check that a valid mode has been requested */
+ switch( mode ) {
+ case GCRY_CIPHER_MODE_ECB:
+ case GCRY_CIPHER_MODE_CBC:
+ case GCRY_CIPHER_MODE_CFB:
+ break;
+ case GCRY_CIPHER_MODE_NONE:
+ /* FIXME: issue a warning when this mode is used */
+ break;
+ default:
+ set_lasterr( GCRYERR_INV_ALGO );
+ return NULL;
}
- else
- hd->mode = mode;
- return hd;
+ /* ? perform selftest here and mark this with a flag in cipher_table ? */
+
+ h = secure ? m_alloc_secure_clear( sizeof *h
+ + cipher_table[idx].contextsize
+ - sizeof(PROPERLY_ALIGNED_TYPE) )
+ : m_alloc_clear( sizeof *h + cipher_table[idx].contextsize
+ - sizeof(PROPERLY_ALIGNED_TYPE) );
+ h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL;
+ h->algo = algo;
+ h->mode = mode;
+ h->flags = flags;
+ h->blocksize = cipher_table[idx].blocksize;
+ h->setkey = cipher_table[idx].setkey;
+ h->encrypt = cipher_table[idx].encrypt;
+ h->decrypt = cipher_table[idx].decrypt;
+
+ return h;
}
void
-cipher_close( CIPHER_HANDLE c )
+gcry_cipher_close( GCRY_CIPHER_HD h )
{
- m_free(c);
+ if( !h )
+ return;
+ if( h->magic != CTX_MAGIC_SECURE && h->magic != CTX_MAGIC_NORMAL ) {
+ fatal_invalid_arg("gcry_cipher_close: already closed/invalid handle");
+ return;
+ }
+ h->magic = 0;
+ m_free(h);
}
-int
-cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen )
+static int
+cipher_setkey( GCRY_CIPHER_HD c, byte *key, unsigned keylen )
{
return (*c->setkey)( &c->context.c, key, keylen );
}
-
-void
-cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen )
+static void
+cipher_setiv( GCRY_CIPHER_HD c, const byte *iv, unsigned ivlen )
{
memset( c->iv, 0, c->blocksize );
if( iv ) {
@@ -408,7 +449,7 @@ cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen )
static void
-do_ecb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
+do_ecb_encrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nblocks )
{
unsigned n;
@@ -420,7 +461,7 @@ do_ecb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
}
static void
-do_ecb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
+do_ecb_decrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nblocks )
{
unsigned n;
@@ -432,7 +473,7 @@ do_ecb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
}
static void
-do_cbc_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
+do_cbc_encrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nblocks )
{
unsigned int n;
byte *ivp;
@@ -453,7 +494,7 @@ do_cbc_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
}
static void
-do_cbc_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
+do_cbc_decrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nblocks )
{
unsigned int n;
byte *ivp;
@@ -476,7 +517,7 @@ do_cbc_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
static void
-do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
+do_cfb_encrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
byte *ivp;
size_t blocksize = c->blocksize;
@@ -520,7 +561,7 @@ do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
}
static void
-do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
+do_cfb_decrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
byte *ivp;
ulong temp;
@@ -582,23 +623,22 @@ do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
* inbuf and outbuf may overlap or be the same.
* Depending on the mode some some contraints apply to NBYTES.
*/
-void
-cipher_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
+static void
+cipher_encrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
switch( c->mode ) {
- case CIPHER_MODE_ECB:
+ case GCRY_CIPHER_MODE_ECB:
assert(!(nbytes%8));
do_ecb_encrypt(c, outbuf, inbuf, nbytes/8 );
break;
- case CIPHER_MODE_CBC:
+ case GCRY_CIPHER_MODE_CBC:
assert(!(nbytes%8)); /* fixme: should be blocksize */
do_cbc_encrypt(c, outbuf, inbuf, nbytes/8 );
break;
- case CIPHER_MODE_CFB:
- case CIPHER_MODE_PHILS_CFB:
+ case GCRY_CIPHER_MODE_CFB:
do_cfb_encrypt(c, outbuf, inbuf, nbytes );
break;
- case CIPHER_MODE_DUMMY:
+ case GCRY_CIPHER_MODE_NONE:
if( inbuf != outbuf )
memmove( outbuf, inbuf, nbytes );
break;
@@ -608,27 +648,53 @@ cipher_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
/****************
+ * 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,
+ const byte *in, size_t 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, 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, out, in, inlen );
+ }
+ return 0;
+}
+
+
+
+/****************
* Decrypt INBUF to OUTBUF with the mode selected at open.
* inbuf and outbuf may overlap or be the same.
* Depending on the mode some some contraints apply to NBYTES.
*/
-void
-cipher_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
+static void
+cipher_decrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
switch( c->mode ) {
- case CIPHER_MODE_ECB:
+ case GCRY_CIPHER_MODE_ECB:
assert(!(nbytes%8));
do_ecb_decrypt(c, outbuf, inbuf, nbytes/8 );
break;
- case CIPHER_MODE_CBC:
+ case GCRY_CIPHER_MODE_CBC:
assert(!(nbytes%8)); /* fixme: should assert on blocksize */
do_cbc_decrypt(c, outbuf, inbuf, nbytes/8 );
break;
- case CIPHER_MODE_CFB:
- case CIPHER_MODE_PHILS_CFB:
+ case GCRY_CIPHER_MODE_CFB:
do_cfb_decrypt(c, outbuf, inbuf, nbytes );
break;
- case CIPHER_MODE_DUMMY:
+ case GCRY_CIPHER_MODE_NONE:
if( inbuf != outbuf )
memmove( outbuf, inbuf, nbytes );
break;
@@ -637,18 +703,160 @@ cipher_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
}
+int
+gcry_cipher_decrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize,
+ const byte *in, size_t 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, 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, out, in, inlen );
+ }
+ return 0;
+}
+
+
/****************
* Used for PGP's somewhat strange CFB mode. Only works if
- * the handle is in PHILS_CFB mode
+ * the corresponding flag is set.
*/
-void
-cipher_sync( CIPHER_HANDLE c )
+static void
+cipher_sync( GCRY_CIPHER_HD c )
{
- if( c->mode == CIPHER_MODE_PHILS_CFB && c->unused ) {
+ if( (c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused ) {
memmove(c->iv + c->unused, c->iv, c->blocksize - c->unused );
memcpy(c->iv, c->lastiv + c->blocksize - c->unused, c->unused);
c->unused = 0;
}
}
+
+int
+gcry_cipher_ctl( GCRY_CIPHER_HD h, int cmd, void *buffer, size_t buflen)
+{
+ switch( cmd ) {
+ case GCRYCTL_SET_KEY:
+ cipher_setkey( h, buffer, buflen );
+ break;
+ case GCRYCTL_SET_IV:
+ cipher_setiv( h, buffer, buflen );
+ break;
+ case GCRYCTL_CFB_SYNC:
+ cipher_sync( h );
+ break;
+
+ case GCRYCTL_DISABLE_ALGO:
+ /* this one expects a NULL handle and buffer pointing to an
+ * integer with the algo number.
+ */
+ if( h || !buffer || buflen != sizeof(int) )
+ return set_lasterr( GCRYERR_INV_ARG );
+ disable_cipher_algo( *(int*)buffer );
+ break;
+
+ default:
+ return set_lasterr( GCRYERR_INV_OP );
+ }
+ return 0;
+}
+
+
+/****************
+ * 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, void *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.
+ * The keylength is returned in _bytes_.
+ * 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)
+{
+ unsigned int ui;
+
+ switch( what ) {
+ case GCRYCTL_GET_KEYLEN:
+ if( buffer || nbytes ) {
+ set_lasterr( GCRYERR_INV_ARG );
+ break;
+ }
+ ui = cipher_get_keylen( algo );
+ if( ui > 0 && ui <= 512 )
+ return (int)ui/8;
+ /* the only reason is an invalid algo or a strange blocksize */
+ set_lasterr( GCRYERR_INV_ALGO );
+ break;
+
+ case GCRYCTL_GET_BLKLEN:
+ if( buffer || nbytes ) {
+ set_lasterr( GCRYERR_INV_ARG );
+ break;
+ }
+ 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 );
+ break;
+
+ case GCRYCTL_TEST_ALGO:
+ if( buffer || nbytes ) {
+ set_lasterr( GCRYERR_INV_ARG );
+ break;
+ }
+ if( check_cipher_algo( algo ) ) {
+ set_lasterr( GCRYERR_INV_ALGO );
+ break;
+ }
+ return 0;
+
+ default:
+ set_lasterr( GCRYERR_INV_OP );
+ }
+ return -1;
+}
+
+
+