1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-03 22:56:33 +02:00

Support the not anymore patented IDEA cipher algorithm.

* cipher/idea.c: New.  Take from Libgcrypt master and adjust for
direct use in GnuPG.
* cipher/idea-stub.c: Remove.
* cipher/Makefile.am: Add idea.c and remove idea-stub.c rules.
* configure.ac: Remove idea-stub code.
* g10/gpg.c (check_permissions): Remove code path for ITEM==2.
(main): Make --load-extension a dummy option.
* g10/keygen.c (keygen_set_std_prefs): Include IDEA only in PGP2
compatibility mode.
* g10/misc.c (idea_cipher_warn): Remove.  Also remove all callers.
* g10/seckey-cert.c (do_check): Remove emitting of STATUS_RSA_OR_IDEA.
* g10/status.c (get_status_string): Remove STATUS_RSA_OR_IDEA.
* g10/status.h (STATUS_RSA_OR_IDEA): Remove.

--

To keep the number of actually used algorithms low, we support IDEA
only in a basically read-only way (unless --pgp2 is used during key
generation).  It does not make sense to suggest the use of this old 64
bit blocksize algorithm.  However, there is old data available where
it might be helpful to have IDEA available.
This commit is contained in:
Werner Koch 2012-11-08 13:25:02 +01:00
parent c3a5448379
commit b1eac93431
18 changed files with 575 additions and 452 deletions

View file

@ -7,12 +7,12 @@
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
## Process this file with automake to produce Makefile.in
@ -37,6 +37,7 @@ libcipher_a_SOURCES = cipher.c \
cast5.c \
rijndael.c \
camellia.c camellia.h camellia-glue.c \
idea.c \
elgamal.c \
elgamal.h \
rsa.c rsa.h \
@ -73,7 +74,3 @@ endif
if USE_SHA512
libcipher_a_SOURCES+=sha512.c
endif
EXTRA_libcipher_a_SOURCES=idea-stub.c
libcipher_a_DEPENDENCIES=@IDEA_O@
libcipher_a_LIBADD=@IDEA_O@

View file

@ -1,182 +0,0 @@
/* idea-stub.c - Dummy module for the deprecated IDEA cipher.
* Copyright (C) 2002, 2003 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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* IDEA is a patented algorithm and therefore the use of IDEA in
countries where this patent is valid can not be allowed due to the
terms of the GNU General Public License. Those restrictions are
there to help protecting the freedom of software. For more
information on the nonsense of software patents and the general
problem with this, please see http://www.noepatents.org.
However for research purposes and in certain situations it might be
useful to use this algorithm anyway.
We provide this stub which will dynload a idea module and is only
used if the configure run did't found statically linked file.
See http://www.gnupg.org/why-not-dea.html for details.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_DL_DLOPEN
#include <dlfcn.h>
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#include "util.h"
#include "algorithms.h"
#ifndef RTLD_NOW
#define RTLD_NOW 1
#endif
#ifdef _WIN32
#define HAVE_DL_DLOPEN 1
#define USE_DYNAMIC_LINKING 1
static int last_error = 0;
void*
dlopen (const char *pathname, int mode)
{
void *h = LoadLibrary (pathname);
if (!h)
{
log_error ("LoadLibrary failed: %s\n", w32_strerror (errno));
last_error = 1;
return NULL;
}
return h;
}
int
dlclose ( void *handle )
{
last_error = 0;
return FreeLibrary (handle);
}
const char*
dlerror (void)
{
if (last_error)
return w32_strerror (0);
return NULL;
}
void*
dlsym (void *handle, const char *name)
{
void *h = GetProcAddress (handle, name);
if (!h)
{
log_error ("GetProcAddress failed: %s\n", w32_strerror (errno));
last_error = 1;
}
return h;
}
#endif /*_WIN32*/
/* We do only support dlopen and the Windows emulation of it. */
#ifndef HAVE_DL_DLOPEN
#undef USE_DYNAMIC_LINKING
#endif
typedef
const char *(*INFO_FNC)(int, size_t*, size_t*, size_t*,
int (**)( void *, const byte *, unsigned),
void (**)( void *, byte *, const byte *),
void (**)( void *, byte *, const byte *));
static INFO_FNC
load_module (const char *name)
{
#ifdef USE_DYNAMIC_LINKING
const char *err;
void *handle;
void *sym;
#ifndef _WIN32
/* Make sure we are not setuid. */
if (getuid () != geteuid ())
log_bug("trying to load an extension while still setuid\n");
#endif
handle = dlopen (name, RTLD_NOW);
if (!handle)
{
err=dlerror();
goto failure;
}
dlerror (); /* Clear old errors or initialize dlerror. */
sym = dlsym (handle, "idea_get_info");
if (dlerror ())
sym = dlsym (handle, "_idea_get_info");
if ((err=dlerror()))
goto failure;
return (INFO_FNC)sym;
failure:
log_info ("invalid module `%s': %s\n", name?name:"???", err?err:"???");
if (handle)
dlclose (handle);
#endif /*USE_DYNAMIC_LINKING*/
return NULL;
}
const char *
idea_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**r_setkey)( void *c, const byte *key, unsigned keylen ),
void (**r_encrypt)( void *c, byte *outbuf, const byte *inbuf ),
void (**r_decrypt)( void *c, byte *outbuf, const byte *inbuf )
)
{
static int initialized;
static INFO_FNC info_fnc;
const char *rstr;
int i;
if (!initialized)
{
initialized = 1;
for (i=0; (rstr = dynload_enum_module_names (i)); i++)
{
info_fnc = load_module (rstr);
if (info_fnc)
break;
}
}
if (!info_fnc)
return NULL; /* dynloadable module not found. */
rstr = info_fnc (algo, keylen, blocksize, contextsize,
r_setkey, r_encrypt, r_decrypt);
if (rstr && *keylen == 128 && *blocksize == 8
&& *r_setkey && *r_encrypt && r_decrypt)
return rstr;
return NULL;
}

411
cipher/idea.c Normal file
View file

@ -0,0 +1,411 @@
/* idea.c - IDEA function
* Copyright (c) 1997, 1998, 1999, 2001 by Werner Koch (dd9jn)
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* WERNER KOCH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Werner Koch shall not be
* used in advertising or otherwise to promote the sale, use or other dealings
* in this Software without prior written authorization from Werner Koch.
*
* Patents on IDEA have expired:
* Europe: EP0482154 on 2011-05-16,
* Japan: JP3225440 on 2011-05-16,
* U.S.: 5,214,703 on 2012-01-07.
*/
/*
* Please see http://www.noepatents.org/ to learn why software patents
* are bad for society and what you can do to fight them.
*
* The code herein is based on the one from:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
* ISBN 0-471-11709-9.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "types.h" /* for byte and u32 typedefs */
#include "util.h"
#include "errors.h"
#include "algorithms.h"
#define FNCCAST_SETKEY(f) ((int(*)(void*, byte*, unsigned int))(f))
#define FNCCAST_CRYPT(f) ((void(*)(void*, byte*, byte*))(f))
#define CIPHER_ALGO_IDEA 1
#define IDEA_KEYSIZE 16
#define IDEA_BLOCKSIZE 8
#define IDEA_ROUNDS 8
#define IDEA_KEYLEN (6*IDEA_ROUNDS+4)
typedef struct {
u16 ek[IDEA_KEYLEN];
u16 dk[IDEA_KEYLEN];
int have_dk;
} IDEA_context;
static const char *selftest(void);
static void
burn_stack (int bytes)
{
char buf[64];
wipememory(buf,sizeof buf);
bytes -= sizeof buf;
if (bytes > 0)
burn_stack (bytes);
}
static u16
mul_inv( u16 x )
{
u16 t0, t1;
u16 q, y;
if( x < 2 )
return x;
t1 = 0x10001L / x;
y = 0x10001L % x;
if( y == 1 )
return (1-t1) & 0xffff;
t0 = 1;
do {
q = x / y;
x = x % y;
t0 += q * t1;
if( x == 1 )
return t0;
q = y / x;
y = y % x;
t1 += q * t0;
} while( y != 1 );
return (1-t1) & 0xffff;
}
static void
expand_key( const byte *userkey, u16 *ek )
{
int i,j;
for(j=0; j < 8; j++ ) {
ek[j] = (*userkey << 8) + userkey[1];
userkey += 2;
}
for(i=0; j < IDEA_KEYLEN; j++ ) {
i++;
ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7;
ek += i & 8;
i &= 7;
}
}
static void
invert_key( u16 *ek, u16 dk[IDEA_KEYLEN] )
{
int i;
u16 t1, t2, t3;
u16 temp[IDEA_KEYLEN];
u16 *p = temp + IDEA_KEYLEN;
t1 = mul_inv( *ek++ );
t2 = -*ek++;
t3 = -*ek++;
*--p = mul_inv( *ek++ );
*--p = t3;
*--p = t2;
*--p = t1;
for(i=0; i < IDEA_ROUNDS-1; i++ ) {
t1 = *ek++;
*--p = *ek++;
*--p = t1;
t1 = mul_inv( *ek++ );
t2 = -*ek++;
t3 = -*ek++;
*--p = mul_inv( *ek++ );
*--p = t2;
*--p = t3;
*--p = t1;
}
t1 = *ek++;
*--p = *ek++;
*--p = t1;
t1 = mul_inv( *ek++ );
t2 = -*ek++;
t3 = -*ek++;
*--p = mul_inv( *ek++ );
*--p = t3;
*--p = t2;
*--p = t1;
memcpy(dk, temp, sizeof(temp) );
wipememory(temp, sizeof(temp) ); /* burn temp */
}
static void
cipher( byte *outbuf, const byte *inbuf, u16 *key )
{
u16 x1, x2, x3,x4, s2, s3;
u16 *in, *out;
int r = IDEA_ROUNDS;
#define MUL(x,y) \
do {u16 _t16; u32 _t32; \
if( (_t16 = (y)) ) { \
if( (x = (x)&0xffff) ) { \
_t32 = (u32)x * _t16; \
x = _t32 & 0xffff; \
_t16 = _t32 >> 16; \
x = ((x)-_t16) + (x<_t16?1:0); \
} \
else { \
x = 1 - _t16; \
} \
} \
else { \
x = 1 - x; \
} \
} while(0)
in = (u16*)inbuf;
x1 = *in++;
x2 = *in++;
x3 = *in++;
x4 = *in;
#ifndef WORDS_BIGENDIAN
x1 = (x1>>8) | (x1<<8);
x2 = (x2>>8) | (x2<<8);
x3 = (x3>>8) | (x3<<8);
x4 = (x4>>8) | (x4<<8);
#endif
do {
MUL(x1, *key++);
x2 += *key++;
x3 += *key++;
MUL(x4, *key++ );
s3 = x3;
x3 ^= x1;
MUL(x3, *key++);
s2 = x2;
x2 ^=x4;
x2 += x3;
MUL(x2, *key++);
x3 += x2;
x1 ^= x2;
x4 ^= x3;
x2 ^= s3;
x3 ^= s2;
} while( --r );
MUL(x1, *key++);
x3 += *key++;
x2 += *key++;
MUL(x4, *key);
out = (u16*)outbuf;
#ifndef WORDS_BIGENDIAN
*out++ = (x1>>8) | (x1<<8);
*out++ = (x3>>8) | (x3<<8);
*out++ = (x2>>8) | (x2<<8);
*out = (x4>>8) | (x4<<8);
#else
*out++ = x1;
*out++ = x3;
*out++ = x2;
*out = x4;
#endif
#undef MUL
}
static int
do_setkey( IDEA_context *c, const byte *key, unsigned int keylen )
{
static int initialized = 0;
static const char *selftest_failed = 0;
if( !initialized ) {
initialized = 1;
selftest_failed = selftest();
if( selftest_failed )
log_error( "%s\n", selftest_failed );
}
if( selftest_failed )
return G10ERR_SELFTEST_FAILED;
assert(keylen == 16);
c->have_dk = 0;
expand_key( key, c->ek );
invert_key( c->ek, c->dk );
return 0;
}
static int
idea_setkey (void *context, const byte *key, unsigned int keylen)
{
IDEA_context *ctx = context;
int rc = do_setkey (ctx, key, keylen);
burn_stack (23+6*sizeof(void*));
return rc;
}
static void
encrypt_block( IDEA_context *c, byte *outbuf, const byte *inbuf )
{
cipher( outbuf, inbuf, c->ek );
}
static void
idea_encrypt (void *context, byte *out, const byte *in)
{
IDEA_context *ctx = context;
encrypt_block (ctx, out, in);
burn_stack (24+3*sizeof (void*));
}
static void
decrypt_block( IDEA_context *c, byte *outbuf, const byte *inbuf )
{
if( !c->have_dk ) {
c->have_dk = 1;
invert_key( c->ek, c->dk );
}
cipher( outbuf, inbuf, c->dk );
}
static void
idea_decrypt (void *context, byte *out, const byte *in)
{
IDEA_context *ctx = context;
decrypt_block (ctx, out, in);
burn_stack (24+3*sizeof (void*));
}
static const char *
selftest( void )
{
static struct {
byte key[16];
byte plain[8];
byte cipher[8];
} test_vectors[] = {
{ { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03 },
{ 0x11, 0xFB, 0xED, 0x2B, 0x01, 0x98, 0x6D, 0xE5 } },
{ { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
{ 0x54, 0x0E, 0x5F, 0xEA, 0x18, 0xC2, 0xF8, 0xB1 } },
{ { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
{ 0x00, 0x19, 0x32, 0x4B, 0x64, 0x7D, 0x96, 0xAF },
{ 0x9F, 0x0A, 0x0A, 0xB6, 0xE1, 0x0C, 0xED, 0x78 } },
{ { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
{ 0xF5, 0x20, 0x2D, 0x5B, 0x9C, 0x67, 0x1B, 0x08 },
{ 0xCF, 0x18, 0xFD, 0x73, 0x55, 0xE2, 0xC5, 0xC5 } },
{ { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
{ 0xFA, 0xE6, 0xD2, 0xBE, 0xAA, 0x96, 0x82, 0x6E },
{ 0x85, 0xDF, 0x52, 0x00, 0x56, 0x08, 0x19, 0x3D } },
{ { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
{ 0x0A, 0x14, 0x1E, 0x28, 0x32, 0x3C, 0x46, 0x50 },
{ 0x2F, 0x7D, 0xE7, 0x50, 0x21, 0x2F, 0xB7, 0x34 } },
{ { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
{ 0x05, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x23, 0x28 },
{ 0x7B, 0x73, 0x14, 0x92, 0x5D, 0xE5, 0x9C, 0x09 } },
{ { 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0F, 0x00, 0x14,
0x00, 0x19, 0x00, 0x1E, 0x00, 0x23, 0x00, 0x28 },
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
{ 0x3E, 0xC0, 0x47, 0x80, 0xBE, 0xFF, 0x6E, 0x20 } },
{ { 0x3A, 0x98, 0x4E, 0x20, 0x00, 0x19, 0x5D, 0xB3,
0x2E, 0xE5, 0x01, 0xC8, 0xC4, 0x7C, 0xEA, 0x60 },
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
{ 0x97, 0xBC, 0xD8, 0x20, 0x07, 0x80, 0xDA, 0x86 } },
{ { 0x00, 0x64, 0x00, 0xC8, 0x01, 0x2C, 0x01, 0x90,
0x01, 0xF4, 0x02, 0x58, 0x02, 0xBC, 0x03, 0x20 },
{ 0x05, 0x32, 0x0A, 0x64, 0x14, 0xC8, 0x19, 0xFA },
{ 0x65, 0xBE, 0x87, 0xE7, 0xA2, 0x53, 0x8A, 0xED } },
{ { 0x9D, 0x40, 0x75, 0xC1, 0x03, 0xBC, 0x32, 0x2A,
0xFB, 0x03, 0xE7, 0xBE, 0x6A, 0xB3, 0x00, 0x06 },
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 },
{ 0xF5, 0xDB, 0x1A, 0xC4, 0x5E, 0x5E, 0xF9, 0xF9 } }
};
IDEA_context c;
byte buffer[8];
int i;
for(i=0; i < DIM(test_vectors); i++ ) {
do_setkey( &c, test_vectors[i].key, 16 );
encrypt_block( &c, buffer, test_vectors[i].plain );
if( memcmp( buffer, test_vectors[i].cipher, 8 ) )
return "IDEA test encryption failed.";
decrypt_block( &c, buffer, test_vectors[i].cipher );
if( memcmp( buffer, test_vectors[i].plain, 8 ) )
return "IDEA test decryption failed.";
}
return NULL;
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
const char *
idea_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**r_setkey)( void *c, const byte *key, unsigned keylen ),
void (**r_encrypt)( void *c, byte *outbuf, const byte *inbuf ),
void (**r_decrypt)( void *c, byte *outbuf, const byte *inbuf )
)
{
*keylen = 128;
*blocksize = IDEA_BLOCKSIZE;
*contextsize = sizeof(IDEA_context);
*r_setkey = idea_setkey;
*r_encrypt = idea_encrypt;
*r_decrypt = idea_decrypt;
if( algo == CIPHER_ALGO_IDEA )
return "IDEA";
return NULL;
}