Page MenuHome GnuPG

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/cipher/arcfour.c b/cipher/arcfour.c
index 6ef07fb2..dc32b070 100644
--- a/cipher/arcfour.c
+++ b/cipher/arcfour.c
@@ -1,155 +1,156 @@
/* arcfour.c - The arcfour stream cipher
* Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*
* For a description of the algorithm, see:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
* ISBN 0-471-11709-9. Pages 397 ff.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "g10lib.h"
#include "cipher.h"
static const char *selftest(void);
typedef struct {
int idx_i, idx_j;
byte sbox[256];
} ARCFOUR_context;
static void
do_encrypt_stream( ARCFOUR_context *ctx,
byte *outbuf, const byte *inbuf, unsigned int length )
{
register int i = ctx->idx_i;
register int j = ctx->idx_j;
register byte *sbox = ctx->sbox;
register int t;
while ( length-- )
{
i++;
i = i & 255; /* The and-op seems to be faster than the mod-op. */
j += sbox[i];
j &= 255;
t = sbox[i]; sbox[i] = sbox[j]; sbox[j] = t;
*outbuf++ = *inbuf++ ^ sbox[(sbox[i] + sbox[j]) & 255];
}
ctx->idx_i = i;
ctx->idx_j = j;
}
static void
encrypt_stream (void *context,
byte *outbuf, const byte *inbuf, unsigned int length)
{
ARCFOUR_context *ctx = (ARCFOUR_context *) context;
do_encrypt_stream (ctx, outbuf, inbuf, length );
_gcry_burn_stack (64);
}
static gcry_err_code_t
do_arcfour_setkey (void *context, const byte *key, unsigned int keylen)
{
static int initialized;
static const char* selftest_failed;
int i, j;
byte karr[256];
ARCFOUR_context *ctx = (ARCFOUR_context *) context;
if (!initialized )
{
initialized = 1;
selftest_failed = selftest();
if( selftest_failed )
log_error ("ARCFOUR selftest failed (%s)\n", selftest_failed );
}
if( selftest_failed )
return GPG_ERR_SELFTEST_FAILED;
if( keylen < 40/8 ) /* we want at least 40 bits */
return GPG_ERR_INV_KEYLEN;
ctx->idx_i = ctx->idx_j = 0;
for (i=0; i < 256; i++ )
ctx->sbox[i] = i;
for (i=0; i < 256; i++ )
karr[i] = key[i%keylen];
for (i=j=0; i < 256; i++ )
{
int t;
j = (j + ctx->sbox[i] + karr[i]) % 256;
t = ctx->sbox[i];
ctx->sbox[i] = ctx->sbox[j];
ctx->sbox[j] = t;
}
memset( karr, 0, 256 );
return GPG_ERR_NO_ERROR;
}
static gcry_err_code_t
arcfour_setkey ( void *context, const byte *key, unsigned int keylen )
{
ARCFOUR_context *ctx = (ARCFOUR_context *) context;
gcry_err_code_t rc = do_arcfour_setkey (ctx, key, keylen );
_gcry_burn_stack (300);
return rc;
}
static const char*
selftest(void)
{
ARCFOUR_context ctx;
byte scratch[16];
/* Test vector from Cryptlib labeled there: "from the
State/Commerce Department". */
static byte key_1[] =
{ 0x61, 0x8A, 0x63, 0xD2, 0xFB };
static byte plaintext_1[] =
{ 0xDC, 0xEE, 0x4C, 0xF9, 0x2C };
static const byte ciphertext_1[] =
{ 0xF1, 0x38, 0x29, 0xC9, 0xDE };
arcfour_setkey( &ctx, key_1, sizeof(key_1));
encrypt_stream( &ctx, scratch, plaintext_1, sizeof(plaintext_1));
if ( memcmp (scratch, ciphertext_1, sizeof (ciphertext_1)))
return "Arcfour encryption test 1 failed.";
arcfour_setkey( &ctx, key_1, sizeof(key_1));
encrypt_stream(&ctx, scratch, scratch, sizeof(plaintext_1)); /* decrypt */
if ( memcmp (scratch, plaintext_1, sizeof (plaintext_1)))
return "Arcfour decryption test 1 failed.";
return NULL;
}
gcry_cipher_spec_t _gcry_cipher_spec_arcfour =
{
+ GCRY_CIPHER_ARCFOUR, {0, 0},
"ARCFOUR", NULL, NULL, 1, 128, sizeof (ARCFOUR_context),
arcfour_setkey, NULL, NULL, encrypt_stream, encrypt_stream,
};
diff --git a/cipher/blowfish.c b/cipher/blowfish.c
index 61042ed9..2f739c8f 100644
--- a/cipher/blowfish.c
+++ b/cipher/blowfish.c
@@ -1,966 +1,967 @@
/* blowfish.c - Blowfish encryption
* Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*
* For a description of the algorithm, see:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
* ISBN 0-471-11709-9. Pages 336 ff.
*/
/* Test values:
* key "abcdefghijklmnopqrstuvwxyz";
* plain "BLOWFISH"
* cipher 32 4E D0 FE F4 13 A2 03
*
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "g10lib.h"
#include "cipher.h"
#include "bufhelp.h"
#include "cipher-selftest.h"
#define BLOWFISH_BLOCKSIZE 8
#define BLOWFISH_ROUNDS 16
/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
#undef USE_AMD64_ASM
#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && \
(BLOWFISH_ROUNDS == 16)
# define USE_AMD64_ASM 1
#endif
/* USE_ARMV6_ASM indicates whether to use ARMv6 assembly code. */
#undef USE_ARMV6_ASM
#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__)
# if (BLOWFISH_ROUNDS == 16) && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS)
# define USE_ARMV6_ASM 1
# endif
#endif
typedef struct {
u32 s0[256];
u32 s1[256];
u32 s2[256];
u32 s3[256];
u32 p[BLOWFISH_ROUNDS+2];
} BLOWFISH_context;
static gcry_err_code_t bf_setkey (void *c, const byte *key, unsigned keylen);
static unsigned int encrypt_block (void *bc, byte *outbuf, const byte *inbuf);
static unsigned int decrypt_block (void *bc, byte *outbuf, const byte *inbuf);
/* precomputed S boxes */
static const u32 ks0[256] = {
0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96,
0xBA7C9045,0xF12C7F99,0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16,
0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,0x0D95748F,0x728EB658,
0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013,
0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E,
0x6C9E0E8B,0xB01E8A3E,0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60,
0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,0x55CA396A,0x2AAB10B6,
0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A,
0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C,
0x7A325381,0x28958677,0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193,
0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,0xEF845D5D,0xE98575B1,
0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239,
0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A,
0x670C9C61,0xABD388F0,0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3,
0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,0xA1F1651D,0x39AF0176,
0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE,
0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706,
0x1BFEDF72,0x429B023D,0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B,
0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,0xE3FE501A,0xB6794C3B,
0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463,
0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C,
0xCC814544,0xAF5EBD09,0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3,
0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,0x5579C0BD,0x1A60320A,
0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8,
0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760,
0x53317B48,0x3E00DF82,0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB,
0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,0x695B27B0,0xBBCA58C8,
0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B,
0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33,
0x62FB1341,0xCEE4C6E8,0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4,
0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,0xD08ED1D0,0xAFC725E0,
0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C,
0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777,
0xEA752DFE,0x8B021FA1,0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299,
0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,0x165FA266,0x80957705,
0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF,
0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E,
0x226800BB,0x57B8E0AF,0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA,
0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,0x83260376,0x6295CFA9,
0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915,
0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F,
0xF296EC6B,0x2A0DD915,0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664,
0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A };
static const u32 ks1[256] = {
0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D,
0x9CEE60B8,0x8FEDB266,0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1,
0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,0x3F54989A,0x5B429D65,
0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1,
0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9,
0x3C971814,0x6B6A70A1,0x687F3584,0x52A0E286,0xB79C5305,0xAA500737,
0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,0xB03ADA37,0xF0500C0D,
0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD,
0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC,
0xC8B57634,0x9AF3DDA7,0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41,
0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,0x4E548B38,0x4F6DB908,
0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF,
0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124,
0x501ADDE6,0x9F84CD87,0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C,
0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,0xEF1C1847,0x3215D908,
0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD,
0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B,
0x3C11183B,0x5924A509,0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E,
0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,0x771FE71C,0x4E3D06FA,
0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A,
0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D,
0x1939260F,0x19C27960,0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66,
0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,0xC332DDEF,0xBE6C5AA5,
0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84,
0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96,
0x0334FE1E,0xAA0363CF,0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14,
0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,0x648B1EAF,0x19BDF0CA,
0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7,
0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77,
0x11ED935F,0x16681281,0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99,
0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,0xCDB30AEB,0x532E3054,
0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73,
0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA,
0xDB6C4F15,0xFACB4FD0,0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105,
0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,0xCF62A1F2,0x5B8D2646,
0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285,
0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA,
0x1DADF43E,0x233F7061,0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB,
0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,0xA6078084,0x19F8509E,
0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC,
0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD,
0x675FDA79,0xE3674340,0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20,
0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7 };
static const u32 ks2[256] = {
0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7,
0xBCF46B2E,0xD4A20068,0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF,
0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,0x4D95FC1D,0x96B591AF,
0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504,
0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4,
0x0A2C86DA,0xE9B66DFB,0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE,
0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,0xAACE1E7C,0xD3375FEC,
0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B,
0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332,
0x6841E7F7,0xCA7820FB,0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527,
0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,0x55A867BC,0xA1159A58,
0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C,
0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22,
0x48C1133F,0xC70F86DC,0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17,
0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,0x257B7834,0x602A9C60,
0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115,
0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99,
0xDE720C8C,0x2DA2F728,0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0,
0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,0x0A476341,0x992EFF74,
0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D,
0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3,
0xB5390F92,0x690FED0B,0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3,
0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,0x37392EB3,0xCC115979,
0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C,
0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA,
0x3D25BDD8,0xE2E1C3C9,0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A,
0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,0x9DBC8057,0xF0F7C086,
0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC,
0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24,
0x55464299,0xBF582E61,0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2,
0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,0x7AEB2661,0x8B1DDF84,
0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C,
0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09,
0x662D09A1,0xC4324633,0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10,
0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,0xDCB7DA83,0x573906FE,
0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027,
0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0,
0x006058AA,0x30DC7D62,0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634,
0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,0x6F05E409,0x4B7C0188,
0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC,
0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8,
0xA28514D9,0x6C51133C,0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837,
0xD79A3234,0x92638212,0x670EFA8E,0x406000E0 };
static const u32 ks3[256] = {
0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742,
0xD3822740,0x99BC9BBE,0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B,
0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,0x5748AB2F,0xBC946E79,
0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6,
0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A,
0x63EF8CE2,0x9A86EE22,0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4,
0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,0x2826A2F9,0xA73A3AE1,
0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59,
0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797,
0x2CF0B7D9,0x022B8B51,0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28,
0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,0xE029AC71,0xE019A5E6,
0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28,
0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA,
0x03A16125,0x0564F0BD,0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A,
0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,0x7533D928,0xB155FDF5,
0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F,
0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE,
0x5121CE64,0x774FBE32,0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680,
0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,0xB39A460A,0x6445C0DD,
0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB,
0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB,
0x8D6612AE,0xBF3C6F47,0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370,
0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,0x4040CB08,0x4EB4E2CC,
0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048,
0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC,
0xBB3A792B,0x344525BD,0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9,
0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,0x1A908749,0xD44FBD9A,
0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F,
0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A,
0x0F91FC71,0x9B941525,0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1,
0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,0xE0EC6E0E,0x1698DB3B,
0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E,
0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E,
0xE60B6F47,0x0FE3F11D,0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F,
0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,0xF523F357,0xA6327623,
0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC,
0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A,
0x45E1D006,0xC3F27B9A,0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6,
0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,0x53113EC0,0x1640E3D3,
0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060,
0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C,
0x01C36AE4,0xD6EBE1F9,0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F,
0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6 };
static const u32 ps[BLOWFISH_ROUNDS+2] = {
0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,
0x082EFA98,0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,
0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B };
#ifdef USE_AMD64_ASM
/* Assembly implementations of Blowfish. */
extern void _gcry_blowfish_amd64_do_encrypt(BLOWFISH_context *c, u32 *ret_xl,
u32 *ret_xr);
extern void _gcry_blowfish_amd64_encrypt_block(BLOWFISH_context *c, byte *out,
const byte *in);
extern void _gcry_blowfish_amd64_decrypt_block(BLOWFISH_context *c, byte *out,
const byte *in);
/* These assembly implementations process four blocks in parallel. */
extern void _gcry_blowfish_amd64_ctr_enc(BLOWFISH_context *ctx, byte *out,
const byte *in, byte *ctr);
extern void _gcry_blowfish_amd64_cbc_dec(BLOWFISH_context *ctx, byte *out,
const byte *in, byte *iv);
extern void _gcry_blowfish_amd64_cfb_dec(BLOWFISH_context *ctx, byte *out,
const byte *in, byte *iv);
static void
do_encrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
_gcry_blowfish_amd64_do_encrypt (bc, ret_xl, ret_xr);
}
static void
do_encrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf)
{
_gcry_blowfish_amd64_encrypt_block (context, outbuf, inbuf);
}
static void
do_decrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf)
{
_gcry_blowfish_amd64_decrypt_block (context, outbuf, inbuf);
}
static unsigned int
encrypt_block (void *context , byte *outbuf, const byte *inbuf)
{
BLOWFISH_context *c = (BLOWFISH_context *) context;
do_encrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (2*8);
}
static unsigned int
decrypt_block (void *context, byte *outbuf, const byte *inbuf)
{
BLOWFISH_context *c = (BLOWFISH_context *) context;
do_decrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (2*8);
}
#elif defined(USE_ARMV6_ASM)
/* Assembly implementations of Blowfish. */
extern void _gcry_blowfish_armv6_do_encrypt(BLOWFISH_context *c, u32 *ret_xl,
u32 *ret_xr);
extern void _gcry_blowfish_armv6_encrypt_block(BLOWFISH_context *c, byte *out,
const byte *in);
extern void _gcry_blowfish_armv6_decrypt_block(BLOWFISH_context *c, byte *out,
const byte *in);
/* These assembly implementations process two blocks in parallel. */
extern void _gcry_blowfish_armv6_ctr_enc(BLOWFISH_context *ctx, byte *out,
const byte *in, byte *ctr);
extern void _gcry_blowfish_armv6_cbc_dec(BLOWFISH_context *ctx, byte *out,
const byte *in, byte *iv);
extern void _gcry_blowfish_armv6_cfb_dec(BLOWFISH_context *ctx, byte *out,
const byte *in, byte *iv);
static void
do_encrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
_gcry_blowfish_armv6_do_encrypt (bc, ret_xl, ret_xr);
}
static void
do_encrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf)
{
_gcry_blowfish_armv6_encrypt_block (context, outbuf, inbuf);
}
static void
do_decrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf)
{
_gcry_blowfish_armv6_decrypt_block (context, outbuf, inbuf);
}
static unsigned int
encrypt_block (void *context , byte *outbuf, const byte *inbuf)
{
BLOWFISH_context *c = (BLOWFISH_context *) context;
do_encrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (10*4);
}
static unsigned int
decrypt_block (void *context, byte *outbuf, const byte *inbuf)
{
BLOWFISH_context *c = (BLOWFISH_context *) context;
do_decrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (10*4);
}
#else /*USE_ARMV6_ASM*/
#if BLOWFISH_ROUNDS != 16
static inline u32
function_F( BLOWFISH_context *bc, u32 x )
{
u16 a, b, c, d;
#ifdef WORDS_BIGENDIAN
a = ((byte*)&x)[0];
b = ((byte*)&x)[1];
c = ((byte*)&x)[2];
d = ((byte*)&x)[3];
#else
a = ((byte*)&x)[3];
b = ((byte*)&x)[2];
c = ((byte*)&x)[1];
d = ((byte*)&x)[0];
#endif
return ((bc->s0[a] + bc->s1[b]) ^ bc->s2[c] ) + bc->s3[d];
}
#endif
#ifdef WORDS_BIGENDIAN
#define F(x) ((( s0[((byte*)&x)[0]] + s1[((byte*)&x)[1]]) \
^ s2[((byte*)&x)[2]]) + s3[((byte*)&x)[3]] )
#else
#define F(x) ((( s0[((byte*)&x)[3]] + s1[((byte*)&x)[2]]) \
^ s2[((byte*)&x)[1]]) + s3[((byte*)&x)[0]] )
#endif
#define R(l,r,i) do { l ^= p[i]; r ^= F(l); } while(0)
static void
do_encrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
#if BLOWFISH_ROUNDS == 16
u32 xl, xr, *s0, *s1, *s2, *s3, *p;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
s0 = bc->s0;
s1 = bc->s1;
s2 = bc->s2;
s3 = bc->s3;
R( xl, xr, 0);
R( xr, xl, 1);
R( xl, xr, 2);
R( xr, xl, 3);
R( xl, xr, 4);
R( xr, xl, 5);
R( xl, xr, 6);
R( xr, xl, 7);
R( xl, xr, 8);
R( xr, xl, 9);
R( xl, xr, 10);
R( xr, xl, 11);
R( xl, xr, 12);
R( xr, xl, 13);
R( xl, xr, 14);
R( xr, xl, 15);
xl ^= p[BLOWFISH_ROUNDS];
xr ^= p[BLOWFISH_ROUNDS+1];
*ret_xl = xr;
*ret_xr = xl;
#else
u32 xl, xr, temp, *p;
int i;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
for(i=0; i < BLOWFISH_ROUNDS; i++ )
{
xl ^= p[i];
xr ^= function_F(bc, xl);
temp = xl;
xl = xr;
xr = temp;
}
temp = xl;
xl = xr;
xr = temp;
xr ^= p[BLOWFISH_ROUNDS];
xl ^= p[BLOWFISH_ROUNDS+1];
*ret_xl = xl;
*ret_xr = xr;
#endif
}
static void
decrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
#if BLOWFISH_ROUNDS == 16
u32 xl, xr, *s0, *s1, *s2, *s3, *p;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
s0 = bc->s0;
s1 = bc->s1;
s2 = bc->s2;
s3 = bc->s3;
R( xl, xr, 17);
R( xr, xl, 16);
R( xl, xr, 15);
R( xr, xl, 14);
R( xl, xr, 13);
R( xr, xl, 12);
R( xl, xr, 11);
R( xr, xl, 10);
R( xl, xr, 9);
R( xr, xl, 8);
R( xl, xr, 7);
R( xr, xl, 6);
R( xl, xr, 5);
R( xr, xl, 4);
R( xl, xr, 3);
R( xr, xl, 2);
xl ^= p[1];
xr ^= p[0];
*ret_xl = xr;
*ret_xr = xl;
#else
u32 xl, xr, temp, *p;
int i;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
for (i=BLOWFISH_ROUNDS+1; i > 1; i-- )
{
xl ^= p[i];
xr ^= function_F(bc, xl);
temp = xl;
xl = xr;
xr = temp;
}
temp = xl;
xl = xr;
xr = temp;
xr ^= p[1];
xl ^= p[0];
*ret_xl = xl;
*ret_xr = xr;
#endif
}
#undef F
#undef R
static void
do_encrypt_block ( BLOWFISH_context *bc, byte *outbuf, const byte *inbuf )
{
u32 d1, d2;
d1 = buf_get_be32(inbuf);
d2 = buf_get_be32(inbuf + 4);
do_encrypt( bc, &d1, &d2 );
buf_put_be32(outbuf, d1);
buf_put_be32(outbuf + 4, d2);
}
static unsigned int
encrypt_block (void *context, byte *outbuf, const byte *inbuf)
{
BLOWFISH_context *bc = (BLOWFISH_context *) context;
do_encrypt_block (bc, outbuf, inbuf);
return /*burn_stack*/ (64);
}
static void
do_decrypt_block (BLOWFISH_context *bc, byte *outbuf, const byte *inbuf)
{
u32 d1, d2;
d1 = buf_get_be32(inbuf);
d2 = buf_get_be32(inbuf + 4);
decrypt( bc, &d1, &d2 );
buf_put_be32(outbuf, d1);
buf_put_be32(outbuf + 4, d2);
}
static unsigned int
decrypt_block (void *context, byte *outbuf, const byte *inbuf)
{
BLOWFISH_context *bc = (BLOWFISH_context *) context;
do_decrypt_block (bc, outbuf, inbuf);
return /*burn_stack*/ (64);
}
#endif /*!USE_AMD64_ASM&&!USE_ARMV6_ASM*/
/* Bulk encryption of complete blocks in CTR mode. This function is only
intended for the bulk encryption feature of cipher.c. CTR is expected to be
of size BLOWFISH_BLOCKSIZE. */
void
_gcry_blowfish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg,
const void *inbuf_arg, unsigned int nblocks)
{
BLOWFISH_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char tmpbuf[BLOWFISH_BLOCKSIZE];
int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE;
int i;
#ifdef USE_AMD64_ASM
{
if (nblocks >= 4)
burn_stack_depth += 5 * sizeof(void*);
/* Process data in 4 block chunks. */
while (nblocks >= 4)
{
_gcry_blowfish_amd64_ctr_enc(ctx, outbuf, inbuf, ctr);
nblocks -= 4;
outbuf += 4 * BLOWFISH_BLOCKSIZE;
inbuf += 4 * BLOWFISH_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
/* TODO: use caching instead? */
}
#elif defined(USE_ARMV6_ASM)
{
/* Process data in 2 block chunks. */
while (nblocks >= 2)
{
_gcry_blowfish_armv6_ctr_enc(ctx, outbuf, inbuf, ctr);
nblocks -= 2;
outbuf += 2 * BLOWFISH_BLOCKSIZE;
inbuf += 2 * BLOWFISH_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
/* TODO: use caching instead? */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* Encrypt the counter. */
do_encrypt_block(ctx, tmpbuf, ctr);
/* XOR the input with the encrypted counter and store in output. */
buf_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE);
outbuf += BLOWFISH_BLOCKSIZE;
inbuf += BLOWFISH_BLOCKSIZE;
/* Increment the counter. */
for (i = BLOWFISH_BLOCKSIZE; i > 0; i--)
{
ctr[i-1]++;
if (ctr[i-1])
break;
}
}
wipememory(tmpbuf, sizeof(tmpbuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CBC mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_blowfish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
const void *inbuf_arg, unsigned int nblocks)
{
BLOWFISH_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char savebuf[BLOWFISH_BLOCKSIZE];
int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE;
#ifdef USE_AMD64_ASM
{
if (nblocks >= 4)
burn_stack_depth += 5 * sizeof(void*);
/* Process data in 4 block chunks. */
while (nblocks >= 4)
{
_gcry_blowfish_amd64_cbc_dec(ctx, outbuf, inbuf, iv);
nblocks -= 4;
outbuf += 4 * BLOWFISH_BLOCKSIZE;
inbuf += 4 * BLOWFISH_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#elif defined(USE_ARMV6_ASM)
{
/* Process data in 2 block chunks. */
while (nblocks >= 2)
{
_gcry_blowfish_armv6_cbc_dec(ctx, outbuf, inbuf, iv);
nblocks -= 2;
outbuf += 2 * BLOWFISH_BLOCKSIZE;
inbuf += 2 * BLOWFISH_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* We need to save INBUF away because it may be identical to
OUTBUF. */
memcpy(savebuf, inbuf, BLOWFISH_BLOCKSIZE);
do_decrypt_block (ctx, outbuf, inbuf);
buf_xor(outbuf, outbuf, iv, BLOWFISH_BLOCKSIZE);
memcpy(iv, savebuf, BLOWFISH_BLOCKSIZE);
inbuf += BLOWFISH_BLOCKSIZE;
outbuf += BLOWFISH_BLOCKSIZE;
}
wipememory(savebuf, sizeof(savebuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CFB mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_blowfish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg,
const void *inbuf_arg, unsigned int nblocks)
{
BLOWFISH_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE;
#ifdef USE_AMD64_ASM
{
if (nblocks >= 4)
burn_stack_depth += 5 * sizeof(void*);
/* Process data in 4 block chunks. */
while (nblocks >= 4)
{
_gcry_blowfish_amd64_cfb_dec(ctx, outbuf, inbuf, iv);
nblocks -= 4;
outbuf += 4 * BLOWFISH_BLOCKSIZE;
inbuf += 4 * BLOWFISH_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#elif defined(USE_ARMV6_ASM)
{
/* Process data in 2 block chunks. */
while (nblocks >= 2)
{
_gcry_blowfish_armv6_cfb_dec(ctx, outbuf, inbuf, iv);
nblocks -= 2;
outbuf += 2 * BLOWFISH_BLOCKSIZE;
inbuf += 2 * BLOWFISH_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
do_encrypt_block(ctx, iv, iv);
buf_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE);
outbuf += BLOWFISH_BLOCKSIZE;
inbuf += BLOWFISH_BLOCKSIZE;
}
_gcry_burn_stack(burn_stack_depth);
}
/* Run the self-tests for BLOWFISH-CTR, tests IV increment of bulk CTR
encryption. Returns NULL on success. */
static const char *
selftest_ctr (void)
{
const int nblocks = 4+1;
const int blocksize = BLOWFISH_BLOCKSIZE;
const int context_size = sizeof(BLOWFISH_context);
return _gcry_selftest_helper_ctr("BLOWFISH", &bf_setkey,
&encrypt_block, &_gcry_blowfish_ctr_enc, nblocks, blocksize,
context_size);
}
/* Run the self-tests for BLOWFISH-CBC, tests bulk CBC decryption.
Returns NULL on success. */
static const char *
selftest_cbc (void)
{
const int nblocks = 4+2;
const int blocksize = BLOWFISH_BLOCKSIZE;
const int context_size = sizeof(BLOWFISH_context);
return _gcry_selftest_helper_cbc("BLOWFISH", &bf_setkey,
&encrypt_block, &_gcry_blowfish_cbc_dec, nblocks, blocksize,
context_size);
}
/* Run the self-tests for BLOWFISH-CFB, tests bulk CBC decryption.
Returns NULL on success. */
static const char *
selftest_cfb (void)
{
const int nblocks = 4+2;
const int blocksize = BLOWFISH_BLOCKSIZE;
const int context_size = sizeof(BLOWFISH_context);
return _gcry_selftest_helper_cfb("BLOWFISH", &bf_setkey,
&encrypt_block, &_gcry_blowfish_cfb_dec, nblocks, blocksize,
context_size);
}
static const char*
selftest(void)
{
BLOWFISH_context c;
byte plain[] = "BLOWFISH";
byte buffer[8];
byte plain3[] = { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 };
byte key3[] = { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 };
byte cipher3[] = { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 };
const char *r;
bf_setkey( (void *) &c,
(const unsigned char*)"abcdefghijklmnopqrstuvwxyz", 26 );
encrypt_block( (void *) &c, buffer, plain );
if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) )
return "Blowfish selftest failed (1).";
decrypt_block( (void *) &c, buffer, buffer );
if( memcmp( buffer, plain, 8 ) )
return "Blowfish selftest failed (2).";
bf_setkey( (void *) &c, key3, 8 );
encrypt_block( (void *) &c, buffer, plain3 );
if( memcmp( buffer, cipher3, 8 ) )
return "Blowfish selftest failed (3).";
decrypt_block( (void *) &c, buffer, buffer );
if( memcmp( buffer, plain3, 8 ) )
return "Blowfish selftest failed (4).";
if ( (r = selftest_cbc ()) )
return r;
if ( (r = selftest_cfb ()) )
return r;
if ( (r = selftest_ctr ()) )
return r;
return NULL;
}
static gcry_err_code_t
do_bf_setkey (BLOWFISH_context *c, const byte *key, unsigned keylen)
{
int i, j;
u32 data, datal, datar;
static int initialized;
static const char *selftest_failed;
if( !initialized )
{
initialized = 1;
selftest_failed = selftest();
if( selftest_failed )
log_error ("%s\n", selftest_failed );
}
if( selftest_failed )
return GPG_ERR_SELFTEST_FAILED;
for(i=0; i < BLOWFISH_ROUNDS+2; i++ )
c->p[i] = ps[i];
for(i=0; i < 256; i++ )
{
c->s0[i] = ks0[i];
c->s1[i] = ks1[i];
c->s2[i] = ks2[i];
c->s3[i] = ks3[i];
}
for(i=j=0; i < BLOWFISH_ROUNDS+2; i++ )
{
data = ((u32)key[j] << 24) |
((u32)key[(j+1)%keylen] << 16) |
((u32)key[(j+2)%keylen] << 8) |
((u32)key[(j+3)%keylen]);
c->p[i] ^= data;
j = (j+4) % keylen;
}
datal = datar = 0;
for(i=0; i < BLOWFISH_ROUNDS+2; i += 2 )
{
do_encrypt( c, &datal, &datar );
c->p[i] = datal;
c->p[i+1] = datar;
}
for(i=0; i < 256; i += 2 )
{
do_encrypt( c, &datal, &datar );
c->s0[i] = datal;
c->s0[i+1] = datar;
}
for(i=0; i < 256; i += 2 )
{
do_encrypt( c, &datal, &datar );
c->s1[i] = datal;
c->s1[i+1] = datar;
}
for(i=0; i < 256; i += 2 )
{
do_encrypt( c, &datal, &datar );
c->s2[i] = datal;
c->s2[i+1] = datar;
}
for(i=0; i < 256; i += 2 )
{
do_encrypt( c, &datal, &datar );
c->s3[i] = datal;
c->s3[i+1] = datar;
}
/* Check for weak key. A weak key is a key in which a value in
the P-array (here c) occurs more than once per table. */
for(i=0; i < 255; i++ )
{
for( j=i+1; j < 256; j++)
{
if( (c->s0[i] == c->s0[j]) || (c->s1[i] == c->s1[j]) ||
(c->s2[i] == c->s2[j]) || (c->s3[i] == c->s3[j]) )
return GPG_ERR_WEAK_KEY;
}
}
return GPG_ERR_NO_ERROR;
}
static gcry_err_code_t
bf_setkey (void *context, const byte *key, unsigned keylen)
{
BLOWFISH_context *c = (BLOWFISH_context *) context;
gcry_err_code_t rc = do_bf_setkey (c, key, keylen);
_gcry_burn_stack (64);
return rc;
}
gcry_cipher_spec_t _gcry_cipher_spec_blowfish =
{
+ GCRY_CIPHER_BLOWFISH, {0, 0},
"BLOWFISH", NULL, NULL, BLOWFISH_BLOCKSIZE, 128,
sizeof (BLOWFISH_context),
bf_setkey, encrypt_block, decrypt_block
};
diff --git a/cipher/camellia-glue.c b/cipher/camellia-glue.c
index 2842c3ba..29cb7a55 100644
--- a/cipher/camellia-glue.c
+++ b/cipher/camellia-glue.c
@@ -1,708 +1,711 @@
/* camellia-glue.c - Glue for the Camellia cipher
* Copyright (C) 2007 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/* I put all the libgcrypt-specific stuff in this file to keep the
camellia.c/camellia.h files exactly as provided by NTT. If they
update their code, this should make it easier to bring the changes
in. - dshaw
There is one small change which needs to be done: Include the
following code at the top of camellia.h: */
#if 0
/* To use Camellia with libraries it is often useful to keep the name
* space of the library clean. The following macro is thus useful:
*
* #define CAMELLIA_EXT_SYM_PREFIX foo_
*
* This prefixes all external symbols with "foo_".
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef CAMELLIA_EXT_SYM_PREFIX
#define CAMELLIA_PREFIX1(x,y) x ## y
#define CAMELLIA_PREFIX2(x,y) CAMELLIA_PREFIX1(x,y)
#define CAMELLIA_PREFIX(x) CAMELLIA_PREFIX2(CAMELLIA_EXT_SYM_PREFIX,x)
#define Camellia_Ekeygen CAMELLIA_PREFIX(Camellia_Ekeygen)
#define Camellia_EncryptBlock CAMELLIA_PREFIX(Camellia_EncryptBlock)
#define Camellia_DecryptBlock CAMELLIA_PREFIX(Camellia_DecryptBlock)
#define camellia_decrypt128 CAMELLIA_PREFIX(camellia_decrypt128)
#define camellia_decrypt256 CAMELLIA_PREFIX(camellia_decrypt256)
#define camellia_encrypt128 CAMELLIA_PREFIX(camellia_encrypt128)
#define camellia_encrypt256 CAMELLIA_PREFIX(camellia_encrypt256)
#define camellia_setup128 CAMELLIA_PREFIX(camellia_setup128)
#define camellia_setup192 CAMELLIA_PREFIX(camellia_setup192)
#define camellia_setup256 CAMELLIA_PREFIX(camellia_setup256)
#endif /*CAMELLIA_EXT_SYM_PREFIX*/
#endif /* Code sample. */
#include <config.h>
#include "types.h"
#include "g10lib.h"
#include "cipher.h"
#include "camellia.h"
#include "bufhelp.h"
#include "cipher-selftest.h"
/* Helper macro to force alignment to 16 bytes. */
#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
# define ATTR_ALIGNED_16 __attribute__ ((aligned (16)))
#else
# define ATTR_ALIGNED_16
#endif
/* USE_AESNI inidicates whether to compile with Intel AES-NI/AVX code. */
#undef USE_AESNI_AVX
#if defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX_SUPPORT)
# if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
# define USE_AESNI_AVX 1
# endif
#endif
/* USE_AESNI_AVX2 inidicates whether to compile with Intel AES-NI/AVX2 code. */
#undef USE_AESNI_AVX2
#if defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX2_SUPPORT)
# if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
# define USE_AESNI_AVX2 1
# endif
#endif
typedef struct
{
int keybitlength;
KEY_TABLE_TYPE keytable;
#ifdef USE_AESNI_AVX
int use_aesni_avx; /* AES-NI/AVX implementation shall be used. */
#endif /*USE_AESNI_AVX*/
#ifdef USE_AESNI_AVX2
int use_aesni_avx2; /* AES-NI/AVX2 implementation shall be used. */
#endif /*USE_AESNI_AVX2*/
} CAMELLIA_context;
#ifdef USE_AESNI_AVX
/* Assembler implementations of Camellia using AES-NI and AVX. Process data
in 16 block same time.
*/
extern void _gcry_camellia_aesni_avx_ctr_enc(CAMELLIA_context *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *ctr);
extern void _gcry_camellia_aesni_avx_cbc_dec(CAMELLIA_context *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *iv);
extern void _gcry_camellia_aesni_avx_cfb_dec(CAMELLIA_context *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *iv);
#endif
#ifdef USE_AESNI_AVX2
/* Assembler implementations of Camellia using AES-NI and AVX2. Process data
in 32 block same time.
*/
extern void _gcry_camellia_aesni_avx2_ctr_enc(CAMELLIA_context *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *ctr);
extern void _gcry_camellia_aesni_avx2_cbc_dec(CAMELLIA_context *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *iv);
extern void _gcry_camellia_aesni_avx2_cfb_dec(CAMELLIA_context *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *iv);
#endif
static const char *selftest(void);
static gcry_err_code_t
camellia_setkey(void *c, const byte *key, unsigned keylen)
{
CAMELLIA_context *ctx=c;
static int initialized=0;
static const char *selftest_failed=NULL;
if(keylen!=16 && keylen!=24 && keylen!=32)
return GPG_ERR_INV_KEYLEN;
if(!initialized)
{
initialized=1;
selftest_failed=selftest();
if(selftest_failed)
log_error("%s\n",selftest_failed);
}
if(selftest_failed)
return GPG_ERR_SELFTEST_FAILED;
ctx->keybitlength=keylen*8;
Camellia_Ekeygen(ctx->keybitlength,key,ctx->keytable);
_gcry_burn_stack
((19+34+34)*sizeof(u32)+2*sizeof(void*) /* camellia_setup256 */
+(4+32)*sizeof(u32)+2*sizeof(void*) /* camellia_setup192 */
+0+sizeof(int)+2*sizeof(void*) /* Camellia_Ekeygen */
+3*2*sizeof(void*) /* Function calls. */
);
#ifdef USE_AESNI_AVX
ctx->use_aesni_avx = 0;
if ((_gcry_get_hw_features () & HWF_INTEL_AESNI) &&
(_gcry_get_hw_features () & HWF_INTEL_AVX))
{
ctx->use_aesni_avx = 1;
}
#endif
#ifdef USE_AESNI_AVX2
ctx->use_aesni_avx2 = 0;
if ((_gcry_get_hw_features () & HWF_INTEL_AESNI) &&
(_gcry_get_hw_features () & HWF_INTEL_AVX2))
{
ctx->use_aesni_avx2 = 1;
}
#endif
return 0;
}
#ifdef USE_ARMV6_ASM
/* Assembly implementations of CAST5. */
extern void _gcry_camellia_armv6_encrypt_block(const KEY_TABLE_TYPE keyTable,
byte *outbuf, const byte *inbuf,
const int keybits);
extern void _gcry_camellia_armv6_decrypt_block(const KEY_TABLE_TYPE keyTable,
byte *outbuf, const byte *inbuf,
const int keybits);
static void Camellia_EncryptBlock(const int keyBitLength,
const unsigned char *plaintext,
const KEY_TABLE_TYPE keyTable,
unsigned char *cipherText)
{
_gcry_camellia_armv6_encrypt_block(keyTable, cipherText, plaintext,
keyBitLength);
}
static void Camellia_DecryptBlock(const int keyBitLength,
const unsigned char *cipherText,
const KEY_TABLE_TYPE keyTable,
unsigned char *plaintext)
{
_gcry_camellia_armv6_decrypt_block(keyTable, plaintext, cipherText,
keyBitLength);
}
static unsigned int
camellia_encrypt(void *c, byte *outbuf, const byte *inbuf)
{
CAMELLIA_context *ctx = c;
Camellia_EncryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf);
#define CAMELLIA_encrypt_stack_burn_size (15*4)
return /*burn_stack*/ (CAMELLIA_encrypt_stack_burn_size);
}
static unsigned int
camellia_decrypt(void *c, byte *outbuf, const byte *inbuf)
{
CAMELLIA_context *ctx=c;
Camellia_DecryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf);
#define CAMELLIA_decrypt_stack_burn_size (15*4)
return /*burn_stack*/ (CAMELLIA_decrypt_stack_burn_size);
}
#else /*USE_ARMV6_ASM*/
static unsigned int
camellia_encrypt(void *c, byte *outbuf, const byte *inbuf)
{
CAMELLIA_context *ctx=c;
Camellia_EncryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf);
#define CAMELLIA_encrypt_stack_burn_size \
(sizeof(int)+2*sizeof(unsigned char *)+sizeof(void*/*KEY_TABLE_TYPE*/) \
+4*sizeof(u32)+4*sizeof(u32) \
+2*sizeof(u32*)+4*sizeof(u32) \
+2*2*sizeof(void*) /* Function calls. */ \
)
return /*burn_stack*/ (CAMELLIA_encrypt_stack_burn_size);
}
static unsigned int
camellia_decrypt(void *c, byte *outbuf, const byte *inbuf)
{
CAMELLIA_context *ctx=c;
Camellia_DecryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf);
#define CAMELLIA_decrypt_stack_burn_size \
(sizeof(int)+2*sizeof(unsigned char *)+sizeof(void*/*KEY_TABLE_TYPE*/) \
+4*sizeof(u32)+4*sizeof(u32) \
+2*sizeof(u32*)+4*sizeof(u32) \
+2*2*sizeof(void*) /* Function calls. */ \
)
return /*burn_stack*/ (CAMELLIA_decrypt_stack_burn_size);
}
#endif /*!USE_ARMV6_ASM*/
/* Bulk encryption of complete blocks in CTR mode. This function is only
intended for the bulk encryption feature of cipher.c. CTR is expected to be
of size CAMELLIA_BLOCK_SIZE. */
void
_gcry_camellia_ctr_enc(void *context, unsigned char *ctr,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
CAMELLIA_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char tmpbuf[CAMELLIA_BLOCK_SIZE];
int burn_stack_depth = CAMELLIA_encrypt_stack_burn_size;
int i;
#ifdef USE_AESNI_AVX2
if (ctx->use_aesni_avx2)
{
int did_use_aesni_avx2 = 0;
/* Process data in 32 block chunks. */
while (nblocks >= 32)
{
_gcry_camellia_aesni_avx2_ctr_enc(ctx, outbuf, inbuf, ctr);
nblocks -= 32;
outbuf += 32 * CAMELLIA_BLOCK_SIZE;
inbuf += 32 * CAMELLIA_BLOCK_SIZE;
did_use_aesni_avx2 = 1;
}
if (did_use_aesni_avx2)
{
int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 +
2 * sizeof(void *);
if (burn_stack_depth < avx2_burn_stack_depth)
burn_stack_depth = avx2_burn_stack_depth;
}
/* Use generic code to handle smaller chunks... */
/* TODO: use caching instead? */
}
#endif
#ifdef USE_AESNI_AVX
if (ctx->use_aesni_avx)
{
int did_use_aesni_avx = 0;
/* Process data in 16 block chunks. */
while (nblocks >= 16)
{
_gcry_camellia_aesni_avx_ctr_enc(ctx, outbuf, inbuf, ctr);
nblocks -= 16;
outbuf += 16 * CAMELLIA_BLOCK_SIZE;
inbuf += 16 * CAMELLIA_BLOCK_SIZE;
did_use_aesni_avx = 1;
}
if (did_use_aesni_avx)
{
if (burn_stack_depth < 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *))
burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *);
}
/* Use generic code to handle smaller chunks... */
/* TODO: use caching instead? */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* Encrypt the counter. */
Camellia_EncryptBlock(ctx->keybitlength, ctr, ctx->keytable, tmpbuf);
/* XOR the input with the encrypted counter and store in output. */
buf_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE);
outbuf += CAMELLIA_BLOCK_SIZE;
inbuf += CAMELLIA_BLOCK_SIZE;
/* Increment the counter. */
for (i = CAMELLIA_BLOCK_SIZE; i > 0; i--)
{
ctr[i-1]++;
if (ctr[i-1])
break;
}
}
wipememory(tmpbuf, sizeof(tmpbuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CBC mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_camellia_cbc_dec(void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
CAMELLIA_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char savebuf[CAMELLIA_BLOCK_SIZE];
int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size;
#ifdef USE_AESNI_AVX2
if (ctx->use_aesni_avx2)
{
int did_use_aesni_avx2 = 0;
/* Process data in 32 block chunks. */
while (nblocks >= 32)
{
_gcry_camellia_aesni_avx2_cbc_dec(ctx, outbuf, inbuf, iv);
nblocks -= 32;
outbuf += 32 * CAMELLIA_BLOCK_SIZE;
inbuf += 32 * CAMELLIA_BLOCK_SIZE;
did_use_aesni_avx2 = 1;
}
if (did_use_aesni_avx2)
{
int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 +
2 * sizeof(void *);
if (burn_stack_depth < avx2_burn_stack_depth)
burn_stack_depth = avx2_burn_stack_depth;
}
/* Use generic code to handle smaller chunks... */
}
#endif
#ifdef USE_AESNI_AVX
if (ctx->use_aesni_avx)
{
int did_use_aesni_avx = 0;
/* Process data in 16 block chunks. */
while (nblocks >= 16)
{
_gcry_camellia_aesni_avx_cbc_dec(ctx, outbuf, inbuf, iv);
nblocks -= 16;
outbuf += 16 * CAMELLIA_BLOCK_SIZE;
inbuf += 16 * CAMELLIA_BLOCK_SIZE;
did_use_aesni_avx = 1;
}
if (did_use_aesni_avx)
{
if (burn_stack_depth < 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *))
burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *);
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* We need to save INBUF away because it may be identical to
OUTBUF. */
memcpy(savebuf, inbuf, CAMELLIA_BLOCK_SIZE);
Camellia_DecryptBlock(ctx->keybitlength, inbuf, ctx->keytable, outbuf);
buf_xor(outbuf, outbuf, iv, CAMELLIA_BLOCK_SIZE);
memcpy(iv, savebuf, CAMELLIA_BLOCK_SIZE);
inbuf += CAMELLIA_BLOCK_SIZE;
outbuf += CAMELLIA_BLOCK_SIZE;
}
wipememory(savebuf, sizeof(savebuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CFB mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_camellia_cfb_dec(void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
CAMELLIA_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size;
#ifdef USE_AESNI_AVX2
if (ctx->use_aesni_avx2)
{
int did_use_aesni_avx2 = 0;
/* Process data in 32 block chunks. */
while (nblocks >= 32)
{
_gcry_camellia_aesni_avx2_cfb_dec(ctx, outbuf, inbuf, iv);
nblocks -= 32;
outbuf += 32 * CAMELLIA_BLOCK_SIZE;
inbuf += 32 * CAMELLIA_BLOCK_SIZE;
did_use_aesni_avx2 = 1;
}
if (did_use_aesni_avx2)
{
int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 +
2 * sizeof(void *);
if (burn_stack_depth < avx2_burn_stack_depth)
burn_stack_depth = avx2_burn_stack_depth;
}
/* Use generic code to handle smaller chunks... */
}
#endif
#ifdef USE_AESNI_AVX
if (ctx->use_aesni_avx)
{
int did_use_aesni_avx = 0;
/* Process data in 16 block chunks. */
while (nblocks >= 16)
{
_gcry_camellia_aesni_avx_cfb_dec(ctx, outbuf, inbuf, iv);
nblocks -= 16;
outbuf += 16 * CAMELLIA_BLOCK_SIZE;
inbuf += 16 * CAMELLIA_BLOCK_SIZE;
did_use_aesni_avx = 1;
}
if (did_use_aesni_avx)
{
if (burn_stack_depth < 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *))
burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *);
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
Camellia_EncryptBlock(ctx->keybitlength, iv, ctx->keytable, iv);
buf_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE);
outbuf += CAMELLIA_BLOCK_SIZE;
inbuf += CAMELLIA_BLOCK_SIZE;
}
_gcry_burn_stack(burn_stack_depth);
}
/* Run the self-tests for CAMELLIA-CTR-128, tests IV increment of bulk CTR
encryption. Returns NULL on success. */
static const char*
selftest_ctr_128 (void)
{
const int nblocks = 32+1;
const int blocksize = CAMELLIA_BLOCK_SIZE;
const int context_size = sizeof(CAMELLIA_context);
return _gcry_selftest_helper_ctr("CAMELLIA", &camellia_setkey,
&camellia_encrypt, &_gcry_camellia_ctr_enc, nblocks, blocksize,
context_size);
}
/* Run the self-tests for CAMELLIA-CBC-128, tests bulk CBC decryption.
Returns NULL on success. */
static const char*
selftest_cbc_128 (void)
{
const int nblocks = 32+2;
const int blocksize = CAMELLIA_BLOCK_SIZE;
const int context_size = sizeof(CAMELLIA_context);
return _gcry_selftest_helper_cbc("CAMELLIA", &camellia_setkey,
&camellia_encrypt, &_gcry_camellia_cbc_dec, nblocks, blocksize,
context_size);
}
/* Run the self-tests for CAMELLIA-CFB-128, tests bulk CFB decryption.
Returns NULL on success. */
static const char*
selftest_cfb_128 (void)
{
const int nblocks = 32+2;
const int blocksize = CAMELLIA_BLOCK_SIZE;
const int context_size = sizeof(CAMELLIA_context);
return _gcry_selftest_helper_cfb("CAMELLIA", &camellia_setkey,
&camellia_encrypt, &_gcry_camellia_cfb_dec, nblocks, blocksize,
context_size);
}
static const char *
selftest(void)
{
CAMELLIA_context ctx;
byte scratch[16];
const char *r;
/* These test vectors are from RFC-3713 */
const byte plaintext[]=
{
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10
};
const byte key_128[]=
{
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10
};
const byte ciphertext_128[]=
{
0x67,0x67,0x31,0x38,0x54,0x96,0x69,0x73,
0x08,0x57,0x06,0x56,0x48,0xea,0xbe,0x43
};
const byte key_192[]=
{
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,
0x76,0x54,0x32,0x10,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77
};
const byte ciphertext_192[]=
{
0xb4,0x99,0x34,0x01,0xb3,0xe9,0x96,0xf8,
0x4e,0xe5,0xce,0xe7,0xd7,0x9b,0x09,0xb9
};
const byte key_256[]=
{
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,
0x98,0x76,0x54,0x32,0x10,0x00,0x11,0x22,0x33,0x44,0x55,
0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff
};
const byte ciphertext_256[]=
{
0x9a,0xcc,0x23,0x7d,0xff,0x16,0xd7,0x6c,
0x20,0xef,0x7c,0x91,0x9e,0x3a,0x75,0x09
};
camellia_setkey(&ctx,key_128,sizeof(key_128));
camellia_encrypt(&ctx,scratch,plaintext);
if(memcmp(scratch,ciphertext_128,sizeof(ciphertext_128))!=0)
return "CAMELLIA-128 test encryption failed.";
camellia_decrypt(&ctx,scratch,scratch);
if(memcmp(scratch,plaintext,sizeof(plaintext))!=0)
return "CAMELLIA-128 test decryption failed.";
camellia_setkey(&ctx,key_192,sizeof(key_192));
camellia_encrypt(&ctx,scratch,plaintext);
if(memcmp(scratch,ciphertext_192,sizeof(ciphertext_192))!=0)
return "CAMELLIA-192 test encryption failed.";
camellia_decrypt(&ctx,scratch,scratch);
if(memcmp(scratch,plaintext,sizeof(plaintext))!=0)
return "CAMELLIA-192 test decryption failed.";
camellia_setkey(&ctx,key_256,sizeof(key_256));
camellia_encrypt(&ctx,scratch,plaintext);
if(memcmp(scratch,ciphertext_256,sizeof(ciphertext_256))!=0)
return "CAMELLIA-256 test encryption failed.";
camellia_decrypt(&ctx,scratch,scratch);
if(memcmp(scratch,plaintext,sizeof(plaintext))!=0)
return "CAMELLIA-256 test decryption failed.";
if ( (r = selftest_ctr_128 ()) )
return r;
if ( (r = selftest_cbc_128 ()) )
return r;
if ( (r = selftest_cfb_128 ()) )
return r;
return NULL;
}
/* These oids are from
<http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications_oid.html>,
retrieved May 1, 2007. */
static gcry_cipher_oid_spec_t camellia128_oids[] =
{
{"1.2.392.200011.61.1.1.1.2", GCRY_CIPHER_MODE_CBC},
{"0.3.4401.5.3.1.9.1", GCRY_CIPHER_MODE_ECB},
{"0.3.4401.5.3.1.9.3", GCRY_CIPHER_MODE_OFB},
{"0.3.4401.5.3.1.9.4", GCRY_CIPHER_MODE_CFB},
{ NULL }
};
static gcry_cipher_oid_spec_t camellia192_oids[] =
{
{"1.2.392.200011.61.1.1.1.3", GCRY_CIPHER_MODE_CBC},
{"0.3.4401.5.3.1.9.21", GCRY_CIPHER_MODE_ECB},
{"0.3.4401.5.3.1.9.23", GCRY_CIPHER_MODE_OFB},
{"0.3.4401.5.3.1.9.24", GCRY_CIPHER_MODE_CFB},
{ NULL }
};
static gcry_cipher_oid_spec_t camellia256_oids[] =
{
{"1.2.392.200011.61.1.1.1.4", GCRY_CIPHER_MODE_CBC},
{"0.3.4401.5.3.1.9.41", GCRY_CIPHER_MODE_ECB},
{"0.3.4401.5.3.1.9.43", GCRY_CIPHER_MODE_OFB},
{"0.3.4401.5.3.1.9.44", GCRY_CIPHER_MODE_CFB},
{ NULL }
};
gcry_cipher_spec_t _gcry_cipher_spec_camellia128 =
{
+ GCRY_CIPHER_CAMELLIA128, {0, 0},
"CAMELLIA128",NULL,camellia128_oids,CAMELLIA_BLOCK_SIZE,128,
sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt
};
gcry_cipher_spec_t _gcry_cipher_spec_camellia192 =
{
+ GCRY_CIPHER_CAMELLIA192, {0, 0},
"CAMELLIA192",NULL,camellia192_oids,CAMELLIA_BLOCK_SIZE,192,
sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt
};
gcry_cipher_spec_t _gcry_cipher_spec_camellia256 =
{
+ GCRY_CIPHER_CAMELLIA256, {0, 0},
"CAMELLIA256",NULL,camellia256_oids,CAMELLIA_BLOCK_SIZE,256,
sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt
};
diff --git a/cipher/cast5.c b/cipher/cast5.c
index ae6b509a..92d9af8c 100644
--- a/cipher/cast5.c
+++ b/cipher/cast5.c
@@ -1,988 +1,989 @@
/* cast5.c - CAST5 cipher (RFC2144)
* Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Test vectors:
*
* 128-bit key = 01 23 45 67 12 34 56 78 23 45 67 89 34 56 78 9A
* plaintext = 01 23 45 67 89 AB CD EF
* ciphertext = 23 8B 4F E5 84 7E 44 B2
*
* 80-bit key = 01 23 45 67 12 34 56 78 23 45
* = 01 23 45 67 12 34 56 78 23 45 00 00 00 00 00 00
* plaintext = 01 23 45 67 89 AB CD EF
* ciphertext = EB 6A 71 1A 2C 02 27 1B
*
* 40-bit key = 01 23 45 67 12
* = 01 23 45 67 12 00 00 00 00 00 00 00 00 00 00 00
* plaintext = 01 23 45 67 89 AB CD EF
* ciphertext = 7A C8 16 D1 6E 9B 30 2E
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "g10lib.h"
#include "types.h"
#include "cipher.h"
#include "bithelp.h"
#include "bufhelp.h"
#include "cipher-selftest.h"
/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
#undef USE_AMD64_ASM
#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
# define USE_AMD64_ASM 1
#endif
/* USE_ARMV6_ASM indicates whether to use ARMv6 assembly code. */
#undef USE_ARMV6_ASM
#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__)
# ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS
# define USE_ARMV6_ASM 1
# endif
#endif
#define CAST5_BLOCKSIZE 8
typedef struct {
u32 Km[16];
byte Kr[16];
#ifdef USE_ARMV6_ASM
u32 Kr_arm_enc[16 / sizeof(u32)];
u32 Kr_arm_dec[16 / sizeof(u32)];
#endif
} CAST5_context;
static gcry_err_code_t cast_setkey (void *c, const byte *key, unsigned keylen);
static unsigned int encrypt_block (void *c, byte *outbuf, const byte *inbuf);
static unsigned int decrypt_block (void *c, byte *outbuf, const byte *inbuf);
#define s1 _gcry_cast5_s1to4[0]
#define s2 _gcry_cast5_s1to4[1]
#define s3 _gcry_cast5_s1to4[2]
#define s4 _gcry_cast5_s1to4[3]
const u32 _gcry_cast5_s1to4[4][256] = { {
0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
}, {
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
}, {
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
}, {
0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
} };
static const u32 s5[256] = {
0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
};
static const u32 s6[256] = {
0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
};
static const u32 s7[256] = {
0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
};
static const u32 s8[256] = {
0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e
};
#ifdef USE_AMD64_ASM
/* Assembly implementations of CAST5. */
extern void _gcry_cast5_amd64_encrypt_block(CAST5_context *c, byte *outbuf,
const byte *inbuf);
extern void _gcry_cast5_amd64_decrypt_block(CAST5_context *c, byte *outbuf,
const byte *inbuf);
/* These assembly implementations process four blocks in parallel. */
extern void _gcry_cast5_amd64_ctr_enc(CAST5_context *ctx, byte *out,
const byte *in, byte *ctr);
extern void _gcry_cast5_amd64_cbc_dec(CAST5_context *ctx, byte *out,
const byte *in, byte *iv);
extern void _gcry_cast5_amd64_cfb_dec(CAST5_context *ctx, byte *out,
const byte *in, byte *iv);
static void
do_encrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf)
{
_gcry_cast5_amd64_encrypt_block (context, outbuf, inbuf);
}
static void
do_decrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf)
{
_gcry_cast5_amd64_decrypt_block (context, outbuf, inbuf);
}
static unsigned int
encrypt_block (void *context , byte *outbuf, const byte *inbuf)
{
CAST5_context *c = (CAST5_context *) context;
do_encrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (2*8);
}
static unsigned int
decrypt_block (void *context, byte *outbuf, const byte *inbuf)
{
CAST5_context *c = (CAST5_context *) context;
_gcry_cast5_amd64_decrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (2*8);
}
#elif defined(USE_ARMV6_ASM)
/* ARMv6 assembly implementations of CAST5. */
extern void _gcry_cast5_armv6_encrypt_block(CAST5_context *c, byte *outbuf,
const byte *inbuf);
extern void _gcry_cast5_armv6_decrypt_block(CAST5_context *c, byte *outbuf,
const byte *inbuf);
/* These assembly implementations process two blocks in parallel. */
extern void _gcry_cast5_armv6_ctr_enc(CAST5_context *ctx, byte *out,
const byte *in, byte *ctr);
extern void _gcry_cast5_armv6_cbc_dec(CAST5_context *ctx, byte *out,
const byte *in, byte *iv);
extern void _gcry_cast5_armv6_cfb_dec(CAST5_context *ctx, byte *out,
const byte *in, byte *iv);
static void
do_encrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf)
{
_gcry_cast5_armv6_encrypt_block (context, outbuf, inbuf);
}
static void
do_decrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf)
{
_gcry_cast5_armv6_decrypt_block (context, outbuf, inbuf);
}
static unsigned int
encrypt_block (void *context , byte *outbuf, const byte *inbuf)
{
CAST5_context *c = (CAST5_context *) context;
do_encrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (10*4);
}
static unsigned int
decrypt_block (void *context, byte *outbuf, const byte *inbuf)
{
CAST5_context *c = (CAST5_context *) context;
do_decrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (10*4);
}
#else /*USE_ARMV6_ASM*/
#define F1(D,m,r) ( (I = ((m) + (D))), (I=rol(I,(r))), \
(((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]) )
#define F2(D,m,r) ( (I = ((m) ^ (D))), (I=rol(I,(r))), \
(((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]) )
#define F3(D,m,r) ( (I = ((m) - (D))), (I=rol(I,(r))), \
(((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) )
static void
do_encrypt_block( CAST5_context *c, byte *outbuf, const byte *inbuf )
{
u32 l, r, t;
u32 I; /* used by the Fx macros */
u32 *Km;
byte *Kr;
Km = c->Km;
Kr = c->Kr;
/* (L0,R0) <-- (m1...m64). (Split the plaintext into left and
* right 32-bit halves L0 = m1...m32 and R0 = m33...m64.)
*/
l = buf_get_be32(inbuf + 0);
r = buf_get_be32(inbuf + 4);
/* (16 rounds) for i from 1 to 16, compute Li and Ri as follows:
* Li = Ri-1;
* Ri = Li-1 ^ f(Ri-1,Kmi,Kri), where f is defined in Section 2.2
* Rounds 1, 4, 7, 10, 13, and 16 use f function Type 1.
* Rounds 2, 5, 8, 11, and 14 use f function Type 2.
* Rounds 3, 6, 9, 12, and 15 use f function Type 3.
*/
t = l; l = r; r = t ^ F1(r, Km[ 0], Kr[ 0]);
t = l; l = r; r = t ^ F2(r, Km[ 1], Kr[ 1]);
t = l; l = r; r = t ^ F3(r, Km[ 2], Kr[ 2]);
t = l; l = r; r = t ^ F1(r, Km[ 3], Kr[ 3]);
t = l; l = r; r = t ^ F2(r, Km[ 4], Kr[ 4]);
t = l; l = r; r = t ^ F3(r, Km[ 5], Kr[ 5]);
t = l; l = r; r = t ^ F1(r, Km[ 6], Kr[ 6]);
t = l; l = r; r = t ^ F2(r, Km[ 7], Kr[ 7]);
t = l; l = r; r = t ^ F3(r, Km[ 8], Kr[ 8]);
t = l; l = r; r = t ^ F1(r, Km[ 9], Kr[ 9]);
t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
/* c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and
* concatenate to form the ciphertext.) */
buf_put_be32(outbuf + 0, r);
buf_put_be32(outbuf + 4, l);
}
static unsigned int
encrypt_block (void *context , byte *outbuf, const byte *inbuf)
{
CAST5_context *c = (CAST5_context *) context;
do_encrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (20+4*sizeof(void*));
}
static void
do_decrypt_block (CAST5_context *c, byte *outbuf, const byte *inbuf )
{
u32 l, r, t;
u32 I;
u32 *Km;
byte *Kr;
Km = c->Km;
Kr = c->Kr;
l = buf_get_be32(inbuf + 0);
r = buf_get_be32(inbuf + 4);
t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
t = l; l = r; r = t ^ F1(r, Km[ 9], Kr[ 9]);
t = l; l = r; r = t ^ F3(r, Km[ 8], Kr[ 8]);
t = l; l = r; r = t ^ F2(r, Km[ 7], Kr[ 7]);
t = l; l = r; r = t ^ F1(r, Km[ 6], Kr[ 6]);
t = l; l = r; r = t ^ F3(r, Km[ 5], Kr[ 5]);
t = l; l = r; r = t ^ F2(r, Km[ 4], Kr[ 4]);
t = l; l = r; r = t ^ F1(r, Km[ 3], Kr[ 3]);
t = l; l = r; r = t ^ F3(r, Km[ 2], Kr[ 2]);
t = l; l = r; r = t ^ F2(r, Km[ 1], Kr[ 1]);
t = l; l = r; r = t ^ F1(r, Km[ 0], Kr[ 0]);
buf_put_be32(outbuf + 0, r);
buf_put_be32(outbuf + 4, l);
}
static unsigned int
decrypt_block (void *context, byte *outbuf, const byte *inbuf)
{
CAST5_context *c = (CAST5_context *) context;
do_decrypt_block (c, outbuf, inbuf);
return /*burn_stack*/ (20+4*sizeof(void*));
}
#endif /*!USE_ARMV6_ASM*/
/* Bulk encryption of complete blocks in CTR mode. This function is only
intended for the bulk encryption feature of cipher.c. CTR is expected to be
of size CAST5_BLOCKSIZE. */
void
_gcry_cast5_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg,
const void *inbuf_arg, unsigned int nblocks)
{
CAST5_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char tmpbuf[CAST5_BLOCKSIZE];
int burn_stack_depth = (20 + 4 * sizeof(void*)) + 2 * CAST5_BLOCKSIZE;
int i;
#ifdef USE_AMD64_ASM
{
if (nblocks >= 4)
burn_stack_depth += 8 * sizeof(void*);
/* Process data in 4 block chunks. */
while (nblocks >= 4)
{
_gcry_cast5_amd64_ctr_enc(ctx, outbuf, inbuf, ctr);
nblocks -= 4;
outbuf += 4 * CAST5_BLOCKSIZE;
inbuf += 4 * CAST5_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
/* TODO: use caching instead? */
}
#elif defined(USE_ARMV6_ASM)
{
/* Process data in 2 block chunks. */
while (nblocks >= 2)
{
_gcry_cast5_armv6_ctr_enc(ctx, outbuf, inbuf, ctr);
nblocks -= 2;
outbuf += 2 * CAST5_BLOCKSIZE;
inbuf += 2 * CAST5_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
/* TODO: use caching instead? */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* Encrypt the counter. */
do_encrypt_block(ctx, tmpbuf, ctr);
/* XOR the input with the encrypted counter and store in output. */
buf_xor(outbuf, tmpbuf, inbuf, CAST5_BLOCKSIZE);
outbuf += CAST5_BLOCKSIZE;
inbuf += CAST5_BLOCKSIZE;
/* Increment the counter. */
for (i = CAST5_BLOCKSIZE; i > 0; i--)
{
ctr[i-1]++;
if (ctr[i-1])
break;
}
}
wipememory(tmpbuf, sizeof(tmpbuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CBC mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_cast5_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
const void *inbuf_arg, unsigned int nblocks)
{
CAST5_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char savebuf[CAST5_BLOCKSIZE];
int burn_stack_depth = (20 + 4 * sizeof(void*)) + 2 * CAST5_BLOCKSIZE;
#ifdef USE_AMD64_ASM
{
if (nblocks >= 4)
burn_stack_depth += 8 * sizeof(void*);
/* Process data in 4 block chunks. */
while (nblocks >= 4)
{
_gcry_cast5_amd64_cbc_dec(ctx, outbuf, inbuf, iv);
nblocks -= 4;
outbuf += 4 * CAST5_BLOCKSIZE;
inbuf += 4 * CAST5_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#elif defined(USE_ARMV6_ASM)
{
/* Process data in 2 block chunks. */
while (nblocks >= 2)
{
_gcry_cast5_armv6_cbc_dec(ctx, outbuf, inbuf, iv);
nblocks -= 2;
outbuf += 2 * CAST5_BLOCKSIZE;
inbuf += 2 * CAST5_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* We need to save INBUF away because it may be identical to
OUTBUF. */
memcpy(savebuf, inbuf, CAST5_BLOCKSIZE);
do_decrypt_block (ctx, outbuf, inbuf);
buf_xor(outbuf, outbuf, iv, CAST5_BLOCKSIZE);
memcpy(iv, savebuf, CAST5_BLOCKSIZE);
inbuf += CAST5_BLOCKSIZE;
outbuf += CAST5_BLOCKSIZE;
}
wipememory(savebuf, sizeof(savebuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CFB mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_cast5_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg,
const void *inbuf_arg, unsigned int nblocks)
{
CAST5_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
int burn_stack_depth = (20 + 4 * sizeof(void*)) + 2 * CAST5_BLOCKSIZE;
#ifdef USE_AMD64_ASM
{
if (nblocks >= 4)
burn_stack_depth += 8 * sizeof(void*);
/* Process data in 4 block chunks. */
while (nblocks >= 4)
{
_gcry_cast5_amd64_cfb_dec(ctx, outbuf, inbuf, iv);
nblocks -= 4;
outbuf += 4 * CAST5_BLOCKSIZE;
inbuf += 4 * CAST5_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#elif defined(USE_ARMV6_ASM)
{
/* Process data in 2 block chunks. */
while (nblocks >= 2)
{
_gcry_cast5_armv6_cfb_dec(ctx, outbuf, inbuf, iv);
nblocks -= 2;
outbuf += 2 * CAST5_BLOCKSIZE;
inbuf += 2 * CAST5_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
do_encrypt_block(ctx, iv, iv);
buf_xor_n_copy(outbuf, iv, inbuf, CAST5_BLOCKSIZE);
outbuf += CAST5_BLOCKSIZE;
inbuf += CAST5_BLOCKSIZE;
}
_gcry_burn_stack(burn_stack_depth);
}
/* Run the self-tests for CAST5-CTR, tests IV increment of bulk CTR
encryption. Returns NULL on success. */
static const char *
selftest_ctr (void)
{
const int nblocks = 4+1;
const int blocksize = CAST5_BLOCKSIZE;
const int context_size = sizeof(CAST5_context);
return _gcry_selftest_helper_ctr("CAST5", &cast_setkey,
&encrypt_block, &_gcry_cast5_ctr_enc, nblocks, blocksize,
context_size);
}
/* Run the self-tests for CAST5-CBC, tests bulk CBC decryption.
Returns NULL on success. */
static const char *
selftest_cbc (void)
{
const int nblocks = 4+2;
const int blocksize = CAST5_BLOCKSIZE;
const int context_size = sizeof(CAST5_context);
return _gcry_selftest_helper_cbc("CAST5", &cast_setkey,
&encrypt_block, &_gcry_cast5_cbc_dec, nblocks, blocksize,
context_size);
}
/* Run the self-tests for CAST5-CFB, tests bulk CBC decryption.
Returns NULL on success. */
static const char *
selftest_cfb (void)
{
const int nblocks = 4+2;
const int blocksize = CAST5_BLOCKSIZE;
const int context_size = sizeof(CAST5_context);
return _gcry_selftest_helper_cfb("CAST5", &cast_setkey,
&encrypt_block, &_gcry_cast5_cfb_dec, nblocks, blocksize,
context_size);
}
static const char*
selftest(void)
{
CAST5_context c;
byte key[16] = { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A };
byte plain[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
byte cipher[8]= { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 };
byte buffer[8];
const char *r;
cast_setkey( &c, key, 16 );
encrypt_block( &c, buffer, plain );
if( memcmp( buffer, cipher, 8 ) )
return "1";
decrypt_block( &c, buffer, buffer );
if( memcmp( buffer, plain, 8 ) )
return "2";
#if 0 /* full maintenance test */
{
int i;
byte a0[16] = { 0x01,0x23,0x45,0x67,0x12,0x34,0x56,0x78,
0x23,0x45,0x67,0x89,0x34,0x56,0x78,0x9A };
byte b0[16] = { 0x01,0x23,0x45,0x67,0x12,0x34,0x56,0x78,
0x23,0x45,0x67,0x89,0x34,0x56,0x78,0x9A };
byte a1[16] = { 0xEE,0xA9,0xD0,0xA2,0x49,0xFD,0x3B,0xA6,
0xB3,0x43,0x6F,0xB8,0x9D,0x6D,0xCA,0x92 };
byte b1[16] = { 0xB2,0xC9,0x5E,0xB0,0x0C,0x31,0xAD,0x71,
0x80,0xAC,0x05,0xB8,0xE8,0x3D,0x69,0x6E };
for(i=0; i < 1000000; i++ ) {
cast_setkey( &c, b0, 16 );
encrypt_block( &c, a0, a0 );
encrypt_block( &c, a0+8, a0+8 );
cast_setkey( &c, a0, 16 );
encrypt_block( &c, b0, b0 );
encrypt_block( &c, b0+8, b0+8 );
}
if( memcmp( a0, a1, 16 ) || memcmp( b0, b1, 16 ) )
return "3";
}
#endif
if ( (r = selftest_cbc ()) )
return r;
if ( (r = selftest_cfb ()) )
return r;
if ( (r = selftest_ctr ()) )
return r;
return NULL;
}
static void
key_schedule( u32 *x, u32 *z, u32 *k )
{
#define xi(i) ((x[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
#define zi(i) ((z[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
z[0] = x[0] ^ s5[xi(13)]^s6[xi(15)]^s7[xi(12)]^s8[xi(14)]^s7[xi( 8)];
z[1] = x[2] ^ s5[zi( 0)]^s6[zi( 2)]^s7[zi( 1)]^s8[zi( 3)]^s8[xi(10)];
z[2] = x[3] ^ s5[zi( 7)]^s6[zi( 6)]^s7[zi( 5)]^s8[zi( 4)]^s5[xi( 9)];
z[3] = x[1] ^ s5[zi(10)]^s6[zi( 9)]^s7[zi(11)]^s8[zi( 8)]^s6[xi(11)];
k[0] = s5[zi( 8)]^s6[zi( 9)]^s7[zi( 7)]^s8[zi( 6)]^s5[zi( 2)];
k[1] = s5[zi(10)]^s6[zi(11)]^s7[zi( 5)]^s8[zi( 4)]^s6[zi( 6)];
k[2] = s5[zi(12)]^s6[zi(13)]^s7[zi( 3)]^s8[zi( 2)]^s7[zi( 9)];
k[3] = s5[zi(14)]^s6[zi(15)]^s7[zi( 1)]^s8[zi( 0)]^s8[zi(12)];
x[0] = z[2] ^ s5[zi( 5)]^s6[zi( 7)]^s7[zi( 4)]^s8[zi( 6)]^s7[zi( 0)];
x[1] = z[0] ^ s5[xi( 0)]^s6[xi( 2)]^s7[xi( 1)]^s8[xi( 3)]^s8[zi( 2)];
x[2] = z[1] ^ s5[xi( 7)]^s6[xi( 6)]^s7[xi( 5)]^s8[xi( 4)]^s5[zi( 1)];
x[3] = z[3] ^ s5[xi(10)]^s6[xi( 9)]^s7[xi(11)]^s8[xi( 8)]^s6[zi( 3)];
k[4] = s5[xi( 3)]^s6[xi( 2)]^s7[xi(12)]^s8[xi(13)]^s5[xi( 8)];
k[5] = s5[xi( 1)]^s6[xi( 0)]^s7[xi(14)]^s8[xi(15)]^s6[xi(13)];
k[6] = s5[xi( 7)]^s6[xi( 6)]^s7[xi( 8)]^s8[xi( 9)]^s7[xi( 3)];
k[7] = s5[xi( 5)]^s6[xi( 4)]^s7[xi(10)]^s8[xi(11)]^s8[xi( 7)];
z[0] = x[0] ^ s5[xi(13)]^s6[xi(15)]^s7[xi(12)]^s8[xi(14)]^s7[xi( 8)];
z[1] = x[2] ^ s5[zi( 0)]^s6[zi( 2)]^s7[zi( 1)]^s8[zi( 3)]^s8[xi(10)];
z[2] = x[3] ^ s5[zi( 7)]^s6[zi( 6)]^s7[zi( 5)]^s8[zi( 4)]^s5[xi( 9)];
z[3] = x[1] ^ s5[zi(10)]^s6[zi( 9)]^s7[zi(11)]^s8[zi( 8)]^s6[xi(11)];
k[8] = s5[zi( 3)]^s6[zi( 2)]^s7[zi(12)]^s8[zi(13)]^s5[zi( 9)];
k[9] = s5[zi( 1)]^s6[zi( 0)]^s7[zi(14)]^s8[zi(15)]^s6[zi(12)];
k[10]= s5[zi( 7)]^s6[zi( 6)]^s7[zi( 8)]^s8[zi( 9)]^s7[zi( 2)];
k[11]= s5[zi( 5)]^s6[zi( 4)]^s7[zi(10)]^s8[zi(11)]^s8[zi( 6)];
x[0] = z[2] ^ s5[zi( 5)]^s6[zi( 7)]^s7[zi( 4)]^s8[zi( 6)]^s7[zi( 0)];
x[1] = z[0] ^ s5[xi( 0)]^s6[xi( 2)]^s7[xi( 1)]^s8[xi( 3)]^s8[zi( 2)];
x[2] = z[1] ^ s5[xi( 7)]^s6[xi( 6)]^s7[xi( 5)]^s8[xi( 4)]^s5[zi( 1)];
x[3] = z[3] ^ s5[xi(10)]^s6[xi( 9)]^s7[xi(11)]^s8[xi( 8)]^s6[zi( 3)];
k[12]= s5[xi( 8)]^s6[xi( 9)]^s7[xi( 7)]^s8[xi( 6)]^s5[xi( 3)];
k[13]= s5[xi(10)]^s6[xi(11)]^s7[xi( 5)]^s8[xi( 4)]^s6[xi( 7)];
k[14]= s5[xi(12)]^s6[xi(13)]^s7[xi( 3)]^s8[xi( 2)]^s7[xi( 8)];
k[15]= s5[xi(14)]^s6[xi(15)]^s7[xi( 1)]^s8[xi( 0)]^s8[xi(13)];
#undef xi
#undef zi
}
static gcry_err_code_t
do_cast_setkey( CAST5_context *c, const byte *key, unsigned keylen )
{
static int initialized;
static const char* selftest_failed;
int i;
u32 x[4];
u32 z[4];
u32 k[16];
if( !initialized )
{
initialized = 1;
selftest_failed = selftest();
if( selftest_failed )
log_error ("CAST5 selftest failed (%s).\n", selftest_failed );
}
if( selftest_failed )
return GPG_ERR_SELFTEST_FAILED;
if( keylen != 16 )
return GPG_ERR_INV_KEYLEN;
x[0] = buf_get_be32(key + 0);
x[1] = buf_get_be32(key + 4);
x[2] = buf_get_be32(key + 8);
x[3] = buf_get_be32(key + 12);
key_schedule( x, z, k );
for(i=0; i < 16; i++ )
c->Km[i] = k[i];
key_schedule( x, z, k );
for(i=0; i < 16; i++ )
c->Kr[i] = k[i] & 0x1f;
#ifdef USE_ARMV6_ASM
for (i = 0; i < 4; i++)
{
byte Kr_arm[4];
/* Convert rotate left to rotate right and add shift left
* by 2. */
Kr_arm[0] = ((32 - c->Kr[4 * i + 0]) - 2) & 0x1f;
Kr_arm[1] = ((32 - c->Kr[4 * i + 1]) - 2) & 0x1f;
Kr_arm[2] = ((32 - c->Kr[4 * i + 2]) - 2) & 0x1f;
Kr_arm[3] = ((32 - c->Kr[4 * i + 3]) - 2) & 0x1f;
/* Endian friendly store. */
c->Kr_arm_enc[i] = Kr_arm[0] |
(Kr_arm[1] << 8) |
(Kr_arm[2] << 16) |
(Kr_arm[3] << 24);
c->Kr_arm_dec[i] = Kr_arm[3] |
(Kr_arm[2] << 8) |
(Kr_arm[1] << 16) |
(Kr_arm[0] << 24);
wipememory(Kr_arm, sizeof(Kr_arm));
}
#endif
memset(&x,0, sizeof x);
memset(&z,0, sizeof z);
memset(&k,0, sizeof k);
#undef xi
#undef zi
return GPG_ERR_NO_ERROR;
}
static gcry_err_code_t
cast_setkey (void *context, const byte *key, unsigned keylen )
{
CAST5_context *c = (CAST5_context *) context;
gcry_err_code_t rc = do_cast_setkey (c, key, keylen);
_gcry_burn_stack (96+7*sizeof(void*));
return rc;
}
gcry_cipher_spec_t _gcry_cipher_spec_cast5 =
{
+ GCRY_CIPHER_CAST5, {0, 0},
"CAST5", NULL, NULL, CAST5_BLOCKSIZE, 128, sizeof (CAST5_context),
cast_setkey, encrypt_block, decrypt_block
};
diff --git a/cipher/cipher-aeswrap.c b/cipher/cipher-aeswrap.c
index 931dec10..03b0ea78 100644
--- a/cipher/cipher-aeswrap.c
+++ b/cipher/cipher-aeswrap.c
@@ -1,210 +1,210 @@
/* cipher-aeswrap.c - Generic AESWRAP mode implementation
* Copyright (C) 2009, 2011 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "cipher.h"
#include "ath.h"
#include "bufhelp.h"
#include "./cipher-internal.h"
/* Perform the AES-Wrap algorithm as specified by RFC3394. We
implement this as a mode usable with any cipher algorithm of
blocksize 128. */
gcry_err_code_t
_gcry_cipher_aeswrap_encrypt (gcry_cipher_hd_t c,
byte *outbuf, unsigned int outbuflen,
const byte *inbuf, unsigned int inbuflen )
{
int j, x;
unsigned int n, i;
unsigned char *r, *a, *b;
unsigned char t[8];
unsigned int burn, nburn;
#if MAX_BLOCKSIZE < 8
#error Invalid block size
#endif
/* We require a cipher with a 128 bit block length. */
- if (c->cipher->blocksize != 16)
+ if (c->spec->blocksize != 16)
return GPG_ERR_INV_LENGTH;
/* The output buffer must be able to hold the input data plus one
additional block. */
if (outbuflen < inbuflen + 8)
return GPG_ERR_BUFFER_TOO_SHORT;
/* Input data must be multiple of 64 bits. */
if (inbuflen % 8)
return GPG_ERR_INV_ARG;
n = inbuflen / 8;
/* We need at least two 64 bit blocks. */
if (n < 2)
return GPG_ERR_INV_ARG;
burn = 0;
r = outbuf;
a = outbuf; /* We store A directly in OUTBUF. */
b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
/* If an IV has been set we use that IV as the Alternative Initial
Value; if it has not been set we use the standard value. */
if (c->marks.iv)
memcpy (a, c->u_iv.iv, 8);
else
memset (a, 0xa6, 8);
/* Copy the inbuf to the outbuf. */
memmove (r+8, inbuf, inbuflen);
memset (t, 0, sizeof t); /* t := 0. */
for (j = 0; j <= 5; j++)
{
for (i = 1; i <= n; i++)
{
/* B := AES_k( A | R[i] ) */
memcpy (b, a, 8);
memcpy (b+8, r+i*8, 8);
- nburn = c->cipher->encrypt (&c->context.c, b, b);
+ nburn = c->spec->encrypt (&c->context.c, b, b);
burn = nburn > burn ? nburn : burn;
/* t := t + 1 */
for (x = 7; x >= 0; x--)
{
t[x]++;
if (t[x])
break;
}
/* A := MSB_64(B) ^ t */
buf_xor(a, b, t, 8);
/* R[i] := LSB_64(B) */
memcpy (r+i*8, b+8, 8);
}
}
if (burn > 0)
_gcry_burn_stack (burn + 4 * sizeof(void *));
return 0;
}
/* Perform the AES-Unwrap algorithm as specified by RFC3394. We
implement this as a mode usable with any cipher algorithm of
blocksize 128. */
gcry_err_code_t
_gcry_cipher_aeswrap_decrypt (gcry_cipher_hd_t c,
byte *outbuf, unsigned int outbuflen,
const byte *inbuf, unsigned int inbuflen)
{
int j, x;
unsigned int n, i;
unsigned char *r, *a, *b;
unsigned char t[8];
unsigned int burn, nburn;
#if MAX_BLOCKSIZE < 8
#error Invalid block size
#endif
/* We require a cipher with a 128 bit block length. */
- if (c->cipher->blocksize != 16)
+ if (c->spec->blocksize != 16)
return GPG_ERR_INV_LENGTH;
/* The output buffer must be able to hold the input data minus one
additional block. Fixme: The caller has more restrictive checks
- we may want to fix them for this mode. */
if (outbuflen + 8 < inbuflen)
return GPG_ERR_BUFFER_TOO_SHORT;
/* Input data must be multiple of 64 bits. */
if (inbuflen % 8)
return GPG_ERR_INV_ARG;
n = inbuflen / 8;
/* We need at least three 64 bit blocks. */
if (n < 3)
return GPG_ERR_INV_ARG;
burn = 0;
r = outbuf;
a = c->lastiv; /* We use c->LASTIV as buffer for A. */
b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
/* Copy the inbuf to the outbuf and save A. */
memcpy (a, inbuf, 8);
memmove (r, inbuf+8, inbuflen-8);
n--; /* Reduce to actual number of data blocks. */
/* t := 6 * n */
i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */
for (x=0; x < 8 && x < sizeof (i); x++)
t[7-x] = i >> (8*x);
for (; x < 8; x++)
t[7-x] = 0;
for (j = 5; j >= 0; j--)
{
for (i = n; i >= 1; i--)
{
/* B := AES_k^1( (A ^ t)| R[i] ) */
buf_xor(b, a, t, 8);
memcpy (b+8, r+(i-1)*8, 8);
- nburn = c->cipher->decrypt (&c->context.c, b, b);
+ nburn = c->spec->decrypt (&c->context.c, b, b);
burn = nburn > burn ? nburn : burn;
/* t := t - 1 */
for (x = 7; x >= 0; x--)
{
t[x]--;
if (t[x] != 0xff)
break;
}
/* A := MSB_64(B) */
memcpy (a, b, 8);
/* R[i] := LSB_64(B) */
memcpy (r+(i-1)*8, b+8, 8);
}
}
/* If an IV has been set we compare against this Alternative Initial
Value; if it has not been set we compare against the standard IV. */
if (c->marks.iv)
j = memcmp (a, c->u_iv.iv, 8);
else
{
for (j=0, x=0; x < 8; x++)
if (a[x] != 0xa6)
{
j=1;
break;
}
}
if (burn > 0)
_gcry_burn_stack (burn + 4 * sizeof(void *));
return j? GPG_ERR_CHECKSUM : 0;
}
diff --git a/cipher/cipher-cbc.c b/cipher/cipher-cbc.c
index 55a1c74a..523f5a69 100644
--- a/cipher/cipher-cbc.c
+++ b/cipher/cipher-cbc.c
@@ -1,200 +1,200 @@
/* cipher-cbc.c - Generic CBC mode implementation
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "cipher.h"
#include "ath.h"
#include "./cipher-internal.h"
#include "bufhelp.h"
gcry_err_code_t
_gcry_cipher_cbc_encrypt (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen)
{
unsigned int n;
unsigned char *ivp;
int i;
- size_t blocksize = c->cipher->blocksize;
+ size_t blocksize = c->spec->blocksize;
unsigned nblocks = inbuflen / blocksize;
unsigned int burn, nburn;
if (outbuflen < ((c->flags & GCRY_CIPHER_CBC_MAC)? blocksize : inbuflen))
return GPG_ERR_BUFFER_TOO_SHORT;
- if ((inbuflen % c->cipher->blocksize)
- && !(inbuflen > c->cipher->blocksize
+ if ((inbuflen % c->spec->blocksize)
+ && !(inbuflen > c->spec->blocksize
&& (c->flags & GCRY_CIPHER_CBC_CTS)))
return GPG_ERR_INV_LENGTH;
burn = 0;
if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize)
{
if ((inbuflen % blocksize) == 0)
nblocks--;
}
if (c->bulk.cbc_enc)
{
c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks,
(c->flags & GCRY_CIPHER_CBC_MAC));
inbuf += nblocks * blocksize;
if (!(c->flags & GCRY_CIPHER_CBC_MAC))
outbuf += nblocks * blocksize;
}
else
{
for (n=0; n < nblocks; n++ )
{
buf_xor(outbuf, inbuf, c->u_iv.iv, blocksize);
- nburn = c->cipher->encrypt ( &c->context.c, outbuf, outbuf );
+ nburn = c->spec->encrypt ( &c->context.c, outbuf, outbuf );
burn = nburn > burn ? nburn : burn;
memcpy (c->u_iv.iv, outbuf, blocksize );
inbuf += blocksize;
if (!(c->flags & GCRY_CIPHER_CBC_MAC))
outbuf += blocksize;
}
}
if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize)
{
/* We have to be careful here, since outbuf might be equal to
inbuf. */
int restbytes;
unsigned char b;
if ((inbuflen % blocksize) == 0)
restbytes = blocksize;
else
restbytes = inbuflen % blocksize;
outbuf -= blocksize;
for (ivp = c->u_iv.iv, i = 0; i < restbytes; i++)
{
b = inbuf[i];
outbuf[blocksize + i] = outbuf[i];
outbuf[i] = b ^ *ivp++;
}
for (; i < blocksize; i++)
outbuf[i] = 0 ^ *ivp++;
- nburn = c->cipher->encrypt (&c->context.c, outbuf, outbuf);
+ nburn = c->spec->encrypt (&c->context.c, outbuf, outbuf);
burn = nburn > burn ? nburn : burn;
memcpy (c->u_iv.iv, outbuf, blocksize);
}
if (burn > 0)
_gcry_burn_stack (burn + 4 * sizeof(void *));
return 0;
}
gcry_err_code_t
_gcry_cipher_cbc_decrypt (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen)
{
unsigned int n;
int i;
- size_t blocksize = c->cipher->blocksize;
+ size_t blocksize = c->spec->blocksize;
unsigned int nblocks = inbuflen / blocksize;
unsigned int burn, nburn;
if (outbuflen < inbuflen)
return GPG_ERR_BUFFER_TOO_SHORT;
- if ((inbuflen % c->cipher->blocksize)
- && !(inbuflen > c->cipher->blocksize
+ if ((inbuflen % c->spec->blocksize)
+ && !(inbuflen > c->spec->blocksize
&& (c->flags & GCRY_CIPHER_CBC_CTS)))
return GPG_ERR_INV_LENGTH;
burn = 0;
if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize)
{
nblocks--;
if ((inbuflen % blocksize) == 0)
nblocks--;
memcpy (c->lastiv, c->u_iv.iv, blocksize);
}
if (c->bulk.cbc_dec)
{
c->bulk.cbc_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
inbuf += nblocks * blocksize;
outbuf += nblocks * blocksize;
}
else
{
for (n=0; n < nblocks; n++ )
{
/* Because outbuf and inbuf might be the same, we have to
* save the original ciphertext block. We use LASTIV for
* this here because it is not used otherwise. */
memcpy (c->lastiv, inbuf, blocksize);
- nburn = c->cipher->decrypt ( &c->context.c, outbuf, inbuf );
+ nburn = c->spec->decrypt ( &c->context.c, outbuf, inbuf );
burn = nburn > burn ? nburn : burn;
buf_xor(outbuf, outbuf, c->u_iv.iv, blocksize);
memcpy(c->u_iv.iv, c->lastiv, blocksize );
- inbuf += c->cipher->blocksize;
- outbuf += c->cipher->blocksize;
+ inbuf += c->spec->blocksize;
+ outbuf += c->spec->blocksize;
}
}
if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize)
{
int restbytes;
if ((inbuflen % blocksize) == 0)
restbytes = blocksize;
else
restbytes = inbuflen % blocksize;
memcpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */
memcpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */
- nburn = c->cipher->decrypt ( &c->context.c, outbuf, inbuf );
+ nburn = c->spec->decrypt ( &c->context.c, outbuf, inbuf );
burn = nburn > burn ? nburn : burn;
buf_xor(outbuf, outbuf, c->u_iv.iv, restbytes);
memcpy(outbuf + blocksize, outbuf, restbytes);
for(i=restbytes; i < blocksize; i++)
c->u_iv.iv[i] = outbuf[i];
- nburn = c->cipher->decrypt (&c->context.c, outbuf, c->u_iv.iv);
+ nburn = c->spec->decrypt (&c->context.c, outbuf, c->u_iv.iv);
burn = nburn > burn ? nburn : burn;
buf_xor(outbuf, outbuf, c->lastiv, blocksize);
/* c->lastiv is now really lastlastiv, does this matter? */
}
if (burn > 0)
_gcry_burn_stack (burn + 4 * sizeof(void *));
return 0;
}
diff --git a/cipher/cipher-cfb.c b/cipher/cipher-cfb.c
index f772280d..244f5fdd 100644
--- a/cipher/cipher-cfb.c
+++ b/cipher/cipher-cfb.c
@@ -1,224 +1,224 @@
/* cipher-cfb.c - Generic CFB mode implementation
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "cipher.h"
#include "ath.h"
#include "bufhelp.h"
#include "./cipher-internal.h"
gcry_err_code_t
_gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen)
{
unsigned char *ivp;
- size_t blocksize = c->cipher->blocksize;
+ size_t blocksize = c->spec->blocksize;
size_t blocksize_x_2 = blocksize + blocksize;
unsigned int burn, nburn;
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 + c->cipher->blocksize - c->unused;
+ ivp = c->u_iv.iv + c->spec->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)
{
unsigned int 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 = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &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. */
memcpy( c->lastiv, c->u_iv.iv, blocksize );
- nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &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. */
memcpy( c->lastiv, c->u_iv.iv, blocksize );
- nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &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;
}
gcry_err_code_t
_gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen)
{
unsigned char *ivp;
- size_t blocksize = c->cipher->blocksize;
+ size_t blocksize = c->spec->blocksize;
size_t blocksize_x_2 = blocksize + blocksize;
unsigned int burn, nburn;
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_n_copy(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_n_copy(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_dec)
{
unsigned int nblocks = inbuflen / blocksize;
c->bulk.cfb_dec (&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 = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &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_n_copy(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. */
memcpy ( c->lastiv, c->u_iv.iv, blocksize);
- nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &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_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
outbuf += blocksize;
inbuf += blocksize;
inbuflen -= blocksize;
}
if (inbuflen)
{
/* Save the current IV and then encrypt the IV. */
memcpy ( c->lastiv, c->u_iv.iv, blocksize );
- nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &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_n_copy(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;
}
diff --git a/cipher/cipher-ctr.c b/cipher/cipher-ctr.c
index ff1742c6..fbc898f1 100644
--- a/cipher/cipher-ctr.c
+++ b/cipher/cipher-ctr.c
@@ -1,110 +1,110 @@
/* cipher-ctr.c - Generic CTR mode implementation
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "cipher.h"
#include "ath.h"
#include "bufhelp.h"
#include "./cipher-internal.h"
gcry_err_code_t
_gcry_cipher_ctr_encrypt (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen)
{
unsigned int n;
int i;
- unsigned int blocksize = c->cipher->blocksize;
+ unsigned int blocksize = c->spec->blocksize;
unsigned int nblocks;
unsigned int burn, nburn;
if (outbuflen < inbuflen)
return GPG_ERR_BUFFER_TOO_SHORT;
burn = 0;
/* First process a left over encrypted counter. */
if (c->unused)
{
gcry_assert (c->unused < blocksize);
i = blocksize - c->unused;
n = c->unused > inbuflen ? inbuflen : c->unused;
buf_xor(outbuf, inbuf, &c->lastiv[i], n);
c->unused -= n;
inbuf += n;
outbuf += n;
inbuflen -= n;
}
/* Use a bulk method if available. */
nblocks = inbuflen / blocksize;
if (nblocks && c->bulk.ctr_enc)
{
c->bulk.ctr_enc (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks);
inbuf += nblocks * blocksize;
outbuf += nblocks * blocksize;
inbuflen -= nblocks * blocksize;
}
/* If we don't have a bulk method use the standard method. We also
use this method for the a remaining partial block. */
if (inbuflen)
{
unsigned char tmp[MAX_BLOCKSIZE];
do {
- nburn = c->cipher->encrypt (&c->context.c, tmp, c->u_ctr.ctr);
+ nburn = c->spec->encrypt (&c->context.c, tmp, c->u_ctr.ctr);
burn = nburn > burn ? nburn : burn;
for (i = blocksize; i > 0; i--)
{
c->u_ctr.ctr[i-1]++;
if (c->u_ctr.ctr[i-1] != 0)
break;
}
n = blocksize < inbuflen ? blocksize : inbuflen;
buf_xor(outbuf, inbuf, tmp, n);
inbuflen -= n;
outbuf += n;
inbuf += n;
} while (inbuflen);
/* Save the unused bytes of the counter. */
c->unused = blocksize - n;
if (c->unused)
memcpy (c->lastiv+n, tmp+n, c->unused);
wipememory (tmp, sizeof tmp);
}
if (burn > 0)
_gcry_burn_stack (burn + 4 * sizeof(void *));
return 0;
}
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index 025bf2ec..cabcd1f9 100644
--- a/cipher/cipher-internal.h
+++ b/cipher/cipher-internal.h
@@ -1,181 +1,180 @@
/* cipher-internal.h - Internal defs for cipher.c
* Copyright (C) 2011 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef G10_CIPHER_INTERNAL_H
#define G10_CIPHER_INTERNAL_H
/* The maximum supported size of a block in bytes. */
#define MAX_BLOCKSIZE 16
/* Magic values for the context structure. */
#define CTX_MAGIC_NORMAL 0x24091964
#define CTX_MAGIC_SECURE 0x46919042
/* Try to use 16 byte aligned cipher context for better performance.
We use the aligned attribute, thus it is only possible to implement
this with gcc. */
#undef NEED_16BYTE_ALIGNED_CONTEXT
#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
# define NEED_16BYTE_ALIGNED_CONTEXT 1
#endif
/* A VIA processor with the Padlock engine as well as the Intel AES_NI
instructions require an alignment of most data on a 16 byte
boundary. Because we trick out the compiler while allocating the
context, the align attribute as used in rijndael.c does not work on
its own. Thus we need to make sure that the entire context
structure is a aligned on that boundary. We achieve this by
defining a new type and use that instead of our usual alignment
type. */
typedef union
{
PROPERLY_ALIGNED_TYPE foo;
#ifdef NEED_16BYTE_ALIGNED_CONTEXT
char bar[16] __attribute__ ((aligned (16)));
#endif
char c[1];
} cipher_context_alignment_t;
/* The handle structure. */
struct gcry_cipher_handle
{
int magic;
size_t actual_handle_size; /* Allocated size of this handle. */
size_t handle_offset; /* Offset to the malloced block. */
- gcry_cipher_spec_t *cipher;
- cipher_extra_spec_t *extraspec;
+ gcry_cipher_spec_t *spec;
gcry_module_t module;
/* The algorithm id. This is a hack required because the module
interface does not easily allow to retrieve this value. */
int algo;
/* A structure with function pointers for bulk operations. Due to
limitations of the module system (we don't want to change the
API) we need to keep these function pointers here. The cipher
open function intializes them and the actual encryption routines
use them if they are not NULL. */
struct {
void (*cfb_enc)(void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void (*cfb_dec)(void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void (*cbc_enc)(void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks, int cbc_mac);
void (*cbc_dec)(void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void (*ctr_enc)(void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
} bulk;
int mode;
unsigned int flags;
struct {
unsigned int key:1; /* Set to 1 if a key has been set. */
unsigned int iv:1; /* Set to 1 if a IV has been set. */
} marks;
/* The initialization vector. For best performance we make sure
that it is properly aligned. In particular some implementations
of bulk operations expect an 16 byte aligned IV. */
union {
cipher_context_alignment_t iv_align;
unsigned char iv[MAX_BLOCKSIZE];
} u_iv;
/* The counter for CTR mode. This field is also used by AESWRAP and
thus we can't use the U_IV union. */
union {
cipher_context_alignment_t iv_align;
unsigned char ctr[MAX_BLOCKSIZE];
} u_ctr;
/* Space to save an IV or CTR for chaining operations. */
unsigned char lastiv[MAX_BLOCKSIZE];
int unused; /* Number of unused bytes in LASTIV. */
/* What follows are two contexts of the cipher in use. The first
one needs to be aligned well enough for the cipher operation
whereas the second one is a copy created by cipher_setkey and
used by cipher_reset. That second copy has no need for proper
aligment because it is only accessed by memcpy. */
cipher_context_alignment_t context;
};
/*-- cipher-cbc.c --*/
gcry_err_code_t _gcry_cipher_cbc_encrypt
/* */ (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen);
gcry_err_code_t _gcry_cipher_cbc_decrypt
/* */ (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen);
/*-- cipher-cfb.c --*/
gcry_err_code_t _gcry_cipher_cfb_encrypt
/* */ (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen);
gcry_err_code_t _gcry_cipher_cfb_decrypt
/* */ (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen);
/*-- cipher-ofb.c --*/
gcry_err_code_t _gcry_cipher_ofb_encrypt
/* */ (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen);
gcry_err_code_t _gcry_cipher_ofb_decrypt
/* */ (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen);
/*-- cipher-ctr.c --*/
gcry_err_code_t _gcry_cipher_ctr_encrypt
/* */ (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen);
/*-- cipher-aeswrap.c --*/
gcry_err_code_t _gcry_cipher_aeswrap_encrypt
/* */ (gcry_cipher_hd_t c,
byte *outbuf, unsigned int outbuflen,
const byte *inbuf, unsigned int inbuflen);
gcry_err_code_t _gcry_cipher_aeswrap_decrypt
/* */ (gcry_cipher_hd_t c,
byte *outbuf, unsigned int outbuflen,
const byte *inbuf, unsigned int inbuflen);
#endif /*G10_CIPHER_INTERNAL_H*/
diff --git a/cipher/cipher-ofb.c b/cipher/cipher-ofb.c
index 3fb9b0d2..3d9d54c3 100644
--- a/cipher/cipher-ofb.c
+++ b/cipher/cipher-ofb.c
@@ -1,163 +1,163 @@
/* cipher-ofb.c - Generic OFB mode implementation
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "cipher.h"
#include "ath.h"
#include "bufhelp.h"
#include "./cipher-internal.h"
gcry_err_code_t
_gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen)
{
unsigned char *ivp;
- size_t blocksize = c->cipher->blocksize;
+ size_t blocksize = c->spec->blocksize;
unsigned int burn, nburn;
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 */
- ivp = c->u_iv.iv + c->cipher->blocksize - c->unused;
+ ivp = c->u_iv.iv + c->spec->blocksize - c->unused;
buf_xor(outbuf, ivp, inbuf, inbuflen);
c->unused -= inbuflen;
return 0;
}
burn = 0;
if( c->unused )
{
inbuflen -= c->unused;
ivp = c->u_iv.iv + blocksize - c->unused;
buf_xor(outbuf, ivp, inbuf, c->unused);
outbuf += c->unused;
inbuf += c->unused;
c->unused = 0;
}
/* Now we can process complete blocks. */
while ( inbuflen >= blocksize )
{
/* Encrypt the IV (and save the current one). */
memcpy( c->lastiv, c->u_iv.iv, blocksize );
- nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
burn = nburn > burn ? nburn : burn;
buf_xor(outbuf, c->u_iv.iv, inbuf, blocksize);
outbuf += blocksize;
inbuf += blocksize;
inbuflen -= blocksize;
}
if ( inbuflen )
{ /* process the remaining bytes */
memcpy( c->lastiv, c->u_iv.iv, blocksize );
- nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
burn = nburn > burn ? nburn : burn;
c->unused = blocksize;
c->unused -= inbuflen;
buf_xor(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;
}
gcry_err_code_t
_gcry_cipher_ofb_decrypt (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen)
{
unsigned char *ivp;
- size_t blocksize = c->cipher->blocksize;
+ size_t blocksize = c->spec->blocksize;
unsigned int burn, nburn;
if (outbuflen < inbuflen)
return GPG_ERR_BUFFER_TOO_SHORT;
if( inbuflen <= c->unused )
{
/* Short enough to be encoded by the remaining XOR mask. */
ivp = c->u_iv.iv + blocksize - c->unused;
buf_xor(outbuf, ivp, inbuf, inbuflen);
c->unused -= inbuflen;
return 0;
}
burn = 0;
if ( c->unused )
{
inbuflen -= c->unused;
ivp = c->u_iv.iv + blocksize - c->unused;
buf_xor(outbuf, ivp, inbuf, c->unused);
outbuf += c->unused;
inbuf += c->unused;
c->unused = 0;
}
/* Now we can process complete blocks. */
while ( inbuflen >= blocksize )
{
/* Encrypt the IV (and save the current one). */
memcpy( c->lastiv, c->u_iv.iv, blocksize );
- nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
burn = nburn > burn ? nburn : burn;
buf_xor(outbuf, c->u_iv.iv, inbuf, blocksize);
outbuf += blocksize;
inbuf += blocksize;
inbuflen -= blocksize;
}
if ( inbuflen )
{ /* Process the remaining bytes. */
/* Encrypt the IV (and save the current one). */
memcpy( c->lastiv, c->u_iv.iv, blocksize );
- nburn = c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+ nburn = c->spec->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
burn = nburn > burn ? nburn : burn;
c->unused = blocksize;
c->unused -= inbuflen;
buf_xor(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;
}
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 23cb99c2..ca61375a 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -1,1484 +1,1175 @@
/* cipher.c - cipher dispatcher
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "cipher.h"
#include "ath.h"
#include "./cipher-internal.h"
-/* A dummy extraspec so that we do not need to tests the extraspec
- field from the module specification against NULL and instead
- directly test the respective fields of extraspecs. */
-static cipher_extra_spec_t dummy_extra_spec;
/* This is the list of the default ciphers, which are included in
libgcrypt. */
-static struct cipher_table_entry
-{
- gcry_cipher_spec_t *cipher;
- cipher_extra_spec_t *extraspec;
- unsigned int algorithm;
- int fips_allowed;
-} cipher_table[] =
+static gcry_cipher_spec_t *cipher_list[] =
{
#if USE_BLOWFISH
- { &_gcry_cipher_spec_blowfish,
- &dummy_extra_spec, GCRY_CIPHER_BLOWFISH },
+ &_gcry_cipher_spec_blowfish,
#endif
#if USE_DES
- { &_gcry_cipher_spec_des,
- &dummy_extra_spec, GCRY_CIPHER_DES },
- { &_gcry_cipher_spec_tripledes,
- &_gcry_cipher_extraspec_tripledes, GCRY_CIPHER_3DES, 1 },
+ &_gcry_cipher_spec_des,
+ &_gcry_cipher_spec_tripledes,
#endif
#if USE_ARCFOUR
- { &_gcry_cipher_spec_arcfour,
- &dummy_extra_spec, GCRY_CIPHER_ARCFOUR },
+ &_gcry_cipher_spec_arcfour,
#endif
#if USE_CAST5
- { &_gcry_cipher_spec_cast5,
- &dummy_extra_spec, GCRY_CIPHER_CAST5 },
+ &_gcry_cipher_spec_cast5,
#endif
#if USE_AES
- { &_gcry_cipher_spec_aes,
- &_gcry_cipher_extraspec_aes, GCRY_CIPHER_AES, 1 },
- { &_gcry_cipher_spec_aes192,
- &_gcry_cipher_extraspec_aes192, GCRY_CIPHER_AES192, 1 },
- { &_gcry_cipher_spec_aes256,
- &_gcry_cipher_extraspec_aes256, GCRY_CIPHER_AES256, 1 },
+ &_gcry_cipher_spec_aes,
+ &_gcry_cipher_spec_aes192,
+ &_gcry_cipher_spec_aes256,
#endif
#if USE_TWOFISH
- { &_gcry_cipher_spec_twofish,
- &dummy_extra_spec, GCRY_CIPHER_TWOFISH },
- { &_gcry_cipher_spec_twofish128,
- &dummy_extra_spec, GCRY_CIPHER_TWOFISH128 },
+ &_gcry_cipher_spec_twofish,
+ &_gcry_cipher_spec_twofish128,
#endif
#if USE_SERPENT
- { &_gcry_cipher_spec_serpent128,
- &dummy_extra_spec, GCRY_CIPHER_SERPENT128 },
- { &_gcry_cipher_spec_serpent192,
- &dummy_extra_spec, GCRY_CIPHER_SERPENT192 },
- { &_gcry_cipher_spec_serpent256,
- &dummy_extra_spec, GCRY_CIPHER_SERPENT256 },
+ &_gcry_cipher_spec_serpent128,
+ &_gcry_cipher_spec_serpent192,
+ &_gcry_cipher_spec_serpent256,
#endif
#if USE_RFC2268
- { &_gcry_cipher_spec_rfc2268_40,
- &dummy_extra_spec, GCRY_CIPHER_RFC2268_40 },
- { &_gcry_cipher_spec_rfc2268_128,
- &dummy_extra_spec, GCRY_CIPHER_RFC2268_128 },
+ &_gcry_cipher_spec_rfc2268_40,
+ &_gcry_cipher_spec_rfc2268_128,
#endif
#if USE_SEED
- { &_gcry_cipher_spec_seed,
- &dummy_extra_spec, GCRY_CIPHER_SEED },
+ &_gcry_cipher_spec_seed,
#endif
#if USE_CAMELLIA
- { &_gcry_cipher_spec_camellia128,
- &dummy_extra_spec, GCRY_CIPHER_CAMELLIA128 },
- { &_gcry_cipher_spec_camellia192,
- &dummy_extra_spec, GCRY_CIPHER_CAMELLIA192 },
- { &_gcry_cipher_spec_camellia256,
- &dummy_extra_spec, GCRY_CIPHER_CAMELLIA256 },
+ &_gcry_cipher_spec_camellia128,
+ &_gcry_cipher_spec_camellia192,
+ &_gcry_cipher_spec_camellia256,
#endif
#ifdef USE_IDEA
- { &_gcry_cipher_spec_idea,
- &dummy_extra_spec, GCRY_CIPHER_IDEA },
+ &_gcry_cipher_spec_idea,
#endif
#if USE_SALSA20
- { &_gcry_cipher_spec_salsa20,
- &_gcry_cipher_extraspec_salsa20, GCRY_CIPHER_SALSA20 },
- { &_gcry_cipher_spec_salsa20r12,
- &_gcry_cipher_extraspec_salsa20, GCRY_CIPHER_SALSA20R12 },
+ &_gcry_cipher_spec_salsa20,
+ &_gcry_cipher_spec_salsa20r12,
#endif
#if USE_GOST28147
- { &_gcry_cipher_spec_gost28147,
- &dummy_extra_spec, GCRY_CIPHER_GOST28147 },
+ &_gcry_cipher_spec_gost28147,
#endif
- { NULL }
+ NULL
};
-/* List of registered ciphers. */
-static gcry_module_t ciphers_registered;
-
-/* This is the lock protecting CIPHERS_REGISTERED. It is initialized
- by _gcry_cipher_init. */
-static ath_mutex_t ciphers_registered_lock;
-
-/* Flag to check whether the default ciphers have already been
- registered. */
-static int default_ciphers_registered;
-
-/* Convenient macro for registering the default ciphers. */
-#define REGISTER_DEFAULT_CIPHERS \
- do \
- { \
- ath_mutex_lock (&ciphers_registered_lock); \
- if (! default_ciphers_registered) \
- { \
- cipher_register_default (); \
- default_ciphers_registered = 1; \
- } \
- ath_mutex_unlock (&ciphers_registered_lock); \
- } \
- while (0)
-/* These dummy functions are used in case a cipher implementation
- refuses to provide it's own functions. */
-
-static gcry_err_code_t
-dummy_setkey (void *c, const unsigned char *key, unsigned int keylen)
+static int
+map_algo (int algo)
{
- (void)c;
- (void)key;
- (void)keylen;
- return GPG_ERR_NO_ERROR;
+ return algo;
}
-static unsigned int
-dummy_encrypt_block (void *c,
- unsigned char *outbuf, const unsigned char *inbuf)
-{
- (void)c;
- (void)outbuf;
- (void)inbuf;
- BUG();
- return 0;
-}
-static unsigned int
-dummy_decrypt_block (void *c,
- unsigned char *outbuf, const unsigned char *inbuf)
+/* Return the spec structure for the cipher algorithm ALGO. For
+ an unknown algorithm NULL is returned. */
+static gcry_cipher_spec_t *
+spec_from_algo (int algo)
{
- (void)c;
- (void)outbuf;
- (void)inbuf;
- BUG();
- return 0;
-}
+ int idx;
+ gcry_cipher_spec_t *spec;
-static void
-dummy_encrypt_stream (void *c,
- unsigned char *outbuf, const unsigned char *inbuf,
- unsigned int n)
-{
- (void)c;
- (void)outbuf;
- (void)inbuf;
- (void)n;
- BUG();
-}
+ algo = map_algo (algo);
-static void
-dummy_decrypt_stream (void *c,
- unsigned char *outbuf, const unsigned char *inbuf,
- unsigned int n)
-{
- (void)c;
- (void)outbuf;
- (void)inbuf;
- (void)n;
- BUG();
+ for (idx = 0; (spec = cipher_list[idx]); idx++)
+ if (algo == spec->algo)
+ return spec;
+ return NULL;
}
-
-/* Internal function. Register all the ciphers included in
- CIPHER_TABLE. Note, that this function gets only used by the macro
- REGISTER_DEFAULT_CIPHERS which protects it using a mutex. */
-static void
-cipher_register_default (void)
+
+/* Lookup a cipher's spec by its name. */
+static gcry_cipher_spec_t *
+spec_from_name (const char *name)
{
- gcry_err_code_t err = GPG_ERR_NO_ERROR;
- int i;
+ gcry_cipher_spec_t *spec;
+ int idx;
+ const char **aliases;
- for (i = 0; !err && cipher_table[i].cipher; i++)
+ for (idx=0; (spec = cipher_list[idx]); idx++)
{
- if (! cipher_table[i].cipher->setkey)
- cipher_table[i].cipher->setkey = dummy_setkey;
- if (! cipher_table[i].cipher->encrypt)
- cipher_table[i].cipher->encrypt = dummy_encrypt_block;
- if (! cipher_table[i].cipher->decrypt)
- cipher_table[i].cipher->decrypt = dummy_decrypt_block;
- if (! cipher_table[i].cipher->stencrypt)
- cipher_table[i].cipher->stencrypt = dummy_encrypt_stream;
- if (! cipher_table[i].cipher->stdecrypt)
- cipher_table[i].cipher->stdecrypt = dummy_decrypt_stream;
-
- if ( fips_mode () && !cipher_table[i].fips_allowed )
- continue;
-
- err = _gcry_module_add (&ciphers_registered,
- cipher_table[i].algorithm,
- (void *) cipher_table[i].cipher,
- (void *) cipher_table[i].extraspec,
- NULL);
+ if (!stricmp (name, spec->name))
+ return spec;
+ if (spec->aliases)
+ {
+ for (aliases = spec->aliases; *aliases; aliases++)
+ if (!stricmp (name, *aliases))
+ return spec;
+ }
}
- if (err)
- BUG ();
+ return NULL;
}
-/* Internal callback function. Used via _gcry_module_lookup. */
-static int
-gcry_cipher_lookup_func_name (void *spec, void *data)
-{
- gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec;
- char *name = (char *) data;
- const char **aliases = cipher->aliases;
- int i, ret = ! stricmp (name, cipher->name);
-
- if (aliases)
- for (i = 0; aliases[i] && (! ret); i++)
- ret = ! stricmp (name, aliases[i]);
-
- return ret;
-}
-/* Internal callback function. Used via _gcry_module_lookup. */
-static int
-gcry_cipher_lookup_func_oid (void *spec, void *data)
-{
- gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec;
- char *oid = (char *) data;
- gcry_cipher_oid_spec_t *oid_specs = cipher->oids;
- int ret = 0, i;
-
- if (oid_specs)
- for (i = 0; oid_specs[i].oid && (! ret); i++)
- if (! stricmp (oid, oid_specs[i].oid))
- ret = 1;
-
- return ret;
-}
-
-/* Internal function. Lookup a cipher entry by it's name. */
-static gcry_module_t
-gcry_cipher_lookup_name (const char *name)
-{
- gcry_module_t cipher;
-
- cipher = _gcry_module_lookup (ciphers_registered, (void *) name,
- gcry_cipher_lookup_func_name);
-
- return cipher;
-}
-
-/* Internal function. Lookup a cipher entry by it's oid. */
-static gcry_module_t
-gcry_cipher_lookup_oid (const char *oid)
-{
- gcry_module_t cipher;
-
- cipher = _gcry_module_lookup (ciphers_registered, (void *) oid,
- gcry_cipher_lookup_func_oid);
-
- return cipher;
-}
-
-/* Register a new cipher module whose specification can be found in
- CIPHER. On success, a new algorithm ID is stored in ALGORITHM_ID
- and a pointer representhing this module is stored in MODULE. */
-gcry_error_t
-_gcry_cipher_register (gcry_cipher_spec_t *cipher,
- cipher_extra_spec_t *extraspec,
- int *algorithm_id,
- gcry_module_t *module)
+/* Lookup a cipher's spec by its OID. */
+static gcry_cipher_spec_t *
+spec_from_oid (const char *oid)
{
- gcry_err_code_t err = 0;
- gcry_module_t mod;
-
- /* We do not support module loading in fips mode. */
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
-
- ath_mutex_lock (&ciphers_registered_lock);
- err = _gcry_module_add (&ciphers_registered, 0,
- (void *)cipher,
- (void *)(extraspec? extraspec : &dummy_extra_spec),
- &mod);
- ath_mutex_unlock (&ciphers_registered_lock);
+ gcry_cipher_spec_t *spec;
+ gcry_cipher_oid_spec_t *oid_specs;
+ int idx, j;
- if (! err)
+ for (idx=0; (spec = cipher_list[idx]); idx++)
{
- *module = mod;
- *algorithm_id = mod->mod_id;
+ oid_specs = spec->oids;
+ if (oid_specs)
+ {
+ for (j = 0; oid_specs[j].oid; j++)
+ if (!stricmp (oid, oid_specs[j].oid))
+ return spec;
+ }
}
- return gcry_error (err);
+ return NULL;
}
-/* Unregister the cipher identified by MODULE, which must have been
- registered with gcry_cipher_register. */
-void
-_gcry_cipher_unregister (gcry_module_t module)
-{
- ath_mutex_lock (&ciphers_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&ciphers_registered_lock);
-}
-/* Locate the OID in the oid table and return the index or -1 when not
- found. An opitonal "oid." or "OID." prefix in OID is ignored, the
- OID is expected to be in standard IETF dotted notation. The
- internal algorithm number is returned in ALGORITHM unless it
- ispassed as NULL. A pointer to the specification of the module
- implementing this algorithm is return in OID_SPEC unless passed as
- NULL.*/
-static int
-search_oid (const char *oid, int *algorithm, gcry_cipher_oid_spec_t *oid_spec)
+/* Locate the OID in the oid table and return the spec or NULL if not
+ found. An optional "oid." or "OID." prefix in OID is ignored, the
+ OID is expected to be in standard IETF dotted notation. A pointer
+ to the OID specification of the module implementing this algorithm
+ is return in OID_SPEC unless passed as NULL.*/
+static gcry_cipher_spec_t *
+search_oid (const char *oid, gcry_cipher_oid_spec_t *oid_spec)
{
- gcry_module_t module;
- int ret = 0;
+ gcry_cipher_spec_t *spec;
+ int i;
if (oid && ((! strncmp (oid, "oid.", 4))
|| (! strncmp (oid, "OID.", 4))))
oid += 4;
- module = gcry_cipher_lookup_oid (oid);
- if (module)
+ spec = spec_from_oid (oid);
+ if (spec && spec->oids)
{
- gcry_cipher_spec_t *cipher = module->spec;
- int i;
-
- for (i = 0; cipher->oids[i].oid && !ret; i++)
- if (! stricmp (oid, cipher->oids[i].oid))
+ for (i = 0; spec->oids[i].oid; i++)
+ if (!stricmp (oid, spec->oids[i].oid))
{
- if (algorithm)
- *algorithm = module->mod_id;
if (oid_spec)
- *oid_spec = cipher->oids[i];
- ret = 1;
+ *oid_spec = spec->oids[i];
+ return spec;
}
- _gcry_module_release (module);
}
- return ret;
+ return NULL;
}
+
/* Map STRING to the cipher algorithm identifier. Returns the
algorithm ID of the cipher for the given name or 0 if the name is
not known. It is valid to pass NULL for STRING which results in a
return value of 0. */
int
gcry_cipher_map_name (const char *string)
{
- gcry_module_t cipher;
- int ret, algorithm = 0;
+ gcry_cipher_spec_t *spec;
- if (! string)
+ if (!string)
return 0;
- REGISTER_DEFAULT_CIPHERS;
-
/* If the string starts with a digit (optionally prefixed with
either "OID." or "oid."), we first look into our table of ASN.1
object identifiers to figure out the algorithm */
- ath_mutex_lock (&ciphers_registered_lock);
-
- ret = search_oid (string, &algorithm, NULL);
- if (! ret)
- {
- cipher = gcry_cipher_lookup_name (string);
- if (cipher)
- {
- algorithm = cipher->mod_id;
- _gcry_module_release (cipher);
- }
- }
+ spec = search_oid (string, NULL);
+ if (spec)
+ return spec->algo;
- ath_mutex_unlock (&ciphers_registered_lock);
+ spec = spec_from_name (string);
+ if (spec)
+ return spec->algo;
- return algorithm;
+ return 0;
}
/* Given a STRING with an OID in dotted decimal notation, this
function returns the cipher mode (GCRY_CIPHER_MODE_*) associated
with that OID or 0 if no mode is known. Passing NULL for string
yields a return value of 0. */
int
gcry_cipher_mode_from_oid (const char *string)
{
+ gcry_cipher_spec_t *spec;
gcry_cipher_oid_spec_t oid_spec;
- int ret = 0, mode = 0;
if (!string)
return 0;
- ath_mutex_lock (&ciphers_registered_lock);
- ret = search_oid (string, NULL, &oid_spec);
- if (ret)
- mode = oid_spec.mode;
- ath_mutex_unlock (&ciphers_registered_lock);
+ spec = search_oid (string, &oid_spec);
+ if (spec)
+ return oid_spec.mode;
- return mode;
+ return 0;
}
-/* Map the cipher algorithm whose ID is contained in ALGORITHM to a
- string representation of the algorithm name. For unknown algorithm
- IDs this function returns "?". */
-static const char *
-cipher_algo_to_string (int algorithm)
-{
- gcry_module_t cipher;
- const char *name;
-
- REGISTER_DEFAULT_CIPHERS;
-
- ath_mutex_lock (&ciphers_registered_lock);
- cipher = _gcry_module_lookup_id (ciphers_registered, algorithm);
- if (cipher)
- {
- name = ((gcry_cipher_spec_t *) cipher->spec)->name;
- _gcry_module_release (cipher);
- }
- else
- name = "?";
- ath_mutex_unlock (&ciphers_registered_lock);
-
- return name;
-}
-
/* Map the cipher algorithm identifier ALGORITHM to a string
representing this algorithm. This string is the default name as
- used by Libgcrypt. An pointer to an empty string is returned for
- an unknown algorithm. NULL is never returned. */
+ used by Libgcrypt. A "?" is returned for an unknown algorithm.
+ NULL is never returned. */
const char *
gcry_cipher_algo_name (int algorithm)
{
- return cipher_algo_to_string (algorithm);
+ gcry_cipher_spec_t *spec;
+
+ spec = spec_from_algo (algorithm);
+ return spec? spec->name : "?";
}
/* Flag the cipher algorithm with the identifier ALGORITHM as
disabled. There is no error return, the function does nothing for
- unknown algorithms. Disabled algorithms are vitually not available
- in Libgcrypt. */
+ unknown algorithms. Disabled algorithms are virtually not
+ available in Libgcrypt. This is not thread safe and should thus be
+ called early. */
static void
-disable_cipher_algo (int algorithm)
+disable_cipher_algo (int algo)
{
- gcry_module_t cipher;
-
- REGISTER_DEFAULT_CIPHERS;
+ gcry_cipher_spec_t *spec = spec_from_algo (algo);
- ath_mutex_lock (&ciphers_registered_lock);
- cipher = _gcry_module_lookup_id (ciphers_registered, algorithm);
- if (cipher)
- {
- if (! (cipher->flags & FLAG_MODULE_DISABLED))
- cipher->flags |= FLAG_MODULE_DISABLED;
- _gcry_module_release (cipher);
- }
- ath_mutex_unlock (&ciphers_registered_lock);
+ if (spec)
+ spec->flags.disabled = 1;
}
/* Return 0 if the cipher algorithm with identifier ALGORITHM is
available. Returns a basic error code value if it is not
available. */
static gcry_err_code_t
check_cipher_algo (int algorithm)
{
- gcry_err_code_t err = GPG_ERR_NO_ERROR;
- gcry_module_t cipher;
-
- REGISTER_DEFAULT_CIPHERS;
+ gcry_cipher_spec_t *spec;
- ath_mutex_lock (&ciphers_registered_lock);
- cipher = _gcry_module_lookup_id (ciphers_registered, algorithm);
- if (cipher)
- {
- if (cipher->flags & FLAG_MODULE_DISABLED)
- err = GPG_ERR_CIPHER_ALGO;
- _gcry_module_release (cipher);
- }
- else
- err = GPG_ERR_CIPHER_ALGO;
- ath_mutex_unlock (&ciphers_registered_lock);
+ spec = spec_from_algo (algorithm);
+ if (spec && !spec->flags.disabled)
+ return 0;
- return err;
+ return GPG_ERR_CIPHER_ALGO;
}
/* Return the standard length in bits of the key for the cipher
algorithm with the identifier ALGORITHM. */
static unsigned int
cipher_get_keylen (int algorithm)
{
- gcry_module_t cipher;
+ gcry_cipher_spec_t *spec;
unsigned len = 0;
- REGISTER_DEFAULT_CIPHERS;
-
- ath_mutex_lock (&ciphers_registered_lock);
- cipher = _gcry_module_lookup_id (ciphers_registered, algorithm);
- if (cipher)
+ spec = spec_from_algo (algorithm);
+ if (spec)
{
- len = ((gcry_cipher_spec_t *) cipher->spec)->keylen;
+ len = spec->keylen;
if (!len)
log_bug ("cipher %d w/o key length\n", algorithm);
- _gcry_module_release (cipher);
}
- ath_mutex_unlock (&ciphers_registered_lock);
return len;
}
+
/* Return the block length of the cipher algorithm with the identifier
ALGORITHM. This function return 0 for an invalid algorithm. */
static unsigned int
cipher_get_blocksize (int algorithm)
{
- gcry_module_t cipher;
+ gcry_cipher_spec_t *spec;
unsigned len = 0;
- REGISTER_DEFAULT_CIPHERS;
-
- ath_mutex_lock (&ciphers_registered_lock);
- cipher = _gcry_module_lookup_id (ciphers_registered, algorithm);
- if (cipher)
+ spec = spec_from_algo (algorithm);
+ if (spec)
{
- len = ((gcry_cipher_spec_t *) cipher->spec)->blocksize;
- if (! len)
- log_bug ("cipher %d w/o blocksize\n", algorithm);
- _gcry_module_release (cipher);
+ len = spec->blocksize;
+ if (!len)
+ log_bug ("cipher %d w/o blocksize\n", algorithm);
}
- ath_mutex_unlock (&ciphers_registered_lock);
return len;
}
/*
Open a cipher handle for use with cipher algorithm ALGORITHM, using
the cipher mode MODE (one of the GCRY_CIPHER_MODE_*) and return a
handle in HANDLE. Put NULL into HANDLE and return an error code if
something goes wrong. FLAGS may be used to modify the
operation. The defined flags are:
GCRY_CIPHER_SECURE: allocate all internal buffers in secure memory.
GCRY_CIPHER_ENABLE_SYNC: Enable the sync operation as used in OpenPGP.
GCRY_CIPHER_CBC_CTS: Enable CTS mode.
GCRY_CIPHER_CBC_MAC: Enable MAC mode.
Values for these flags may be combined using OR.
*/
gcry_error_t
gcry_cipher_open (gcry_cipher_hd_t *handle,
int algo, int mode, unsigned int flags)
{
int secure = (flags & GCRY_CIPHER_SECURE);
- gcry_cipher_spec_t *cipher = NULL;
- cipher_extra_spec_t *extraspec = NULL;
- gcry_module_t module = NULL;
+ gcry_cipher_spec_t *spec;
gcry_cipher_hd_t h = NULL;
- gcry_err_code_t err = 0;
+ gcry_err_code_t err;
/* If the application missed to call the random poll function, we do
it here to ensure that it is used once in a while. */
_gcry_fast_random_poll ();
- REGISTER_DEFAULT_CIPHERS;
-
- /* Fetch the according module and check whether the cipher is marked
- available for use. */
- ath_mutex_lock (&ciphers_registered_lock);
- module = _gcry_module_lookup_id (ciphers_registered, algo);
- if (module)
- {
- /* Found module. */
-
- if (module->flags & FLAG_MODULE_DISABLED)
- {
- /* Not available for use. */
- err = GPG_ERR_CIPHER_ALGO;
- }
- else
- {
- cipher = (gcry_cipher_spec_t *) module->spec;
- extraspec = module->extraspec;
- }
- }
- else
+ spec = spec_from_algo (algo);
+ if (!spec)
+ err = GPG_ERR_CIPHER_ALGO;
+ else if (spec->flags.disabled)
err = GPG_ERR_CIPHER_ALGO;
- ath_mutex_unlock (&ciphers_registered_lock);
+ else
+ err = 0;
/* check flags */
if ((! err)
&& ((flags & ~(0
| GCRY_CIPHER_SECURE
| GCRY_CIPHER_ENABLE_SYNC
| GCRY_CIPHER_CBC_CTS
| GCRY_CIPHER_CBC_MAC))
|| (flags & GCRY_CIPHER_CBC_CTS & GCRY_CIPHER_CBC_MAC)))
err = GPG_ERR_CIPHER_ALGO;
/* check that a valid mode has been requested */
if (! err)
switch (mode)
{
case GCRY_CIPHER_MODE_ECB:
case GCRY_CIPHER_MODE_CBC:
case GCRY_CIPHER_MODE_CFB:
case GCRY_CIPHER_MODE_OFB:
case GCRY_CIPHER_MODE_CTR:
case GCRY_CIPHER_MODE_AESWRAP:
- if ((cipher->encrypt == dummy_encrypt_block)
- || (cipher->decrypt == dummy_decrypt_block))
+ if (!spec->encrypt || !spec->decrypt)
err = GPG_ERR_INV_CIPHER_MODE;
break;
case GCRY_CIPHER_MODE_STREAM:
- if ((cipher->stencrypt == dummy_encrypt_stream)
- || (cipher->stdecrypt == dummy_decrypt_stream))
+ if (!spec->stencrypt || !spec->stdecrypt)
err = GPG_ERR_INV_CIPHER_MODE;
break;
case GCRY_CIPHER_MODE_NONE:
/* This mode may be used for debugging. It copies the main
text verbatim to the ciphertext. We do not allow this in
fips mode or if no debug flag has been set. */
if (fips_mode () || !_gcry_get_debug_flag (0))
err = GPG_ERR_INV_CIPHER_MODE;
break;
default:
err = GPG_ERR_INV_CIPHER_MODE;
}
/* Perform selftest here and mark this with a flag in cipher_table?
No, we should not do this as it takes too long. Further it does
not make sense to exclude algorithms with failing selftests at
- runtime: If a selftest fails there is something seriously wrong
- with the system and thus we better die immediately. */
+ runtime: If a selftest fails there is something seriously wrong with the system and thus we better die immediately. */
if (! err)
{
size_t size = (sizeof (*h)
- + 2 * cipher->contextsize
+ + 2 * spec->contextsize
- sizeof (cipher_context_alignment_t)
#ifdef NEED_16BYTE_ALIGNED_CONTEXT
+ 15 /* Space for leading alignment gap. */
#endif /*NEED_16BYTE_ALIGNED_CONTEXT*/
);
if (secure)
h = gcry_calloc_secure (1, size);
else
h = gcry_calloc (1, size);
if (! h)
err = gpg_err_code_from_syserror ();
else
{
size_t off = 0;
#ifdef NEED_16BYTE_ALIGNED_CONTEXT
if ( ((unsigned long)h & 0x0f) )
{
/* The malloced block is not aligned on a 16 byte
boundary. Correct for this. */
off = 16 - ((unsigned long)h & 0x0f);
h = (void*)((char*)h + off);
}
#endif /*NEED_16BYTE_ALIGNED_CONTEXT*/
h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL;
h->actual_handle_size = size - off;
h->handle_offset = off;
- h->cipher = cipher;
- h->extraspec = extraspec;
- h->module = module;
+ h->spec = spec;
h->algo = algo;
h->mode = mode;
h->flags = flags;
/* Setup bulk encryption routines. */
switch (algo)
{
#ifdef USE_AES
case GCRY_CIPHER_AES128:
case GCRY_CIPHER_AES192:
case GCRY_CIPHER_AES256:
h->bulk.cfb_enc = _gcry_aes_cfb_enc;
h->bulk.cfb_dec = _gcry_aes_cfb_dec;
h->bulk.cbc_enc = _gcry_aes_cbc_enc;
h->bulk.cbc_dec = _gcry_aes_cbc_dec;
h->bulk.ctr_enc = _gcry_aes_ctr_enc;
break;
#endif /*USE_AES*/
#ifdef USE_BLOWFISH
case GCRY_CIPHER_BLOWFISH:
h->bulk.cfb_dec = _gcry_blowfish_cfb_dec;
h->bulk.cbc_dec = _gcry_blowfish_cbc_dec;
h->bulk.ctr_enc = _gcry_blowfish_ctr_enc;
break;
#endif /*USE_BLOWFISH*/
#ifdef USE_CAST5
case GCRY_CIPHER_CAST5:
h->bulk.cfb_dec = _gcry_cast5_cfb_dec;
h->bulk.cbc_dec = _gcry_cast5_cbc_dec;
h->bulk.ctr_enc = _gcry_cast5_ctr_enc;
break;
#endif /*USE_CAMELLIA*/
#ifdef USE_CAMELLIA
case GCRY_CIPHER_CAMELLIA128:
case GCRY_CIPHER_CAMELLIA192:
case GCRY_CIPHER_CAMELLIA256:
h->bulk.cbc_dec = _gcry_camellia_cbc_dec;
h->bulk.cfb_dec = _gcry_camellia_cfb_dec;
h->bulk.ctr_enc = _gcry_camellia_ctr_enc;
break;
#endif /*USE_CAMELLIA*/
#ifdef USE_SERPENT
case GCRY_CIPHER_SERPENT128:
case GCRY_CIPHER_SERPENT192:
case GCRY_CIPHER_SERPENT256:
h->bulk.cbc_dec = _gcry_serpent_cbc_dec;
h->bulk.cfb_dec = _gcry_serpent_cfb_dec;
h->bulk.ctr_enc = _gcry_serpent_ctr_enc;
break;
#endif /*USE_SERPENT*/
#ifdef USE_TWOFISH
case GCRY_CIPHER_TWOFISH:
case GCRY_CIPHER_TWOFISH128:
h->bulk.cbc_dec = _gcry_twofish_cbc_dec;
h->bulk.cfb_dec = _gcry_twofish_cfb_dec;
h->bulk.ctr_enc = _gcry_twofish_ctr_enc;
break;
#endif /*USE_TWOFISH*/
default:
break;
}
}
}
/* Done. */
- if (err)
- {
- if (module)
- {
- /* Release module. */
- ath_mutex_lock (&ciphers_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&ciphers_registered_lock);
- }
- }
-
*handle = err ? NULL : h;
return gcry_error (err);
}
/* Release all resources associated with the cipher handle H. H may be
NULL in which case this is a no-operation. */
void
gcry_cipher_close (gcry_cipher_hd_t h)
{
size_t off;
if (!h)
return;
if ((h->magic != CTX_MAGIC_SECURE)
&& (h->magic != CTX_MAGIC_NORMAL))
_gcry_fatal_error(GPG_ERR_INTERNAL,
"gcry_cipher_close: already closed/invalid handle");
else
h->magic = 0;
- /* Release module. */
- ath_mutex_lock (&ciphers_registered_lock);
- _gcry_module_release (h->module);
- ath_mutex_unlock (&ciphers_registered_lock);
-
/* We always want to wipe out the memory even when the context has
been allocated in secure memory. The user might have disabled
secure memory or is using his own implementation which does not
do the wiping. To accomplish this we need to keep track of the
actual size of this structure because we have no way to known
how large the allocated area was when using a standard malloc. */
off = h->handle_offset;
wipememory (h, h->actual_handle_size);
gcry_free ((char*)h - off);
}
/* Set the key to be used for the encryption context C to KEY with
length KEYLEN. The length should match the required length. */
static gcry_error_t
cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned int keylen)
{
gcry_err_code_t ret;
- ret = (*c->cipher->setkey) (&c->context.c, key, keylen);
+ ret = c->spec->setkey (&c->context.c, key, keylen);
if (!ret)
{
/* Duplicate initial context. */
- memcpy ((void *) ((char *) &c->context.c + c->cipher->contextsize),
+ memcpy ((void *) ((char *) &c->context.c + c->spec->contextsize),
(void *) &c->context.c,
- c->cipher->contextsize);
+ c->spec->contextsize);
c->marks.key = 1;
}
else
c->marks.key = 0;
return gcry_error (ret);
}
/* Set the IV to be used for the encryption context C to IV with
length IVLEN. The length should match the required length. */
static void
cipher_setiv (gcry_cipher_hd_t c, const byte *iv, unsigned ivlen)
{
/* If the cipher has its own IV handler, we use only this one. This
is currently used for stream ciphers requiring a nonce. */
- if (c->extraspec && c->extraspec->setiv)
+ if (c->spec->setiv)
{
- c->extraspec->setiv (&c->context.c, iv, ivlen);
+ c->spec->setiv (&c->context.c, iv, ivlen);
return;
}
- memset (c->u_iv.iv, 0, c->cipher->blocksize);
+ memset (c->u_iv.iv, 0, c->spec->blocksize);
if (iv)
{
- if (ivlen != c->cipher->blocksize)
+ if (ivlen != c->spec->blocksize)
{
log_info ("WARNING: cipher_setiv: ivlen=%u blklen=%u\n",
- ivlen, (unsigned int)c->cipher->blocksize);
+ ivlen, (unsigned int)c->spec->blocksize);
fips_signal_error ("IV length does not match blocklength");
}
- if (ivlen > c->cipher->blocksize)
- ivlen = c->cipher->blocksize;
+ if (ivlen > c->spec->blocksize)
+ ivlen = c->spec->blocksize;
memcpy (c->u_iv.iv, iv, ivlen);
c->marks.iv = 1;
}
else
c->marks.iv = 0;
c->unused = 0;
}
/* Reset the cipher context to the initial context. This is basically
the same as an release followed by a new. */
static void
cipher_reset (gcry_cipher_hd_t c)
{
memcpy (&c->context.c,
- (char *) &c->context.c + c->cipher->contextsize,
- c->cipher->contextsize);
+ (char *) &c->context.c + c->spec->contextsize,
+ c->spec->contextsize);
memset (&c->marks, 0, sizeof c->marks);
- memset (c->u_iv.iv, 0, c->cipher->blocksize);
- memset (c->lastiv, 0, c->cipher->blocksize);
- memset (c->u_ctr.ctr, 0, c->cipher->blocksize);
+ memset (c->u_iv.iv, 0, c->spec->blocksize);
+ memset (c->lastiv, 0, c->spec->blocksize);
+ memset (c->u_ctr.ctr, 0, c->spec->blocksize);
}
static gcry_err_code_t
do_ecb_encrypt (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen)
{
- unsigned int blocksize = c->cipher->blocksize;
+ unsigned int blocksize = c->spec->blocksize;
unsigned int n, nblocks;
unsigned int burn, nburn;
if (outbuflen < inbuflen)
return GPG_ERR_BUFFER_TOO_SHORT;
if ((inbuflen % blocksize))
return GPG_ERR_INV_LENGTH;
- nblocks = inbuflen / c->cipher->blocksize;
+ nblocks = inbuflen / c->spec->blocksize;
burn = 0;
for (n=0; n < nblocks; n++ )
{
- nburn = c->cipher->encrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf);
+ nburn = c->spec->encrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf);
burn = nburn > burn ? nburn : burn;
inbuf += blocksize;
outbuf += blocksize;
}
if (burn > 0)
_gcry_burn_stack (burn + 4 * sizeof(void *));
return 0;
}
static gcry_err_code_t
do_ecb_decrypt (gcry_cipher_hd_t c,
unsigned char *outbuf, unsigned int outbuflen,
const unsigned char *inbuf, unsigned int inbuflen)
{
- unsigned int blocksize = c->cipher->blocksize;
+ unsigned int blocksize = c->spec->blocksize;
unsigned int n, nblocks;
unsigned int burn, nburn;
if (outbuflen < inbuflen)
return GPG_ERR_BUFFER_TOO_SHORT;
if ((inbuflen % blocksize))
return GPG_ERR_INV_LENGTH;
- nblocks = inbuflen / c->cipher->blocksize;
+ nblocks = inbuflen / c->spec->blocksize;
burn = 0;
for (n=0; n < nblocks; n++ )
{
- nburn = c->cipher->decrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf);
+ nburn = c->spec->decrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf);
burn = nburn > burn ? nburn : burn;
inbuf += blocksize;
outbuf += blocksize;
}
if (burn > 0)
_gcry_burn_stack (burn + 4 * sizeof(void *));
return 0;
}
/****************
* Encrypt INBUF to OUTBUF with the mode selected at open.
* inbuf and outbuf may overlap or be the same.
* Depending on the mode some constraints apply to INBUFLEN.
*/
static gcry_err_code_t
cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen,
const byte *inbuf, unsigned int inbuflen)
{
gcry_err_code_t rc;
switch (c->mode)
{
case GCRY_CIPHER_MODE_ECB:
rc = do_ecb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_CBC:
rc = _gcry_cipher_cbc_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_CFB:
rc = _gcry_cipher_cfb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_OFB:
rc = _gcry_cipher_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_CTR:
rc = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_AESWRAP:
rc = _gcry_cipher_aeswrap_encrypt (c, outbuf, outbuflen,
inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_STREAM:
- c->cipher->stencrypt (&c->context.c,
- outbuf, (byte*)/*arggg*/inbuf, inbuflen);
+ c->spec->stencrypt (&c->context.c,
+ outbuf, (byte*)/*arggg*/inbuf, inbuflen);
rc = 0;
break;
case GCRY_CIPHER_MODE_NONE:
if (fips_mode () || !_gcry_get_debug_flag (0))
{
fips_signal_error ("cipher mode NONE used");
rc = GPG_ERR_INV_CIPHER_MODE;
}
else
{
if (inbuf != outbuf)
memmove (outbuf, inbuf, inbuflen);
rc = 0;
}
break;
default:
log_fatal ("cipher_encrypt: invalid mode %d\n", c->mode );
rc = GPG_ERR_INV_CIPHER_MODE;
break;
}
return rc;
}
/****************
* Encrypt IN and write it to OUT. If IN is NULL, in-place encryption has
* been requested.
*/
gcry_error_t
gcry_cipher_encrypt (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_encrypt (h, out, outsize, out, outsize);
else
err = cipher_encrypt (h, out, outsize, in, inlen);
/* Failsafe: Make sure that the plaintext will never make it into
OUT if the encryption returned an error. */
if (err && out)
memset (out, 0x42, outsize);
return gcry_error (err);
}
/****************
* 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 INBUFLEN.
*/
static gcry_err_code_t
cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen,
const byte *inbuf, unsigned int inbuflen)
{
gcry_err_code_t rc;
switch (c->mode)
{
case GCRY_CIPHER_MODE_ECB:
rc = do_ecb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_CBC:
rc = _gcry_cipher_cbc_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_CFB:
rc = _gcry_cipher_cfb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_OFB:
rc = _gcry_cipher_ofb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_CTR:
rc = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_AESWRAP:
rc = _gcry_cipher_aeswrap_decrypt (c, outbuf, outbuflen,
inbuf, inbuflen);
break;
case GCRY_CIPHER_MODE_STREAM:
- c->cipher->stdecrypt (&c->context.c,
- outbuf, (byte*)/*arggg*/inbuf, inbuflen);
+ c->spec->stdecrypt (&c->context.c,
+ outbuf, (byte*)/*arggg*/inbuf, inbuflen);
rc = 0;
break;
case GCRY_CIPHER_MODE_NONE:
if (fips_mode () || !_gcry_get_debug_flag (0))
{
fips_signal_error ("cipher mode NONE used");
rc = GPG_ERR_INV_CIPHER_MODE;
}
else
{
if (inbuf != outbuf)
memmove (outbuf, inbuf, inbuflen);
rc = 0;
}
break;
default:
log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode );
rc = GPG_ERR_INV_CIPHER_MODE;
break;
}
return rc;
}
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);
}
/****************
* Used for PGP's somewhat strange CFB mode. Only works if
* the corresponding flag is set.
*/
static void
cipher_sync (gcry_cipher_hd_t c)
{
if ((c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused)
{
memmove (c->u_iv.iv + c->unused,
- c->u_iv.iv, c->cipher->blocksize - c->unused);
+ c->u_iv.iv, c->spec->blocksize - c->unused);
memcpy (c->u_iv.iv,
- c->lastiv + c->cipher->blocksize - c->unused, c->unused);
+ c->lastiv + c->spec->blocksize - c->unused, c->unused);
c->unused = 0;
}
}
gcry_error_t
_gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen)
{
return cipher_setkey (hd, (void*)key, keylen);
}
gcry_error_t
_gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen)
{
cipher_setiv (hd, iv, ivlen);
return 0;
}
/* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of
block size length, or (NULL,0) to set the CTR to the all-zero
block. */
gpg_error_t
_gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen)
{
- if (ctr && ctrlen == hd->cipher->blocksize)
+ if (ctr && ctrlen == hd->spec->blocksize)
{
- memcpy (hd->u_ctr.ctr, ctr, hd->cipher->blocksize);
+ memcpy (hd->u_ctr.ctr, ctr, hd->spec->blocksize);
hd->unused = 0;
}
else if (!ctr || !ctrlen)
{
- memset (hd->u_ctr.ctr, 0, hd->cipher->blocksize);
+ memset (hd->u_ctr.ctr, 0, hd->spec->blocksize);
hd->unused = 0;
}
else
return gpg_error (GPG_ERR_INV_ARG);
return 0;
}
gcry_error_t
gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
{
gcry_err_code_t rc = GPG_ERR_NO_ERROR;
switch (cmd)
{
case GCRYCTL_SET_KEY: /* Deprecated; use gcry_cipher_setkey. */
rc = cipher_setkey( h, buffer, buflen );
break;
case GCRYCTL_SET_IV: /* Deprecated; use gcry_cipher_setiv. */
cipher_setiv( h, buffer, buflen );
break;
case GCRYCTL_RESET:
cipher_reset (h);
break;
case GCRYCTL_CFB_SYNC:
cipher_sync( h );
break;
case GCRYCTL_SET_CBC_CTS:
if (buflen)
if (h->flags & GCRY_CIPHER_CBC_MAC)
rc = GPG_ERR_INV_FLAG;
else
h->flags |= GCRY_CIPHER_CBC_CTS;
else
h->flags &= ~GCRY_CIPHER_CBC_CTS;
break;
case GCRYCTL_SET_CBC_MAC:
if (buflen)
if (h->flags & GCRY_CIPHER_CBC_CTS)
rc = GPG_ERR_INV_FLAG;
else
h->flags |= GCRY_CIPHER_CBC_MAC;
else
h->flags &= ~GCRY_CIPHER_CBC_MAC;
break;
case GCRYCTL_DISABLE_ALGO:
/* This command expects NULL for H and BUFFER to point to an
integer with the algo number. */
if( h || !buffer || buflen != sizeof(int) )
return gcry_error (GPG_ERR_CIPHER_ALGO);
disable_cipher_algo( *(int*)buffer );
break;
case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr. */
rc = gpg_err_code (_gcry_cipher_setctr (h, buffer, buflen));
break;
case 61: /* Disable weak key detection (private). */
- if (h->extraspec->set_extra_info)
- rc = h->extraspec->set_extra_info
+ if (h->spec->set_extra_info)
+ rc = h->spec->set_extra_info
(&h->context.c, CIPHER_INFO_NO_WEAK_KEY, NULL, 0);
else
rc = GPG_ERR_NOT_SUPPORTED;
break;
case 62: /* Return current input vector (private). */
/* This is the input block as used in CFB and OFB mode which has
initially been set as IV. The returned format is:
1 byte Actual length of the block in bytes.
n byte The block.
If the provided buffer is too short, an error is returned. */
- if (buflen < (1 + h->cipher->blocksize))
+ if (buflen < (1 + h->spec->blocksize))
rc = GPG_ERR_TOO_SHORT;
else
{
unsigned char *ivp;
unsigned char *dst = buffer;
int n = h->unused;
if (!n)
- n = h->cipher->blocksize;
- gcry_assert (n <= h->cipher->blocksize);
+ n = h->spec->blocksize;
+ gcry_assert (n <= h->spec->blocksize);
*dst++ = n;
- ivp = h->u_iv.iv + h->cipher->blocksize - n;
+ ivp = h->u_iv.iv + h->spec->blocksize - n;
while (n--)
*dst++ = *ivp++;
}
break;
default:
rc = GPG_ERR_INV_OP;
}
return gcry_error (rc);
}
/* Return information about the cipher handle H. CMD is the kind of
information requested. BUFFER and NBYTES are reserved for now.
There are no values for CMD yet defined.
The function always returns GPG_ERR_INV_OP.
*/
gcry_error_t
gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
(void)h;
(void)buffer;
(void)nbytes;
switch (cmd)
{
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
/* Return information about the given cipher algorithm ALGO.
WHAT select the kind of information returned:
GCRYCTL_GET_KEYLEN:
Return the length of the key. If the algorithm ALGO
supports multiple key lengths, the maximum supported key length
is returned. The key length is returned as number of octets.
BUFFER and NBYTES must be zero.
GCRYCTL_GET_BLKLEN:
Return the blocklength of the algorithm ALGO counted in octets.
BUFFER and NBYTES must be zero.
GCRYCTL_TEST_ALGO:
Returns 0 if the specified algorithm ALGO is available for use.
BUFFER and NBYTES must be zero.
Note: Because this function is in most cases 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 occurred or not (i.e. while
checking the block size)
*/
gcry_error_t
gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
unsigned int ui;
switch (what)
{
case GCRYCTL_GET_KEYLEN:
if (buffer || (! nbytes))
err = GPG_ERR_CIPHER_ALGO;
else
{
ui = cipher_get_keylen (algo);
if ((ui > 0) && (ui <= 512))
*nbytes = (size_t) ui / 8;
else
/* The only reason for an error is an invalid algo. */
err = GPG_ERR_CIPHER_ALGO;
}
break;
case GCRYCTL_GET_BLKLEN:
if (buffer || (! nbytes))
err = GPG_ERR_CIPHER_ALGO;
else
{
ui = cipher_get_blocksize (algo);
if ((ui > 0) && (ui < 10000))
*nbytes = ui;
else
/* The only reason is an invalid algo or a strange
blocksize. */
err = GPG_ERR_CIPHER_ALGO;
}
break;
case GCRYCTL_TEST_ALGO:
if (buffer || nbytes)
err = GPG_ERR_INV_ARG;
else
err = check_cipher_algo (algo);
break;
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
/* This function returns length of the key for algorithm ALGO. If the
algorithm supports multiple key lengths, the maximum supported key
length is returned. On error 0 is returned. The key length is
returned as number of octets.
This is a convenience functions which should be preferred over
gcry_cipher_algo_info because it allows for proper type
checking. */
size_t
gcry_cipher_get_algo_keylen (int algo)
{
size_t n;
if (gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &n))
n = 0;
return n;
}
/* This functions returns the blocklength of the algorithm ALGO
counted in octets. On error 0 is returned.
This is a convenience functions which should be preferred over
gcry_cipher_algo_info because it allows for proper type
checking. */
size_t
gcry_cipher_get_algo_blklen (int algo)
{
size_t n;
if (gcry_cipher_algo_info( algo, GCRYCTL_GET_BLKLEN, NULL, &n))
n = 0;
return n;
}
/* Explicitly initialize this module. */
gcry_err_code_t
_gcry_cipher_init (void)
{
- gcry_err_code_t err;
-
- err = ath_mutex_init (&ciphers_registered_lock);
- if (err)
- return gpg_err_code_from_errno (err);
-
- REGISTER_DEFAULT_CIPHERS;
-
- return err;
+ return 0;
}
/* Run the selftests for cipher algorithm ALGO with optional reporting
function REPORT. */
gpg_error_t
_gcry_cipher_selftest (int algo, int extended, selftest_report_func_t report)
{
- gcry_module_t module = NULL;
- cipher_extra_spec_t *extraspec = NULL;
gcry_err_code_t ec = 0;
+ gcry_cipher_spec_t *spec;
- REGISTER_DEFAULT_CIPHERS;
-
- ath_mutex_lock (&ciphers_registered_lock);
- module = _gcry_module_lookup_id (ciphers_registered, algo);
- if (module && !(module->flags & FLAG_MODULE_DISABLED))
- extraspec = module->extraspec;
- ath_mutex_unlock (&ciphers_registered_lock);
- if (extraspec && extraspec->selftest)
- ec = extraspec->selftest (algo, extended, report);
+ spec = spec_from_algo (algo);
+ if (spec && !spec->flags.disabled && spec->selftest)
+ ec = spec->selftest (algo, extended, report);
else
{
ec = GPG_ERR_CIPHER_ALGO;
if (report)
report ("cipher", algo, "module",
- module && !(module->flags & FLAG_MODULE_DISABLED)?
+ (spec && !spec->flags.disabled)?
"no selftest available" :
- module? "algorithm disabled" : "algorithm not found");
+ spec? "algorithm disabled" : "algorithm not found");
}
- if (module)
- {
- ath_mutex_lock (&ciphers_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&ciphers_registered_lock);
- }
return gpg_error (ec);
}
diff --git a/cipher/des.c b/cipher/des.c
index f1550d1d..3464d53d 100644
--- a/cipher/des.c
+++ b/cipher/des.c
@@ -1,1195 +1,1194 @@
/* des.c - DES and Triple-DES encryption/decryption Algorithm
* Copyright (C) 1998, 1999, 2001, 2002, 2003,
* 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*
* For a description of triple encryption, see:
* Bruce Schneier: Applied Cryptography. Second Edition.
* John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
* This implementation is according to the definition of DES in FIPS
* PUB 46-2 from December 1993.
*/
/*
* Written by Michael Roth <mroth@nessie.de>, September 1998
*/
/*
* U S A G E
* ===========
*
* For DES or Triple-DES encryption/decryption you must initialize a proper
* encryption context with a key.
*
* A DES key is 64bit wide but only 56bits of the key are used. The remaining
* bits are parity bits and they will _not_ checked in this implementation, but
* simply ignored.
*
* For Triple-DES you could use either two 64bit keys or three 64bit keys.
* The parity bits will _not_ checked, too.
*
* After initializing a context with a key you could use this context to
* encrypt or decrypt data in 64bit blocks in Electronic Codebook Mode.
*
* (In the examples below the slashes at the beginning and ending of comments
* are omited.)
*
* DES Example
* -----------
* unsigned char key[8];
* unsigned char plaintext[8];
* unsigned char ciphertext[8];
* unsigned char recoverd[8];
* des_ctx context;
*
* * Fill 'key' and 'plaintext' with some data *
* ....
*
* * Set up the DES encryption context *
* des_setkey(context, key);
*
* * Encrypt the plaintext *
* des_ecb_encrypt(context, plaintext, ciphertext);
*
* * To recover the orginal plaintext from ciphertext use: *
* des_ecb_decrypt(context, ciphertext, recoverd);
*
*
* Triple-DES Example
* ------------------
* unsigned char key1[8];
* unsigned char key2[8];
* unsigned char key3[8];
* unsigned char plaintext[8];
* unsigned char ciphertext[8];
* unsigned char recoverd[8];
* tripledes_ctx context;
*
* * If you would like to use two 64bit keys, fill 'key1' and'key2'
* then setup the encryption context: *
* tripledes_set2keys(context, key1, key2);
*
* * To use three 64bit keys with Triple-DES use: *
* tripledes_set3keys(context, key1, key2, key3);
*
* * Encrypting plaintext with Triple-DES *
* tripledes_ecb_encrypt(context, plaintext, ciphertext);
*
* * Decrypting ciphertext to recover the plaintext with Triple-DES *
* tripledes_ecb_decrypt(context, ciphertext, recoverd);
*
*
* Selftest
* --------
* char *error_msg;
*
* * To perform a selftest of this DES/Triple-DES implementation use the
* function selftest(). It will return an error string if there are
* some problems with this library. *
*
* if ( (error_msg = selftest()) )
* {
* fprintf(stderr, "An error in the DES/Triple-DES implementation occurred: %s\n", error_msg);
* abort();
* }
*/
#include <config.h>
#include <stdio.h>
#include <string.h> /* memcpy, memcmp */
#include "types.h" /* for byte and u32 typedefs */
#include "g10lib.h"
#include "cipher.h"
#include "bufhelp.h"
#if defined(__GNUC__) && defined(__GNU_LIBRARY__)
#define working_memcmp memcmp
#else
/*
* According to the SunOS man page, memcmp returns indeterminate sign
* depending on whether characters are signed or not.
*/
static int
working_memcmp( const char *a, const char *b, size_t n )
{
for( ; n; n--, a++, b++ )
if( *a != *b )
return (int)(*(byte*)a) - (int)(*(byte*)b);
return 0;
}
#endif
/*
* Encryption/Decryption context of DES
*/
typedef struct _des_ctx
{
u32 encrypt_subkeys[32];
u32 decrypt_subkeys[32];
}
des_ctx[1];
/*
* Encryption/Decryption context of Triple-DES
*/
typedef struct _tripledes_ctx
{
u32 encrypt_subkeys[96];
u32 decrypt_subkeys[96];
struct {
int no_weak_key;
} flags;
}
tripledes_ctx[1];
static void des_key_schedule (const byte *, u32 *);
static int des_setkey (struct _des_ctx *, const byte *);
static int des_ecb_crypt (struct _des_ctx *, const byte *, byte *, int);
static int tripledes_set2keys (struct _tripledes_ctx *,
const byte *, const byte *);
static int tripledes_set3keys (struct _tripledes_ctx *,
const byte *, const byte *, const byte *);
static int tripledes_ecb_crypt (struct _tripledes_ctx *,
const byte *, byte *, int);
static int is_weak_key ( const byte *key );
static const char *selftest (void);
static int initialized;
/*
* The s-box values are permuted according to the 'primitive function P'
* and are rotated one bit to the left.
*/
static u32 sbox1[64] =
{
0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000,
0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004,
0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404,
0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000,
0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400,
0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404,
0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400,
0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004
};
static u32 sbox2[64] =
{
0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020,
0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020,
0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000,
0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020,
0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000,
0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000,
0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020,
0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000
};
static u32 sbox3[64] =
{
0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200,
0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208,
0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208,
0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000,
0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000,
0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008,
0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008,
0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200
};
static u32 sbox4[64] =
{
0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001,
0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001,
0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080,
0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081,
0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000,
0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081,
0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080
};
static u32 sbox5[64] =
{
0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000,
0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000,
0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100,
0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100,
0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100,
0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000,
0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000,
0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100
};
static u32 sbox6[64] =
{
0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000,
0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010,
0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010,
0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000,
0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010,
0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000,
0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010,
0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010
};
static u32 sbox7[64] =
{
0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800,
0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802,
0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002,
0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800,
0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002,
0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800,
0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802,
0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002
};
static u32 sbox8[64] =
{
0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000,
0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040,
0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000,
0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000,
0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040,
0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040,
0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000,
0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000
};
/*
* These two tables are part of the 'permuted choice 1' function.
* In this implementation several speed improvements are done.
*/
static u32 leftkey_swap[16] =
{
0x00000000, 0x00000001, 0x00000100, 0x00000101,
0x00010000, 0x00010001, 0x00010100, 0x00010101,
0x01000000, 0x01000001, 0x01000100, 0x01000101,
0x01010000, 0x01010001, 0x01010100, 0x01010101
};
static u32 rightkey_swap[16] =
{
0x00000000, 0x01000000, 0x00010000, 0x01010000,
0x00000100, 0x01000100, 0x00010100, 0x01010100,
0x00000001, 0x01000001, 0x00010001, 0x01010001,
0x00000101, 0x01000101, 0x00010101, 0x01010101,
};
/*
* Numbers of left shifts per round for encryption subkeys.
* To calculate the decryption subkeys we just reverse the
* ordering of the calculated encryption subkeys. So their
* is no need for a decryption rotate tab.
*/
static byte encrypt_rotate_tab[16] =
{
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
/*
* Table with weak DES keys sorted in ascending order.
* In DES their are 64 known keys which are weak. They are weak
* because they produce only one, two or four different
* subkeys in the subkey scheduling process.
* The keys in this table have all their parity bits cleared.
*/
static byte weak_keys[64][8] =
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /*w*/
{ 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e },
{ 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0 },
{ 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe },
{ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e }, /*sw*/
{ 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00 },
{ 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe },
{ 0x00, 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0 },
{ 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0 }, /*sw*/
{ 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe },
{ 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00 },
{ 0x00, 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e },
{ 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe }, /*sw*/
{ 0x00, 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0 },
{ 0x00, 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e },
{ 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00 },
{ 0x1e, 0x00, 0x00, 0x1e, 0x0e, 0x00, 0x00, 0x0e },
{ 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 }, /*sw*/
{ 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0, 0xfe },
{ 0x1e, 0x00, 0xfe, 0xe0, 0x0e, 0x00, 0xfe, 0xf0 },
{ 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00 },
{ 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e }, /*w*/
{ 0x1e, 0x1e, 0xe0, 0xe0, 0x0e, 0x0e, 0xf0, 0xf0 },
{ 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe, 0xfe },
{ 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00, 0xfe },
{ 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 }, /*sw*/
{ 0x1e, 0xe0, 0xe0, 0x1e, 0x0e, 0xf0, 0xf0, 0x0e },
{ 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe, 0x00 },
{ 0x1e, 0xfe, 0x00, 0xe0, 0x0e, 0xfe, 0x00, 0xf0 },
{ 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe }, /*sw*/
{ 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0, 0x00 },
{ 0x1e, 0xfe, 0xfe, 0x1e, 0x0e, 0xfe, 0xfe, 0x0e },
{ 0xe0, 0x00, 0x00, 0xe0, 0xf0, 0x00, 0x00, 0xf0 },
{ 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e, 0xfe },
{ 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 }, /*sw*/
{ 0xe0, 0x00, 0xfe, 0x1e, 0xf0, 0x00, 0xfe, 0x0e },
{ 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00, 0xfe },
{ 0xe0, 0x1e, 0x1e, 0xe0, 0xf0, 0x0e, 0x0e, 0xf0 },
{ 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e }, /*sw*/
{ 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe, 0x00 },
{ 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00 },
{ 0xe0, 0xe0, 0x1e, 0x1e, 0xf0, 0xf0, 0x0e, 0x0e },
{ 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 }, /*w*/
{ 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe, 0xfe },
{ 0xe0, 0xfe, 0x00, 0x1e, 0xf0, 0xfe, 0x00, 0x0e },
{ 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e, 0x00 },
{ 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe }, /*sw*/
{ 0xe0, 0xfe, 0xfe, 0xe0, 0xf0, 0xfe, 0xfe, 0xf0 },
{ 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe },
{ 0xfe, 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0 },
{ 0xfe, 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e },
{ 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00 }, /*sw*/
{ 0xfe, 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0 },
{ 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe },
{ 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00 },
{ 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e }, /*sw*/
{ 0xfe, 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e },
{ 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00 },
{ 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe },
{ 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 }, /*sw*/
{ 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00 },
{ 0xfe, 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e },
{ 0xfe, 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0 },
{ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe } /*w*/
};
static unsigned char weak_keys_chksum[20] = {
0xD0, 0xCF, 0x07, 0x38, 0x93, 0x70, 0x8A, 0x83, 0x7D, 0xD7,
0x8A, 0x36, 0x65, 0x29, 0x6C, 0x1F, 0x7C, 0x3F, 0xD3, 0x41
};
/*
* Macro to swap bits across two words.
*/
#define DO_PERMUTATION(a, temp, b, offset, mask) \
temp = ((a>>offset) ^ b) & mask; \
b ^= temp; \
a ^= temp<<offset;
/*
* This performs the 'initial permutation' of the data to be encrypted
* or decrypted. Additionally the resulting two words are rotated one bit
* to the left.
*/
#define INITIAL_PERMUTATION(left, temp, right) \
DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f) \
DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
right = (right << 1) | (right >> 31); \
temp = (left ^ right) & 0xaaaaaaaa; \
right ^= temp; \
left ^= temp; \
left = (left << 1) | (left >> 31);
/*
* The 'inverse initial permutation'.
*/
#define FINAL_PERMUTATION(left, temp, right) \
left = (left << 31) | (left >> 1); \
temp = (left ^ right) & 0xaaaaaaaa; \
left ^= temp; \
right ^= temp; \
right = (right << 31) | (right >> 1); \
DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)
/*
* A full DES round including 'expansion function', 'sbox substitution'
* and 'primitive function P' but without swapping the left and right word.
* Please note: The data in 'from' and 'to' is already rotated one bit to
* the left, done in the initial permutation.
*/
#define DES_ROUND(from, to, work, subkey) \
work = from ^ *subkey++; \
to ^= sbox8[ work & 0x3f ]; \
to ^= sbox6[ (work>>8) & 0x3f ]; \
to ^= sbox4[ (work>>16) & 0x3f ]; \
to ^= sbox2[ (work>>24) & 0x3f ]; \
work = ((from << 28) | (from >> 4)) ^ *subkey++; \
to ^= sbox7[ work & 0x3f ]; \
to ^= sbox5[ (work>>8) & 0x3f ]; \
to ^= sbox3[ (work>>16) & 0x3f ]; \
to ^= sbox1[ (work>>24) & 0x3f ];
/*
* Macros to convert 8 bytes from/to 32bit words.
*/
#define READ_64BIT_DATA(data, left, right) \
left = buf_get_be32(data + 0); \
right = buf_get_be32(data + 4);
#define WRITE_64BIT_DATA(data, left, right) \
buf_put_be32(data + 0, left); \
buf_put_be32(data + 4, right);
/*
* Handy macros for encryption and decryption of data
*/
#define des_ecb_encrypt(ctx, from, to) des_ecb_crypt(ctx, from, to, 0)
#define des_ecb_decrypt(ctx, from, to) des_ecb_crypt(ctx, from, to, 1)
#define tripledes_ecb_encrypt(ctx, from, to) tripledes_ecb_crypt(ctx,from,to,0)
#define tripledes_ecb_decrypt(ctx, from, to) tripledes_ecb_crypt(ctx,from,to,1)
/*
* des_key_schedule(): Calculate 16 subkeys pairs (even/odd) for
* 16 encryption rounds.
* To calculate subkeys for decryption the caller
* have to reorder the generated subkeys.
*
* rawkey: 8 Bytes of key data
* subkey: Array of at least 32 u32s. Will be filled
* with calculated subkeys.
*
*/
static void
des_key_schedule (const byte * rawkey, u32 * subkey)
{
u32 left, right, work;
int round;
READ_64BIT_DATA (rawkey, left, right)
DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f)
DO_PERMUTATION (right, work, left, 0, 0x10101010)
left = ((leftkey_swap[(left >> 0) & 0xf] << 3)
| (leftkey_swap[(left >> 8) & 0xf] << 2)
| (leftkey_swap[(left >> 16) & 0xf] << 1)
| (leftkey_swap[(left >> 24) & 0xf])
| (leftkey_swap[(left >> 5) & 0xf] << 7)
| (leftkey_swap[(left >> 13) & 0xf] << 6)
| (leftkey_swap[(left >> 21) & 0xf] << 5)
| (leftkey_swap[(left >> 29) & 0xf] << 4));
left &= 0x0fffffff;
right = ((rightkey_swap[(right >> 1) & 0xf] << 3)
| (rightkey_swap[(right >> 9) & 0xf] << 2)
| (rightkey_swap[(right >> 17) & 0xf] << 1)
| (rightkey_swap[(right >> 25) & 0xf])
| (rightkey_swap[(right >> 4) & 0xf] << 7)
| (rightkey_swap[(right >> 12) & 0xf] << 6)
| (rightkey_swap[(right >> 20) & 0xf] << 5)
| (rightkey_swap[(right >> 28) & 0xf] << 4));
right &= 0x0fffffff;
for (round = 0; round < 16; ++round)
{
left = ((left << encrypt_rotate_tab[round])
| (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
right = ((right << encrypt_rotate_tab[round])
| (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
*subkey++ = (((left << 4) & 0x24000000)
| ((left << 28) & 0x10000000)
| ((left << 14) & 0x08000000)
| ((left << 18) & 0x02080000)
| ((left << 6) & 0x01000000)
| ((left << 9) & 0x00200000)
| ((left >> 1) & 0x00100000)
| ((left << 10) & 0x00040000)
| ((left << 2) & 0x00020000)
| ((left >> 10) & 0x00010000)
| ((right >> 13) & 0x00002000)
| ((right >> 4) & 0x00001000)
| ((right << 6) & 0x00000800)
| ((right >> 1) & 0x00000400)
| ((right >> 14) & 0x00000200)
| (right & 0x00000100)
| ((right >> 5) & 0x00000020)
| ((right >> 10) & 0x00000010)
| ((right >> 3) & 0x00000008)
| ((right >> 18) & 0x00000004)
| ((right >> 26) & 0x00000002)
| ((right >> 24) & 0x00000001));
*subkey++ = (((left << 15) & 0x20000000)
| ((left << 17) & 0x10000000)
| ((left << 10) & 0x08000000)
| ((left << 22) & 0x04000000)
| ((left >> 2) & 0x02000000)
| ((left << 1) & 0x01000000)
| ((left << 16) & 0x00200000)
| ((left << 11) & 0x00100000)
| ((left << 3) & 0x00080000)
| ((left >> 6) & 0x00040000)
| ((left << 15) & 0x00020000)
| ((left >> 4) & 0x00010000)
| ((right >> 2) & 0x00002000)
| ((right << 8) & 0x00001000)
| ((right >> 14) & 0x00000808)
| ((right >> 9) & 0x00000400)
| ((right) & 0x00000200)
| ((right << 7) & 0x00000100)
| ((right >> 7) & 0x00000020)
| ((right >> 3) & 0x00000011)
| ((right << 2) & 0x00000004)
| ((right >> 21) & 0x00000002));
}
}
/*
* Fill a DES context with subkeys calculated from a 64bit key.
* Does not check parity bits, but simply ignore them.
* Does not check for weak keys.
*/
static int
des_setkey (struct _des_ctx *ctx, const byte * key)
{
static const char *selftest_failed;
int i;
if (!fips_mode () && !initialized)
{
initialized = 1;
selftest_failed = selftest ();
if (selftest_failed)
log_error ("%s\n", selftest_failed);
}
if (selftest_failed)
return GPG_ERR_SELFTEST_FAILED;
des_key_schedule (key, ctx->encrypt_subkeys);
_gcry_burn_stack (32);
for(i=0; i<32; i+=2)
{
ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i];
ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i];
}
return 0;
}
/*
* Electronic Codebook Mode DES encryption/decryption of data according
* to 'mode'.
*/
static int
des_ecb_crypt (struct _des_ctx *ctx, const byte * from, byte * to, int mode)
{
u32 left, right, work;
u32 *keys;
keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
READ_64BIT_DATA (from, left, right)
INITIAL_PERMUTATION (left, work, right)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
FINAL_PERMUTATION (right, work, left)
WRITE_64BIT_DATA (to, right, left)
return 0;
}
/*
* Fill a Triple-DES context with subkeys calculated from two 64bit keys.
* Does not check the parity bits of the keys, but simply ignore them.
* Does not check for weak keys.
*/
static int
tripledes_set2keys (struct _tripledes_ctx *ctx,
const byte * key1,
const byte * key2)
{
int i;
des_key_schedule (key1, ctx->encrypt_subkeys);
des_key_schedule (key2, &(ctx->decrypt_subkeys[32]));
_gcry_burn_stack (32);
for(i=0; i<32; i+=2)
{
ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i];
ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i];
ctx->encrypt_subkeys[i+32] = ctx->decrypt_subkeys[62-i];
ctx->encrypt_subkeys[i+33] = ctx->decrypt_subkeys[63-i];
ctx->encrypt_subkeys[i+64] = ctx->encrypt_subkeys[i];
ctx->encrypt_subkeys[i+65] = ctx->encrypt_subkeys[i+1];
ctx->decrypt_subkeys[i+64] = ctx->decrypt_subkeys[i];
ctx->decrypt_subkeys[i+65] = ctx->decrypt_subkeys[i+1];
}
return 0;
}
/*
* Fill a Triple-DES context with subkeys calculated from three 64bit keys.
* Does not check the parity bits of the keys, but simply ignore them.
* Does not check for weak keys.
*/
static int
tripledes_set3keys (struct _tripledes_ctx *ctx,
const byte * key1,
const byte * key2,
const byte * key3)
{
static const char *selftest_failed;
int i;
if (!fips_mode () && !initialized)
{
initialized = 1;
selftest_failed = selftest ();
if (selftest_failed)
log_error ("%s\n", selftest_failed);
}
if (selftest_failed)
return GPG_ERR_SELFTEST_FAILED;
des_key_schedule (key1, ctx->encrypt_subkeys);
des_key_schedule (key2, &(ctx->decrypt_subkeys[32]));
des_key_schedule (key3, &(ctx->encrypt_subkeys[64]));
_gcry_burn_stack (32);
for(i=0; i<32; i+=2)
{
ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[94-i];
ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[95-i];
ctx->encrypt_subkeys[i+32] = ctx->decrypt_subkeys[62-i];
ctx->encrypt_subkeys[i+33] = ctx->decrypt_subkeys[63-i];
ctx->decrypt_subkeys[i+64] = ctx->encrypt_subkeys[30-i];
ctx->decrypt_subkeys[i+65] = ctx->encrypt_subkeys[31-i];
}
return 0;
}
/*
* Electronic Codebook Mode Triple-DES encryption/decryption of data
* according to 'mode'. Sometimes this mode is named 'EDE' mode
* (Encryption-Decryption-Encryption).
*/
static int
tripledes_ecb_crypt (struct _tripledes_ctx *ctx, const byte * from,
byte * to, int mode)
{
u32 left, right, work;
u32 *keys;
keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
READ_64BIT_DATA (from, left, right)
INITIAL_PERMUTATION (left, work, right)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
FINAL_PERMUTATION (right, work, left)
WRITE_64BIT_DATA (to, right, left)
return 0;
}
/*
* Check whether the 8 byte key is weak.
* Does not check the parity bits of the key but simple ignore them.
*/
static int
is_weak_key ( const byte *key )
{
byte work[8];
int i, left, right, middle, cmp_result;
/* clear parity bits */
for(i=0; i<8; ++i)
work[i] = key[i] & 0xfe;
/* binary search in the weak key table */
left = 0;
right = 63;
while(left <= right)
{
middle = (left + right) / 2;
if ( !(cmp_result=working_memcmp(work, weak_keys[middle], 8)) )
return -1;
if ( cmp_result > 0 )
left = middle + 1;
else
right = middle - 1;
}
return 0;
}
/*
* Performs a selftest of this DES/Triple-DES implementation.
* Returns an string with the error text on failure.
* Returns NULL if all is ok.
*/
static const char *
selftest (void)
{
/*
* Check if 'u32' is really 32 bits wide. This DES / 3DES implementation
* need this.
*/
if (sizeof (u32) != 4)
return "Wrong word size for DES configured.";
/*
* DES Maintenance Test
*/
{
int i;
byte key[8] =
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
byte input[8] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
byte result[8] =
{0x24, 0x6e, 0x9d, 0xb9, 0xc5, 0x50, 0x38, 0x1a};
byte temp1[8], temp2[8], temp3[8];
des_ctx des;
for (i = 0; i < 64; ++i)
{
des_setkey (des, key);
des_ecb_encrypt (des, input, temp1);
des_ecb_encrypt (des, temp1, temp2);
des_setkey (des, temp2);
des_ecb_decrypt (des, temp1, temp3);
memcpy (key, temp3, 8);
memcpy (input, temp1, 8);
}
if (memcmp (temp3, result, 8))
return "DES maintenance test failed.";
}
/*
* Self made Triple-DES test (Does somebody know an official test?)
*/
{
int i;
byte input[8] =
{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
byte key1[8] =
{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
byte key2[8] =
{0x11, 0x22, 0x33, 0x44, 0xff, 0xaa, 0xcc, 0xdd};
byte result[8] =
{0x7b, 0x38, 0x3b, 0x23, 0xa2, 0x7d, 0x26, 0xd3};
tripledes_ctx des3;
for (i = 0; i < 16; ++i)
{
tripledes_set2keys (des3, key1, key2);
tripledes_ecb_encrypt (des3, input, key1);
tripledes_ecb_decrypt (des3, input, key2);
tripledes_set3keys (des3, key1, input, key2);
tripledes_ecb_encrypt (des3, input, input);
}
if (memcmp (input, result, 8))
return "Triple-DES test failed.";
}
/*
* More Triple-DES test. These are testvectors as used by SSLeay,
* thanks to Jeroen C. van Gelderen.
*/
{
struct { byte key[24]; byte plain[8]; byte cipher[8]; } testdata[] = {
{ { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },
{ 0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00 },
{ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
},
{ { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },
{ 0x9D,0x64,0x55,0x5A,0x9A,0x10,0xB8,0x52, },
{ 0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00 }
},
{ { 0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E,
0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E,
0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E },
{ 0x51,0x45,0x4B,0x58,0x2D,0xDF,0x44,0x0A },
{ 0x71,0x78,0x87,0x6E,0x01,0xF1,0x9B,0x2A }
},
{ { 0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6,
0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6,
0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6 },
{ 0x42,0xFD,0x44,0x30,0x59,0x57,0x7F,0xA2 },
{ 0xAF,0x37,0xFB,0x42,0x1F,0x8C,0x40,0x95 }
},
{ { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF },
{ 0x73,0x6F,0x6D,0x65,0x64,0x61,0x74,0x61 },
{ 0x3D,0x12,0x4F,0xE2,0x19,0x8B,0xA3,0x18 }
},
{ { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF },
{ 0x73,0x6F,0x6D,0x65,0x64,0x61,0x74,0x61 },
{ 0xFB,0xAB,0xA1,0xFF,0x9D,0x05,0xE9,0xB1 }
},
{ { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10 },
{ 0x73,0x6F,0x6D,0x65,0x64,0x61,0x74,0x61 },
{ 0x18,0xd7,0x48,0xe5,0x63,0x62,0x05,0x72 }
},
{ { 0x03,0x52,0x02,0x07,0x67,0x20,0x82,0x17,
0x86,0x02,0x87,0x66,0x59,0x08,0x21,0x98,
0x64,0x05,0x6A,0xBD,0xFE,0xA9,0x34,0x57 },
{ 0x73,0x71,0x75,0x69,0x67,0x67,0x6C,0x65 },
{ 0xc0,0x7d,0x2a,0x0f,0xa5,0x66,0xfa,0x30 }
},
{ { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x80,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0xe6,0xe6,0xdd,0x5b,0x7e,0x72,0x29,0x74 }
},
{ { 0x10,0x46,0x10,0x34,0x89,0x98,0x80,0x20,
0x91,0x07,0xD0,0x15,0x89,0x19,0x01,0x01,
0x19,0x07,0x92,0x10,0x98,0x1A,0x01,0x01 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0xe1,0xef,0x62,0xc3,0x32,0xfe,0x82,0x5b }
}
};
byte result[8];
int i;
tripledes_ctx des3;
for (i=0; i<sizeof(testdata)/sizeof(*testdata); ++i)
{
tripledes_set3keys (des3, testdata[i].key,
testdata[i].key + 8, testdata[i].key + 16);
tripledes_ecb_encrypt (des3, testdata[i].plain, result);
if (memcmp (testdata[i].cipher, result, 8))
return "Triple-DES SSLeay test failed on encryption.";
tripledes_ecb_decrypt (des3, testdata[i].cipher, result);
if (memcmp (testdata[i].plain, result, 8))
return "Triple-DES SSLeay test failed on decryption.";;
}
}
/*
* Check the weak key detection. We simply assume that the table
* with weak keys is ok and check every key in the table if it is
* detected... (This test is a little bit stupid).
*/
{
int i;
unsigned char *p;
gcry_md_hd_t h;
if (_gcry_md_open (&h, GCRY_MD_SHA1, 0))
return "SHA1 not available";
for (i = 0; i < 64; ++i)
_gcry_md_write (h, weak_keys[i], 8);
p = _gcry_md_read (h, GCRY_MD_SHA1);
i = memcmp (p, weak_keys_chksum, 20);
_gcry_md_close (h);
if (i)
return "weak key table defect";
for (i = 0; i < 64; ++i)
if (!is_weak_key(weak_keys[i]))
return "DES weak key detection failed";
}
return 0;
}
static gcry_err_code_t
do_tripledes_setkey ( void *context, const byte *key, unsigned keylen )
{
struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context;
if( keylen != 24 )
return GPG_ERR_INV_KEYLEN;
tripledes_set3keys ( ctx, key, key+8, key+16);
if (ctx->flags.no_weak_key)
; /* Detection has been disabled. */
else if (is_weak_key (key) || is_weak_key (key+8) || is_weak_key (key+16))
{
_gcry_burn_stack (64);
return GPG_ERR_WEAK_KEY;
}
_gcry_burn_stack (64);
return GPG_ERR_NO_ERROR;
}
static gcry_err_code_t
do_tripledes_set_extra_info (void *context, int what,
const void *buffer, size_t buflen)
{
struct _tripledes_ctx *ctx = (struct _tripledes_ctx *)context;
gpg_err_code_t ec = 0;
(void)buffer;
(void)buflen;
switch (what)
{
case CIPHER_INFO_NO_WEAK_KEY:
ctx->flags.no_weak_key = 1;
break;
default:
ec = GPG_ERR_INV_OP;
break;
}
return ec;
}
static unsigned int
do_tripledes_encrypt( void *context, byte *outbuf, const byte *inbuf )
{
struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context;
tripledes_ecb_encrypt ( ctx, inbuf, outbuf );
return /*burn_stack*/ (32);
}
static unsigned int
do_tripledes_decrypt( void *context, byte *outbuf, const byte *inbuf )
{
struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context;
tripledes_ecb_decrypt ( ctx, inbuf, outbuf );
return /*burn_stack*/ (32);
}
static gcry_err_code_t
do_des_setkey (void *context, const byte *key, unsigned keylen)
{
struct _des_ctx *ctx = (struct _des_ctx *) context;
if (keylen != 8)
return GPG_ERR_INV_KEYLEN;
des_setkey (ctx, key);
if (is_weak_key (key)) {
_gcry_burn_stack (64);
return GPG_ERR_WEAK_KEY;
}
_gcry_burn_stack (64);
return GPG_ERR_NO_ERROR;
}
static unsigned int
do_des_encrypt( void *context, byte *outbuf, const byte *inbuf )
{
struct _des_ctx *ctx = (struct _des_ctx *) context;
des_ecb_encrypt ( ctx, inbuf, outbuf );
return /*burn_stack*/ (32);
}
static unsigned int
do_des_decrypt( void *context, byte *outbuf, const byte *inbuf )
{
struct _des_ctx *ctx = (struct _des_ctx *) context;
des_ecb_decrypt ( ctx, inbuf, outbuf );
return /*burn_stack*/ (32);
}
/*
Self-test section.
*/
/* Selftest for TripleDES. */
static gpg_err_code_t
selftest_fips (int extended, selftest_report_func_t report)
{
const char *what;
const char *errtxt;
(void)extended; /* No extended tests available. */
what = "low-level";
errtxt = selftest ();
if (errtxt)
goto failed;
/* The low-level self-tests are quite extensive and thus we can do
without high level tests. This is also justified because we have
no custom block code implementation for 3des but always use the
standard high level block code. */
return 0; /* Succeeded. */
failed:
if (report)
report ("cipher", GCRY_CIPHER_3DES, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
/* Run a full self-test for ALGO and return 0 on success. */
static gpg_err_code_t
run_selftests (int algo, int extended, selftest_report_func_t report)
{
gpg_err_code_t ec;
switch (algo)
{
case GCRY_CIPHER_3DES:
ec = selftest_fips (extended, report);
break;
default:
ec = GPG_ERR_CIPHER_ALGO;
break;
}
return ec;
}
gcry_cipher_spec_t _gcry_cipher_spec_des =
{
+ GCRY_CIPHER_DES, {0, 0},
"DES", NULL, NULL, 8, 64, sizeof (struct _des_ctx),
do_des_setkey, do_des_encrypt, do_des_decrypt
};
static gcry_cipher_oid_spec_t oids_tripledes[] =
{
{ "1.2.840.113549.3.7", GCRY_CIPHER_MODE_CBC },
/* Teletrust specific OID for 3DES. */
{ "1.3.36.3.1.3.2.1", GCRY_CIPHER_MODE_CBC },
/* pbeWithSHAAnd3_KeyTripleDES_CBC */
{ "1.2.840.113549.1.12.1.3", GCRY_CIPHER_MODE_CBC },
{ NULL }
};
gcry_cipher_spec_t _gcry_cipher_spec_tripledes =
{
+ GCRY_CIPHER_3DES, {0, 1},
"3DES", NULL, oids_tripledes, 8, 192, sizeof (struct _tripledes_ctx),
- do_tripledes_setkey, do_tripledes_encrypt, do_tripledes_decrypt
- };
-
-cipher_extra_spec_t _gcry_cipher_extraspec_tripledes =
- {
+ do_tripledes_setkey, do_tripledes_encrypt, do_tripledes_decrypt,
+ NULL, NULL,
run_selftests,
do_tripledes_set_extra_info
};
diff --git a/cipher/gost28147.c b/cipher/gost28147.c
index c669148d..2bda8689 100644
--- a/cipher/gost28147.c
+++ b/cipher/gost28147.c
@@ -1,235 +1,236 @@
/* gost28147.c - GOST 28147-89 implementation for Libgcrypt
* Copyright (C) 2012 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* GOST 28147-89 defines several modes of encryption:
* - ECB which should be used only for key transfer
* - CFB mode
* - OFB-like mode with additional transformation on keystream
* RFC 5830 names this 'counter encryption' mode
* Original GOST text uses the term 'gammirovanie'
* - MAC mode
*
* This implementation handles ECB and CFB modes via usual libgcrypt handling.
* OFB-like and MAC modes are unsupported.
*/
#include <config.h>
#include "types.h"
#include "g10lib.h"
#include "cipher.h"
#define max(a, b) (((a) > (b)) ? (a) : (b))
/* This is an s-box from RFC4357, named GostR3411-94-TestParamSet
* For now it is the only s-box supported, as libgcrypt lacks mechanism
* for passing parameters to cipher in a usefull way. */
unsigned char test_sbox[16 * 8] = {
0x4, 0xE, 0x5, 0x7, 0x6, 0x4, 0xD, 0x1,
0xA, 0xB, 0x8, 0xD, 0xC, 0xB, 0xB, 0xF,
0x9, 0x4, 0x1, 0xA, 0x7, 0xA, 0x4, 0xD,
0x2, 0xC, 0xD, 0x1, 0x1, 0x0, 0x1, 0x0,
0xD, 0x6, 0xA, 0x0, 0x5, 0x7, 0x3, 0x5,
0x8, 0xD, 0x3, 0x8, 0xF, 0x2, 0xF, 0x7,
0x0, 0xF, 0x4, 0x9, 0xD, 0x1, 0x5, 0xA,
0xE, 0xA, 0x2, 0xF, 0x8, 0xD, 0x9, 0x4,
0x6, 0x2, 0xE, 0xE, 0x4, 0x3, 0x0, 0x9,
0xB, 0x3, 0xF, 0x4, 0xA, 0x6, 0xA, 0x2,
0x1, 0x8, 0xC, 0x6, 0x9, 0x8, 0xE, 0x3,
0xC, 0x1, 0x7, 0xC, 0xE, 0x5, 0x7, 0xE,
0x7, 0x0, 0x6, 0xB, 0x0, 0x9, 0x6, 0x6,
0xF, 0x7, 0x0, 0x2, 0x3, 0xC, 0x8, 0xB,
0x5, 0x5, 0x9, 0x5, 0xB, 0xF, 0x2, 0x8,
0x3, 0x9, 0xB, 0x3, 0x2, 0xE, 0xC, 0xC,
};
#include "gost.h"
static gcry_err_code_t
gost_setkey (void *c, const byte *key, unsigned keylen)
{
int i;
GOST28147_context *ctx = c;
if (keylen != 256 / 8)
return GPG_ERR_INV_KEYLEN;
for (i = 0; i < 8; i++)
{
ctx->key[i] = (key[4 * i + 3] << 24) |
(key[4 * i + 2] << 16) |
(key[4 * i + 1] << 8) |
(key[4 * i + 0] << 0);
}
return GPG_ERR_NO_ERROR;
}
static void
gost_set_subst (GOST28147_context *ctx, unsigned char *sbox)
{
unsigned i, j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 256; j++)
{
ctx->subst[i][j] = sbox[ (j & 0xf) * 8 + 2 * i + 0] |
(sbox[ (j >> 4) * 8 + 2 * i + 1] << 4);
}
}
ctx->subst_set = 1;
}
static u32
gost_val (GOST28147_context *ctx, u32 cm1, int subkey)
{
cm1 += ctx->key[subkey];
cm1 = (ctx->subst[0][ (cm1 >> 0) & 0xff] << 0) |
(ctx->subst[1][ (cm1 >> 8) & 0xff] << 8) |
(ctx->subst[2][ (cm1 >> 16) & 0xff] << 16) |
(ctx->subst[3][ (cm1 >> 24) & 0xff] << 24);
return (cm1 << 11) | (cm1 >> 21);
}
static unsigned int
gost_encrypt_block (void *c, byte *outbuf, const byte *inbuf)
{
GOST28147_context *ctx = c;
u32 n1, n2;
if (!ctx->subst_set)
gost_set_subst (ctx, test_sbox);
n1 = (inbuf[0] << 0) |
(inbuf[1] << 8) |
(inbuf[2] << 16) |
(inbuf[3] << 24);
n2 = (inbuf[4] << 0) |
(inbuf[5] << 8) |
(inbuf[6] << 16) |
(inbuf[7] << 24);
n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff;
outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff;
outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff;
outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff;
outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff;
outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff;
outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff;
outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff;
return /* burn_stack */ 4*sizeof(void*) /* func call */ +
3*sizeof(void*) /* stack */ +
max( 4*sizeof(void*) /* gost_val call */,
3*sizeof(void*) /* gost_set_subst call */ +
2*sizeof(void*) /* gost_set subst stack*/ );
}
unsigned int _gcry_gost_enc_one (GOST28147_context *c, const byte *key,
byte *out, byte *in)
{
gost_setkey (c, key, 32);
return gost_encrypt_block (c, out, in) + 5 * sizeof(void *);
}
static unsigned int
gost_decrypt_block (void *c, byte *outbuf, const byte *inbuf)
{
GOST28147_context *ctx = c;
u32 n1, n2;
if (!ctx->subst_set)
gost_set_subst (ctx, test_sbox);
n1 = (inbuf[0] << 0) |
(inbuf[1] << 8) |
(inbuf[2] << 16) |
(inbuf[3] << 24);
n2 = (inbuf[4] << 0) |
(inbuf[5] << 8) |
(inbuf[6] << 16) |
(inbuf[7] << 24);
n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1);
n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3);
n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5);
n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7);
n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6);
n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4);
n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2);
n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0);
outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff;
outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff;
outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff;
outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff;
outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff;
outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff;
outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff;
outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff;
return /* burn_stack */ 4*sizeof(void*) /* func call */ +
3*sizeof(void*) /* stack */ +
max( 4*sizeof(void*) /* gost_val call */,
3*sizeof(void*) /* gost_set_subst call */ +
2*sizeof(void*) /* gost_set subst stack*/ );
}
gcry_cipher_spec_t _gcry_cipher_spec_gost28147 =
{
+ GCRY_CIPHER_GOST28147, {0, 0},
"GOST28147", NULL, NULL, 8, 256,
sizeof (GOST28147_context),
gost_setkey,
gost_encrypt_block,
gost_decrypt_block,
};
diff --git a/cipher/idea.c b/cipher/idea.c
index 6e81e84b..7d91a9a3 100644
--- a/cipher/idea.c
+++ b/cipher/idea.c
@@ -1,378 +1,379 @@
/* idea.c - IDEA function
* Copyright 1997, 1998, 1999, 2001 Werner Koch (dd9jn)
* Copyright 2013 g10 Code GmbH
*
* 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 "g10lib.h"
#include "cipher.h"
#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 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) );
memset(temp, 0, sizeof(temp) ); /* burn temp */
}
static void
cipher( byte *outbuf, const byte *inbuf, u16 *key )
{
u16 s2, s3;
u16 in[4];
int r = IDEA_ROUNDS;
#define x1 (in[0])
#define x2 (in[1])
#define x3 (in[2])
#define x4 (in[3])
#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)
memcpy (in, inbuf, sizeof 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);
#ifndef WORDS_BIGENDIAN
x1 = (x1>>8) | (x1<<8);
x2 = (x2>>8) | (x2<<8);
x3 = (x3>>8) | (x3<<8);
x4 = (x4>>8) | (x4<<8);
#endif
memcpy (outbuf+0, &x1, 2);
memcpy (outbuf+2, &x3, 2);
memcpy (outbuf+4, &x2, 2);
memcpy (outbuf+6, &x4, 2);
#undef MUL
#undef x1
#undef x2
#undef x3
#undef x4
}
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 GPG_ERR_SELFTEST_FAILED;
assert(keylen == 16);
c->have_dk = 0;
expand_key( key, c->ek );
invert_key( c->ek, c->dk );
return 0;
}
static gcry_err_code_t
idea_setkey (void *context, const byte *key, unsigned int keylen)
{
IDEA_context *ctx = context;
int rc = do_setkey (ctx, key, keylen);
_gcry_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 unsigned int
idea_encrypt (void *context, byte *out, const byte *in)
{
IDEA_context *ctx = context;
encrypt_block (ctx, out, in);
return /*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 unsigned int
idea_decrypt (void *context, byte *out, const byte *in)
{
IDEA_context *ctx = context;
decrypt_block (ctx, out, in);
return /*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;
}
gcry_cipher_spec_t _gcry_cipher_spec_idea =
-{
+ {
+ GCRY_CIPHER_IDEA, {0, 0},
"IDEA", NULL, NULL, IDEA_BLOCKSIZE, 128,
sizeof (IDEA_context),
idea_setkey, idea_encrypt, idea_decrypt
-};
+ };
diff --git a/cipher/md.c b/cipher/md.c
index 280c5d5f..c65eb70b 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -1,1446 +1,1446 @@
/* md.c - message digest dispatcher
* Copyright (C) 1998, 1999, 2002, 2003, 2006,
* 2008 Free Software Foundation, Inc.
* Copyright (C) 2013 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "cipher.h"
#include "ath.h"
#include "rmd.h"
/* A dummy extraspec so that we do not need to tests the extraspec
field from the module specification against NULL and instead
directly test the respective fields of extraspecs. */
static md_extra_spec_t dummy_extra_spec;
/* This is the list of the digest implementations included in
libgcrypt. */
static struct digest_table_entry
{
gcry_md_spec_t *digest;
md_extra_spec_t *extraspec;
unsigned int algorithm;
int fips_allowed;
} digest_table[] =
{
#if USE_CRC
/* We allow the CRC algorithms even in FIPS mode because they are
actually no cryptographic primitives. */
{ &_gcry_digest_spec_crc32,
&dummy_extra_spec, GCRY_MD_CRC32, 1 },
{ &_gcry_digest_spec_crc32_rfc1510,
&dummy_extra_spec, GCRY_MD_CRC32_RFC1510, 1 },
{ &_gcry_digest_spec_crc24_rfc2440,
&dummy_extra_spec, GCRY_MD_CRC24_RFC2440, 1 },
#endif
#ifdef USE_GOST_R_3411_94
{ &_gcry_digest_spec_gost3411_94,
&dummy_extra_spec, GCRY_MD_GOSTR3411_94 },
#endif
#ifdef USE_GOST_R_3411_12
{ &_gcry_digest_spec_stribog_256,
&dummy_extra_spec, GCRY_MD_STRIBOG256 },
{ &_gcry_digest_spec_stribog_512,
&dummy_extra_spec, GCRY_MD_STRIBOG512 },
#endif
#if USE_MD4
{ &_gcry_digest_spec_md4,
&dummy_extra_spec, GCRY_MD_MD4 },
#endif
#if USE_MD5
{ &_gcry_digest_spec_md5,
&dummy_extra_spec, GCRY_MD_MD5, 1 },
#endif
#if USE_RMD160
{ &_gcry_digest_spec_rmd160,
&dummy_extra_spec, GCRY_MD_RMD160 },
#endif
#if USE_SHA1
{ &_gcry_digest_spec_sha1,
&_gcry_digest_extraspec_sha1, GCRY_MD_SHA1, 1 },
#endif
#if USE_SHA256
{ &_gcry_digest_spec_sha256,
&_gcry_digest_extraspec_sha256, GCRY_MD_SHA256, 1 },
{ &_gcry_digest_spec_sha224,
&_gcry_digest_extraspec_sha224, GCRY_MD_SHA224, 1 },
#endif
#if USE_SHA512
{ &_gcry_digest_spec_sha512,
&_gcry_digest_extraspec_sha512, GCRY_MD_SHA512, 1 },
{ &_gcry_digest_spec_sha384,
&_gcry_digest_extraspec_sha384, GCRY_MD_SHA384, 1 },
#endif
#if USE_TIGER
{ &_gcry_digest_spec_tiger,
&dummy_extra_spec, GCRY_MD_TIGER },
{ &_gcry_digest_spec_tiger1,
&dummy_extra_spec, GCRY_MD_TIGER1 },
{ &_gcry_digest_spec_tiger2,
&dummy_extra_spec, GCRY_MD_TIGER2 },
#endif
#if USE_WHIRLPOOL
{ &_gcry_digest_spec_whirlpool,
&dummy_extra_spec, GCRY_MD_WHIRLPOOL },
#endif
{ NULL },
};
/* List of registered digests. */
static gcry_module_t digests_registered;
/* This is the lock protecting DIGESTS_REGISTERED. */
static ath_mutex_t digests_registered_lock;
/* Flag to check whether the default ciphers have already been
registered. */
static int default_digests_registered;
typedef struct gcry_md_list
{
gcry_md_spec_t *digest;
gcry_module_t module;
struct gcry_md_list *next;
size_t actual_struct_size; /* Allocated size of this structure. */
PROPERLY_ALIGNED_TYPE context;
} GcryDigestEntry;
/* this structure is put right after the gcry_md_hd_t buffer, so that
* only one memory block is needed. */
struct gcry_md_context
{
int magic;
size_t actual_handle_size; /* Allocated size of this handle. */
int secure;
FILE *debug;
int finalized;
GcryDigestEntry *list;
byte *macpads;
int macpads_Bsize; /* Blocksize as used for the HMAC pads. */
};
#define CTX_MAGIC_NORMAL 0x11071961
#define CTX_MAGIC_SECURE 0x16917011
/* Convenient macro for registering the default digests. */
#define REGISTER_DEFAULT_DIGESTS \
do \
{ \
ath_mutex_lock (&digests_registered_lock); \
if (! default_digests_registered) \
{ \
md_register_default (); \
default_digests_registered = 1; \
} \
ath_mutex_unlock (&digests_registered_lock); \
} \
while (0)
static const char * digest_algo_to_string( int algo );
static gcry_err_code_t check_digest_algo (int algo);
static gcry_err_code_t md_open (gcry_md_hd_t *h, int algo,
int secure, int hmac);
static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo);
static gcry_err_code_t md_copy (gcry_md_hd_t a, gcry_md_hd_t *b);
static void md_close (gcry_md_hd_t a);
static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen);
static void md_final(gcry_md_hd_t a);
static byte *md_read( gcry_md_hd_t a, int algo );
static int md_get_algo( gcry_md_hd_t a );
static int md_digest_length( int algo );
static const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen );
static void md_start_debug ( gcry_md_hd_t a, const char *suffix );
static void md_stop_debug ( gcry_md_hd_t a );
/* Internal function. Register all the ciphers included in
CIPHER_TABLE. Returns zero on success or an error code. */
static void
md_register_default (void)
{
gcry_err_code_t err = 0;
int i;
for (i = 0; !err && digest_table[i].digest; i++)
{
if ( fips_mode ())
{
if (!digest_table[i].fips_allowed)
continue;
if (digest_table[i].algorithm == GCRY_MD_MD5
&& _gcry_enforced_fips_mode () )
continue; /* Do not register in enforced fips mode. */
}
err = _gcry_module_add (&digests_registered,
digest_table[i].algorithm,
(void *) digest_table[i].digest,
(void *) digest_table[i].extraspec,
NULL);
}
if (err)
BUG ();
}
/* Internal callback function. */
static int
gcry_md_lookup_func_name (void *spec, void *data)
{
gcry_md_spec_t *digest = (gcry_md_spec_t *) spec;
char *name = (char *) data;
return (! stricmp (digest->name, name));
}
/* Internal callback function. Used via _gcry_module_lookup. */
static int
gcry_md_lookup_func_oid (void *spec, void *data)
{
gcry_md_spec_t *digest = (gcry_md_spec_t *) spec;
char *oid = (char *) data;
gcry_md_oid_spec_t *oid_specs = digest->oids;
int ret = 0, i;
if (oid_specs)
{
for (i = 0; oid_specs[i].oidstring && (! ret); i++)
if (! stricmp (oid, oid_specs[i].oidstring))
ret = 1;
}
return ret;
}
/* Internal function. Lookup a digest entry by it's name. */
static gcry_module_t
gcry_md_lookup_name (const char *name)
{
gcry_module_t digest;
digest = _gcry_module_lookup (digests_registered, (void *) name,
gcry_md_lookup_func_name);
return digest;
}
/* Internal function. Lookup a cipher entry by it's oid. */
static gcry_module_t
gcry_md_lookup_oid (const char *oid)
{
gcry_module_t digest;
digest = _gcry_module_lookup (digests_registered, (void *) oid,
gcry_md_lookup_func_oid);
return digest;
}
/* Register a new digest module whose specification can be found in
DIGEST. On success, a new algorithm ID is stored in ALGORITHM_ID
and a pointer representhing this module is stored in MODULE. */
gcry_error_t
_gcry_md_register (gcry_md_spec_t *digest,
md_extra_spec_t *extraspec,
unsigned int *algorithm_id,
gcry_module_t *module)
{
gcry_err_code_t err = 0;
gcry_module_t mod;
/* We do not support module loading in fips mode. */
if (fips_mode ())
return gpg_error (GPG_ERR_NOT_SUPPORTED);
ath_mutex_lock (&digests_registered_lock);
err = _gcry_module_add (&digests_registered, 0,
(void *) digest,
(void *)(extraspec? extraspec : &dummy_extra_spec),
&mod);
ath_mutex_unlock (&digests_registered_lock);
if (! err)
{
*module = mod;
*algorithm_id = mod->mod_id;
}
return gcry_error (err);
}
static int
search_oid (const char *oid, int *algorithm, gcry_md_oid_spec_t *oid_spec)
{
gcry_module_t module;
int ret = 0;
if (oid && ((! strncmp (oid, "oid.", 4))
|| (! strncmp (oid, "OID.", 4))))
oid += 4;
module = gcry_md_lookup_oid (oid);
if (module)
{
gcry_md_spec_t *digest = module->spec;
int i;
for (i = 0; digest->oids[i].oidstring && !ret; i++)
if (! stricmp (oid, digest->oids[i].oidstring))
{
if (algorithm)
*algorithm = module->mod_id;
if (oid_spec)
*oid_spec = digest->oids[i];
ret = 1;
}
_gcry_module_release (module);
}
return ret;
}
/****************
* Map a string to the digest algo
*/
int
gcry_md_map_name (const char *string)
{
gcry_module_t digest;
int ret, algorithm = 0;
if (! string)
return 0;
REGISTER_DEFAULT_DIGESTS;
/* If the string starts with a digit (optionally prefixed with
either "OID." or "oid."), we first look into our table of ASN.1
object identifiers to figure out the algorithm */
ath_mutex_lock (&digests_registered_lock);
ret = search_oid (string, &algorithm, NULL);
if (! ret)
{
/* Not found, search a matching digest name. */
digest = gcry_md_lookup_name (string);
if (digest)
{
algorithm = digest->mod_id;
_gcry_module_release (digest);
}
}
ath_mutex_unlock (&digests_registered_lock);
return algorithm;
}
/****************
* Map a digest algo to a string
*/
static const char *
digest_algo_to_string (int algorithm)
{
const char *name = NULL;
gcry_module_t digest;
REGISTER_DEFAULT_DIGESTS;
ath_mutex_lock (&digests_registered_lock);
digest = _gcry_module_lookup_id (digests_registered, algorithm);
if (digest)
{
name = ((gcry_md_spec_t *) digest->spec)->name;
_gcry_module_release (digest);
}
ath_mutex_unlock (&digests_registered_lock);
return name;
}
/****************
* This function simply returns the name of the algorithm or some constant
* string when there is no algo. It will never return NULL.
* Use the macro gcry_md_test_algo() to check whether the algorithm
* is valid.
*/
const char *
gcry_md_algo_name (int algorithm)
{
const char *s = digest_algo_to_string (algorithm);
return s ? s : "?";
}
static gcry_err_code_t
check_digest_algo (int algorithm)
{
gcry_err_code_t rc = 0;
gcry_module_t digest;
REGISTER_DEFAULT_DIGESTS;
ath_mutex_lock (&digests_registered_lock);
digest = _gcry_module_lookup_id (digests_registered, algorithm);
if (digest)
_gcry_module_release (digest);
else
rc = GPG_ERR_DIGEST_ALGO;
ath_mutex_unlock (&digests_registered_lock);
return rc;
}
/****************
* Open a message digest handle for use with algorithm ALGO.
* More algorithms may be added by md_enable(). The initial algorithm
* may be 0.
*/
static gcry_err_code_t
md_open (gcry_md_hd_t *h, int algo, int secure, int hmac)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
int bufsize = secure ? 512 : 1024;
struct gcry_md_context *ctx;
gcry_md_hd_t hd;
size_t n;
/* Allocate a memory area to hold the caller visible buffer with it's
* control information and the data required by this module. Set the
* context pointer at the beginning to this area.
* We have to use this strange scheme because we want to hide the
* internal data but have a variable sized buffer.
*
* +---+------+---........------+-------------+
* !ctx! bctl ! buffer ! private !
* +---+------+---........------+-------------+
* ! ^
* !---------------------------!
*
* We have to make sure that private is well aligned.
*/
n = sizeof (struct gcry_md_handle) + bufsize;
n = ((n + sizeof (PROPERLY_ALIGNED_TYPE) - 1)
/ sizeof (PROPERLY_ALIGNED_TYPE)) * sizeof (PROPERLY_ALIGNED_TYPE);
/* Allocate and set the Context pointer to the private data */
if (secure)
hd = gcry_malloc_secure (n + sizeof (struct gcry_md_context));
else
hd = gcry_malloc (n + sizeof (struct gcry_md_context));
if (! hd)
err = gpg_err_code_from_errno (errno);
if (! err)
{
hd->ctx = ctx = (struct gcry_md_context *) ((char *) hd + n);
/* Setup the globally visible data (bctl in the diagram).*/
hd->bufsize = n - sizeof (struct gcry_md_handle) + 1;
hd->bufpos = 0;
/* Initialize the private data. */
memset (hd->ctx, 0, sizeof *hd->ctx);
ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL;
ctx->actual_handle_size = n + sizeof (struct gcry_md_context);
ctx->secure = secure;
if (hmac)
{
switch (algo)
{
case GCRY_MD_SHA384:
case GCRY_MD_SHA512:
ctx->macpads_Bsize = 128;
break;
default:
ctx->macpads_Bsize = 64;
break;
}
ctx->macpads = gcry_malloc_secure (2*(ctx->macpads_Bsize));
if (!ctx->macpads)
{
err = gpg_err_code_from_errno (errno);
md_close (hd);
}
}
}
if (! err)
{
/* Hmmm, should we really do that? - yes [-wk] */
_gcry_fast_random_poll ();
if (algo)
{
err = md_enable (hd, algo);
if (err)
md_close (hd);
}
}
if (! err)
*h = hd;
return err;
}
/* Create a message digest object for algorithm ALGO. FLAGS may be
given as an bitwise OR of the gcry_md_flags values. ALGO may be
given as 0 if the algorithms to be used are later set using
gcry_md_enable. H is guaranteed to be a valid handle or NULL on
error. */
gcry_error_t
gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_md_hd_t hd;
if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)))
err = GPG_ERR_INV_ARG;
else
{
err = md_open (&hd, algo, (flags & GCRY_MD_FLAG_SECURE),
(flags & GCRY_MD_FLAG_HMAC));
}
*h = err? NULL : hd;
return gcry_error (err);
}
static gcry_err_code_t
md_enable (gcry_md_hd_t hd, int algorithm)
{
struct gcry_md_context *h = hd->ctx;
gcry_md_spec_t *digest = NULL;
GcryDigestEntry *entry;
gcry_module_t module;
gcry_err_code_t err = 0;
for (entry = h->list; entry; entry = entry->next)
if (entry->module->mod_id == algorithm)
return err; /* already enabled */
REGISTER_DEFAULT_DIGESTS;
ath_mutex_lock (&digests_registered_lock);
module = _gcry_module_lookup_id (digests_registered, algorithm);
ath_mutex_unlock (&digests_registered_lock);
if (! module)
{
log_debug ("md_enable: algorithm %d not available\n", algorithm);
err = GPG_ERR_DIGEST_ALGO;
}
else
digest = (gcry_md_spec_t *) module->spec;
if (!err && algorithm == GCRY_MD_MD5 && fips_mode ())
{
_gcry_inactivate_fips_mode ("MD5 used");
if (_gcry_enforced_fips_mode () )
{
/* We should never get to here because we do not register
MD5 in enforced fips mode. But better throw an error. */
err = GPG_ERR_DIGEST_ALGO;
}
}
if (!err)
{
size_t size = (sizeof (*entry)
+ digest->contextsize
- sizeof (entry->context));
/* And allocate a new list entry. */
if (h->secure)
entry = gcry_malloc_secure (size);
else
entry = gcry_malloc (size);
if (! entry)
err = gpg_err_code_from_errno (errno);
else
{
entry->digest = digest;
entry->module = module;
entry->next = h->list;
entry->actual_struct_size = size;
h->list = entry;
/* And init this instance. */
entry->digest->init (&entry->context.c);
}
}
if (err)
{
if (module)
{
ath_mutex_lock (&digests_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&digests_registered_lock);
}
}
return err;
}
gcry_error_t
gcry_md_enable (gcry_md_hd_t hd, int algorithm)
{
return gcry_error (md_enable (hd, algorithm));
}
static gcry_err_code_t
md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
struct gcry_md_context *a = ahd->ctx;
struct gcry_md_context *b;
GcryDigestEntry *ar, *br;
gcry_md_hd_t bhd;
size_t n;
if (ahd->bufpos)
md_write (ahd, NULL, 0);
n = (char *) ahd->ctx - (char *) ahd;
if (a->secure)
bhd = gcry_malloc_secure (n + sizeof (struct gcry_md_context));
else
bhd = gcry_malloc (n + sizeof (struct gcry_md_context));
if (! bhd)
err = gpg_err_code_from_errno (errno);
if (! err)
{
bhd->ctx = b = (struct gcry_md_context *) ((char *) bhd + n);
/* No need to copy the buffer due to the write above. */
gcry_assert (ahd->bufsize == (n - sizeof (struct gcry_md_handle) + 1));
bhd->bufsize = ahd->bufsize;
bhd->bufpos = 0;
gcry_assert (! ahd->bufpos);
memcpy (b, a, sizeof *a);
b->list = NULL;
b->debug = NULL;
if (a->macpads)
{
b->macpads = gcry_malloc_secure (2*(a->macpads_Bsize));
if (! b->macpads)
{
err = gpg_err_code_from_errno (errno);
md_close (bhd);
}
else
memcpy (b->macpads, a->macpads, (2*(a->macpads_Bsize)));
}
}
/* Copy the complete list of algorithms. The copied list is
reversed, but that doesn't matter. */
if (!err)
{
for (ar = a->list; ar; ar = ar->next)
{
if (a->secure)
br = gcry_malloc_secure (sizeof *br
+ ar->digest->contextsize
- sizeof(ar->context));
else
br = gcry_malloc (sizeof *br
+ ar->digest->contextsize
- sizeof (ar->context));
if (!br)
{
err = gpg_err_code_from_errno (errno);
md_close (bhd);
break;
}
memcpy (br, ar, (sizeof (*br) + ar->digest->contextsize
- sizeof (ar->context)));
br->next = b->list;
b->list = br;
/* Add a reference to the module. */
ath_mutex_lock (&digests_registered_lock);
_gcry_module_use (br->module);
ath_mutex_unlock (&digests_registered_lock);
}
}
if (a->debug && !err)
md_start_debug (bhd, "unknown");
if (!err)
*b_hd = bhd;
return err;
}
gcry_error_t
gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd)
{
gcry_err_code_t err;
err = md_copy (hd, handle);
if (err)
*handle = NULL;
return gcry_error (err);
}
/*
* Reset all contexts and discard any buffered stuff. This may be used
* instead of a md_close(); md_open().
*/
void
gcry_md_reset (gcry_md_hd_t a)
{
GcryDigestEntry *r;
/* Note: We allow this even in fips non operational mode. */
a->bufpos = a->ctx->finalized = 0;
for (r = a->ctx->list; r; r = r->next)
{
memset (r->context.c, 0, r->digest->contextsize);
(*r->digest->init) (&r->context.c);
}
if (a->ctx->macpads)
md_write (a, a->ctx->macpads, a->ctx->macpads_Bsize); /* inner pad */
}
static void
md_close (gcry_md_hd_t a)
{
GcryDigestEntry *r, *r2;
if (! a)
return;
if (a->ctx->debug)
md_stop_debug (a);
for (r = a->ctx->list; r; r = r2)
{
r2 = r->next;
ath_mutex_lock (&digests_registered_lock);
_gcry_module_release (r->module);
ath_mutex_unlock (&digests_registered_lock);
wipememory (r, r->actual_struct_size);
gcry_free (r);
}
if (a->ctx->macpads)
{
wipememory (a->ctx->macpads, 2*(a->ctx->macpads_Bsize));
gcry_free(a->ctx->macpads);
}
wipememory (a, a->ctx->actual_handle_size);
gcry_free(a);
}
void
gcry_md_close (gcry_md_hd_t hd)
{
/* Note: We allow this even in fips non operational mode. */
md_close (hd);
}
static void
md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen)
{
GcryDigestEntry *r;
if (a->ctx->debug)
{
if (a->bufpos && fwrite (a->buf, a->bufpos, 1, a->ctx->debug) != 1)
BUG();
if (inlen && fwrite (inbuf, inlen, 1, a->ctx->debug) != 1)
BUG();
}
for (r = a->ctx->list; r; r = r->next)
{
if (a->bufpos)
(*r->digest->write) (&r->context.c, a->buf, a->bufpos);
(*r->digest->write) (&r->context.c, inbuf, inlen);
}
a->bufpos = 0;
}
void
gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen)
{
md_write (hd, inbuf, inlen);
}
static void
md_final (gcry_md_hd_t a)
{
GcryDigestEntry *r;
if (a->ctx->finalized)
return;
if (a->bufpos)
md_write (a, NULL, 0);
for (r = a->ctx->list; r; r = r->next)
(*r->digest->final) (&r->context.c);
a->ctx->finalized = 1;
if (a->ctx->macpads)
{
/* Finish the hmac. */
int algo = md_get_algo (a);
byte *p = md_read (a, algo);
size_t dlen = md_digest_length (algo);
gcry_md_hd_t om;
gcry_err_code_t err = md_open (&om, algo, a->ctx->secure, 0);
if (err)
_gcry_fatal_error (err, NULL);
md_write (om,
(a->ctx->macpads)+(a->ctx->macpads_Bsize),
a->ctx->macpads_Bsize);
md_write (om, p, dlen);
md_final (om);
/* Replace our digest with the mac (they have the same size). */
memcpy (p, md_read (om, algo), dlen);
md_close (om);
}
}
static gcry_err_code_t
prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen)
{
int i;
int algo = md_get_algo (hd);
unsigned char *helpkey = NULL;
unsigned char *ipad, *opad;
if (!algo)
return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */
if ( keylen > hd->ctx->macpads_Bsize )
{
helpkey = gcry_malloc_secure (md_digest_length (algo));
if (!helpkey)
return gpg_err_code_from_errno (errno);
gcry_md_hash_buffer (algo, helpkey, key, keylen);
key = helpkey;
keylen = md_digest_length (algo);
gcry_assert ( keylen <= hd->ctx->macpads_Bsize );
}
memset ( hd->ctx->macpads, 0, 2*(hd->ctx->macpads_Bsize) );
ipad = hd->ctx->macpads;
opad = (hd->ctx->macpads)+(hd->ctx->macpads_Bsize);
memcpy ( ipad, key, keylen );
memcpy ( opad, key, keylen );
for (i=0; i < hd->ctx->macpads_Bsize; i++ )
{
ipad[i] ^= 0x36;
opad[i] ^= 0x5c;
}
gcry_free (helpkey);
return GPG_ERR_NO_ERROR;
}
gcry_error_t
gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen)
{
gcry_err_code_t rc = 0;
switch (cmd)
{
case GCRYCTL_FINALIZE:
md_final (hd);
break;
case GCRYCTL_SET_KEY:
rc = gcry_err_code (gcry_md_setkey (hd, buffer, buflen));
break;
case GCRYCTL_START_DUMP:
md_start_debug (hd, buffer);
break;
case GCRYCTL_STOP_DUMP:
md_stop_debug ( hd );
break;
default:
rc = GPG_ERR_INV_OP;
}
return gcry_error (rc);
}
gcry_error_t
gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
{
gcry_err_code_t rc = GPG_ERR_NO_ERROR;
if (!hd->ctx->macpads)
rc = GPG_ERR_CONFLICT;
else
{
rc = prepare_macpads (hd, key, keylen);
if (! rc)
gcry_md_reset (hd);
}
return gcry_error (rc);
}
/* The new debug interface. If SUFFIX is a string it creates an debug
file for the context HD. IF suffix is NULL, the file is closed and
debugging is stopped. */
void
gcry_md_debug (gcry_md_hd_t hd, const char *suffix)
{
if (suffix)
md_start_debug (hd, suffix);
else
md_stop_debug (hd);
}
/****************
* if ALGO is null get the digest for the used algo (which should be only one)
*/
static byte *
md_read( gcry_md_hd_t a, int algo )
{
GcryDigestEntry *r = a->ctx->list;
if (! algo)
{
/* Return the first algorithm */
if (r)
{
if (r->next)
log_debug ("more than one algorithm in md_read(0)\n");
return r->digest->read (&r->context.c);
}
}
else
{
for (r = a->ctx->list; r; r = r->next)
if (r->module->mod_id == algo)
return r->digest->read (&r->context.c);
}
BUG();
return NULL;
}
/*
* Read out the complete digest, this function implictly finalizes
* the hash.
*/
byte *
gcry_md_read (gcry_md_hd_t hd, int algo)
{
/* This function is expected to always return a digest, thus we
can't return an error which we actually should do in
non-operational state. */
gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
return md_read (hd, algo);
}
/*
* Read out an intermediate digest. Not yet functional.
*/
gcry_err_code_t
gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen)
{
(void)hd;
(void)algo;
(void)buffer;
(void)buflen;
/*md_digest ... */
fips_signal_error ("unimplemented function called");
return GPG_ERR_INTERNAL;
}
/*
* Shortcut function to hash a buffer with a given algo. The only
* guaranteed supported algorithms are RIPE-MD160 and SHA-1. The
* supplied digest buffer must be large enough to store the resulting
* hash. No error is returned, the function will abort on an invalid
* algo. DISABLED_ALGOS are ignored here. */
void
gcry_md_hash_buffer (int algo, void *digest,
const void *buffer, size_t length)
{
if (algo == GCRY_MD_SHA1)
_gcry_sha1_hash_buffer (digest, buffer, length);
else if (algo == GCRY_MD_RMD160 && !fips_mode () )
_gcry_rmd160_hash_buffer (digest, buffer, length);
else
{
/* For the others we do not have a fast function, so we use the
normal functions. */
gcry_md_hd_t h;
gpg_err_code_t err;
if (algo == GCRY_MD_MD5 && fips_mode ())
{
_gcry_inactivate_fips_mode ("MD5 used");
if (_gcry_enforced_fips_mode () )
{
/* We should never get to here because we do not register
MD5 in enforced fips mode. */
_gcry_fips_noreturn ();
}
}
err = md_open (&h, algo, 0, 0);
if (err)
log_bug ("gcry_md_open failed for algo %d: %s",
algo, gpg_strerror (gcry_error(err)));
md_write (h, (byte *) buffer, length);
md_final (h);
memcpy (digest, md_read (h, algo), md_digest_length (algo));
md_close (h);
}
}
/* Shortcut function to hash multiple buffers with a given algo. In
contrast to gcry_md_hash_buffer, this function returns an error on
invalid arguments or on other problems; disabled algorithms are
_not_ ignored but flagged as an error.
The data to sign is taken from the array IOV which has IOVCNT items.
The only supported flag in FLAGS is GCRY_MD_FLAG_HMAC which turns
this function into a HMAC function; the first item in IOV is then
used as the key.
On success 0 is returned and resulting hash or HMAC is stored at
DIGEST which must have been provided by the caller with an
appropriate length. */
gpg_err_code_t
gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
const gcry_buffer_t *iov, int iovcnt)
{
int hmac;
if (!iov || iovcnt < 0)
return GPG_ERR_INV_ARG;
if (flags & ~(GCRY_MD_FLAG_HMAC))
return GPG_ERR_INV_ARG;
hmac = !!(flags & GCRY_MD_FLAG_HMAC);
if (hmac && iovcnt < 1)
return GPG_ERR_INV_ARG;
if (algo == GCRY_MD_SHA1 && !hmac)
_gcry_sha1_hash_buffers (digest, iov, iovcnt);
else
{
/* For the others we do not have a fast function, so we use the
normal functions. */
gcry_md_hd_t h;
gpg_err_code_t rc;
if (algo == GCRY_MD_MD5 && fips_mode ())
{
_gcry_inactivate_fips_mode ("MD5 used");
if (_gcry_enforced_fips_mode () )
{
/* We should never get to here because we do not register
MD5 in enforced fips mode. */
_gcry_fips_noreturn ();
}
}
rc = md_open (&h, algo, 0, hmac);
if (rc)
return rc;
if (hmac)
{
rc = gcry_err_code
(gcry_md_setkey (h, (const char*)iov[0].data + iov[0].off,
iov[0].len));
if (rc)
{
md_close (h);
return rc;
}
iov++; iovcnt--;
}
for (;iovcnt; iov++, iovcnt--)
md_write (h, (const char*)iov[0].data + iov[0].off, iov[0].len);
md_final (h);
memcpy (digest, md_read (h, algo), md_digest_length (algo));
md_close (h);
}
return 0;
}
static int
md_get_algo (gcry_md_hd_t a)
{
GcryDigestEntry *r = a->ctx->list;
if (r && r->next)
{
fips_signal_error ("possible usage error");
log_error ("WARNING: more than one algorithm in md_get_algo()\n");
}
return r ? r->module->mod_id : 0;
}
int
gcry_md_get_algo (gcry_md_hd_t hd)
{
return md_get_algo (hd);
}
/****************
* Return the length of the digest
*/
static int
md_digest_length (int algorithm)
{
gcry_module_t digest;
int mdlen = 0;
REGISTER_DEFAULT_DIGESTS;
ath_mutex_lock (&digests_registered_lock);
digest = _gcry_module_lookup_id (digests_registered, algorithm);
if (digest)
{
mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen;
_gcry_module_release (digest);
}
ath_mutex_unlock (&digests_registered_lock);
return mdlen;
}
/****************
* Return the length of the digest in bytes.
* This function will return 0 in case of errors.
*/
unsigned int
gcry_md_get_algo_dlen (int algorithm)
{
return md_digest_length (algorithm);
}
/* Hmmm: add a mode to enumerate the OIDs
* to make g10/sig-check.c more portable */
static const byte *
md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen)
{
const byte *asnoid = NULL;
gcry_module_t digest;
REGISTER_DEFAULT_DIGESTS;
ath_mutex_lock (&digests_registered_lock);
digest = _gcry_module_lookup_id (digests_registered, algorithm);
if (digest)
{
if (asnlen)
*asnlen = ((gcry_md_spec_t *) digest->spec)->asnlen;
if (mdlen)
*mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen;
asnoid = ((gcry_md_spec_t *) digest->spec)->asnoid;
_gcry_module_release (digest);
}
else
log_bug ("no ASN.1 OID for md algo %d\n", algorithm);
ath_mutex_unlock (&digests_registered_lock);
return asnoid;
}
/****************
* Return information about the given cipher algorithm
* WHAT select the kind of information returned:
* GCRYCTL_TEST_ALGO:
* Returns 0 when the specified algorithm is available for use.
* buffer and nbytes must be zero.
* GCRYCTL_GET_ASNOID:
* Return the ASNOID of the algorithm in buffer. if buffer is NULL, only
* the required length is returned.
*
* Note: Because this function is in most cases 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 occurred or not (i.e. while checking
* the block size)
*/
gcry_error_t
gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
switch (what)
{
case GCRYCTL_TEST_ALGO:
if (buffer || nbytes)
err = GPG_ERR_INV_ARG;
else
err = check_digest_algo (algo);
break;
case GCRYCTL_GET_ASNOID:
/* We need to check that the algo is available because
md_asn_oid would otherwise raise an assertion. */
err = check_digest_algo (algo);
if (!err)
{
const char unsigned *asn;
size_t asnlen;
asn = md_asn_oid (algo, &asnlen, NULL);
if (buffer && (*nbytes >= asnlen))
{
memcpy (buffer, asn, asnlen);
*nbytes = asnlen;
}
else if (!buffer && nbytes)
*nbytes = asnlen;
else
{
if (buffer)
err = GPG_ERR_TOO_SHORT;
else
err = GPG_ERR_INV_ARG;
}
}
break;
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
static void
md_start_debug ( gcry_md_hd_t md, const char *suffix )
{
static int idx=0;
char buf[50];
if (fips_mode ())
return;
if ( md->ctx->debug )
{
log_debug("Oops: md debug already started\n");
return;
}
idx++;
snprintf (buf, DIM(buf)-1, "dbgmd-%05d.%.10s", idx, suffix );
md->ctx->debug = fopen(buf, "w");
if ( !md->ctx->debug )
log_debug("md debug: can't open %s\n", buf );
}
static void
md_stop_debug( gcry_md_hd_t md )
{
if ( md->ctx->debug )
{
if ( md->bufpos )
md_write ( md, NULL, 0 );
fclose (md->ctx->debug);
md->ctx->debug = NULL;
}
#ifdef HAVE_U64_TYPEDEF
{ /* a kludge to pull in the __muldi3 for Solaris */
volatile u32 a = (u32)(ulong)md;
volatile u64 b = 42;
volatile u64 c;
c = a * b;
(void)c;
}
#endif
}
/*
* Return information about the digest handle.
* GCRYCTL_IS_SECURE:
* Returns 1 when the handle works on secured memory
* otherwise 0 is returned. There is no error return.
* GCRYCTL_IS_ALGO_ENABLED:
* Returns 1 if the algo is enabled for that handle.
* The algo must be passed as the address of an int.
*/
gcry_error_t
gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
switch (cmd)
{
case GCRYCTL_IS_SECURE:
*nbytes = h->ctx->secure;
break;
case GCRYCTL_IS_ALGO_ENABLED:
{
GcryDigestEntry *r;
int algo;
if ( !buffer || (nbytes && (*nbytes != sizeof (int))))
err = GPG_ERR_INV_ARG;
else
{
algo = *(int*)buffer;
*nbytes = 0;
for(r=h->ctx->list; r; r = r->next ) {
if (r->module->mod_id == algo)
{
*nbytes = 1;
break;
}
}
}
break;
}
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
/* Explicitly initialize this module. */
gcry_err_code_t
_gcry_md_init (void)
{
gcry_err_code_t err;
err = ath_mutex_init (&digests_registered_lock);
if (err)
return gpg_err_code_from_errno (err);
REGISTER_DEFAULT_DIGESTS;
return err;
}
int
gcry_md_is_secure (gcry_md_hd_t a)
{
size_t value;
if (gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &value))
value = 1; /* It seems to be better to assume secure memory on
error. */
return value;
}
int
gcry_md_is_enabled (gcry_md_hd_t a, int algo)
{
size_t value;
value = sizeof algo;
if (gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value))
value = 0;
return value;
}
/* Run the selftests for digest algorithm ALGO with optional reporting
function REPORT. */
gpg_error_t
_gcry_md_selftest (int algo, int extended, selftest_report_func_t report)
{
gcry_module_t module = NULL;
- cipher_extra_spec_t *extraspec = NULL;
+ md_extra_spec_t *extraspec = NULL;
gcry_err_code_t ec = 0;
REGISTER_DEFAULT_DIGESTS;
ath_mutex_lock (&digests_registered_lock);
module = _gcry_module_lookup_id (digests_registered, algo);
if (module && !(module->flags & FLAG_MODULE_DISABLED))
extraspec = module->extraspec;
ath_mutex_unlock (&digests_registered_lock);
if (extraspec && extraspec->selftest)
ec = extraspec->selftest (algo, extended, report);
else
{
ec = GPG_ERR_DIGEST_ALGO;
if (report)
report ("digest", algo, "module",
module && !(module->flags & FLAG_MODULE_DISABLED)?
"no selftest available" :
module? "algorithm disabled" : "algorithm not found");
}
if (module)
{
ath_mutex_lock (&digests_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&digests_registered_lock);
}
return gpg_error (ec);
}
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 4738c29b..16284674 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1,2375 +1,2375 @@
/* pubkey.c - pubkey dispatcher
* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005,
* 2007, 2008, 2011 Free Software Foundation, Inc.
* Copyright (C) 2013 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "ath.h"
#include "context.h"
#include "pubkey-internal.h"
/* This is the list of the public-key algorithms included in
Libgcrypt. */
static gcry_pk_spec_t *pubkey_list[] =
{
#if USE_ECC
&_gcry_pubkey_spec_ecc,
#endif
#if USE_RSA
&_gcry_pubkey_spec_rsa,
#endif
#if USE_DSA
&_gcry_pubkey_spec_dsa,
#endif
#if USE_ELGAMAL
&_gcry_pubkey_spec_elg,
&_gcry_pubkey_spec_elg,
#endif
NULL
};
static int
map_algo (int algo)
{
switch (algo)
{
case GCRY_PK_ECDSA:
case GCRY_PK_ECDH:
return GCRY_PK_ECC;
default:
return algo;
}
}
/* Return the spec structure for the public key algorithm ALGO. For
an unknown algorithm NULL is returned. */
static gcry_pk_spec_t *
spec_from_algo (int algo)
{
int idx;
gcry_pk_spec_t *spec;
algo = map_algo (algo);
for (idx = 0; (spec = pubkey_list[idx]); idx++)
if (algo == spec->algo)
return spec;
return NULL;
}
/* Return the spec structure for the public key algorithm with NAME.
For an unknown name NULL is returned. */
static gcry_pk_spec_t *
spec_from_name (const char *name)
{
gcry_pk_spec_t *spec;
int idx;
const char **aliases;
for (idx=0; (spec = pubkey_list[idx]); idx++)
{
if (!stricmp (name, spec->name))
return spec;
for (aliases = spec->aliases; *aliases; aliases++)
if (!stricmp (name, *aliases))
return spec;
}
return NULL;
}
/* Disable the use of the algorithm ALGO. This is not thread safe and
should thus be called early. */
static void
disable_pubkey_algo (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
if (spec)
spec->flags.disabled = 1;
}
/* Free the MPIs stored in the NULL terminated ARRAY of MPIs and set
the slots to NULL. */
static void
release_mpi_array (gcry_mpi_t *array)
{
for (; *array; array++)
{
mpi_free(*array);
*array = NULL;
}
}
/*
* Map a string to the pubkey algo
*/
int
gcry_pk_map_name (const char *string)
{
gcry_pk_spec_t *spec;
if (!string)
return 0;
spec = spec_from_name (string);
if (!spec)
return 0;
if (spec->flags.disabled)
return 0;
return spec->algo;
}
/* Map the public key algorithm whose ID is contained in ALGORITHM to
a string representation of the algorithm name. For unknown
algorithm IDs this functions returns "?". */
const char *
gcry_pk_algo_name (int algo)
{
gcry_pk_spec_t *spec;
spec = spec_from_algo (algo);
if (spec)
return spec->name;
return "?";
}
/****************
* A USE of 0 means: don't care.
*/
static gcry_err_code_t
check_pubkey_algo (int algo, unsigned use)
{
gcry_err_code_t err = 0;
gcry_pk_spec_t *spec;
spec = spec_from_algo (algo);
if (spec)
{
if (((use & GCRY_PK_USAGE_SIGN)
&& (! (spec->use & GCRY_PK_USAGE_SIGN)))
|| ((use & GCRY_PK_USAGE_ENCR)
&& (! (spec->use & GCRY_PK_USAGE_ENCR))))
err = GPG_ERR_WRONG_PUBKEY_ALGO;
}
else
err = GPG_ERR_PUBKEY_ALGO;
return err;
}
/****************
* Return the number of public key material numbers
*/
static int
pubkey_get_npkey (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
return spec? strlen (spec->elements_pkey) : 0;
}
/****************
* Return the number of secret key material numbers
*/
static int
pubkey_get_nskey (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
return spec? strlen (spec->elements_skey) : 0;
}
/****************
* Return the number of signature material numbers
*/
static int
pubkey_get_nsig (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
return spec? strlen (spec->elements_sig) : 0;
}
/****************
* Return the number of encryption material numbers
*/
static int
pubkey_get_nenc (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
return spec? strlen (spec->elements_enc) : 0;
}
static gcry_err_code_t
pubkey_check_secret_key (int algo, gcry_mpi_t *skey)
{
gcry_err_code_t rc;
gcry_pk_spec_t *spec = spec_from_algo (algo);
if (spec && spec->check_secret_key)
rc = spec->check_secret_key (algo, skey);
else if (spec)
rc = GPG_ERR_NOT_IMPLEMENTED;
else
rc = GPG_ERR_PUBKEY_ALGO;
return rc;
}
/* Internal function. */
static gcry_err_code_t
sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
gcry_mpi_t *elements, const char *algo_name, int opaque)
{
gcry_err_code_t err = 0;
int i, idx;
const char *name;
gcry_sexp_t list;
for (name = element_names, idx = 0; *name && !err; name++, idx++)
{
list = gcry_sexp_find_token (key_sexp, name, 1);
if (!list)
elements[idx] = NULL;
else if (opaque)
{
elements[idx] = _gcry_sexp_nth_opaque_mpi (list, 1);
gcry_sexp_release (list);
if (!elements[idx])
err = GPG_ERR_INV_OBJ;
}
else
{
elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (list);
if (!elements[idx])
err = GPG_ERR_INV_OBJ;
}
}
if (!err)
{
/* Check that all elements are available. */
for (name = element_names, i = 0; *name; name++, i++)
if (!elements[i])
break;
if (*name)
{
err = GPG_ERR_NO_OBJ;
/* Some are missing. Before bailing out we test for
optional parameters. */
if (algo_name && !strcmp (algo_name, "RSA")
&& !strcmp (element_names, "nedpqu") )
{
/* This is RSA. Test whether we got N, E and D and that
the optional P, Q and U are all missing. */
if (elements[0] && elements[1] && elements[2]
&& !elements[3] && !elements[4] && !elements[5])
err = 0;
}
}
}
if (err)
{
for (i = 0; i < idx; i++)
if (elements[i])
mpi_free (elements[i]);
}
return err;
}
/* Internal function used for ecc. Note, that this function makes use
of its intimate knowledge about the ECC parameters from ecc.c. */
static gcry_err_code_t
sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
gcry_mpi_t *elements, gcry_pk_spec_t *spec,
int want_private)
{
gcry_err_code_t err = 0;
int idx;
const char *name;
gcry_sexp_t list;
/* Clear the array for easier error cleanup. */
for (name = element_names, idx = 0; *name; name++, idx++)
elements[idx] = NULL;
gcry_assert (idx >= 5); /* We know that ECC has at least 5 elements
(params only) or 6 (full public key). */
if (idx == 5)
elements[5] = NULL; /* Extra clear for the params only case. */
/* Init the array with the available curve parameters. */
for (name = element_names, idx = 0; *name && !err; name++, idx++)
{
list = gcry_sexp_find_token (key_sexp, name, 1);
if (!list)
elements[idx] = NULL;
else
{
switch (idx)
{
case 5: /* The public and */
case 6: /* the secret key must to be passed opaque. */
elements[idx] = _gcry_sexp_nth_opaque_mpi (list, 1);
break;
default:
elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_STD);
break;
}
gcry_sexp_release (list);
if (!elements[idx])
{
err = GPG_ERR_INV_OBJ;
goto leave;
}
}
}
/* Check whether a curve parameter has been given and then fill any
missing elements. */
list = gcry_sexp_find_token (key_sexp, "curve", 5);
if (list)
{
if (spec->get_param)
{
char *curve;
gcry_mpi_t params[6];
for (idx = 0; idx < DIM(params); idx++)
params[idx] = NULL;
curve = _gcry_sexp_nth_string (list, 1);
gcry_sexp_release (list);
if (!curve)
{
/* No curve name given (or out of core). */
err = GPG_ERR_INV_OBJ;
goto leave;
}
err = spec->get_param (curve, params);
gcry_free (curve);
if (err)
goto leave;
for (idx = 0; idx < DIM(params); idx++)
{
if (!elements[idx])
elements[idx] = params[idx];
else
mpi_free (params[idx]);
}
}
else
{
gcry_sexp_release (list);
err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */
goto leave;
}
}
/* Check that all parameters are known. */
for (name = element_names, idx = 0; *name; name++, idx++)
if (!elements[idx])
{
if (want_private && *name == 'q')
; /* Q is optional. */
else
{
err = GPG_ERR_NO_OBJ;
goto leave;
}
}
leave:
if (err)
{
for (name = element_names, idx = 0; *name; name++, idx++)
if (elements[idx])
mpi_free (elements[idx]);
}
return err;
}
/****************
* Convert a S-Exp with either a private or a public key to our
* internal format. Currently we do only support the following
* algorithms:
* dsa
* rsa
* openpgp-dsa
* openpgp-rsa
* openpgp-elg
* openpgp-elg-sig
* ecdsa
* ecdh
* Provide a SE with the first element be either "private-key" or
* or "public-key". It is followed by a list with its first element
* be one of the above algorithm identifiers and the remaning
* elements are pairs with parameter-id and value.
* NOTE: we look through the list to find a list beginning with
* "private-key" or "public-key" - the first one found is used.
*
* If OVERRIDE_ELEMS is not NULL those elems override the parameter
* specification taken from the module. This ise used by
* gcry_pk_get_curve.
*
* Returns: A pointer to an allocated array of MPIs if the return value is
* zero; the caller has to release this array.
*
* Example of a DSA public key:
* (private-key
* (dsa
* (p <mpi>)
* (g <mpi>)
* (y <mpi>)
* (x <mpi>)
* )
* )
* The <mpi> are expected to be in GCRYMPI_FMT_USG
*/
static gcry_err_code_t
sexp_to_key (gcry_sexp_t sexp, int want_private, int use,
const char *override_elems,
gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec, int *r_is_ecc)
{
gcry_err_code_t err = 0;
gcry_sexp_t list, l2;
char *name;
const char *elems;
gcry_mpi_t *array;
gcry_pk_spec_t *spec;
int is_ecc;
/* Check that the first element is valid. If we are looking for a
public key but a private key was supplied, we allow the use of
the private key anyway. The rationale for this is that the
private key is a superset of the public key. */
list = gcry_sexp_find_token (sexp,
want_private? "private-key":"public-key", 0);
if (!list && !want_private)
list = gcry_sexp_find_token (sexp, "private-key", 0);
if (!list)
return GPG_ERR_INV_OBJ; /* Does not contain a key object. */
l2 = gcry_sexp_cadr( list );
gcry_sexp_release ( list );
list = l2;
name = _gcry_sexp_nth_string (list, 0);
if (!name)
{
gcry_sexp_release ( list );
return GPG_ERR_INV_OBJ; /* Invalid structure of object. */
}
/* Fixme: We should make sure that an ECC key is always named "ecc"
and not "ecdsa". "ecdsa" should be used for the signature
itself. We need a function to test whether an algorithm given
with a key is compatible with an application of the key (signing,
encryption). For RSA this is easy, but ECC is the first
algorithm which has many flavours.
We use an ugly hack here to decide whether to use ecdsa or ecdh.
*/
if (!strcmp (name, "ecc"))
is_ecc = 2;
else if (!strcmp (name, "ecdsa") || !strcmp (name, "ecdh"))
is_ecc = 1;
else
is_ecc = 0;
if (is_ecc == 2 && (use & GCRY_PK_USAGE_SIGN))
spec = spec_from_name ("ecdsa");
else if (is_ecc == 2 && (use & GCRY_PK_USAGE_ENCR))
spec = spec_from_name ("ecdh");
else
spec = spec_from_name (name);
gcry_free (name);
if (!spec)
{
gcry_sexp_release (list);
return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
}
if (override_elems)
elems = override_elems;
else if (want_private)
elems = spec->elements_skey;
else
elems = spec->elements_pkey;
array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
if (!array)
err = gpg_err_code_from_syserror ();
if (!err)
{
if (is_ecc)
err = sexp_elements_extract_ecc (list, elems, array, spec,
want_private);
else
err = sexp_elements_extract (list, elems, array, spec->name, 0);
}
gcry_sexp_release (list);
if (err)
{
gcry_free (array);
}
else
{
*retarray = array;
*r_spec = spec;
if (r_is_ecc)
*r_is_ecc = is_ecc;
}
return err;
}
/* Parse SEXP and store the elements into a newly allocated array of
MPIs which will be stored at RETARRAY. If OPAQUE is set, store the
MPI as opaque data. */
static gcry_err_code_t
sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray,
gcry_pk_spec_t **r_spec, int opaque)
{
gcry_err_code_t err = 0;
gcry_sexp_t list, l2;
char *name;
const char *elems;
gcry_mpi_t *array;
gcry_pk_spec_t *spec;
/* Check that the first element is valid. */
list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
if (!list)
return GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */
l2 = gcry_sexp_nth (list, 1);
if (!l2)
{
gcry_sexp_release (list);
return GPG_ERR_NO_OBJ; /* No cadr for the sig object. */
}
name = _gcry_sexp_nth_string (l2, 0);
if (!name)
{
gcry_sexp_release (list);
gcry_sexp_release (l2);
return GPG_ERR_INV_OBJ; /* Invalid structure of object. */
}
else if (!strcmp (name, "flags"))
{
/* Skip flags, since they are not used but here just for the
sake of consistent S-expressions. */
gcry_free (name);
gcry_sexp_release (l2);
l2 = gcry_sexp_nth (list, 2);
if (!l2)
{
gcry_sexp_release (list);
return GPG_ERR_INV_OBJ;
}
name = _gcry_sexp_nth_string (l2, 0);
}
spec = spec_from_name (name);
gcry_free (name);
name = NULL;
if (!spec)
{
gcry_sexp_release (l2);
gcry_sexp_release (list);
return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
}
elems = spec->elements_sig;
array = gcry_calloc (strlen (elems) + 1 , sizeof *array );
if (!array)
err = gpg_err_code_from_syserror ();
if (!err)
err = sexp_elements_extract (list, elems, array, NULL, opaque);
gcry_sexp_release (l2);
gcry_sexp_release (list);
if (err)
{
gcry_free (array);
}
else
{
*retarray = array;
*r_spec = spec;
}
return err;
}
static inline int
get_hash_algo (const char *s, size_t n)
{
static const struct { const char *name; int algo; } hashnames[] = {
{ "sha1", GCRY_MD_SHA1 },
{ "md5", GCRY_MD_MD5 },
{ "sha256", GCRY_MD_SHA256 },
{ "ripemd160", GCRY_MD_RMD160 },
{ "rmd160", GCRY_MD_RMD160 },
{ "sha384", GCRY_MD_SHA384 },
{ "sha512", GCRY_MD_SHA512 },
{ "sha224", GCRY_MD_SHA224 },
{ "md2", GCRY_MD_MD2 },
{ "md4", GCRY_MD_MD4 },
{ "tiger", GCRY_MD_TIGER },
{ "haval", GCRY_MD_HAVAL },
{ NULL, 0 }
};
int algo;
int i;
for (i=0; hashnames[i].name; i++)
{
if ( strlen (hashnames[i].name) == n
&& !memcmp (hashnames[i].name, s, n))
break;
}
if (hashnames[i].name)
algo = hashnames[i].algo;
else
{
/* In case of not listed or dynamically allocated hash
algorithm we fall back to this somewhat slower
method. Further, it also allows to use OIDs as
algorithm names. */
char *tmpname;
tmpname = gcry_malloc (n+1);
if (!tmpname)
algo = 0; /* Out of core - silently give up. */
else
{
memcpy (tmpname, s, n);
tmpname[n] = 0;
algo = gcry_md_map_name (tmpname);
gcry_free (tmpname);
}
}
return algo;
}
/****************
* Take sexp and return an array of MPI as used for our internal decrypt
* function.
* s_data = (enc-val
* [(flags [raw, pkcs1, oaep, no-blinding])]
* [(hash-algo <algo>)]
* [(label <label>)]
* (<algo>
* (<param_name1> <mpi>)
* ...
* (<param_namen> <mpi>)
* ))
* HASH-ALGO and LABEL are specific to OAEP.
* RET_MODERN is set to true when at least an empty flags list has been found.
* CTX is used to return encoding information; it may be NULL in which
* case raw encoding is used.
*/
static gcry_err_code_t
sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec,
int *flags, struct pk_encoding_ctx *ctx)
{
gcry_err_code_t err = 0;
gcry_sexp_t list = NULL;
gcry_sexp_t l2 = NULL;
gcry_pk_spec_t *spec = NULL;
char *name = NULL;
size_t n;
int parsed_flags = 0;
const char *elems;
gcry_mpi_t *array = NULL;
/* Check that the first element is valid. */
list = gcry_sexp_find_token (sexp, "enc-val" , 0);
if (!list)
{
err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */
goto leave;
}
l2 = gcry_sexp_nth (list, 1);
if (!l2)
{
err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */
goto leave;
}
/* Extract identifier of sublist. */
name = _gcry_sexp_nth_string (l2, 0);
if (!name)
{
err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
if (!strcmp (name, "flags"))
{
/* There is a flags element - process it. */
const char *s;
int i;
for (i = gcry_sexp_length (l2) - 1; i > 0; i--)
{
s = gcry_sexp_nth_data (l2, i, &n);
if (! s)
; /* Not a data element - ignore. */
else if (n == 3 && !memcmp (s, "raw", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_RAW;
else if (n == 5 && !memcmp (s, "pkcs1", 5)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_PKCS1;
else if (n == 4 && !memcmp (s, "oaep", 4)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_OAEP;
else if (n == 3 && !memcmp (s, "pss", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
{
err = GPG_ERR_CONFLICT;
goto leave;
}
else if (n == 11 && ! memcmp (s, "no-blinding", 11))
parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
else
{
err = GPG_ERR_INV_FLAG;
goto leave;
}
}
gcry_sexp_release (l2);
/* Get the OAEP parameters HASH-ALGO and LABEL, if any. */
if (ctx->encoding == PUBKEY_ENC_OAEP)
{
/* Get HASH-ALGO. */
l2 = gcry_sexp_find_token (list, "hash-algo", 0);
if (l2)
{
s = gcry_sexp_nth_data (l2, 1, &n);
if (!s)
err = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
err = GPG_ERR_DIGEST_ALGO;
}
gcry_sexp_release (l2);
if (err)
goto leave;
}
/* Get LABEL. */
l2 = gcry_sexp_find_token (list, "label", 0);
if (l2)
{
s = gcry_sexp_nth_data (l2, 1, &n);
if (!s)
err = GPG_ERR_NO_OBJ;
else if (n > 0)
{
ctx->label = gcry_malloc (n);
if (!ctx->label)
err = gpg_err_code_from_syserror ();
else
{
memcpy (ctx->label, s, n);
ctx->labellen = n;
}
}
gcry_sexp_release (l2);
if (err)
goto leave;
}
}
/* Get the next which has the actual data - skip HASH-ALGO and LABEL. */
for (i = 2; (l2 = gcry_sexp_nth (list, i)) != NULL; i++)
{
s = gcry_sexp_nth_data (l2, 0, &n);
if (!(n == 9 && !memcmp (s, "hash-algo", 9))
&& !(n == 5 && !memcmp (s, "label", 5))
&& !(n == 15 && !memcmp (s, "random-override", 15)))
break;
gcry_sexp_release (l2);
}
if (!l2)
{
err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */
goto leave;
}
/* Extract sublist identifier. */
gcry_free (name);
name = _gcry_sexp_nth_string (l2, 0);
if (!name)
{
err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
gcry_sexp_release (list);
list = l2;
l2 = NULL;
}
else
parsed_flags |= PUBKEY_FLAG_LEGACYRESULT;
spec = spec_from_name (name);
if (!spec)
{
err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
goto leave;
}
elems = spec->elements_enc;
array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
if (!array)
{
err = gpg_err_code_from_syserror ();
goto leave;
}
err = sexp_elements_extract (list, elems, array, NULL, 0);
leave:
gcry_sexp_release (list);
gcry_sexp_release (l2);
gcry_free (name);
if (err)
{
gcry_free (array);
gcry_free (ctx->label);
ctx->label = NULL;
}
else
{
*retarray = array;
*r_spec = spec;
*flags = parsed_flags;
}
return err;
}
/* Callback for the pubkey algorithm code to verify PSS signatures.
OPAQUE is the data provided by the actual caller. The meaning of
TMP depends on the actual algorithm (but there is only RSA); now
for RSA it is the output of running the public key function on the
input. */
static int
pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
{
struct pk_encoding_ctx *ctx = opaque;
gcry_mpi_t hash = ctx->verify_arg;
return _gcry_rsa_pss_verify (hash, tmp, ctx->nbits - 1,
ctx->hash_algo, ctx->saltlen);
}
/* Take the hash value and convert into an MPI, suitable for
passing to the low level functions. We currently support the
old style way of passing just a MPI and the modern interface which
allows to pass flags so that we can choose between raw and pkcs1
padding - may be more padding options later.
(<mpi>)
or
(data
[(flags [raw, direct, pkcs1, oaep, pss, no-blinding, rfc6979, eddsa])]
[(hash <algo> <value>)]
[(value <text>)]
[(hash-algo <algo>)]
[(label <label>)]
[(salt-length <length>)]
[(random-override <data>)]
)
Either the VALUE or the HASH element must be present for use
with signatures. VALUE is used for encryption.
HASH-ALGO is specific to OAEP and EDDSA.
LABEL is specific to OAEP.
SALT-LENGTH is for PSS.
RANDOM-OVERRIDE is used to replace random nonces for regression
testing. */
static gcry_err_code_t
sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
struct pk_encoding_ctx *ctx)
{
gcry_err_code_t rc = 0;
gcry_sexp_t ldata, lhash, lvalue;
int i;
size_t n;
const char *s;
int unknown_flag = 0;
int parsed_flags = 0;
int explicit_raw = 0;
*ret_mpi = NULL;
ldata = gcry_sexp_find_token (input, "data", 0);
if (!ldata)
{ /* assume old style */
*ret_mpi = gcry_sexp_nth_mpi (input, 0, 0);
return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ;
}
/* see whether there is a flags object */
{
gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0);
if (lflags)
{ /* parse the flags list. */
for (i=gcry_sexp_length (lflags)-1; i > 0; i--)
{
s = gcry_sexp_nth_data (lflags, i, &n);
if (!s)
; /* not a data element*/
else if (n == 7 && !memcmp (s, "rfc6979", 7))
parsed_flags |= PUBKEY_FLAG_RFC6979;
else if (n == 5 && !memcmp (s, "eddsa", 5))
{
ctx->encoding = PUBKEY_ENC_RAW;
parsed_flags |= PUBKEY_FLAG_EDDSA;
}
else if ( n == 3 && !memcmp (s, "raw", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
{
ctx->encoding = PUBKEY_ENC_RAW;
explicit_raw = 1;
}
else if ( n == 5 && !memcmp (s, "pkcs1", 5)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
{
ctx->encoding = PUBKEY_ENC_PKCS1;
parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
}
else if ( n == 4 && !memcmp (s, "oaep", 4)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
{
ctx->encoding = PUBKEY_ENC_OAEP;
parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
}
else if ( n == 3 && !memcmp (s, "pss", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
{
ctx->encoding = PUBKEY_ENC_PSS;
parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
}
else if (n == 11 && ! memcmp (s, "no-blinding", 11))
parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
else
unknown_flag = 1;
}
gcry_sexp_release (lflags);
}
}
if (ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_RAW; /* default to raw */
/* Get HASH or MPI */
lhash = gcry_sexp_find_token (ldata, "hash", 0);
lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0);
if (!(!lhash ^ !lvalue))
rc = GPG_ERR_INV_OBJ; /* none or both given */
else if (unknown_flag)
rc = GPG_ERR_INV_FLAG;
else if (ctx->encoding == PUBKEY_ENC_RAW
&& (parsed_flags & PUBKEY_FLAG_EDDSA))
{
/* Prepare for EdDSA. */
gcry_sexp_t list;
void *value;
size_t valuelen;
if (!lvalue)
{
rc = GPG_ERR_INV_OBJ;
goto leave;
}
/* Get HASH-ALGO. */
list = gcry_sexp_find_token (ldata, "hash-algo", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
gcry_sexp_release (list);
}
else
rc = GPG_ERR_INV_OBJ;
if (rc)
goto leave;
/* Get VALUE. */
value = gcry_sexp_nth_buffer (lvalue, 1, &valuelen);
if (!value)
{
/* We assume that a zero length message is meant by
"(value)". This is commonly used by test vectors. Note
that S-expression do not allow zero length items. */
valuelen = 0;
value = gcry_malloc (1);
if (!value)
rc = gpg_err_code_from_syserror ();
}
else if ((valuelen * 8) < valuelen)
{
gcry_free (value);
rc = GPG_ERR_TOO_LARGE;
}
if (rc)
goto leave;
/* Note that mpi_set_opaque takes ownership of VALUE. */
*ret_mpi = gcry_mpi_set_opaque (NULL, value, valuelen*8);
}
else if (ctx->encoding == PUBKEY_ENC_RAW && lhash
&& (explicit_raw || (parsed_flags & PUBKEY_FLAG_RFC6979)))
{
/* Raw encoding along with a hash element. This is commonly
used for DSA. For better backward error compatibility we
allow this only if either the rfc6979 flag has been given or
the raw flags was explicitly given. */
if (gcry_sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
void *value;
size_t valuelen;
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else if (!(value=gcry_sexp_nth_buffer (lhash, 2, &valuelen)))
rc = GPG_ERR_INV_OBJ;
else if ((valuelen * 8) < valuelen)
{
gcry_free (value);
rc = GPG_ERR_TOO_LARGE;
}
else
*ret_mpi = gcry_mpi_set_opaque (NULL, value, valuelen*8);
}
}
else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue)
{
/* RFC6969 may only be used with the a hash value and not the
MPI based value. */
if (parsed_flags & PUBKEY_FLAG_RFC6979)
{
rc = GPG_ERR_CONFLICT;
goto leave;
}
/* Get the value */
*ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG);
if (!*ret_mpi)
rc = GPG_ERR_INV_OBJ;
}
else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue
&& ctx->op == PUBKEY_OP_ENCRYPT)
{
const void * value;
size_t valuelen;
gcry_sexp_t list;
void *random_override = NULL;
size_t random_override_len = 0;
if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
rc = GPG_ERR_INV_OBJ;
else
{
/* Get optional RANDOM-OVERRIDE. */
list = gcry_sexp_find_token (ldata, "random-override", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
random_override = gcry_malloc (n);
if (!random_override)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (random_override, s, n);
random_override_len = n;
}
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
rc = _gcry_rsa_pkcs1_encode_for_enc (ret_mpi, ctx->nbits,
value, valuelen,
random_override,
random_override_len);
gcry_free (random_override);
}
}
else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash
&& (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
{
if (gcry_sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
const void * value;
size_t valuelen;
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
|| !valuelen )
rc = GPG_ERR_INV_OBJ;
else
rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits,
value, valuelen,
ctx->hash_algo);
}
}
else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
&& ctx->op == PUBKEY_OP_ENCRYPT)
{
const void * value;
size_t valuelen;
if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
rc = GPG_ERR_INV_OBJ;
else
{
gcry_sexp_t list;
void *random_override = NULL;
size_t random_override_len = 0;
/* Get HASH-ALGO. */
list = gcry_sexp_find_token (ldata, "hash-algo", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
/* Get LABEL. */
list = gcry_sexp_find_token (ldata, "label", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
ctx->label = gcry_malloc (n);
if (!ctx->label)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (ctx->label, s, n);
ctx->labellen = n;
}
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
/* Get optional RANDOM-OVERRIDE. */
list = gcry_sexp_find_token (ldata, "random-override", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
random_override = gcry_malloc (n);
if (!random_override)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (random_override, s, n);
random_override_len = n;
}
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
rc = _gcry_rsa_oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
value, valuelen,
ctx->label, ctx->labellen,
random_override, random_override_len);
gcry_free (random_override);
}
}
else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
&& ctx->op == PUBKEY_OP_SIGN)
{
if (gcry_sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
const void * value;
size_t valuelen;
void *random_override = NULL;
size_t random_override_len = 0;
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
|| !valuelen )
rc = GPG_ERR_INV_OBJ;
else
{
gcry_sexp_t list;
/* Get SALT-LENGTH. */
list = gcry_sexp_find_token (ldata, "salt-length", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
{
rc = GPG_ERR_NO_OBJ;
goto leave;
}
ctx->saltlen = (unsigned int)strtoul (s, NULL, 10);
gcry_sexp_release (list);
}
/* Get optional RANDOM-OVERRIDE. */
list = gcry_sexp_find_token (ldata, "random-override", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
random_override = gcry_malloc (n);
if (!random_override)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (random_override, s, n);
random_override_len = n;
}
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
/* Encode the data. (NBITS-1 is due to 8.1.1, step 1.) */
rc = _gcry_rsa_pss_encode (ret_mpi, ctx->nbits - 1,
ctx->hash_algo,
value, valuelen, ctx->saltlen,
random_override, random_override_len);
gcry_free (random_override);
}
}
}
else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
&& ctx->op == PUBKEY_OP_VERIFY)
{
if (gcry_sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else
{
*ret_mpi = gcry_sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_USG);
if (!*ret_mpi)
rc = GPG_ERR_INV_OBJ;
ctx->verify_cmp = pss_verify_cmp;
ctx->verify_arg = *ret_mpi;
}
}
}
else
rc = GPG_ERR_CONFLICT;
leave:
gcry_sexp_release (ldata);
gcry_sexp_release (lhash);
gcry_sexp_release (lvalue);
if (!rc)
ctx->flags = parsed_flags;
else
{
gcry_free (ctx->label);
ctx->label = NULL;
}
return rc;
}
static void
init_encoding_ctx (struct pk_encoding_ctx *ctx, enum pk_operation op,
unsigned int nbits)
{
ctx->op = op;
ctx->nbits = nbits;
ctx->encoding = PUBKEY_ENC_UNKNOWN;
ctx->flags = 0;
ctx->hash_algo = GCRY_MD_SHA1;
ctx->label = NULL;
ctx->labellen = 0;
ctx->saltlen = 20;
ctx->verify_cmp = NULL;
ctx->verify_arg = NULL;
}
/*
Do a PK encrypt operation
Caller has to provide a public key as the SEXP pkey and data as a
SEXP with just one MPI in it. Alternatively S_DATA might be a
complex S-Expression, similar to the one used for signature
verification. This provides a flag which allows to handle PKCS#1
block type 2 padding. The function returns a sexp which may be
passed to to pk_decrypt.
Returns: 0 or an errorcode.
s_data = See comment for sexp_data_to_mpi
s_pkey = <key-as-defined-in-sexp_to_key>
r_ciph = (enc-val
(<algo>
(<param_name1> <mpi>)
...
(<param_namen> <mpi>)
))
*/
gcry_error_t
gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
{
gcry_err_code_t rc;
gcry_mpi_t *pkey = NULL;
gcry_mpi_t data = NULL;
struct pk_encoding_ctx ctx;
gcry_pk_spec_t *spec = NULL;
int i;
*r_ciph = NULL;
/* Get the key. */
rc = sexp_to_key (s_pkey, 0, GCRY_PK_USAGE_ENCR, NULL, &pkey, &spec, NULL);
if (rc)
goto leave;
gcry_assert (spec);
/* Get the stuff we want to encrypt. */
init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey));
rc = sexp_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
/* In fips mode DBG_CIPHER will never evaluate to true but as an
extra failsafe protection we explicitly test for fips mode
here. */
if (DBG_CIPHER && !fips_mode ())
{
log_debug ("pubkey_encrypt: algo=%d\n", spec->algo);
for(i = 0; i < pubkey_get_npkey (spec->algo); i++)
log_mpidump (" pkey", pkey[i]);
log_mpidump (" data", data);
}
if (spec->encrypt)
rc = spec->encrypt (spec->algo, r_ciph, data, pkey, ctx.flags);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
/* if (DBG_CIPHER && !fips_mode ()) */
/* { */
/* for (i = 0; i < pubkey_get_nenc (spec->algo); i++) */
/* log_mpidump (" encr", ciph[i]); */
/* } */
leave:
mpi_free (data);
if (pkey)
{
release_mpi_array (pkey);
gcry_free (pkey);
}
gcry_free (ctx.label);
return gcry_error (rc);
}
/*
Do a PK decrypt operation
Caller has to provide a secret key as the SEXP skey and data in a
format as created by gcry_pk_encrypt. For historic reasons the
function returns simply an MPI as an S-expression part; this is
deprecated and the new method should be used which returns a real
S-expressionl this is selected by adding at least an empty flags
list to S_DATA.
Returns: 0 or an errorcode.
s_data = (enc-val
[(flags [raw, pkcs1, oaep])]
(<algo>
(<param_name1> <mpi>)
...
(<param_namen> <mpi>)
))
s_skey = <key-as-defined-in-sexp_to_key>
r_plain= Either an incomplete S-expression without the parentheses
or if the flags list is used (even if empty) a real S-expression:
(value PLAIN). In raw mode (or no flags given) the returned value
is to be interpreted as a signed MPI, thus it may have an extra
leading zero octet even if not included in the original data.
With pkcs1 or oaep decoding enabled the returned value is a
verbatim octet string.
*/
gcry_error_t
gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
{
gcry_err_code_t rc;
gcry_mpi_t *skey = NULL;
gcry_mpi_t *data = NULL;
int i;
int flags;
struct pk_encoding_ctx ctx;
gcry_pk_spec_t *spec = NULL;
gcry_pk_spec_t *spec_enc = NULL;
*r_plain = NULL;
ctx.label = NULL;
rc = sexp_to_key (s_skey, 1, GCRY_PK_USAGE_ENCR, NULL,
&skey, &spec, NULL);
if (rc)
goto leave;
init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey));
rc = sexp_to_enc (s_data, &data, &spec_enc, &flags, &ctx);
if (rc)
goto leave;
if (spec->algo != spec_enc->algo)
{
rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */
goto leave;
}
if (DBG_CIPHER && !fips_mode ())
{
log_debug ("gcry_pk_decrypt: algo=%d\n", spec->algo);
for(i = 0; i < pubkey_get_nskey (spec->algo); i++)
log_mpidump (" skey", skey[i]);
for(i = 0; i < pubkey_get_nenc (spec->algo); i++)
log_mpidump (" data", data[i]);
}
if (spec->decrypt)
rc = spec->decrypt (spec->algo, r_plain, data, skey, flags,
ctx.encoding, ctx.hash_algo,
ctx.label, ctx.labellen);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
if (rc)
goto leave;
/* if (DBG_CIPHER && !fips_mode ()) */
/* log_mpidump (" plain", plain); */
leave:
if (skey)
{
release_mpi_array (skey);
gcry_free (skey);
}
if (data)
{
release_mpi_array (data);
gcry_free (data);
}
gcry_free (ctx.label);
return gcry_error (rc);
}
/*
Create a signature.
Caller has to provide a secret key as the SEXP skey and data
expressed as a SEXP list hash with only one element which should
instantly be available as a MPI. Alternatively the structure given
below may be used for S_HASH, it provides the abiliy to pass flags
to the operation; the flags defined by now are "pkcs1" which does
PKCS#1 block type 1 style padding and "pss" for PSS encoding.
Returns: 0 or an errorcode.
In case of 0 the function returns a new SEXP with the
signature value; the structure of this signature depends on the
other arguments but is always suitable to be passed to
gcry_pk_verify
s_hash = See comment for sexp_data_to_mpi
s_skey = <key-as-defined-in-sexp_to_key>
r_sig = (sig-val
(<algo>
(<param_name1> <mpi>)
...
(<param_namen> <mpi>))
[(hash algo)])
Note that (hash algo) in R_SIG is not used.
*/
gcry_error_t
gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
{
gcry_mpi_t *skey = NULL;
gcry_mpi_t hash = NULL;
gcry_pk_spec_t *spec = NULL;
struct pk_encoding_ctx ctx;
int i;
int is_ecc;
gcry_err_code_t rc;
*r_sig = NULL;
rc = sexp_to_key (s_skey, 1, GCRY_PK_USAGE_SIGN, NULL,
&skey, &spec, &is_ecc);
if (rc)
goto leave;
gcry_assert (spec);
/* Get the stuff we want to sign. Note that pk_get_nbits does also
work on a private key. We don't need the number of bits for ECC
here, thus set it to 0 so that we don't need to parse it. */
init_encoding_ctx (&ctx, PUBKEY_OP_SIGN,
is_ecc? 0 : gcry_pk_get_nbits (s_skey));
rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER && !fips_mode ())
{
log_debug ("gcry_pk_sign: algo=%d\n", spec->algo);
for(i = 0; i < pubkey_get_nskey (spec->algo); i++)
log_mpidump (" skey", skey[i]);
log_mpidump(" data", hash);
}
if (spec->sign)
rc = spec->sign (spec->algo, r_sig, hash, skey, ctx.flags, ctx.hash_algo);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
if (rc)
goto leave;
/* Fixme: To print the result we need to print an sexp. */
/* if (!rc && DBG_CIPHER && !fips_mode ()) */
/* for (i = 0; i < pubkey_get_nsig (algo); i++) */
/* log_mpidump (" sig", resarr[i]); */
leave:
if (skey)
{
if (is_ecc)
/* Q is optional and may be NULL, while there is D after Q. */
for (i = 0; i < 7; i++)
{
if (skey[i])
mpi_free (skey[i]);
skey[i] = NULL;
}
else
release_mpi_array (skey);
gcry_free (skey);
}
mpi_free (hash);
return gcry_error (rc);
}
/*
Verify a signature.
Caller has to supply the public key pkey, the signature sig and his
hashvalue data. Public key has to be a standard public key given
as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data
must be an S-Exp like the one in sign too. */
gcry_error_t
gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
{
gcry_err_code_t rc;
gcry_pk_spec_t *spec = NULL;
gcry_pk_spec_t *spec_sig = NULL;
gcry_mpi_t *pkey = NULL;
gcry_mpi_t hash = NULL;
gcry_mpi_t *sig = NULL;
struct pk_encoding_ctx ctx;
int i;
rc = sexp_to_key (s_pkey, 0, GCRY_PK_USAGE_SIGN, NULL,
&pkey, &spec, NULL);
if (rc)
goto leave;
/* Get the stuff we want to verify. */
init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, gcry_pk_get_nbits (s_pkey));
rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
if (rc)
goto leave;
/* Get the signature. */
rc = sexp_to_sig (s_sig, &sig, &spec_sig,
!!(ctx.flags & PUBKEY_FLAG_EDDSA));
if (rc)
goto leave;
/* Fixme: Check that the algorithm of S_SIG is compatible to the one
of S_PKEY. */
if (spec->algo != spec_sig->algo)
{
rc = GPG_ERR_CONFLICT;
goto leave;
}
if (DBG_CIPHER && !fips_mode ())
{
log_debug ("gcry_pk_verify: algo=%d\n", spec->algo);
for (i = 0; i < pubkey_get_npkey (spec->algo); i++)
log_mpidump (" pkey", pkey[i]);
for (i = 0; i < pubkey_get_nsig (spec->algo); i++)
log_mpidump (" sig", sig[i]);
log_mpidump (" hash", hash);
}
if (spec->verify)
rc = spec->verify (spec->algo, hash, sig, pkey,
ctx.verify_cmp, &ctx, ctx.flags, ctx.hash_algo);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
leave:
if (pkey)
{
release_mpi_array (pkey);
gcry_free (pkey);
}
if (sig)
{
release_mpi_array (sig);
gcry_free (sig);
}
if (hash)
mpi_free (hash);
return gcry_error (rc);
}
/*
Test a key.
This may be used either for a public or a secret key to see whether
the internal structure is okay.
Returns: 0 or an errorcode.
s_key = <key-as-defined-in-sexp_to_key> */
gcry_error_t
gcry_pk_testkey (gcry_sexp_t s_key)
{
gcry_pk_spec_t *spec = NULL;
gcry_mpi_t *key = NULL;
gcry_err_code_t rc;
/* Note we currently support only secret key checking. */
rc = sexp_to_key (s_key, 1, 0, NULL, &key, &spec, NULL);
if (!rc)
{
rc = pubkey_check_secret_key (spec->algo, key);
release_mpi_array (key);
gcry_free (key);
}
return gcry_error (rc);
}
/*
Create a public key pair and return it in r_key.
How the key is created depends on s_parms:
(genkey
(algo
(parameter_name_1 ....)
....
(parameter_name_n ....)
))
The key is returned in a format depending on the
algorithm. Both, private and secret keys are returned
and optionally some additional informatin.
For elgamal we return this structure:
(key-data
(public-key
(elg
(p <mpi>)
(g <mpi>)
(y <mpi>)
)
)
(private-key
(elg
(p <mpi>)
(g <mpi>)
(y <mpi>)
(x <mpi>)
)
)
(misc-key-info
(pm1-factors n1 n2 ... nn)
))
*/
gcry_error_t
gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
{
gcry_pk_spec_t *spec = NULL;
gcry_sexp_t list = NULL;
gcry_sexp_t l2 = NULL;
gcry_sexp_t l3 = NULL;
char *name = NULL;
size_t n;
gcry_err_code_t rc = GPG_ERR_NO_ERROR;
unsigned int nbits = 0;
unsigned long use_e = 0;
*r_key = NULL;
list = gcry_sexp_find_token (s_parms, "genkey", 0);
if (!list)
{
rc = GPG_ERR_INV_OBJ; /* Does not contain genkey data. */
goto leave;
}
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
l2 = NULL;
if (! list)
{
rc = GPG_ERR_NO_OBJ; /* No cdr for the genkey. */
goto leave;
}
name = _gcry_sexp_nth_string (list, 0);
if (!name)
{
rc = GPG_ERR_INV_OBJ; /* Algo string missing. */
goto leave;
}
spec = spec_from_name (name);
gcry_free (name);
name = NULL;
if (!spec)
{
rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
goto leave;
}
/* Handle the optional rsa-use-e element. Actually this belong into
the algorithm module but we have this parameter in the public
module API, so we need to parse it right here. */
l2 = gcry_sexp_find_token (list, "rsa-use-e", 0);
if (l2)
{
char buf[50];
const char *s;
s = gcry_sexp_nth_data (l2, 1, &n);
if ( !s || n >= DIM (buf) - 1 )
{
rc = GPG_ERR_INV_OBJ; /* No value or value too large. */
goto leave;
}
memcpy (buf, s, n);
buf[n] = 0;
use_e = strtoul (buf, NULL, 0);
gcry_sexp_release (l2);
l2 = NULL;
}
else
use_e = 65537; /* Not given, use the value generated by old versions. */
/* Get the "nbits" parameter. */
l2 = gcry_sexp_find_token (list, "nbits", 0);
if (l2)
{
char buf[50];
const char *s;
s = gcry_sexp_nth_data (l2, 1, &n);
if (!s || n >= DIM (buf) - 1 )
{
rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr. */
goto leave;
}
memcpy (buf, s, n);
buf[n] = 0;
nbits = (unsigned int)strtoul (buf, NULL, 0);
gcry_sexp_release (l2); l2 = NULL;
}
else
nbits = 0;
if (spec->generate)
rc = spec->generate (spec->algo, nbits, use_e, list, r_key);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
leave:
gcry_sexp_release (list); list = NULL;
gcry_free (name);
gcry_sexp_release (l3);
gcry_sexp_release (l2);
gcry_sexp_release (list);
return gcry_error (rc);
}
/*
Get the number of nbits from the public key.
Hmmm: Should we have really this function or is it better to have a
more general function to retrieve different properties of the key? */
unsigned int
gcry_pk_get_nbits (gcry_sexp_t key)
{
gcry_pk_spec_t *spec;
gcry_mpi_t *keyarr = NULL;
unsigned int nbits = 0;
gcry_err_code_t rc;
/* FIXME: Parsing KEY is often too much overhead. For example for
ECC we would only need to look at P and stop parsing right
away. */
rc = sexp_to_key (key, 0, 0, NULL, &keyarr, &spec, NULL);
if (rc == GPG_ERR_INV_OBJ)
rc = sexp_to_key (key, 1, 0, NULL, &keyarr, &spec, NULL);
if (rc)
return 0; /* Error - 0 is a suitable indication for that. */
nbits = spec->get_nbits (spec->algo, keyarr);
release_mpi_array (keyarr);
gcry_free (keyarr);
return nbits;
}
/* Return the so called KEYGRIP which is the SHA-1 hash of the public
key parameters expressed in a way depending on the algorithm.
ARRAY must either be 20 bytes long or NULL; in the latter case a
newly allocated array of that size is returned, otherwise ARRAY or
NULL is returned to indicate an error which is most likely an
unknown algorithm. The function accepts public or secret keys. */
unsigned char *
gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
{
gcry_sexp_t list = NULL;
gcry_sexp_t l2 = NULL;
gcry_pk_spec_t *spec = NULL;
const char *s;
char *name = NULL;
int idx;
const char *elems;
gcry_md_hd_t md = NULL;
int okay = 0;
/* Check that the first element is valid. */
list = gcry_sexp_find_token (key, "public-key", 0);
if (! list)
list = gcry_sexp_find_token (key, "private-key", 0);
if (! list)
list = gcry_sexp_find_token (key, "protected-private-key", 0);
if (! list)
list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
if (! list)
return NULL; /* No public- or private-key object. */
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
l2 = NULL;
name = _gcry_sexp_nth_string (list, 0);
if (!name)
goto fail; /* Invalid structure of object. */
spec = spec_from_name (name);
if (!spec)
goto fail; /* Unknown algorithm. */
elems = spec->elements_grip;
if (!elems)
goto fail; /* No grip parameter. */
if (gcry_md_open (&md, GCRY_MD_SHA1, 0))
goto fail;
if (spec->comp_keygrip)
{
/* Module specific method to compute a keygrip. */
if (spec->comp_keygrip (md, list))
goto fail;
}
else
{
/* Generic method to compute a keygrip. */
for (idx = 0, s = elems; *s; s++, idx++)
{
const char *data;
size_t datalen;
char buf[30];
l2 = gcry_sexp_find_token (list, s, 1);
if (! l2)
goto fail;
data = gcry_sexp_nth_data (l2, 1, &datalen);
if (! data)
goto fail;
snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen);
gcry_md_write (md, buf, strlen (buf));
gcry_md_write (md, data, datalen);
gcry_sexp_release (l2);
l2 = NULL;
gcry_md_write (md, ")", 1);
}
}
if (!array)
{
array = gcry_malloc (20);
if (! array)
goto fail;
}
memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20);
okay = 1;
fail:
gcry_free (name);
gcry_sexp_release (l2);
gcry_md_close (md);
gcry_sexp_release (list);
return okay? array : NULL;
}
const char *
gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits)
{
gcry_mpi_t *pkey = NULL;
gcry_sexp_t list = NULL;
gcry_sexp_t l2;
char *name = NULL;
const char *result = NULL;
int want_private = 1;
gcry_pk_spec_t *spec = NULL;
if (r_nbits)
*r_nbits = 0;
if (key)
{
iterator = 0;
/* Check that the first element is valid. */
list = gcry_sexp_find_token (key, "public-key", 0);
if (list)
want_private = 0;
if (!list)
list = gcry_sexp_find_token (key, "private-key", 0);
if (!list)
return NULL; /* No public- or private-key object. */
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
l2 = NULL;
name = _gcry_sexp_nth_string (list, 0);
if (!name)
goto leave; /* Invalid structure of object. */
/* Get the key. We pass the names of the parameters for
override_elems; this allows to call this function without the
actual public key parameter. */
if (sexp_to_key (key, want_private, 0, "pabgn", &pkey, &spec, NULL))
goto leave;
}
else
{
spec = spec_from_name ("ecc");
if (!spec)
goto leave;
}
if (!spec || !spec->get_curve)
goto leave;
result = spec->get_curve (pkey, iterator, r_nbits);
leave:
if (pkey)
{
release_mpi_array (pkey);
gcry_free (pkey);
}
gcry_free (name);
gcry_sexp_release (list);
return result;
}
gcry_sexp_t
gcry_pk_get_param (int algo, const char *name)
{
gcry_sexp_t result = NULL;
gcry_pk_spec_t *spec = NULL;
algo = map_algo (algo);
if (algo != GCRY_PK_ECC)
return NULL;
spec = spec_from_name ("ecc");
if (spec)
{
if (spec && spec->get_curve_param)
result = spec->get_curve_param (name);
}
return result;
}
gcry_error_t
gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
switch (cmd)
{
case GCRYCTL_DISABLE_ALGO:
/* This one expects a buffer pointing to an integer with the
algo number. */
if ((! buffer) || (buflen != sizeof (int)))
err = GPG_ERR_INV_ARG;
else
disable_pubkey_algo (*((int *) buffer));
break;
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
/* Return information about the given algorithm
WHAT selects the kind of information returned:
GCRYCTL_TEST_ALGO:
Returns 0 when the specified algorithm is available for use.
Buffer must be NULL, nbytes may have the address of a variable
with the required usage of the algorithm. It may be 0 for don't
care or a combination of the GCRY_PK_USAGE_xxx flags;
GCRYCTL_GET_ALGO_USAGE:
Return the usage flags for the given algo. An invalid algo
returns 0. Disabled algos are ignored here because we
only want to know whether the algo is at all capable of
the usage.
Note: Because this function is in most cases 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 occurred or not (i.e. while
checking the block size) */
gcry_error_t
gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
switch (what)
{
case GCRYCTL_TEST_ALGO:
{
int use = nbytes ? *nbytes : 0;
if (buffer)
err = GPG_ERR_INV_ARG;
else if (check_pubkey_algo (algorithm, use))
err = GPG_ERR_PUBKEY_ALGO;
break;
}
case GCRYCTL_GET_ALGO_USAGE:
{
gcry_pk_spec_t *spec;
spec = spec_from_algo (algorithm);
*nbytes = spec? spec->use : 0;
break;
}
case GCRYCTL_GET_ALGO_NPKEY:
{
/* FIXME? */
int npkey = pubkey_get_npkey (algorithm);
*nbytes = npkey;
break;
}
case GCRYCTL_GET_ALGO_NSKEY:
{
/* FIXME? */
int nskey = pubkey_get_nskey (algorithm);
*nbytes = nskey;
break;
}
case GCRYCTL_GET_ALGO_NSIGN:
{
/* FIXME? */
int nsign = pubkey_get_nsig (algorithm);
*nbytes = nsign;
break;
}
case GCRYCTL_GET_ALGO_NENCR:
{
/* FIXME? */
int nencr = pubkey_get_nenc (algorithm);
*nbytes = nencr;
break;
}
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
/* Return an S-expression representing the context CTX. Depending on
the state of that context, the S-expression may either be a public
key, a private key or any other object used with public key
operations. On success a new S-expression is stored at R_SEXP and
0 is returned, on error NULL is store there and an error code is
returned. MODE is either 0 or one of the GCRY_PK_GET_xxx values.
As of now it only support certain ECC operations because a context
object is right now only defined for ECC. Over time this function
will be extended to cover more algorithms. Note also that the name
of the function is gcry_pubkey_xxx and not gcry_pk_xxx. The idea
is that we will eventually provide variants of the existing
gcry_pk_xxx functions which will take a context parameter. */
gcry_err_code_t
_gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, int mode, gcry_ctx_t ctx)
{
mpi_ec_t ec;
if (!r_sexp)
return GPG_ERR_INV_VALUE;
*r_sexp = NULL;
switch (mode)
{
case 0:
case GCRY_PK_GET_PUBKEY:
case GCRY_PK_GET_SECKEY:
break;
default:
return GPG_ERR_INV_VALUE;
}
if (!ctx)
return GPG_ERR_NO_CRYPT_CTX;
ec = _gcry_ctx_find_pointer (ctx, CONTEXT_TYPE_EC);
if (ec)
return _gcry_pk_ecc_get_sexp (r_sexp, mode, ec);
return GPG_ERR_WRONG_CRYPT_CTX;
}
/* Explicitly initialize this module. */
gcry_err_code_t
_gcry_pk_init (void)
{
return 0;
}
/* Run the selftests for pubkey algorithm ALGO with optional reporting
function REPORT. */
gpg_error_t
_gcry_pk_selftest (int algo, int extended, selftest_report_func_t report)
{
gcry_err_code_t ec;
gcry_pk_spec_t *spec;
algo = map_algo (algo);
spec = spec_from_algo (algo);
- if (spec && spec->selftest)
+ if (spec && !spec->flags.disabled && spec->selftest)
ec = spec->selftest (algo, extended, report);
else
{
ec = GPG_ERR_PUBKEY_ALGO;
/* Fixme: We need to change the report fucntion to allow passing
of an encryption mode (e.g. pkcs1, ecdsa, or ecdh). */
if (report)
report ("pubkey", algo, "module",
spec && !spec->flags.disabled?
"no selftest available" :
spec? "algorithm disabled" :
"algorithm not found");
}
return gpg_error (ec);
}
diff --git a/cipher/rfc2268.c b/cipher/rfc2268.c
index da0b9f40..aed8cadb 100644
--- a/cipher/rfc2268.c
+++ b/cipher/rfc2268.c
@@ -1,371 +1,375 @@
/* rfc2268.c - The cipher described in rfc2268; aka Ron's Cipher 2.
* Copyright (C) 2003 Nikos Mavroyanopoulos
* Copyright (C) 2004 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* This implementation was written by Nikos Mavroyanopoulos for GNUTLS
* as a Libgcrypt module (gnutls/lib/x509/rc2.c) and later adapted for
* direct use by Libgcrypt by Werner Koch. This implementation is
* only useful for pkcs#12 decryption.
*
* The implementation here is based on Peter Gutmann's RRC.2 paper.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "g10lib.h"
#include "types.h"
#include "cipher.h"
#define RFC2268_BLOCKSIZE 8
typedef struct
{
u16 S[64];
} RFC2268_context;
static const unsigned char rfc2268_sbox[] = {
217, 120, 249, 196, 25, 221, 181, 237,
40, 233, 253, 121, 74, 160, 216, 157,
198, 126, 55, 131, 43, 118, 83, 142,
98, 76, 100, 136, 68, 139, 251, 162,
23, 154, 89, 245, 135, 179, 79, 19,
97, 69, 109, 141, 9, 129, 125, 50,
189, 143, 64, 235, 134, 183, 123, 11,
240, 149, 33, 34, 92, 107, 78, 130,
84, 214, 101, 147, 206, 96, 178, 28,
115, 86, 192, 20, 167, 140, 241, 220,
18, 117, 202, 31, 59, 190, 228, 209,
66, 61, 212, 48, 163, 60, 182, 38,
111, 191, 14, 218, 70, 105, 7, 87,
39, 242, 29, 155, 188, 148, 67, 3,
248, 17, 199, 246, 144, 239, 62, 231,
6, 195, 213, 47, 200, 102, 30, 215,
8, 232, 234, 222, 128, 82, 238, 247,
132, 170, 114, 172, 53, 77, 106, 42,
150, 26, 210, 113, 90, 21, 73, 116,
75, 159, 208, 94, 4, 24, 164, 236,
194, 224, 65, 110, 15, 81, 203, 204,
36, 145, 175, 80, 161, 244, 112, 57,
153, 124, 58, 133, 35, 184, 180, 122,
252, 2, 54, 91, 37, 85, 151, 49,
45, 93, 250, 152, 227, 138, 146, 174,
5, 223, 41, 16, 103, 108, 186, 201,
211, 0, 230, 207, 225, 158, 168, 44,
99, 22, 1, 63, 88, 226, 137, 169,
13, 56, 52, 27, 171, 51, 255, 176,
187, 72, 12, 95, 185, 177, 205, 46,
197, 243, 219, 71, 229, 165, 156, 119,
10, 166, 32, 104, 254, 127, 193, 173
};
#define rotl16(x,n) (((x) << ((u16)(n))) | ((x) >> (16 - (u16)(n))))
#define rotr16(x,n) (((x) >> ((u16)(n))) | ((x) << (16 - (u16)(n))))
static const char *selftest (void);
static void
do_encrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf)
{
RFC2268_context *ctx = context;
register int i, j;
u16 word0 = 0, word1 = 0, word2 = 0, word3 = 0;
word0 = (word0 << 8) | inbuf[1];
word0 = (word0 << 8) | inbuf[0];
word1 = (word1 << 8) | inbuf[3];
word1 = (word1 << 8) | inbuf[2];
word2 = (word2 << 8) | inbuf[5];
word2 = (word2 << 8) | inbuf[4];
word3 = (word3 << 8) | inbuf[7];
word3 = (word3 << 8) | inbuf[6];
for (i = 0; i < 16; i++)
{
j = i * 4;
/* For some reason I cannot combine those steps. */
word0 += (word1 & ~word3) + (word2 & word3) + ctx->S[j];
word0 = rotl16(word0, 1);
word1 += (word2 & ~word0) + (word3 & word0) + ctx->S[j + 1];
word1 = rotl16(word1, 2);
word2 += (word3 & ~word1) + (word0 & word1) + ctx->S[j + 2];
word2 = rotl16(word2, 3);
word3 += (word0 & ~word2) + (word1 & word2) + ctx->S[j + 3];
word3 = rotl16(word3, 5);
if (i == 4 || i == 10)
{
word0 += ctx->S[word3 & 63];
word1 += ctx->S[word0 & 63];
word2 += ctx->S[word1 & 63];
word3 += ctx->S[word2 & 63];
}
}
outbuf[0] = word0 & 255;
outbuf[1] = word0 >> 8;
outbuf[2] = word1 & 255;
outbuf[3] = word1 >> 8;
outbuf[4] = word2 & 255;
outbuf[5] = word2 >> 8;
outbuf[6] = word3 & 255;
outbuf[7] = word3 >> 8;
}
static unsigned int
encrypt_block (void *context, unsigned char *outbuf, const unsigned char *inbuf)
{
do_encrypt (context, outbuf, inbuf);
return /*burn_stack*/ (4 * sizeof(void *) + sizeof(void *) + sizeof(u32) * 4);
}
static void
do_decrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf)
{
RFC2268_context *ctx = context;
register int i, j;
u16 word0 = 0, word1 = 0, word2 = 0, word3 = 0;
word0 = (word0 << 8) | inbuf[1];
word0 = (word0 << 8) | inbuf[0];
word1 = (word1 << 8) | inbuf[3];
word1 = (word1 << 8) | inbuf[2];
word2 = (word2 << 8) | inbuf[5];
word2 = (word2 << 8) | inbuf[4];
word3 = (word3 << 8) | inbuf[7];
word3 = (word3 << 8) | inbuf[6];
for (i = 15; i >= 0; i--)
{
j = i * 4;
word3 = rotr16(word3, 5);
word3 -= (word0 & ~word2) + (word1 & word2) + ctx->S[j + 3];
word2 = rotr16(word2, 3);
word2 -= (word3 & ~word1) + (word0 & word1) + ctx->S[j + 2];
word1 = rotr16(word1, 2);
word1 -= (word2 & ~word0) + (word3 & word0) + ctx->S[j + 1];
word0 = rotr16(word0, 1);
word0 -= (word1 & ~word3) + (word2 & word3) + ctx->S[j];
if (i == 5 || i == 11)
{
word3 = word3 - ctx->S[word2 & 63];
word2 = word2 - ctx->S[word1 & 63];
word1 = word1 - ctx->S[word0 & 63];
word0 = word0 - ctx->S[word3 & 63];
}
}
outbuf[0] = word0 & 255;
outbuf[1] = word0 >> 8;
outbuf[2] = word1 & 255;
outbuf[3] = word1 >> 8;
outbuf[4] = word2 & 255;
outbuf[5] = word2 >> 8;
outbuf[6] = word3 & 255;
outbuf[7] = word3 >> 8;
}
static unsigned int
decrypt_block (void *context, unsigned char *outbuf, const unsigned char *inbuf)
{
do_decrypt (context, outbuf, inbuf);
return /*burn_stack*/ (4 * sizeof(void *) + sizeof(void *) + sizeof(u32) * 4);
}
static gpg_err_code_t
setkey_core (void *context, const unsigned char *key, unsigned int keylen, int with_phase2)
{
static int initialized;
static const char *selftest_failed;
RFC2268_context *ctx = context;
unsigned int i;
unsigned char *S, x;
int len;
int bits = keylen * 8;
if (!initialized)
{
initialized = 1;
selftest_failed = selftest ();
if (selftest_failed)
log_error ("RFC2268 selftest failed (%s).\n", selftest_failed);
}
if (selftest_failed)
return GPG_ERR_SELFTEST_FAILED;
if (keylen < 40 / 8) /* We want at least 40 bits. */
return GPG_ERR_INV_KEYLEN;
S = (unsigned char *) ctx->S;
for (i = 0; i < keylen; i++)
S[i] = key[i];
for (i = keylen; i < 128; i++)
S[i] = rfc2268_sbox[(S[i - keylen] + S[i - 1]) & 255];
S[0] = rfc2268_sbox[S[0]];
/* Phase 2 - reduce effective key size to "bits". This was not
* discussed in Gutmann's paper. I've copied that from the public
* domain code posted in sci.crypt. */
if (with_phase2)
{
len = (bits + 7) >> 3;
i = 128 - len;
x = rfc2268_sbox[S[i] & (255 >> (7 & -bits))];
S[i] = x;
while (i--)
{
x = rfc2268_sbox[x ^ S[i + len]];
S[i] = x;
}
}
/* Make the expanded key, endian independent. */
for (i = 0; i < 64; i++)
ctx->S[i] = ( (u16) S[i * 2] | (((u16) S[i * 2 + 1]) << 8));
return 0;
}
static gpg_err_code_t
do_setkey (void *context, const unsigned char *key, unsigned int keylen)
{
return setkey_core (context, key, keylen, 1);
}
static const char *
selftest (void)
{
RFC2268_context ctx;
unsigned char scratch[16];
/* Test vectors from Peter Gutmann's paper. */
static unsigned char key_1[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char plaintext_1[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const unsigned char ciphertext_1[] =
{ 0x1C, 0x19, 0x8A, 0x83, 0x8D, 0xF0, 0x28, 0xB7 };
static unsigned char key_2[] =
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
static unsigned char plaintext_2[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static unsigned char ciphertext_2[] =
{ 0x50, 0xDC, 0x01, 0x62, 0xBD, 0x75, 0x7F, 0x31 };
/* This one was checked against libmcrypt's RFC2268. */
static unsigned char key_3[] =
{ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char plaintext_3[] =
{ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static unsigned char ciphertext_3[] =
{ 0x8f, 0xd1, 0x03, 0x89, 0x33, 0x6b, 0xf9, 0x5e };
/* First test. */
setkey_core (&ctx, key_1, sizeof(key_1), 0);
do_encrypt (&ctx, scratch, plaintext_1);
if (memcmp (scratch, ciphertext_1, sizeof(ciphertext_1)))
return "RFC2268 encryption test 1 failed.";
setkey_core (&ctx, key_1, sizeof(key_1), 0);
do_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext_1, sizeof(plaintext_1)))
return "RFC2268 decryption test 1 failed.";
/* Second test. */
setkey_core (&ctx, key_2, sizeof(key_2), 0);
do_encrypt (&ctx, scratch, plaintext_2);
if (memcmp (scratch, ciphertext_2, sizeof(ciphertext_2)))
return "RFC2268 encryption test 2 failed.";
setkey_core (&ctx, key_2, sizeof(key_2), 0);
do_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext_2, sizeof(plaintext_2)))
return "RFC2268 decryption test 2 failed.";
/* Third test. */
setkey_core(&ctx, key_3, sizeof(key_3), 0);
do_encrypt(&ctx, scratch, plaintext_3);
if (memcmp(scratch, ciphertext_3, sizeof(ciphertext_3)))
return "RFC2268 encryption test 3 failed.";
setkey_core (&ctx, key_3, sizeof(key_3), 0);
do_decrypt (&ctx, scratch, scratch);
if (memcmp(scratch, plaintext_3, sizeof(plaintext_3)))
return "RFC2268 decryption test 3 failed.";
return NULL;
}
static gcry_cipher_oid_spec_t oids_rfc2268_40[] =
{
/*{ "1.2.840.113549.3.2", GCRY_CIPHER_MODE_CBC },*/
/* pbeWithSHAAnd40BitRC2_CBC */
{ "1.2.840.113549.1.12.1.6", GCRY_CIPHER_MODE_CBC },
{ NULL }
};
static gcry_cipher_oid_spec_t oids_rfc2268_128[] =
{
/* pbeWithSHAAnd128BitRC2_CBC */
{ "1.2.840.113549.1.12.1.5", GCRY_CIPHER_MODE_CBC },
{ NULL }
};
-gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40 = {
- "RFC2268_40", NULL, oids_rfc2268_40,
- RFC2268_BLOCKSIZE, 40, sizeof(RFC2268_context),
- do_setkey, encrypt_block, decrypt_block
-};
+gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40 =
+ {
+ GCRY_CIPHER_RFC2268_40, {0, 0},
+ "RFC2268_40", NULL, oids_rfc2268_40,
+ RFC2268_BLOCKSIZE, 40, sizeof(RFC2268_context),
+ do_setkey, encrypt_block, decrypt_block
+ };
-gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128 = {
- "RFC2268_128", NULL, oids_rfc2268_128,
- RFC2268_BLOCKSIZE, 128, sizeof(RFC2268_context),
- do_setkey, encrypt_block, decrypt_block
-};
+gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128 =
+ {
+ GCRY_CIPHER_RFC2268_128, {0, 0},
+ "RFC2268_128", NULL, oids_rfc2268_128,
+ RFC2268_BLOCKSIZE, 128, sizeof(RFC2268_context),
+ do_setkey, encrypt_block, decrypt_block
+ };
diff --git a/cipher/rijndael.c b/cipher/rijndael.c
index 190d0f9f..85c1a41d 100644
--- a/cipher/rijndael.c
+++ b/cipher/rijndael.c
@@ -1,2620 +1,2620 @@
/* Rijndael (AES) for GnuPG
* Copyright (C) 2000, 2001, 2002, 2003, 2007,
* 2008, 2011, 2012 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*******************************************************************
* The code here is based on the optimized implementation taken from
* http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ on Oct 2, 2000,
* which carries this notice:
*------------------------------------------
* rijndael-alg-fst.c v2.3 April '2000
*
* Optimised ANSI C code
*
* authors: v1.0: Antoon Bosselaers
* v2.0: Vincent Rijmen
* v2.3: Paulo Barreto
*
* This code is placed in the public domain.
*------------------------------------------
*
* The SP800-38a document is available at:
* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
*
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for memcmp() */
#include "types.h" /* for byte and u32 typedefs */
#include "g10lib.h"
#include "cipher.h"
#include "bufhelp.h"
#include "cipher-selftest.h"
#define MAXKC (256/32)
#define MAXROUNDS 14
#define BLOCKSIZE (128/8)
/* Helper macro to force alignment to 16 bytes. */
#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
# define ATTR_ALIGNED_16 __attribute__ ((aligned (16)))
#else
# define ATTR_ALIGNED_16
#endif
/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
#undef USE_AMD64_ASM
#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
# define USE_AMD64_ASM 1
#endif
/* USE_ARMV6_ASM indicates whether to use ARMv6 assembly code. */
#undef USE_ARMV6_ASM
#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__)
# ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS
# define USE_ARMV6_ASM 1
# endif
#endif
/* USE_PADLOCK indicates whether to compile the padlock specific
code. */
#undef USE_PADLOCK
#ifdef ENABLE_PADLOCK_SUPPORT
# ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
# if (defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__)
# define USE_PADLOCK 1
# endif
# endif
#endif /*ENABLE_PADLOCK_SUPPORT*/
/* USE_AESNI inidicates whether to compile with Intel AES-NI code. We
need the vector-size attribute which seems to be available since
gcc 3. However, to be on the safe side we require at least gcc 4. */
#undef USE_AESNI
#ifdef ENABLE_AESNI_SUPPORT
# if ((defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__))
# if __GNUC__ >= 4
# define USE_AESNI 1
# endif
# endif
#endif /* ENABLE_AESNI_SUPPORT */
#ifdef USE_AESNI
typedef int m128i_t __attribute__ ((__vector_size__ (16)));
#endif /*USE_AESNI*/
/* Define an u32 variant for the sake of gcc 4.4's strict aliasing. */
#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 4 )
typedef u32 __attribute__ ((__may_alias__)) u32_a_t;
#else
typedef u32 u32_a_t;
#endif
#ifdef USE_AMD64_ASM
/* AMD64 assembly implementations of AES */
extern void _gcry_aes_amd64_encrypt_block(const void *keysched_enc,
unsigned char *out,
const unsigned char *in,
int rounds);
extern void _gcry_aes_amd64_decrypt_block(const void *keysched_dec,
unsigned char *out,
const unsigned char *in,
int rounds);
#endif /*USE_AMD64_ASM*/
#ifdef USE_ARMV6_ASM
/* ARMv6 assembly implementations of AES */
extern void _gcry_aes_armv6_encrypt_block(const void *keysched_enc,
unsigned char *out,
const unsigned char *in,
int rounds);
extern void _gcry_aes_armv6_decrypt_block(const void *keysched_dec,
unsigned char *out,
const unsigned char *in,
int rounds);
#endif /*USE_ARMV6_ASM*/
/* Our context object. */
typedef struct
{
/* The first fields are the keyschedule arrays. This is so that
they are aligned on a 16 byte boundary if using gcc. This
alignment is required for the AES-NI code and a good idea in any
case. The alignment is guaranteed due to the way cipher.c
allocates the space for the context. The PROPERLY_ALIGNED_TYPE
hack is used to force a minimal alignment if not using gcc of if
the alignment requirement is higher that 16 bytes. */
union
{
PROPERLY_ALIGNED_TYPE dummy;
byte keyschedule[MAXROUNDS+1][4][4];
#ifdef USE_PADLOCK
/* The key as passed to the padlock engine. It is only used if
the padlock engine is used (USE_PADLOCK, below). */
unsigned char padlock_key[16] __attribute__ ((aligned (16)));
#endif /*USE_PADLOCK*/
} u1;
union
{
PROPERLY_ALIGNED_TYPE dummy;
byte keyschedule[MAXROUNDS+1][4][4];
} u2;
int rounds; /* Key-length-dependent number of rounds. */
int decryption_prepared; /* The decryption key schedule is available. */
#ifdef USE_PADLOCK
int use_padlock; /* Padlock shall be used. */
#endif /*USE_PADLOCK*/
#ifdef USE_AESNI
int use_aesni; /* AES-NI shall be used. */
#endif /*USE_AESNI*/
} RIJNDAEL_context ATTR_ALIGNED_16;
/* Macros defining alias for the keyschedules. */
#define keyschenc u1.keyschedule
#define keyschdec u2.keyschedule
#define padlockkey u1.padlock_key
/* Two macros to be called prior and after the use of AESNI
instructions. There should be no external function calls between
the use of these macros. There purpose is to make sure that the
SSE regsiters are cleared and won't reveal any information about
the key or the data. */
#ifdef USE_AESNI
# define aesni_prepare() do { } while (0)
# define aesni_cleanup() \
do { asm volatile ("pxor %%xmm0, %%xmm0\n\t" \
"pxor %%xmm1, %%xmm1\n" :: ); \
} while (0)
# define aesni_cleanup_2_5() \
do { asm volatile ("pxor %%xmm2, %%xmm2\n\t" \
"pxor %%xmm3, %%xmm3\n" \
"pxor %%xmm4, %%xmm4\n" \
"pxor %%xmm5, %%xmm5\n":: ); \
} while (0)
#else
# define aesni_prepare() do { } while (0)
# define aesni_cleanup() do { } while (0)
#endif
/* All the numbers. */
#include "rijndael-tables.h"
/* Function prototypes. */
#ifdef USE_AESNI
/* We don't want to inline these functions to help gcc allocate enough
registers. */
static void do_aesni_ctr (const RIJNDAEL_context *ctx, unsigned char *ctr,
unsigned char *b, const unsigned char *a)
__attribute__ ((__noinline__));
static void do_aesni_ctr_4 (const RIJNDAEL_context *ctx, unsigned char *ctr,
unsigned char *b, const unsigned char *a)
__attribute__ ((__noinline__));
#endif /*USE_AESNI*/
static const char *selftest(void);
/* Perform the key setup. */
static gcry_err_code_t
do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen)
{
static int initialized = 0;
static const char *selftest_failed=0;
int rounds;
int i,j, r, t, rconpointer = 0;
int KC;
union
{
PROPERLY_ALIGNED_TYPE dummy;
byte k[MAXKC][4];
} k;
#define k k.k
union
{
PROPERLY_ALIGNED_TYPE dummy;
byte tk[MAXKC][4];
} tk;
#define tk tk.tk
/* The on-the-fly self tests are only run in non-fips mode. In fips
mode explicit self-tests are required. Actually the on-the-fly
self-tests are not fully thread-safe and it might happen that a
failed self-test won't get noticed in another thread.
FIXME: We might want to have a central registry of succeeded
self-tests. */
if (!fips_mode () && !initialized)
{
initialized = 1;
selftest_failed = selftest ();
if (selftest_failed)
log_error ("%s\n", selftest_failed );
}
if (selftest_failed)
return GPG_ERR_SELFTEST_FAILED;
ctx->decryption_prepared = 0;
#ifdef USE_PADLOCK
ctx->use_padlock = 0;
#endif
#ifdef USE_AESNI
ctx->use_aesni = 0;
#endif
if( keylen == 128/8 )
{
rounds = 10;
KC = 4;
if (0)
;
#ifdef USE_PADLOCK
else if ((_gcry_get_hw_features () & HWF_PADLOCK_AES))
{
ctx->use_padlock = 1;
memcpy (ctx->padlockkey, key, keylen);
}
#endif
#ifdef USE_AESNI
else if ((_gcry_get_hw_features () & HWF_INTEL_AESNI))
{
ctx->use_aesni = 1;
}
#endif
}
else if ( keylen == 192/8 )
{
rounds = 12;
KC = 6;
if (0)
{
;
}
#ifdef USE_AESNI
else if ((_gcry_get_hw_features () & HWF_INTEL_AESNI))
{
ctx->use_aesni = 1;
}
#endif
}
else if ( keylen == 256/8 )
{
rounds = 14;
KC = 8;
if (0)
{
;
}
#ifdef USE_AESNI
else if ((_gcry_get_hw_features () & HWF_INTEL_AESNI))
{
ctx->use_aesni = 1;
}
#endif
}
else
return GPG_ERR_INV_KEYLEN;
ctx->rounds = rounds;
/* NB: We don't yet support Padlock hardware key generation. */
if (0)
;
#ifdef USE_AESNI_is_disabled_here
else if (ctx->use_aesni && ctx->rounds == 10)
{
/* Note: This code works for AES-128 but it is not much better
than using the standard key schedule. We disable it for
now and don't put any effort into implementing this for
AES-192 and AES-256. */
asm volatile ("movdqu (%[key]), %%xmm1\n\t" /* xmm1 := key */
"movdqa %%xmm1, (%[ksch])\n\t" /* ksch[0] := xmm1 */
"aeskeygenassist $0x01, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0x10(%[ksch])\n\t" /* ksch[1] := xmm1 */
"aeskeygenassist $0x02, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0x20(%[ksch])\n\t" /* ksch[2] := xmm1 */
"aeskeygenassist $0x04, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0x30(%[ksch])\n\t" /* ksch[3] := xmm1 */
"aeskeygenassist $0x08, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0x40(%[ksch])\n\t" /* ksch[4] := xmm1 */
"aeskeygenassist $0x10, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0x50(%[ksch])\n\t" /* ksch[5] := xmm1 */
"aeskeygenassist $0x20, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0x60(%[ksch])\n\t" /* ksch[6] := xmm1 */
"aeskeygenassist $0x40, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0x70(%[ksch])\n\t" /* ksch[7] := xmm1 */
"aeskeygenassist $0x80, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0x80(%[ksch])\n\t" /* ksch[8] := xmm1 */
"aeskeygenassist $0x1b, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0x90(%[ksch])\n\t" /* ksch[9] := xmm1 */
"aeskeygenassist $0x36, %%xmm1, %%xmm2\n\t"
"call .Lexpand128_%=\n\t"
"movdqa %%xmm1, 0xa0(%[ksch])\n\t" /* ksch[10] := xmm1 */
"jmp .Lleave%=\n"
".Lexpand128_%=:\n\t"
"pshufd $0xff, %%xmm2, %%xmm2\n\t"
"movdqa %%xmm1, %%xmm3\n\t"
"pslldq $4, %%xmm3\n\t"
"pxor %%xmm3, %%xmm1\n\t"
"pslldq $4, %%xmm3\n\t"
"pxor %%xmm3, %%xmm1\n\t"
"pslldq $4, %%xmm3\n\t"
"pxor %%xmm3, %%xmm2\n\t"
"pxor %%xmm2, %%xmm1\n\t"
"ret\n"
".Lleave%=:\n\t"
"pxor %%xmm1, %%xmm1\n\t"
"pxor %%xmm2, %%xmm2\n\t"
"pxor %%xmm3, %%xmm3\n"
:
: [key] "r" (key), [ksch] "r" (ctx->keyschenc)
: "cc", "memory" );
}
#endif /*USE_AESNI*/
else
{
#define W (ctx->keyschenc)
for (i = 0; i < keylen; i++)
{
k[i >> 2][i & 3] = key[i];
}
for (j = KC-1; j >= 0; j--)
{
*((u32_a_t*)tk[j]) = *((u32_a_t*)k[j]);
}
r = 0;
t = 0;
/* Copy values into round key array. */
for (j = 0; (j < KC) && (r < rounds + 1); )
{
for (; (j < KC) && (t < 4); j++, t++)
{
*((u32_a_t*)W[r][t]) = *((u32_a_t*)tk[j]);
}
if (t == 4)
{
r++;
t = 0;
}
}
while (r < rounds + 1)
{
/* While not enough round key material calculated calculate
new values. */
tk[0][0] ^= S[tk[KC-1][1]];
tk[0][1] ^= S[tk[KC-1][2]];
tk[0][2] ^= S[tk[KC-1][3]];
tk[0][3] ^= S[tk[KC-1][0]];
tk[0][0] ^= rcon[rconpointer++];
if (KC != 8)
{
for (j = 1; j < KC; j++)
{
*((u32_a_t*)tk[j]) ^= *((u32_a_t*)tk[j-1]);
}
}
else
{
for (j = 1; j < KC/2; j++)
{
*((u32_a_t*)tk[j]) ^= *((u32_a_t*)tk[j-1]);
}
tk[KC/2][0] ^= S[tk[KC/2 - 1][0]];
tk[KC/2][1] ^= S[tk[KC/2 - 1][1]];
tk[KC/2][2] ^= S[tk[KC/2 - 1][2]];
tk[KC/2][3] ^= S[tk[KC/2 - 1][3]];
for (j = KC/2 + 1; j < KC; j++)
{
*((u32_a_t*)tk[j]) ^= *((u32_a_t*)tk[j-1]);
}
}
/* Copy values into round key array. */
for (j = 0; (j < KC) && (r < rounds + 1); )
{
for (; (j < KC) && (t < 4); j++, t++)
{
*((u32_a_t*)W[r][t]) = *((u32_a_t*)tk[j]);
}
if (t == 4)
{
r++;
t = 0;
}
}
}
#undef W
}
return 0;
#undef tk
#undef k
}
static gcry_err_code_t
rijndael_setkey (void *context, const byte *key, const unsigned keylen)
{
RIJNDAEL_context *ctx = context;
int rc = do_setkey (ctx, key, keylen);
_gcry_burn_stack ( 100 + 16*sizeof(int));
return rc;
}
/* Make a decryption key from an encryption key. */
static void
prepare_decryption( RIJNDAEL_context *ctx )
{
int r;
#ifdef USE_AESNI
if (ctx->use_aesni)
{
/* The AES-NI decrypt instructions use the Equivalent Inverse
Cipher, thus we can't use the the standard decrypt key
preparation. */
m128i_t *ekey = (m128i_t*)ctx->keyschenc;
m128i_t *dkey = (m128i_t*)ctx->keyschdec;
int rr;
dkey[0] = ekey[ctx->rounds];
for (r=1, rr=ctx->rounds-1; r < ctx->rounds; r++, rr--)
{
asm volatile
("movdqu %[ekey], %%xmm1\n\t"
/*"aesimc %%xmm1, %%xmm1\n\t"*/
".byte 0x66, 0x0f, 0x38, 0xdb, 0xc9\n\t"
"movdqu %%xmm1, %[dkey]"
: [dkey] "=m" (dkey[r])
: [ekey] "m" (ekey[rr]) );
}
dkey[r] = ekey[0];
}
else
#endif /*USE_AESNI*/
{
union
{
PROPERLY_ALIGNED_TYPE dummy;
byte *w;
} w;
#define w w.w
for (r=0; r < MAXROUNDS+1; r++ )
{
*((u32_a_t*)ctx->keyschdec[r][0]) = *((u32_a_t*)ctx->keyschenc[r][0]);
*((u32_a_t*)ctx->keyschdec[r][1]) = *((u32_a_t*)ctx->keyschenc[r][1]);
*((u32_a_t*)ctx->keyschdec[r][2]) = *((u32_a_t*)ctx->keyschenc[r][2]);
*((u32_a_t*)ctx->keyschdec[r][3]) = *((u32_a_t*)ctx->keyschenc[r][3]);
}
#define W (ctx->keyschdec)
for (r = 1; r < ctx->rounds; r++)
{
w = W[r][0];
*((u32_a_t*)w) = *((u32_a_t*)U1[w[0]]) ^ *((u32_a_t*)U2[w[1]])
^ *((u32_a_t*)U3[w[2]]) ^ *((u32_a_t*)U4[w[3]]);
w = W[r][1];
*((u32_a_t*)w) = *((u32_a_t*)U1[w[0]]) ^ *((u32_a_t*)U2[w[1]])
^ *((u32_a_t*)U3[w[2]]) ^ *((u32_a_t*)U4[w[3]]);
w = W[r][2];
*((u32_a_t*)w) = *((u32_a_t*)U1[w[0]]) ^ *((u32_a_t*)U2[w[1]])
^ *((u32_a_t*)U3[w[2]]) ^ *((u32_a_t*)U4[w[3]]);
w = W[r][3];
*((u32_a_t*)w) = *((u32_a_t*)U1[w[0]]) ^ *((u32_a_t*)U2[w[1]])
^ *((u32_a_t*)U3[w[2]]) ^ *((u32_a_t*)U4[w[3]]);
}
#undef W
#undef w
}
}
/* Encrypt one block. A and B need to be aligned on a 4 byte
boundary. A and B may be the same. */
static void
do_encrypt_aligned (const RIJNDAEL_context *ctx,
unsigned char *b, const unsigned char *a)
{
#ifdef USE_AMD64_ASM
_gcry_aes_amd64_encrypt_block(ctx->keyschenc, b, a, ctx->rounds);
#elif defined(USE_ARMV6_ASM)
_gcry_aes_armv6_encrypt_block(ctx->keyschenc, b, a, ctx->rounds);
#else
#define rk (ctx->keyschenc)
int rounds = ctx->rounds;
int r;
union
{
u32 tempu32[4]; /* Force correct alignment. */
byte temp[4][4];
} u;
*((u32_a_t*)u.temp[0]) = *((u32_a_t*)(a )) ^ *((u32_a_t*)rk[0][0]);
*((u32_a_t*)u.temp[1]) = *((u32_a_t*)(a+ 4)) ^ *((u32_a_t*)rk[0][1]);
*((u32_a_t*)u.temp[2]) = *((u32_a_t*)(a+ 8)) ^ *((u32_a_t*)rk[0][2]);
*((u32_a_t*)u.temp[3]) = *((u32_a_t*)(a+12)) ^ *((u32_a_t*)rk[0][3]);
*((u32_a_t*)(b )) = (*((u32_a_t*)T1[u.temp[0][0]])
^ *((u32_a_t*)T2[u.temp[1][1]])
^ *((u32_a_t*)T3[u.temp[2][2]])
^ *((u32_a_t*)T4[u.temp[3][3]]));
*((u32_a_t*)(b + 4)) = (*((u32_a_t*)T1[u.temp[1][0]])
^ *((u32_a_t*)T2[u.temp[2][1]])
^ *((u32_a_t*)T3[u.temp[3][2]])
^ *((u32_a_t*)T4[u.temp[0][3]]));
*((u32_a_t*)(b + 8)) = (*((u32_a_t*)T1[u.temp[2][0]])
^ *((u32_a_t*)T2[u.temp[3][1]])
^ *((u32_a_t*)T3[u.temp[0][2]])
^ *((u32_a_t*)T4[u.temp[1][3]]));
*((u32_a_t*)(b +12)) = (*((u32_a_t*)T1[u.temp[3][0]])
^ *((u32_a_t*)T2[u.temp[0][1]])
^ *((u32_a_t*)T3[u.temp[1][2]])
^ *((u32_a_t*)T4[u.temp[2][3]]));
for (r = 1; r < rounds-1; r++)
{
*((u32_a_t*)u.temp[0]) = *((u32_a_t*)(b )) ^ *((u32_a_t*)rk[r][0]);
*((u32_a_t*)u.temp[1]) = *((u32_a_t*)(b+ 4)) ^ *((u32_a_t*)rk[r][1]);
*((u32_a_t*)u.temp[2]) = *((u32_a_t*)(b+ 8)) ^ *((u32_a_t*)rk[r][2]);
*((u32_a_t*)u.temp[3]) = *((u32_a_t*)(b+12)) ^ *((u32_a_t*)rk[r][3]);
*((u32_a_t*)(b )) = (*((u32_a_t*)T1[u.temp[0][0]])
^ *((u32_a_t*)T2[u.temp[1][1]])
^ *((u32_a_t*)T3[u.temp[2][2]])
^ *((u32_a_t*)T4[u.temp[3][3]]));
*((u32_a_t*)(b + 4)) = (*((u32_a_t*)T1[u.temp[1][0]])
^ *((u32_a_t*)T2[u.temp[2][1]])
^ *((u32_a_t*)T3[u.temp[3][2]])
^ *((u32_a_t*)T4[u.temp[0][3]]));
*((u32_a_t*)(b + 8)) = (*((u32_a_t*)T1[u.temp[2][0]])
^ *((u32_a_t*)T2[u.temp[3][1]])
^ *((u32_a_t*)T3[u.temp[0][2]])
^ *((u32_a_t*)T4[u.temp[1][3]]));
*((u32_a_t*)(b +12)) = (*((u32_a_t*)T1[u.temp[3][0]])
^ *((u32_a_t*)T2[u.temp[0][1]])
^ *((u32_a_t*)T3[u.temp[1][2]])
^ *((u32_a_t*)T4[u.temp[2][3]]));
}
/* Last round is special. */
*((u32_a_t*)u.temp[0]) = *((u32_a_t*)(b )) ^ *((u32_a_t*)rk[rounds-1][0]);
*((u32_a_t*)u.temp[1]) = *((u32_a_t*)(b+ 4)) ^ *((u32_a_t*)rk[rounds-1][1]);
*((u32_a_t*)u.temp[2]) = *((u32_a_t*)(b+ 8)) ^ *((u32_a_t*)rk[rounds-1][2]);
*((u32_a_t*)u.temp[3]) = *((u32_a_t*)(b+12)) ^ *((u32_a_t*)rk[rounds-1][3]);
b[ 0] = T1[u.temp[0][0]][1];
b[ 1] = T1[u.temp[1][1]][1];
b[ 2] = T1[u.temp[2][2]][1];
b[ 3] = T1[u.temp[3][3]][1];
b[ 4] = T1[u.temp[1][0]][1];
b[ 5] = T1[u.temp[2][1]][1];
b[ 6] = T1[u.temp[3][2]][1];
b[ 7] = T1[u.temp[0][3]][1];
b[ 8] = T1[u.temp[2][0]][1];
b[ 9] = T1[u.temp[3][1]][1];
b[10] = T1[u.temp[0][2]][1];
b[11] = T1[u.temp[1][3]][1];
b[12] = T1[u.temp[3][0]][1];
b[13] = T1[u.temp[0][1]][1];
b[14] = T1[u.temp[1][2]][1];
b[15] = T1[u.temp[2][3]][1];
*((u32_a_t*)(b )) ^= *((u32_a_t*)rk[rounds][0]);
*((u32_a_t*)(b+ 4)) ^= *((u32_a_t*)rk[rounds][1]);
*((u32_a_t*)(b+ 8)) ^= *((u32_a_t*)rk[rounds][2]);
*((u32_a_t*)(b+12)) ^= *((u32_a_t*)rk[rounds][3]);
#undef rk
#endif /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/
}
static void
do_encrypt (const RIJNDAEL_context *ctx,
unsigned char *bx, const unsigned char *ax)
{
#if !defined(USE_AMD64_ASM) && !defined(USE_ARMV6_ASM)
/* BX and AX are not necessary correctly aligned. Thus we might
need to copy them here. We try to align to a 16 bytes. */
if (((size_t)ax & 0x0f) || ((size_t)bx & 0x0f))
{
union
{
u32 dummy[4];
byte a[16] ATTR_ALIGNED_16;
} a;
union
{
u32 dummy[4];
byte b[16] ATTR_ALIGNED_16;
} b;
memcpy (a.a, ax, 16);
do_encrypt_aligned (ctx, b.b, a.a);
memcpy (bx, b.b, 16);
}
else
#endif /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/
{
do_encrypt_aligned (ctx, bx, ax);
}
}
/* Encrypt or decrypt one block using the padlock engine. A and B may
be the same. */
#ifdef USE_PADLOCK
static void
do_padlock (const RIJNDAEL_context *ctx, int decrypt_flag,
unsigned char *bx, const unsigned char *ax)
{
/* BX and AX are not necessary correctly aligned. Thus we need to
copy them here. */
unsigned char a[16] __attribute__ ((aligned (16)));
unsigned char b[16] __attribute__ ((aligned (16)));
unsigned int cword[4] __attribute__ ((aligned (16)));
int blocks;
/* The control word fields are:
127:12 11:10 9 8 7 6 5 4 3:0
RESERVED KSIZE CRYPT INTER KEYGN CIPHR ALIGN DGEST ROUND */
cword[0] = (ctx->rounds & 15); /* (The mask is just a safeguard.) */
cword[1] = 0;
cword[2] = 0;
cword[3] = 0;
if (decrypt_flag)
cword[0] |= 0x00000200;
memcpy (a, ax, 16);
blocks = 1; /* Init counter for just one block. */
#ifdef __x86_64__
asm volatile
("pushfq\n\t" /* Force key reload. */
"popfq\n\t"
".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t" /* REP XCRYPT ECB. */
: /* No output */
: "S" (a), "D" (b), "d" (cword), "b" (ctx->padlockkey), "c" (blocks)
: "cc", "memory"
);
#else
asm volatile
("pushfl\n\t" /* Force key reload. */
"popfl\n\t"
"xchg %3, %%ebx\n\t" /* Load key. */
".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t" /* REP XCRYPT ECB. */
"xchg %3, %%ebx\n" /* Restore GOT register. */
: /* No output */
: "S" (a), "D" (b), "d" (cword), "r" (ctx->padlockkey), "c" (blocks)
: "cc", "memory"
);
#endif
memcpy (bx, b, 16);
}
#endif /*USE_PADLOCK*/
#ifdef USE_AESNI
/* Encrypt one block using the Intel AES-NI instructions. A and B may
be the same; they need to be properly aligned to 16 bytes.
Our problem here is that gcc does not allow the "x" constraint for
SSE registers in asm unless you compile with -msse. The common
wisdom is to use a separate file for SSE instructions and build it
separately. This would require a lot of extra build system stuff,
similar to what we do in mpi/ for the asm stuff. What we do
instead is to use standard registers and a bit more of plain asm
which copies the data and key stuff to the SSE registers and later
back. If we decide to implement some block modes with parallelized
AES instructions, it might indeed be better to use plain asm ala
mpi/. */
static void
do_aesni_enc_aligned (const RIJNDAEL_context *ctx,
unsigned char *b, const unsigned char *a)
{
#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t"
#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t"
/* Note: For now we relax the alignment requirement for A and B: It
does not make much difference because in many case we would need
to memcpy them to an extra buffer; using the movdqu is much faster
that memcpy and movdqa. For CFB we know that the IV is properly
aligned but that is a special case. We should better implement
CFB direct in asm. */
asm volatile ("movdqu %[src], %%xmm0\n\t" /* xmm0 := *a */
"movdqa (%[key]), %%xmm1\n\t" /* xmm1 := key[0] */
"pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */
"movdqa 0x10(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x20(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x30(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x40(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x50(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x60(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x70(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x80(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x90(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0xa0(%[key]), %%xmm1\n\t"
"cmpl $10, %[rounds]\n\t"
"jz .Lenclast%=\n\t"
aesenc_xmm1_xmm0
"movdqa 0xb0(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0xc0(%[key]), %%xmm1\n\t"
"cmpl $12, %[rounds]\n\t"
"jz .Lenclast%=\n\t"
aesenc_xmm1_xmm0
"movdqa 0xd0(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0xe0(%[key]), %%xmm1\n"
".Lenclast%=:\n\t"
aesenclast_xmm1_xmm0
"movdqu %%xmm0, %[dst]\n"
: [dst] "=m" (*b)
: [src] "m" (*a),
[key] "r" (ctx->keyschenc),
[rounds] "r" (ctx->rounds)
: "cc", "memory");
#undef aesenc_xmm1_xmm0
#undef aesenclast_xmm1_xmm0
}
static void
do_aesni_dec_aligned (const RIJNDAEL_context *ctx,
unsigned char *b, const unsigned char *a)
{
#define aesdec_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xde, 0xc1\n\t"
#define aesdeclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xc1\n\t"
asm volatile ("movdqu %[src], %%xmm0\n\t" /* xmm0 := *a */
"movdqa (%[key]), %%xmm1\n\t"
"pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */
"movdqa 0x10(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0x20(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0x30(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0x40(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0x50(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0x60(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0x70(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0x80(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0x90(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0xa0(%[key]), %%xmm1\n\t"
"cmpl $10, %[rounds]\n\t"
"jz .Ldeclast%=\n\t"
aesdec_xmm1_xmm0
"movdqa 0xb0(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0xc0(%[key]), %%xmm1\n\t"
"cmpl $12, %[rounds]\n\t"
"jz .Ldeclast%=\n\t"
aesdec_xmm1_xmm0
"movdqa 0xd0(%[key]), %%xmm1\n\t"
aesdec_xmm1_xmm0
"movdqa 0xe0(%[key]), %%xmm1\n"
".Ldeclast%=:\n\t"
aesdeclast_xmm1_xmm0
"movdqu %%xmm0, %[dst]\n"
: [dst] "=m" (*b)
: [src] "m" (*a),
[key] "r" (ctx->keyschdec),
[rounds] "r" (ctx->rounds)
: "cc", "memory");
#undef aesdec_xmm1_xmm0
#undef aesdeclast_xmm1_xmm0
}
/* Encrypt four blocks using the Intel AES-NI instructions. Blocks are input
* and output through SSE registers xmm1 to xmm4. */
static void
do_aesni_enc_vec4 (const RIJNDAEL_context *ctx)
{
#define aesenc_xmm0_xmm1 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc8\n\t"
#define aesenc_xmm0_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd0\n\t"
#define aesenc_xmm0_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd8\n\t"
#define aesenc_xmm0_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xe0\n\t"
#define aesenclast_xmm0_xmm1 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc8\n\t"
#define aesenclast_xmm0_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd0\n\t"
#define aesenclast_xmm0_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd8\n\t"
#define aesenclast_xmm0_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xe0\n\t"
asm volatile ("movdqa (%[key]), %%xmm0\n\t"
"pxor %%xmm0, %%xmm1\n\t" /* xmm1 ^= key[0] */
"pxor %%xmm0, %%xmm2\n\t" /* xmm2 ^= key[0] */
"pxor %%xmm0, %%xmm3\n\t" /* xmm3 ^= key[0] */
"pxor %%xmm0, %%xmm4\n\t" /* xmm4 ^= key[0] */
"movdqa 0x10(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0x20(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0x30(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0x40(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0x50(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0x60(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0x70(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0x80(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0x90(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0xa0(%[key]), %%xmm0\n\t"
"cmpl $10, %[rounds]\n\t"
"jz .Ldeclast%=\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0xb0(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0xc0(%[key]), %%xmm0\n\t"
"cmpl $12, %[rounds]\n\t"
"jz .Ldeclast%=\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0xd0(%[key]), %%xmm0\n\t"
aesenc_xmm0_xmm1
aesenc_xmm0_xmm2
aesenc_xmm0_xmm3
aesenc_xmm0_xmm4
"movdqa 0xe0(%[key]), %%xmm0\n"
".Ldeclast%=:\n\t"
aesenclast_xmm0_xmm1
aesenclast_xmm0_xmm2
aesenclast_xmm0_xmm3
aesenclast_xmm0_xmm4
: /* no output */
: [key] "r" (ctx->keyschenc),
[rounds] "r" (ctx->rounds)
: "cc", "memory");
#undef aesenc_xmm0_xmm1
#undef aesenc_xmm0_xmm2
#undef aesenc_xmm0_xmm3
#undef aesenc_xmm0_xmm4
#undef aesenclast_xmm0_xmm1
#undef aesenclast_xmm0_xmm2
#undef aesenclast_xmm0_xmm3
#undef aesenclast_xmm0_xmm4
}
/* Decrypt four blocks using the Intel AES-NI instructions. Blocks are input
* and output through SSE registers xmm1 to xmm4. */
static void
do_aesni_dec_vec4 (const RIJNDAEL_context *ctx)
{
#define aesdec_xmm0_xmm1 ".byte 0x66, 0x0f, 0x38, 0xde, 0xc8\n\t"
#define aesdec_xmm0_xmm2 ".byte 0x66, 0x0f, 0x38, 0xde, 0xd0\n\t"
#define aesdec_xmm0_xmm3 ".byte 0x66, 0x0f, 0x38, 0xde, 0xd8\n\t"
#define aesdec_xmm0_xmm4 ".byte 0x66, 0x0f, 0x38, 0xde, 0xe0\n\t"
#define aesdeclast_xmm0_xmm1 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xc8\n\t"
#define aesdeclast_xmm0_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xd0\n\t"
#define aesdeclast_xmm0_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xd8\n\t"
#define aesdeclast_xmm0_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xe0\n\t"
asm volatile ("movdqa (%[key]), %%xmm0\n\t"
"pxor %%xmm0, %%xmm1\n\t" /* xmm1 ^= key[0] */
"pxor %%xmm0, %%xmm2\n\t" /* xmm2 ^= key[0] */
"pxor %%xmm0, %%xmm3\n\t" /* xmm3 ^= key[0] */
"pxor %%xmm0, %%xmm4\n\t" /* xmm4 ^= key[0] */
"movdqa 0x10(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0x20(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0x30(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0x40(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0x50(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0x60(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0x70(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0x80(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0x90(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0xa0(%[key]), %%xmm0\n\t"
"cmpl $10, %[rounds]\n\t"
"jz .Ldeclast%=\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0xb0(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0xc0(%[key]), %%xmm0\n\t"
"cmpl $12, %[rounds]\n\t"
"jz .Ldeclast%=\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0xd0(%[key]), %%xmm0\n\t"
aesdec_xmm0_xmm1
aesdec_xmm0_xmm2
aesdec_xmm0_xmm3
aesdec_xmm0_xmm4
"movdqa 0xe0(%[key]), %%xmm0\n"
".Ldeclast%=:\n\t"
aesdeclast_xmm0_xmm1
aesdeclast_xmm0_xmm2
aesdeclast_xmm0_xmm3
aesdeclast_xmm0_xmm4
: /* no output */
: [key] "r" (ctx->keyschdec),
[rounds] "r" (ctx->rounds)
: "cc", "memory");
#undef aesdec_xmm0_xmm1
#undef aesdec_xmm0_xmm2
#undef aesdec_xmm0_xmm3
#undef aesdec_xmm0_xmm4
#undef aesdeclast_xmm0_xmm1
#undef aesdeclast_xmm0_xmm2
#undef aesdeclast_xmm0_xmm3
#undef aesdeclast_xmm0_xmm4
}
/* Perform a CFB encryption or decryption round using the
initialization vector IV and the input block A. Write the result
to the output block B and update IV. IV needs to be 16 byte
aligned. */
static void
do_aesni_cfb (const RIJNDAEL_context *ctx, int decrypt_flag,
unsigned char *iv, unsigned char *b, const unsigned char *a)
{
#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t"
#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t"
asm volatile ("movdqa %[iv], %%xmm0\n\t" /* xmm0 := IV */
"movdqa (%[key]), %%xmm1\n\t" /* xmm1 := key[0] */
"pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */
"movdqa 0x10(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x20(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x30(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x40(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x50(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x60(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x70(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x80(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x90(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0xa0(%[key]), %%xmm1\n\t"
"cmpl $10, %[rounds]\n\t"
"jz .Lenclast%=\n\t"
aesenc_xmm1_xmm0
"movdqa 0xb0(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0xc0(%[key]), %%xmm1\n\t"
"cmpl $12, %[rounds]\n\t"
"jz .Lenclast%=\n\t"
aesenc_xmm1_xmm0
"movdqa 0xd0(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0xe0(%[key]), %%xmm1\n"
".Lenclast%=:\n\t"
aesenclast_xmm1_xmm0
"movdqu %[src], %%xmm1\n\t" /* Save input. */
"pxor %%xmm1, %%xmm0\n\t" /* xmm0 = input ^ IV */
"cmpl $1, %[decrypt]\n\t"
"jz .Ldecrypt_%=\n\t"
"movdqa %%xmm0, %[iv]\n\t" /* [encrypt] Store IV. */
"jmp .Lleave_%=\n"
".Ldecrypt_%=:\n\t"
"movdqa %%xmm1, %[iv]\n" /* [decrypt] Store IV. */
".Lleave_%=:\n\t"
"movdqu %%xmm0, %[dst]\n" /* Store output. */
: [iv] "+m" (*iv), [dst] "=m" (*b)
: [src] "m" (*a),
[key] "r" (ctx->keyschenc),
[rounds] "g" (ctx->rounds),
[decrypt] "m" (decrypt_flag)
: "cc", "memory");
#undef aesenc_xmm1_xmm0
#undef aesenclast_xmm1_xmm0
}
/* Perform a CTR encryption round using the counter CTR and the input
block A. Write the result to the output block B and update CTR.
CTR needs to be a 16 byte aligned little-endian value. */
static void
do_aesni_ctr (const RIJNDAEL_context *ctx,
unsigned char *ctr, unsigned char *b, const unsigned char *a)
{
#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t"
#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t"
static unsigned char be_mask[16] __attribute__ ((aligned (16))) =
{ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
asm volatile ("movdqa (%[ctr]), %%xmm0\n\t" /* xmm0, xmm2 := CTR */
"movaps %%xmm0, %%xmm2\n\t"
"pcmpeqd %%xmm1, %%xmm1\n\t"
"psrldq $8, %%xmm1\n\t" /* xmm1 = -1 */
"pshufb %[mask], %%xmm2\n\t"
"psubq %%xmm1, %%xmm2\n\t" /* xmm2++ (big endian) */
/* detect if 64-bit carry handling is needed */
"cmpl $0xffffffff, 8(%[ctr])\n\t"
"jne .Lno_carry%=\n\t"
"cmpl $0xffffffff, 12(%[ctr])\n\t"
"jne .Lno_carry%=\n\t"
"pslldq $8, %%xmm1\n\t" /* move lower 64-bit to high */
"psubq %%xmm1, %%xmm2\n\t" /* add carry to upper 64bits */
".Lno_carry%=:\n\t"
"pshufb %[mask], %%xmm2\n\t"
"movdqa %%xmm2, (%[ctr])\n" /* Update CTR. */
"movdqa (%[key]), %%xmm1\n\t" /* xmm1 := key[0] */
"pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */
"movdqa 0x10(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x20(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x30(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x40(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x50(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x60(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x70(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x80(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0x90(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0xa0(%[key]), %%xmm1\n\t"
"cmpl $10, %[rounds]\n\t"
"jz .Lenclast%=\n\t"
aesenc_xmm1_xmm0
"movdqa 0xb0(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0xc0(%[key]), %%xmm1\n\t"
"cmpl $12, %[rounds]\n\t"
"jz .Lenclast%=\n\t"
aesenc_xmm1_xmm0
"movdqa 0xd0(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
"movdqa 0xe0(%[key]), %%xmm1\n"
".Lenclast%=:\n\t"
aesenclast_xmm1_xmm0
"movdqu %[src], %%xmm1\n\t" /* xmm1 := input */
"pxor %%xmm1, %%xmm0\n\t" /* EncCTR ^= input */
"movdqu %%xmm0, %[dst]" /* Store EncCTR. */
: [dst] "=m" (*b)
: [src] "m" (*a),
[ctr] "r" (ctr),
[key] "r" (ctx->keyschenc),
[rounds] "g" (ctx->rounds),
[mask] "m" (*be_mask)
: "cc", "memory");
#undef aesenc_xmm1_xmm0
#undef aesenclast_xmm1_xmm0
}
/* Four blocks at a time variant of do_aesni_ctr. */
static void
do_aesni_ctr_4 (const RIJNDAEL_context *ctx,
unsigned char *ctr, unsigned char *b, const unsigned char *a)
{
#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t"
#define aesenc_xmm1_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd1\n\t"
#define aesenc_xmm1_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd9\n\t"
#define aesenc_xmm1_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xe1\n\t"
#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t"
#define aesenclast_xmm1_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd1\n\t"
#define aesenclast_xmm1_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd9\n\t"
#define aesenclast_xmm1_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xe1\n\t"
static unsigned char be_mask[16] __attribute__ ((aligned (16))) =
{ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
/* Register usage:
esi keyschedule
xmm0 CTR-0
xmm1 temp / round key
xmm2 CTR-1
xmm3 CTR-2
xmm4 CTR-3
xmm5 temp
*/
asm volatile ("movdqa (%[ctr]), %%xmm0\n\t" /* xmm0, xmm2 := CTR */
"movaps %%xmm0, %%xmm2\n\t"
"pcmpeqd %%xmm1, %%xmm1\n\t"
"psrldq $8, %%xmm1\n\t" /* xmm1 = -1 */
"pshufb %[mask], %%xmm2\n\t" /* xmm2 := le(xmm2) */
"psubq %%xmm1, %%xmm2\n\t" /* xmm2++ */
"movaps %%xmm2, %%xmm3\n\t" /* xmm3 := xmm2 */
"psubq %%xmm1, %%xmm3\n\t" /* xmm3++ */
"movaps %%xmm3, %%xmm4\n\t" /* xmm4 := xmm3 */
"psubq %%xmm1, %%xmm4\n\t" /* xmm4++ */
"movaps %%xmm4, %%xmm5\n\t" /* xmm5 := xmm4 */
"psubq %%xmm1, %%xmm5\n\t" /* xmm5++ */
/* detect if 64-bit carry handling is needed */
"cmpl $0xffffffff, 8(%[ctr])\n\t"
"jne .Lno_carry%=\n\t"
"movl 12(%[ctr]), %%esi\n\t"
"bswapl %%esi\n\t"
"cmpl $0xfffffffc, %%esi\n\t"
"jb .Lno_carry%=\n\t" /* no carry */
"pslldq $8, %%xmm1\n\t" /* move lower 64-bit to high */
"je .Lcarry_xmm5%=\n\t" /* esi == 0xfffffffc */
"cmpl $0xfffffffe, %%esi\n\t"
"jb .Lcarry_xmm4%=\n\t" /* esi == 0xfffffffd */
"je .Lcarry_xmm3%=\n\t" /* esi == 0xfffffffe */
/* esi == 0xffffffff */
"psubq %%xmm1, %%xmm2\n\t"
".Lcarry_xmm3%=:\n\t"
"psubq %%xmm1, %%xmm3\n\t"
".Lcarry_xmm4%=:\n\t"
"psubq %%xmm1, %%xmm4\n\t"
".Lcarry_xmm5%=:\n\t"
"psubq %%xmm1, %%xmm5\n\t"
".Lno_carry%=:\n\t"
"pshufb %[mask], %%xmm2\n\t" /* xmm2 := be(xmm2) */
"pshufb %[mask], %%xmm3\n\t" /* xmm3 := be(xmm3) */
"pshufb %[mask], %%xmm4\n\t" /* xmm4 := be(xmm4) */
"pshufb %[mask], %%xmm5\n\t" /* xmm5 := be(xmm5) */
"movdqa %%xmm5, (%[ctr])\n" /* Update CTR. */
"movdqa (%[key]), %%xmm1\n\t" /* xmm1 := key[0] */
"pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */
"pxor %%xmm1, %%xmm2\n\t" /* xmm2 ^= key[0] */
"pxor %%xmm1, %%xmm3\n\t" /* xmm3 ^= key[0] */
"pxor %%xmm1, %%xmm4\n\t" /* xmm4 ^= key[0] */
"movdqa 0x10(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0x20(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0x30(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0x40(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0x50(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0x60(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0x70(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0x80(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0x90(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0xa0(%[key]), %%xmm1\n\t"
"cmpl $10, %[rounds]\n\t"
"jz .Lenclast%=\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0xb0(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0xc0(%[key]), %%xmm1\n\t"
"cmpl $12, %[rounds]\n\t"
"jz .Lenclast%=\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0xd0(%[key]), %%xmm1\n\t"
aesenc_xmm1_xmm0
aesenc_xmm1_xmm2
aesenc_xmm1_xmm3
aesenc_xmm1_xmm4
"movdqa 0xe0(%[key]), %%xmm1\n"
".Lenclast%=:\n\t"
aesenclast_xmm1_xmm0
aesenclast_xmm1_xmm2
aesenclast_xmm1_xmm3
aesenclast_xmm1_xmm4
"movdqu (%[src]), %%xmm1\n\t" /* Get block 1. */
"pxor %%xmm1, %%xmm0\n\t" /* EncCTR-1 ^= input */
"movdqu %%xmm0, (%[dst])\n\t" /* Store block 1 */
"movdqu 16(%[src]), %%xmm1\n\t" /* Get block 2. */
"pxor %%xmm1, %%xmm2\n\t" /* EncCTR-2 ^= input */
"movdqu %%xmm2, 16(%[dst])\n\t" /* Store block 2. */
"movdqu 32(%[src]), %%xmm1\n\t" /* Get block 3. */
"pxor %%xmm1, %%xmm3\n\t" /* EncCTR-3 ^= input */
"movdqu %%xmm3, 32(%[dst])\n\t" /* Store block 3. */
"movdqu 48(%[src]), %%xmm1\n\t" /* Get block 4. */
"pxor %%xmm1, %%xmm4\n\t" /* EncCTR-4 ^= input */
"movdqu %%xmm4, 48(%[dst])" /* Store block 4. */
:
: [ctr] "r" (ctr),
[src] "r" (a),
[dst] "r" (b),
[key] "r" (ctx->keyschenc),
[rounds] "g" (ctx->rounds),
[mask] "m" (*be_mask)
: "%esi", "cc", "memory");
#undef aesenc_xmm1_xmm0
#undef aesenc_xmm1_xmm2
#undef aesenc_xmm1_xmm3
#undef aesenc_xmm1_xmm4
#undef aesenclast_xmm1_xmm0
#undef aesenclast_xmm1_xmm2
#undef aesenclast_xmm1_xmm3
#undef aesenclast_xmm1_xmm4
}
static void
do_aesni (RIJNDAEL_context *ctx, int decrypt_flag,
unsigned char *bx, const unsigned char *ax)
{
if (decrypt_flag)
{
if (!ctx->decryption_prepared )
{
prepare_decryption ( ctx );
ctx->decryption_prepared = 1;
}
do_aesni_dec_aligned (ctx, bx, ax);
}
else
do_aesni_enc_aligned (ctx, bx, ax);
}
#endif /*USE_AESNI*/
static unsigned int
rijndael_encrypt (void *context, byte *b, const byte *a)
{
RIJNDAEL_context *ctx = context;
unsigned int burn_stack;
if (0)
;
#ifdef USE_PADLOCK
else if (ctx->use_padlock)
{
do_padlock (ctx, 0, b, a);
burn_stack = (48 + 15 /* possible padding for alignment */);
}
#endif /*USE_PADLOCK*/
#ifdef USE_AESNI
else if (ctx->use_aesni)
{
aesni_prepare ();
do_aesni (ctx, 0, b, a);
aesni_cleanup ();
burn_stack = 0;
}
#endif /*USE_AESNI*/
else
{
do_encrypt (ctx, b, a);
burn_stack = (56 + 2*sizeof(int));
}
return burn_stack;
}
/* Bulk encryption of complete blocks in CFB mode. Caller needs to
make sure that IV is aligned on an unsigned long boundary. This
function is only intended for the bulk encryption feature of
cipher.c. */
void
_gcry_aes_cfb_enc (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
RIJNDAEL_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
if (0)
;
#ifdef USE_PADLOCK
else if (ctx->use_padlock)
{
/* Fixme: Let Padlock do the CFBing. */
for ( ;nblocks; nblocks-- )
{
/* Encrypt the IV. */
do_padlock (ctx, 0, iv, iv);
/* XOR the input with the IV and store input into IV. */
buf_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE);
outbuf += BLOCKSIZE;
inbuf += BLOCKSIZE;
}
}
#endif /*USE_PADLOCK*/
#ifdef USE_AESNI
else if (ctx->use_aesni)
{
aesni_prepare ();
for ( ;nblocks; nblocks-- )
{
do_aesni_cfb (ctx, 0, iv, outbuf, inbuf);
outbuf += BLOCKSIZE;
inbuf += BLOCKSIZE;
}
aesni_cleanup ();
}
#endif /*USE_AESNI*/
else
{
for ( ;nblocks; nblocks-- )
{
/* Encrypt the IV. */
do_encrypt_aligned (ctx, iv, iv);
/* XOR the input with the IV and store input into IV. */
buf_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE);
outbuf += BLOCKSIZE;
inbuf += BLOCKSIZE;
}
}
_gcry_burn_stack (48 + 2*sizeof(int));
}
/* Bulk encryption of complete blocks in CBC mode. Caller needs to
make sure that IV is aligned on an unsigned long boundary. This
function is only intended for the bulk encryption feature of
cipher.c. */
void
_gcry_aes_cbc_enc (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks, int cbc_mac)
{
RIJNDAEL_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
#ifdef USE_AESNI
if (ctx->use_aesni)
aesni_prepare ();
#endif /*USE_AESNI*/
for ( ;nblocks; nblocks-- )
{
if (0)
;
#ifdef USE_AESNI
else if (ctx->use_aesni)
{
/* ~35% speed up on Sandy-Bridge when doing xoring and copying with
SSE registers. */
asm volatile ("movdqu %[iv], %%xmm0\n\t"
"movdqu %[inbuf], %%xmm1\n\t"
"pxor %%xmm0, %%xmm1\n\t"
"movdqu %%xmm1, %[outbuf]\n\t"
: /* No output */
: [iv] "m" (*iv),
[inbuf] "m" (*inbuf),
[outbuf] "m" (*outbuf)
: "memory" );
do_aesni (ctx, 0, outbuf, outbuf);
asm volatile ("movdqu %[outbuf], %%xmm0\n\t"
"movdqu %%xmm0, %[iv]\n\t"
: /* No output */
: [outbuf] "m" (*outbuf),
[iv] "m" (*iv)
: "memory" );
}
#endif /*USE_AESNI*/
else
{
buf_xor(outbuf, inbuf, iv, BLOCKSIZE);
if (0)
;
#ifdef USE_PADLOCK
else if (ctx->use_padlock)
do_padlock (ctx, 0, outbuf, outbuf);
#endif /*USE_PADLOCK*/
else
do_encrypt (ctx, outbuf, outbuf );
memcpy (iv, outbuf, BLOCKSIZE);
}
inbuf += BLOCKSIZE;
if (!cbc_mac)
outbuf += BLOCKSIZE;
}
#ifdef USE_AESNI
if (ctx->use_aesni)
aesni_cleanup ();
#endif /*USE_AESNI*/
_gcry_burn_stack (48 + 2*sizeof(int));
}
/* Bulk encryption of complete blocks in CTR mode. Caller needs to
make sure that CTR is aligned on a 16 byte boundary if AESNI; the
minimum alignment is for an u32. This function is only intended
for the bulk encryption feature of cipher.c. CTR is expected to be
of size BLOCKSIZE. */
void
_gcry_aes_ctr_enc (void *context, unsigned char *ctr,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
RIJNDAEL_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
int i;
if (0)
;
#ifdef USE_AESNI
else if (ctx->use_aesni)
{
aesni_prepare ();
for ( ;nblocks > 3 ; nblocks -= 4 )
{
do_aesni_ctr_4 (ctx, ctr, outbuf, inbuf);
outbuf += 4*BLOCKSIZE;
inbuf += 4*BLOCKSIZE;
}
for ( ;nblocks; nblocks-- )
{
do_aesni_ctr (ctx, ctr, outbuf, inbuf);
outbuf += BLOCKSIZE;
inbuf += BLOCKSIZE;
}
aesni_cleanup ();
aesni_cleanup_2_5 ();
}
#endif /*USE_AESNI*/
else
{
union { unsigned char x1[16]; u32 x32[4]; } tmp;
for ( ;nblocks; nblocks-- )
{
/* Encrypt the counter. */
do_encrypt_aligned (ctx, tmp.x1, ctr);
/* XOR the input with the encrypted counter and store in output. */
buf_xor(outbuf, tmp.x1, inbuf, BLOCKSIZE);
outbuf += BLOCKSIZE;
inbuf += BLOCKSIZE;
/* Increment the counter. */
for (i = BLOCKSIZE; i > 0; i--)
{
ctr[i-1]++;
if (ctr[i-1])
break;
}
}
}
_gcry_burn_stack (48 + 2*sizeof(int));
}
/* Decrypt one block. A and B need to be aligned on a 4 byte boundary
and the decryption must have been prepared. A and B may be the
same. */
static void
do_decrypt_aligned (RIJNDAEL_context *ctx,
unsigned char *b, const unsigned char *a)
{
#ifdef USE_AMD64_ASM
_gcry_aes_amd64_decrypt_block(ctx->keyschdec, b, a, ctx->rounds);
#elif defined(USE_ARMV6_ASM)
_gcry_aes_armv6_decrypt_block(ctx->keyschdec, b, a, ctx->rounds);
#else
#define rk (ctx->keyschdec)
int rounds = ctx->rounds;
int r;
union
{
u32 tempu32[4]; /* Force correct alignment. */
byte temp[4][4];
} u;
*((u32_a_t*)u.temp[0]) = *((u32_a_t*)(a )) ^ *((u32_a_t*)rk[rounds][0]);
*((u32_a_t*)u.temp[1]) = *((u32_a_t*)(a+ 4)) ^ *((u32_a_t*)rk[rounds][1]);
*((u32_a_t*)u.temp[2]) = *((u32_a_t*)(a+ 8)) ^ *((u32_a_t*)rk[rounds][2]);
*((u32_a_t*)u.temp[3]) = *((u32_a_t*)(a+12)) ^ *((u32_a_t*)rk[rounds][3]);
*((u32_a_t*)(b )) = (*((u32_a_t*)T5[u.temp[0][0]])
^ *((u32_a_t*)T6[u.temp[3][1]])
^ *((u32_a_t*)T7[u.temp[2][2]])
^ *((u32_a_t*)T8[u.temp[1][3]]));
*((u32_a_t*)(b+ 4)) = (*((u32_a_t*)T5[u.temp[1][0]])
^ *((u32_a_t*)T6[u.temp[0][1]])
^ *((u32_a_t*)T7[u.temp[3][2]])
^ *((u32_a_t*)T8[u.temp[2][3]]));
*((u32_a_t*)(b+ 8)) = (*((u32_a_t*)T5[u.temp[2][0]])
^ *((u32_a_t*)T6[u.temp[1][1]])
^ *((u32_a_t*)T7[u.temp[0][2]])
^ *((u32_a_t*)T8[u.temp[3][3]]));
*((u32_a_t*)(b+12)) = (*((u32_a_t*)T5[u.temp[3][0]])
^ *((u32_a_t*)T6[u.temp[2][1]])
^ *((u32_a_t*)T7[u.temp[1][2]])
^ *((u32_a_t*)T8[u.temp[0][3]]));
for (r = rounds-1; r > 1; r--)
{
*((u32_a_t*)u.temp[0]) = *((u32_a_t*)(b )) ^ *((u32_a_t*)rk[r][0]);
*((u32_a_t*)u.temp[1]) = *((u32_a_t*)(b+ 4)) ^ *((u32_a_t*)rk[r][1]);
*((u32_a_t*)u.temp[2]) = *((u32_a_t*)(b+ 8)) ^ *((u32_a_t*)rk[r][2]);
*((u32_a_t*)u.temp[3]) = *((u32_a_t*)(b+12)) ^ *((u32_a_t*)rk[r][3]);
*((u32_a_t*)(b )) = (*((u32_a_t*)T5[u.temp[0][0]])
^ *((u32_a_t*)T6[u.temp[3][1]])
^ *((u32_a_t*)T7[u.temp[2][2]])
^ *((u32_a_t*)T8[u.temp[1][3]]));
*((u32_a_t*)(b+ 4)) = (*((u32_a_t*)T5[u.temp[1][0]])
^ *((u32_a_t*)T6[u.temp[0][1]])
^ *((u32_a_t*)T7[u.temp[3][2]])
^ *((u32_a_t*)T8[u.temp[2][3]]));
*((u32_a_t*)(b+ 8)) = (*((u32_a_t*)T5[u.temp[2][0]])
^ *((u32_a_t*)T6[u.temp[1][1]])
^ *((u32_a_t*)T7[u.temp[0][2]])
^ *((u32_a_t*)T8[u.temp[3][3]]));
*((u32_a_t*)(b+12)) = (*((u32_a_t*)T5[u.temp[3][0]])
^ *((u32_a_t*)T6[u.temp[2][1]])
^ *((u32_a_t*)T7[u.temp[1][2]])
^ *((u32_a_t*)T8[u.temp[0][3]]));
}
/* Last round is special. */
*((u32_a_t*)u.temp[0]) = *((u32_a_t*)(b )) ^ *((u32_a_t*)rk[1][0]);
*((u32_a_t*)u.temp[1]) = *((u32_a_t*)(b+ 4)) ^ *((u32_a_t*)rk[1][1]);
*((u32_a_t*)u.temp[2]) = *((u32_a_t*)(b+ 8)) ^ *((u32_a_t*)rk[1][2]);
*((u32_a_t*)u.temp[3]) = *((u32_a_t*)(b+12)) ^ *((u32_a_t*)rk[1][3]);
b[ 0] = S5[u.temp[0][0]];
b[ 1] = S5[u.temp[3][1]];
b[ 2] = S5[u.temp[2][2]];
b[ 3] = S5[u.temp[1][3]];
b[ 4] = S5[u.temp[1][0]];
b[ 5] = S5[u.temp[0][1]];
b[ 6] = S5[u.temp[3][2]];
b[ 7] = S5[u.temp[2][3]];
b[ 8] = S5[u.temp[2][0]];
b[ 9] = S5[u.temp[1][1]];
b[10] = S5[u.temp[0][2]];
b[11] = S5[u.temp[3][3]];
b[12] = S5[u.temp[3][0]];
b[13] = S5[u.temp[2][1]];
b[14] = S5[u.temp[1][2]];
b[15] = S5[u.temp[0][3]];
*((u32_a_t*)(b )) ^= *((u32_a_t*)rk[0][0]);
*((u32_a_t*)(b+ 4)) ^= *((u32_a_t*)rk[0][1]);
*((u32_a_t*)(b+ 8)) ^= *((u32_a_t*)rk[0][2]);
*((u32_a_t*)(b+12)) ^= *((u32_a_t*)rk[0][3]);
#undef rk
#endif /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/
}
/* Decrypt one block. AX and BX may be the same. */
static void
do_decrypt (RIJNDAEL_context *ctx, byte *bx, const byte *ax)
{
if ( !ctx->decryption_prepared )
{
prepare_decryption ( ctx );
_gcry_burn_stack (64);
ctx->decryption_prepared = 1;
}
#if !defined(USE_AMD64_ASM) && !defined(USE_ARMV6_ASM)
/* BX and AX are not necessary correctly aligned. Thus we might
need to copy them here. We try to align to a 16 bytes. */
if (((size_t)ax & 0x0f) || ((size_t)bx & 0x0f))
{
union
{
u32 dummy[4];
byte a[16] ATTR_ALIGNED_16;
} a;
union
{
u32 dummy[4];
byte b[16] ATTR_ALIGNED_16;
} b;
memcpy (a.a, ax, 16);
do_decrypt_aligned (ctx, b.b, a.a);
memcpy (bx, b.b, 16);
}
else
#endif /*!USE_AMD64_ASM && !USE_ARMV6_ASM*/
{
do_decrypt_aligned (ctx, bx, ax);
}
}
static unsigned int
rijndael_decrypt (void *context, byte *b, const byte *a)
{
RIJNDAEL_context *ctx = context;
unsigned int burn_stack;
if (0)
;
#ifdef USE_PADLOCK
else if (ctx->use_padlock)
{
do_padlock (ctx, 1, b, a);
burn_stack = (48 + 2*sizeof(int) /* FIXME */);
}
#endif /*USE_PADLOCK*/
#ifdef USE_AESNI
else if (ctx->use_aesni)
{
aesni_prepare ();
do_aesni (ctx, 1, b, a);
aesni_cleanup ();
burn_stack = 0;
}
#endif /*USE_AESNI*/
else
{
do_decrypt (ctx, b, a);
burn_stack = (56+2*sizeof(int));
}
return burn_stack;
}
/* Bulk decryption of complete blocks in CFB mode. Caller needs to
make sure that IV is aligned on an unsigned long boundary. This
function is only intended for the bulk encryption feature of
cipher.c. */
void
_gcry_aes_cfb_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
RIJNDAEL_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
if (0)
;
#ifdef USE_PADLOCK
else if (ctx->use_padlock)
{
/* Fixme: Let Padlock do the CFBing. */
for ( ;nblocks; nblocks-- )
{
do_padlock (ctx, 0, iv, iv);
buf_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE);
outbuf += BLOCKSIZE;
inbuf += BLOCKSIZE;
}
}
#endif /*USE_PADLOCK*/
#ifdef USE_AESNI
else if (ctx->use_aesni)
{
aesni_prepare ();
/* CFB decryption can be parallelized */
for ( ;nblocks >= 4; nblocks -= 4)
{
asm volatile
("movdqu (%[iv]), %%xmm1\n\t" /* load input blocks */
"movdqu 0*16(%[inbuf]), %%xmm2\n\t"
"movdqu 1*16(%[inbuf]), %%xmm3\n\t"
"movdqu 2*16(%[inbuf]), %%xmm4\n\t"
"movdqu 3*16(%[inbuf]), %%xmm0\n\t" /* update IV */
"movdqu %%xmm0, (%[iv])\n\t"
: /* No output */
: [inbuf] "r" (inbuf), [iv] "r" (iv)
: "memory");
do_aesni_enc_vec4 (ctx);
asm volatile
("movdqu 0*16(%[inbuf]), %%xmm5\n\t"
"pxor %%xmm5, %%xmm1\n\t"
"movdqu %%xmm1, 0*16(%[outbuf])\n\t"
"movdqu 1*16(%[inbuf]), %%xmm5\n\t"
"pxor %%xmm5, %%xmm2\n\t"
"movdqu %%xmm2, 1*16(%[outbuf])\n\t"
"movdqu 2*16(%[inbuf]), %%xmm5\n\t"
"pxor %%xmm5, %%xmm3\n\t"
"movdqu %%xmm3, 2*16(%[outbuf])\n\t"
"movdqu 3*16(%[inbuf]), %%xmm5\n\t"
"pxor %%xmm5, %%xmm4\n\t"
"movdqu %%xmm4, 3*16(%[outbuf])\n\t"
: /* No output */
: [inbuf] "r" (inbuf),
[outbuf] "r" (outbuf)
: "memory");
outbuf += 4*BLOCKSIZE;
inbuf += 4*BLOCKSIZE;
}
for ( ;nblocks; nblocks-- )
{
do_aesni_cfb (ctx, 1, iv, outbuf, inbuf);
outbuf += BLOCKSIZE;
inbuf += BLOCKSIZE;
}
aesni_cleanup ();
aesni_cleanup_2_5 ();
}
#endif /*USE_AESNI*/
else
{
for ( ;nblocks; nblocks-- )
{
do_encrypt_aligned (ctx, iv, iv);
buf_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE);
outbuf += BLOCKSIZE;
inbuf += BLOCKSIZE;
}
}
_gcry_burn_stack (48 + 2*sizeof(int));
}
/* Bulk decryption of complete blocks in CBC mode. Caller needs to
make sure that IV is aligned on an unsigned long boundary. This
function is only intended for the bulk encryption feature of
cipher.c. */
void
_gcry_aes_cbc_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
RIJNDAEL_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char savebuf[BLOCKSIZE];
if (0)
;
#ifdef USE_AESNI
else if (ctx->use_aesni)
{
aesni_prepare ();
if (!ctx->decryption_prepared )
{
prepare_decryption ( ctx );
ctx->decryption_prepared = 1;
}
asm volatile
("movdqu %[iv], %%xmm5\n\t" /* use xmm5 as fast IV storage */
: /* No output */
: [iv] "m" (*iv)
: "memory");
for ( ;nblocks > 3 ; nblocks -= 4 )
{
asm volatile
("movdqu 0*16(%[inbuf]), %%xmm1\n\t" /* load input blocks */
"movdqu 1*16(%[inbuf]), %%xmm2\n\t"
"movdqu 2*16(%[inbuf]), %%xmm3\n\t"
"movdqu 3*16(%[inbuf]), %%xmm4\n\t"
: /* No output */
: [inbuf] "r" (inbuf)
: "memory");
do_aesni_dec_vec4 (ctx);
asm volatile
("pxor %%xmm5, %%xmm1\n\t" /* xor IV with output */
"movdqu 0*16(%[inbuf]), %%xmm5\n\t" /* load new IV */
"movdqu %%xmm1, 0*16(%[outbuf])\n\t"
"pxor %%xmm5, %%xmm2\n\t" /* xor IV with output */
"movdqu 1*16(%[inbuf]), %%xmm5\n\t" /* load new IV */
"movdqu %%xmm2, 1*16(%[outbuf])\n\t"
"pxor %%xmm5, %%xmm3\n\t" /* xor IV with output */
"movdqu 2*16(%[inbuf]), %%xmm5\n\t" /* load new IV */
"movdqu %%xmm3, 2*16(%[outbuf])\n\t"
"pxor %%xmm5, %%xmm4\n\t" /* xor IV with output */
"movdqu 3*16(%[inbuf]), %%xmm5\n\t" /* load new IV */
"movdqu %%xmm4, 3*16(%[outbuf])\n\t"
: /* No output */
: [inbuf] "r" (inbuf),
[outbuf] "r" (outbuf)
: "memory");
outbuf += 4*BLOCKSIZE;
inbuf += 4*BLOCKSIZE;
}
for ( ;nblocks; nblocks-- )
{
asm volatile
("movdqu %[inbuf], %%xmm2\n\t" /* use xmm2 as savebuf */
: /* No output */
: [inbuf] "m" (*inbuf)
: "memory");
/* uses only xmm0 and xmm1 */
do_aesni_dec_aligned (ctx, outbuf, inbuf);
asm volatile
("movdqu %[outbuf], %%xmm0\n\t"
"pxor %%xmm5, %%xmm0\n\t" /* xor IV with output */
"movdqu %%xmm0, %[outbuf]\n\t"
"movdqu %%xmm2, %%xmm5\n\t" /* store savebuf as new IV */
: /* No output */
: [outbuf] "m" (*outbuf)
: "memory");
outbuf += BLOCKSIZE;
inbuf += BLOCKSIZE;
}
asm volatile
("movdqu %%xmm5, %[iv]\n\t" /* store IV */
: /* No output */
: [iv] "m" (*iv)
: "memory");
aesni_cleanup ();
aesni_cleanup_2_5 ();
}
#endif /*USE_AESNI*/
else
for ( ;nblocks; nblocks-- )
{
/* We need to save INBUF away because it may be identical to
OUTBUF. */
memcpy (savebuf, inbuf, BLOCKSIZE);
if (0)
;
#ifdef USE_PADLOCK
else if (ctx->use_padlock)
do_padlock (ctx, 1, outbuf, inbuf);
#endif /*USE_PADLOCK*/
else
do_decrypt (ctx, outbuf, inbuf);
buf_xor(outbuf, outbuf, iv, BLOCKSIZE);
memcpy (iv, savebuf, BLOCKSIZE);
inbuf += BLOCKSIZE;
outbuf += BLOCKSIZE;
}
_gcry_burn_stack (48 + 2*sizeof(int) + BLOCKSIZE + 4*sizeof (char*));
}
/* Run the self-tests for AES 128. Returns NULL on success. */
static const char*
selftest_basic_128 (void)
{
RIJNDAEL_context ctx;
unsigned char scratch[16];
/* The test vectors are from the AES supplied ones; more or less
randomly taken from ecb_tbl.txt (I=42,81,14) */
#if 1
static const unsigned char plaintext_128[16] =
{
0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33,
0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A
};
static const unsigned char key_128[16] =
{
0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,0xF0,
0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA
};
static const unsigned char ciphertext_128[16] =
{
0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2,
0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD
};
#else
/* Test vectors from fips-197, appendix C. */
# warning debug test vectors in use
static const unsigned char plaintext_128[16] =
{
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff
};
static const unsigned char key_128[16] =
{
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
/* 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, */
/* 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c */
};
static const unsigned char ciphertext_128[16] =
{
0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30,
0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a
};
#endif
rijndael_setkey (&ctx, key_128, sizeof (key_128));
rijndael_encrypt (&ctx, scratch, plaintext_128);
if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128)))
return "AES-128 test encryption failed.";
rijndael_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext_128, sizeof (plaintext_128)))
return "AES-128 test decryption failed.";
return NULL;
}
/* Run the self-tests for AES 192. Returns NULL on success. */
static const char*
selftest_basic_192 (void)
{
RIJNDAEL_context ctx;
unsigned char scratch[16];
static unsigned char plaintext_192[16] =
{
0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4,
0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72
};
static unsigned char key_192[24] =
{
0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,
0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16,
0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20
};
static const unsigned char ciphertext_192[16] =
{
0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC,
0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA
};
rijndael_setkey (&ctx, key_192, sizeof(key_192));
rijndael_encrypt (&ctx, scratch, plaintext_192);
if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192)))
return "AES-192 test encryption failed.";
rijndael_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext_192, sizeof (plaintext_192)))
return "AES-192 test decryption failed.";
return NULL;
}
/* Run the self-tests for AES 256. Returns NULL on success. */
static const char*
selftest_basic_256 (void)
{
RIJNDAEL_context ctx;
unsigned char scratch[16];
static unsigned char plaintext_256[16] =
{
0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
};
static unsigned char key_256[32] =
{
0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10,
0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A,
0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24,
0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E
};
static const unsigned char ciphertext_256[16] =
{
0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71,
0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3
};
rijndael_setkey (&ctx, key_256, sizeof(key_256));
rijndael_encrypt (&ctx, scratch, plaintext_256);
if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256)))
return "AES-256 test encryption failed.";
rijndael_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext_256, sizeof (plaintext_256)))
return "AES-256 test decryption failed.";
return NULL;
}
/* Run the self-tests for AES-CTR-128, tests IV increment of bulk CTR
encryption. Returns NULL on success. */
static const char*
selftest_ctr_128 (void)
{
const int nblocks = 8+1;
const int blocksize = BLOCKSIZE;
const int context_size = sizeof(RIJNDAEL_context);
return _gcry_selftest_helper_ctr("AES", &rijndael_setkey,
&rijndael_encrypt, &_gcry_aes_ctr_enc, nblocks, blocksize,
context_size);
}
/* Run the self-tests for AES-CBC-128, tests bulk CBC decryption.
Returns NULL on success. */
static const char*
selftest_cbc_128 (void)
{
const int nblocks = 8+2;
const int blocksize = BLOCKSIZE;
const int context_size = sizeof(RIJNDAEL_context);
return _gcry_selftest_helper_cbc("AES", &rijndael_setkey,
&rijndael_encrypt, &_gcry_aes_cbc_dec, nblocks, blocksize,
context_size);
}
/* Run the self-tests for AES-CFB-128, tests bulk CFB decryption.
Returns NULL on success. */
static const char*
selftest_cfb_128 (void)
{
const int nblocks = 8+2;
const int blocksize = BLOCKSIZE;
const int context_size = sizeof(RIJNDAEL_context);
return _gcry_selftest_helper_cfb("AES", &rijndael_setkey,
&rijndael_encrypt, &_gcry_aes_cfb_dec, nblocks, blocksize,
context_size);
}
/* Run all the self-tests and return NULL on success. This function
is used for the on-the-fly self-tests. */
static const char *
selftest (void)
{
const char *r;
if ( (r = selftest_basic_128 ())
|| (r = selftest_basic_192 ())
|| (r = selftest_basic_256 ()) )
return r;
if ( (r = selftest_ctr_128 ()) )
return r;
if ( (r = selftest_cbc_128 ()) )
return r;
if ( (r = selftest_cfb_128 ()) )
return r;
return r;
}
/* SP800-38a.pdf for AES-128. */
static const char *
selftest_fips_128_38a (int requested_mode)
{
struct tv
{
int mode;
const unsigned char key[16];
const unsigned char iv[16];
struct
{
const unsigned char input[16];
const unsigned char output[16];
} data[4];
} tv[2] =
{
{
GCRY_CIPHER_MODE_CFB, /* F.3.13, CFB128-AES128 */
{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
{
{ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a },
{ 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20,
0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } },
{ { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 },
{ 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f,
0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b } },
{ { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef },
{ 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40,
0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf } },
{ { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
{ 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e,
0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6 } }
}
},
{
GCRY_CIPHER_MODE_OFB,
{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
{
{ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a },
{ 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20,
0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } },
{ { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 },
{ 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03,
0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25 } },
{ { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef },
{ 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6,
0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc } },
{ { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
{ 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78,
0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e } },
}
}
};
unsigned char scratch[16];
gpg_error_t err;
int tvi, idx;
gcry_cipher_hd_t hdenc = NULL;
gcry_cipher_hd_t hddec = NULL;
#define Fail(a) do { \
_gcry_cipher_close (hdenc); \
_gcry_cipher_close (hddec); \
return a; \
} while (0)
gcry_assert (sizeof tv[0].data[0].input == sizeof scratch);
gcry_assert (sizeof tv[0].data[0].output == sizeof scratch);
for (tvi=0; tvi < DIM (tv); tvi++)
if (tv[tvi].mode == requested_mode)
break;
if (tvi == DIM (tv))
Fail ("no test data for this mode");
err = _gcry_cipher_open (&hdenc, GCRY_CIPHER_AES, tv[tvi].mode, 0);
if (err)
Fail ("open");
err = _gcry_cipher_open (&hddec, GCRY_CIPHER_AES, tv[tvi].mode, 0);
if (err)
Fail ("open");
err = _gcry_cipher_setkey (hdenc, tv[tvi].key, sizeof tv[tvi].key);
if (!err)
err = _gcry_cipher_setkey (hddec, tv[tvi].key, sizeof tv[tvi].key);
if (err)
Fail ("set key");
err = _gcry_cipher_setiv (hdenc, tv[tvi].iv, sizeof tv[tvi].iv);
if (!err)
err = _gcry_cipher_setiv (hddec, tv[tvi].iv, sizeof tv[tvi].iv);
if (err)
Fail ("set IV");
for (idx=0; idx < DIM (tv[tvi].data); idx++)
{
err = _gcry_cipher_encrypt (hdenc, scratch, sizeof scratch,
tv[tvi].data[idx].input,
sizeof tv[tvi].data[idx].input);
if (err)
Fail ("encrypt command");
if (memcmp (scratch, tv[tvi].data[idx].output, sizeof scratch))
Fail ("encrypt mismatch");
err = _gcry_cipher_decrypt (hddec, scratch, sizeof scratch,
tv[tvi].data[idx].output,
sizeof tv[tvi].data[idx].output);
if (err)
Fail ("decrypt command");
if (memcmp (scratch, tv[tvi].data[idx].input, sizeof scratch))
Fail ("decrypt mismatch");
}
#undef Fail
_gcry_cipher_close (hdenc);
_gcry_cipher_close (hddec);
return NULL;
}
/* Complete selftest for AES-128 with all modes and driver code. */
static gpg_err_code_t
selftest_fips_128 (int extended, selftest_report_func_t report)
{
const char *what;
const char *errtxt;
what = "low-level";
errtxt = selftest_basic_128 ();
if (errtxt)
goto failed;
if (extended)
{
what = "cfb";
errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_CFB);
if (errtxt)
goto failed;
what = "ofb";
errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_OFB);
if (errtxt)
goto failed;
}
return 0; /* Succeeded. */
failed:
if (report)
report ("cipher", GCRY_CIPHER_AES128, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
/* Complete selftest for AES-192. */
static gpg_err_code_t
selftest_fips_192 (int extended, selftest_report_func_t report)
{
const char *what;
const char *errtxt;
(void)extended; /* No extended tests available. */
what = "low-level";
errtxt = selftest_basic_192 ();
if (errtxt)
goto failed;
return 0; /* Succeeded. */
failed:
if (report)
report ("cipher", GCRY_CIPHER_AES192, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
/* Complete selftest for AES-256. */
static gpg_err_code_t
selftest_fips_256 (int extended, selftest_report_func_t report)
{
const char *what;
const char *errtxt;
(void)extended; /* No extended tests available. */
what = "low-level";
errtxt = selftest_basic_256 ();
if (errtxt)
goto failed;
return 0; /* Succeeded. */
failed:
if (report)
report ("cipher", GCRY_CIPHER_AES256, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
/* Run a full self-test for ALGO and return 0 on success. */
static gpg_err_code_t
run_selftests (int algo, int extended, selftest_report_func_t report)
{
gpg_err_code_t ec;
switch (algo)
{
case GCRY_CIPHER_AES128:
ec = selftest_fips_128 (extended, report);
break;
case GCRY_CIPHER_AES192:
ec = selftest_fips_192 (extended, report);
break;
case GCRY_CIPHER_AES256:
ec = selftest_fips_256 (extended, report);
break;
default:
ec = GPG_ERR_CIPHER_ALGO;
break;
}
return ec;
}
static const char *rijndael_names[] =
{
"RIJNDAEL",
"AES128",
"AES-128",
NULL
};
static gcry_cipher_oid_spec_t rijndael_oids[] =
{
{ "2.16.840.1.101.3.4.1.1", GCRY_CIPHER_MODE_ECB },
{ "2.16.840.1.101.3.4.1.2", GCRY_CIPHER_MODE_CBC },
{ "2.16.840.1.101.3.4.1.3", GCRY_CIPHER_MODE_OFB },
{ "2.16.840.1.101.3.4.1.4", GCRY_CIPHER_MODE_CFB },
{ NULL }
};
gcry_cipher_spec_t _gcry_cipher_spec_aes =
{
- "AES", rijndael_names, rijndael_oids, 16, 128, sizeof (RIJNDAEL_context),
- rijndael_setkey, rijndael_encrypt, rijndael_decrypt
- };
-cipher_extra_spec_t _gcry_cipher_extraspec_aes =
- {
+ GCRY_CIPHER_AES, {0, 1},
+ "AES", rijndael_names, rijndael_oids, 16, 128,
+ sizeof (RIJNDAEL_context),
+ rijndael_setkey, rijndael_encrypt, rijndael_decrypt,
+ NULL, NULL,
run_selftests
};
+
static const char *rijndael192_names[] =
{
"RIJNDAEL192",
"AES-192",
NULL
};
static gcry_cipher_oid_spec_t rijndael192_oids[] =
{
{ "2.16.840.1.101.3.4.1.21", GCRY_CIPHER_MODE_ECB },
{ "2.16.840.1.101.3.4.1.22", GCRY_CIPHER_MODE_CBC },
{ "2.16.840.1.101.3.4.1.23", GCRY_CIPHER_MODE_OFB },
{ "2.16.840.1.101.3.4.1.24", GCRY_CIPHER_MODE_CFB },
{ NULL }
};
gcry_cipher_spec_t _gcry_cipher_spec_aes192 =
{
- "AES192", rijndael192_names, rijndael192_oids, 16, 192, sizeof (RIJNDAEL_context),
- rijndael_setkey, rijndael_encrypt, rijndael_decrypt
- };
-cipher_extra_spec_t _gcry_cipher_extraspec_aes192 =
- {
+ GCRY_CIPHER_AES192, {0, 1},
+ "AES192", rijndael192_names, rijndael192_oids, 16, 192,
+ sizeof (RIJNDAEL_context),
+ rijndael_setkey, rijndael_encrypt, rijndael_decrypt,
+ NULL, NULL,
run_selftests
};
+
static const char *rijndael256_names[] =
{
"RIJNDAEL256",
"AES-256",
NULL
};
static gcry_cipher_oid_spec_t rijndael256_oids[] =
{
{ "2.16.840.1.101.3.4.1.41", GCRY_CIPHER_MODE_ECB },
{ "2.16.840.1.101.3.4.1.42", GCRY_CIPHER_MODE_CBC },
{ "2.16.840.1.101.3.4.1.43", GCRY_CIPHER_MODE_OFB },
{ "2.16.840.1.101.3.4.1.44", GCRY_CIPHER_MODE_CFB },
{ NULL }
};
gcry_cipher_spec_t _gcry_cipher_spec_aes256 =
{
+ GCRY_CIPHER_AES256, {0, 1},
"AES256", rijndael256_names, rijndael256_oids, 16, 256,
sizeof (RIJNDAEL_context),
- rijndael_setkey, rijndael_encrypt, rijndael_decrypt
- };
-
-cipher_extra_spec_t _gcry_cipher_extraspec_aes256 =
- {
+ rijndael_setkey, rijndael_encrypt, rijndael_decrypt,
+ NULL, NULL,
run_selftests
};
diff --git a/cipher/salsa20.c b/cipher/salsa20.c
index 88f53725..6189bca9 100644
--- a/cipher/salsa20.c
+++ b/cipher/salsa20.c
@@ -1,409 +1,412 @@
/* salsa20.c - Bernstein's Salsa20 cipher
* Copyright (C) 2012 Simon Josefsson, Niels Möller
* Copyright (C) 2013 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* For a description of the algorithm, see:
* http://cr.yp.to/snuffle/spec.pdf
* http://cr.yp.to/snuffle/design.pdf
*/
/* The code is based on the code in Nettle
(git commit id 9d2d8ddaee35b91a4e1a32ae77cba04bea3480e7)
which in turn is based on
salsa20-ref.c version 20051118
D. J. Bernstein
Public domain.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "g10lib.h"
#include "cipher.h"
#include "bufhelp.h"
#define SALSA20_MIN_KEY_SIZE 16 /* Bytes. */
#define SALSA20_MAX_KEY_SIZE 32 /* Bytes. */
#define SALSA20_BLOCK_SIZE 64 /* Bytes. */
#define SALSA20_IV_SIZE 8 /* Bytes. */
#define SALSA20_INPUT_LENGTH 16 /* Bytes. */
/* Number of rounds. The standard uses 20 rounds. In any case the
number of rounds must be even. */
#define SALSA20_ROUNDS 20
#define SALSA20R12_ROUNDS 12
typedef struct
{
/* Indices 1-4 and 11-14 holds the key (two identical copies for the
shorter key size), indices 0, 5, 10, 15 are constant, indices 6, 7
are the IV, and indices 8, 9 are the block counter:
C K K K
K C I I
B B C K
K K K C
*/
u32 input[SALSA20_INPUT_LENGTH];
u32 pad[SALSA20_INPUT_LENGTH];
unsigned int unused; /* bytes in the pad. */
} SALSA20_context_t;
/* The masking of the right shift is needed to allow n == 0 (using
just 32 - n and 64 - n results in undefined behaviour). Most uses
of these macros use a constant and non-zero rotation count. */
#define ROTL32(n,x) (((x)<<(n)) | ((x)>>((-(n)&31))))
#define LE_SWAP32(v) le_bswap32(v)
#define LE_READ_UINT32(p) buf_get_le32(p)
static void salsa20_setiv (void *context, const byte *iv, unsigned int ivlen);
static const char *selftest (void);
#if 0
# define SALSA20_CORE_DEBUG(i) do { \
unsigned debug_j; \
for (debug_j = 0; debug_j < 16; debug_j++) \
{ \
if (debug_j == 0) \
fprintf(stderr, "%2d:", (i)); \
else if (debug_j % 4 == 0) \
fprintf(stderr, "\n "); \
fprintf(stderr, " %8x", pad[debug_j]); \
} \
fprintf(stderr, "\n"); \
} while (0)
#else
# define SALSA20_CORE_DEBUG(i)
#endif
#define QROUND(x0, x1, x2, x3) \
do { \
x1 ^= ROTL32 ( 7, x0 + x3); \
x2 ^= ROTL32 ( 9, x1 + x0); \
x3 ^= ROTL32 (13, x2 + x1); \
x0 ^= ROTL32 (18, x3 + x2); \
} while(0)
static void
salsa20_core (u32 *dst, const u32 *src, unsigned rounds)
{
u32 pad[SALSA20_INPUT_LENGTH];
unsigned int i;
memcpy (pad, src, sizeof(pad));
for (i = 0; i < rounds; i += 2)
{
SALSA20_CORE_DEBUG (i);
QROUND (pad[0], pad[4], pad[8], pad[12]);
QROUND (pad[5], pad[9], pad[13], pad[1] );
QROUND (pad[10], pad[14], pad[2], pad[6] );
QROUND (pad[15], pad[3], pad[7], pad[11]);
SALSA20_CORE_DEBUG (i+1);
QROUND (pad[0], pad[1], pad[2], pad[3] );
QROUND (pad[5], pad[6], pad[7], pad[4] );
QROUND (pad[10], pad[11], pad[8], pad[9] );
QROUND (pad[15], pad[12], pad[13], pad[14]);
}
SALSA20_CORE_DEBUG (i);
for (i = 0; i < SALSA20_INPUT_LENGTH; i++)
{
u32 t = pad[i] + src[i];
dst[i] = LE_SWAP32 (t);
}
}
#undef QROUND
#undef SALSA20_CORE_DEBUG
static gcry_err_code_t
salsa20_do_setkey (SALSA20_context_t *ctx,
const byte *key, unsigned int keylen)
{
static int initialized;
static const char *selftest_failed;
if (!initialized )
{
initialized = 1;
selftest_failed = selftest ();
if (selftest_failed)
log_error ("SALSA20 selftest failed (%s)\n", selftest_failed );
}
if (selftest_failed)
return GPG_ERR_SELFTEST_FAILED;
if (keylen != SALSA20_MIN_KEY_SIZE
&& keylen != SALSA20_MAX_KEY_SIZE)
return GPG_ERR_INV_KEYLEN;
/* These constants are the little endian encoding of the string
"expand 32-byte k". For the 128 bit variant, the "32" in that
string will be fixed up to "16". */
ctx->input[0] = 0x61707865; /* "apxe" */
ctx->input[5] = 0x3320646e; /* "3 dn" */
ctx->input[10] = 0x79622d32; /* "yb-2" */
ctx->input[15] = 0x6b206574; /* "k et" */
ctx->input[1] = LE_READ_UINT32(key + 0);
ctx->input[2] = LE_READ_UINT32(key + 4);
ctx->input[3] = LE_READ_UINT32(key + 8);
ctx->input[4] = LE_READ_UINT32(key + 12);
if (keylen == SALSA20_MAX_KEY_SIZE) /* 256 bits */
{
ctx->input[11] = LE_READ_UINT32(key + 16);
ctx->input[12] = LE_READ_UINT32(key + 20);
ctx->input[13] = LE_READ_UINT32(key + 24);
ctx->input[14] = LE_READ_UINT32(key + 28);
}
else /* 128 bits */
{
ctx->input[11] = ctx->input[1];
ctx->input[12] = ctx->input[2];
ctx->input[13] = ctx->input[3];
ctx->input[14] = ctx->input[4];
ctx->input[5] -= 0x02000000; /* Change to "1 dn". */
ctx->input[10] += 0x00000004; /* Change to "yb-6". */
}
/* We default to a zero nonce. */
salsa20_setiv (ctx, NULL, 0);
return 0;
}
static gcry_err_code_t
salsa20_setkey (void *context, const byte *key, unsigned int keylen)
{
SALSA20_context_t *ctx = (SALSA20_context_t *)context;
gcry_err_code_t rc = salsa20_do_setkey (ctx, key, keylen);
_gcry_burn_stack (300/* FIXME*/);
return rc;
}
static void
salsa20_setiv (void *context, const byte *iv, unsigned int ivlen)
{
SALSA20_context_t *ctx = (SALSA20_context_t *)context;
if (!iv)
{
ctx->input[6] = 0;
ctx->input[7] = 0;
}
else if (ivlen == SALSA20_IV_SIZE)
{
ctx->input[6] = LE_READ_UINT32(iv + 0);
ctx->input[7] = LE_READ_UINT32(iv + 4);
}
else
{
log_info ("WARNING: salsa20_setiv: bad ivlen=%u\n", ivlen);
ctx->input[6] = 0;
ctx->input[7] = 0;
}
/* Reset the block counter. */
ctx->input[8] = 0;
ctx->input[9] = 0;
/* Reset the unused pad bytes counter. */
ctx->unused = 0;
}
/* Note: This function requires LENGTH > 0. */
static void
salsa20_do_encrypt_stream (SALSA20_context_t *ctx,
byte *outbuf, const byte *inbuf,
unsigned int length, unsigned rounds)
{
if (ctx->unused)
{
unsigned char *p = (void*)ctx->pad;
unsigned int n;
gcry_assert (ctx->unused < SALSA20_BLOCK_SIZE);
n = ctx->unused;
if (n > length)
n = length;
buf_xor (outbuf, inbuf, p + SALSA20_BLOCK_SIZE - ctx->unused, n);
length -= n;
outbuf += n;
inbuf += n;
ctx->unused -= n;
if (!length)
return;
gcry_assert (!ctx->unused);
}
for (;;)
{
/* Create the next pad and bump the block counter. Note that it
is the user's duty to change to another nonce not later than
after 2^70 processed bytes. */
salsa20_core (ctx->pad, ctx->input, rounds);
if (!++ctx->input[8])
ctx->input[9]++;
if (length <= SALSA20_BLOCK_SIZE)
{
buf_xor (outbuf, inbuf, ctx->pad, length);
ctx->unused = SALSA20_BLOCK_SIZE - length;
return;
}
buf_xor (outbuf, inbuf, ctx->pad, SALSA20_BLOCK_SIZE);
length -= SALSA20_BLOCK_SIZE;
outbuf += SALSA20_BLOCK_SIZE;
inbuf += SALSA20_BLOCK_SIZE;
}
}
static void
salsa20_encrypt_stream (void *context,
byte *outbuf, const byte *inbuf, unsigned int length)
{
SALSA20_context_t *ctx = (SALSA20_context_t *)context;
if (length)
{
salsa20_do_encrypt_stream (ctx, outbuf, inbuf, length, SALSA20_ROUNDS);
_gcry_burn_stack (/* salsa20_do_encrypt_stream: */
2*sizeof (void*)
+ 3*sizeof (void*) + sizeof (unsigned int)
/* salsa20_core: */
+ 2*sizeof (void*)
+ 2*sizeof (void*)
+ 64
+ sizeof (unsigned int)
+ sizeof (u32)
);
}
}
static void
salsa20r12_encrypt_stream (void *context,
byte *outbuf, const byte *inbuf, unsigned int length)
{
SALSA20_context_t *ctx = (SALSA20_context_t *)context;
if (length)
{
salsa20_do_encrypt_stream (ctx, outbuf, inbuf, length, SALSA20R12_ROUNDS);
_gcry_burn_stack (/* salsa20_do_encrypt_stream: */
2*sizeof (void*)
+ 3*sizeof (void*) + sizeof (unsigned int)
/* salsa20_core: */
+ 2*sizeof (void*)
+ 2*sizeof (void*)
+ 64
+ sizeof (unsigned int)
+ sizeof (u32)
);
}
}
static const char*
selftest (void)
{
SALSA20_context_t ctx;
byte scratch[8+1];
static byte key_1[] =
{ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const byte nonce_1[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const byte plaintext_1[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const byte ciphertext_1[] =
{ 0xE3, 0xBE, 0x8F, 0xDD, 0x8B, 0xEC, 0xA2, 0xE3};
salsa20_setkey (&ctx, key_1, sizeof key_1);
salsa20_setiv (&ctx, nonce_1, sizeof nonce_1);
scratch[8] = 0;
salsa20_encrypt_stream (&ctx, scratch, plaintext_1, sizeof plaintext_1);
if (memcmp (scratch, ciphertext_1, sizeof ciphertext_1))
return "Salsa20 encryption test 1 failed.";
if (scratch[8])
return "Salsa20 wrote too much.";
salsa20_setkey( &ctx, key_1, sizeof(key_1));
salsa20_setiv (&ctx, nonce_1, sizeof nonce_1);
salsa20_encrypt_stream (&ctx, scratch, scratch, sizeof plaintext_1);
if (memcmp (scratch, plaintext_1, sizeof plaintext_1))
return "Salsa20 decryption test 1 failed.";
return NULL;
}
gcry_cipher_spec_t _gcry_cipher_spec_salsa20 =
{
+ GCRY_CIPHER_SALSA20,
+ {0, 0}, /* flags */
"SALSA20", /* name */
NULL, /* aliases */
NULL, /* oids */
1, /* blocksize in bytes. */
SALSA20_MAX_KEY_SIZE*8, /* standard key length in bits. */
sizeof (SALSA20_context_t),
salsa20_setkey,
NULL,
NULL,
salsa20_encrypt_stream,
- salsa20_encrypt_stream
+ salsa20_encrypt_stream,
+ NULL,
+ NULL,
+ salsa20_setiv
};
gcry_cipher_spec_t _gcry_cipher_spec_salsa20r12 =
{
+ GCRY_CIPHER_SALSA20R12,
+ {0, 0}, /* flags */
"SALSA20R12", /* name */
NULL, /* aliases */
NULL, /* oids */
1, /* blocksize in bytes. */
SALSA20_MAX_KEY_SIZE*8, /* standard key length in bits. */
sizeof (SALSA20_context_t),
salsa20_setkey,
NULL,
NULL,
salsa20r12_encrypt_stream,
- salsa20r12_encrypt_stream
- };
-
-cipher_extra_spec_t _gcry_cipher_extraspec_salsa20 =
- {
+ salsa20r12_encrypt_stream,
NULL,
NULL,
salsa20_setiv
};
diff --git a/cipher/seed.c b/cipher/seed.c
index 474ccbaf..9f87c055 100644
--- a/cipher/seed.c
+++ b/cipher/seed.c
@@ -1,475 +1,476 @@
/* SEED for libgcrypt
* Copyright (C) 2006 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*
* --
* This implementation was provided for libgcrypt in public domain
* by Hye-Shik Chang <perky@FreeBSD.org>, July 2006.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include "types.h" /* for byte and u32 typedefs */
#include "g10lib.h"
#include "cipher.h"
#include "bufhelp.h"
#define NUMKC 16
#define GETU32(pt) buf_get_be32(pt)
#define PUTU32(ct, st) buf_put_be32(ct, st)
union wordbuf
{
u32 w;
byte b[4];
};
#ifdef WORDS_BIGENDIAN
#define b0 b[3]
#define b1 b[2]
#define b2 b[1]
#define b3 b[0]
#else
#define b0 b[0]
#define b1 b[1]
#define b2 b[2]
#define b3 b[3]
#endif
static const char *selftest(void);
typedef struct
{
u32 keyschedule[32];
} SEED_context;
static const u32 SS0[256] = {
0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 0x14445054, 0x1d0d111c,
0x2c8ca0ac, 0x25052124, 0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c,
0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360, 0x28082028, 0x04444044,
0x20002020, 0x1d8d919c, 0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314,
0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, 0x3b8bb3b8, 0x13031310,
0x12c2d2d0, 0x2ecee2ec, 0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8,
0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074, 0x2ccce0ec, 0x15859194,
0x0b0b0308, 0x17475354, 0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100,
0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, 0x10001010, 0x0cccc0cc,
0x32c2f2f0, 0x19c9d1d8, 0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380,
0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8, 0x20406060, 0x10405050,
0x2383a3a0, 0x2bcbe3e8, 0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c,
0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, 0x2686a2a4, 0x12021210,
0x2f8fa3ac, 0x15c5d1d4, 0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140,
0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008, 0x1f0f131c, 0x19899198,
0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0,
0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, 0x3080b0b0, 0x0b8b8388,
0x0e0e020c, 0x2b8ba3a8, 0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c,
0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208, 0x3f8fb3bc, 0x2fcfe3ec,
0x33c3f3f0, 0x05c5c1c4, 0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064,
0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, 0x06060204, 0x21012120,
0x2b4b6368, 0x26466264, 0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288,
0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0, 0x3a4a7278, 0x07474344,
0x16869294, 0x25c5e1e4, 0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc,
0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, 0x36063234, 0x15051114,
0x22022220, 0x38083038, 0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c,
0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394, 0x35053134, 0x0bcbc3c8,
0x0ecec2cc, 0x3c0c303c, 0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188,
0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, 0x14849094, 0x19495158,
0x02828280, 0x04c4c0c4, 0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364,
0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8, 0x0f0f030c, 0x0e8e828c,
0x02424240, 0x23032320, 0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4,
0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, 0x2f4f636c, 0x3d0d313c,
0x2d0d212c, 0x00404040, 0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0,
0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154, 0x3b0b3338, 0x1cccd0dc,
0x28486068, 0x3f4f737c, 0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254,
0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, 0x3585b1b4, 0x2b0b2328,
0x25456164, 0x3acaf2f8, 0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c,
0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0, 0x31013130, 0x2acae2e8,
0x2d4d616c, 0x1f4f535c, 0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088,
0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, 0x22426260, 0x29092128,
0x07070304, 0x33033330, 0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178,
0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298,
};
static const u32 SS1[256] = {
0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, 0xcc0fcfc3, 0xdc1eced2,
0xb03383b3, 0xb83888b0, 0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3,
0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53, 0xc003c3c3, 0x60224262,
0x30330333, 0xb43585b1, 0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3,
0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, 0x1c1c0c10, 0xbc3c8cb0,
0x34360632, 0x480b4b43, 0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0,
0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0, 0xc002c2c2, 0x44054541,
0xe021c1e1, 0xd416c6d2, 0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890,
0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, 0xa42585a1, 0xf839c9f1,
0x0c0d0d01, 0xdc1fcfd3, 0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72,
0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272, 0x40024242, 0xd414c4d0,
0x40014141, 0xc000c0c0, 0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83,
0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, 0xc80acac2, 0x2c2c0c20,
0xa82a8aa2, 0x34340430, 0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1,
0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0, 0x54174753, 0xac2e8ea2,
0x08080800, 0xc405c5c1, 0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1,
0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, 0xf435c5f1, 0x880a8a82,
0x682a4a62, 0xb03181b1, 0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202,
0x20220222, 0x04040400, 0x68284860, 0x70314171, 0x04070703, 0xd81bcbd3,
0x9c1d8d91, 0x98198991, 0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951,
0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, 0x981a8a92, 0xa02383a3,
0xa82b8ba3, 0xd010c0d0, 0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12,
0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3, 0x94168692, 0x783b4b73,
0x5c1c4c50, 0xa02282a2, 0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41,
0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, 0x0c0c0c00, 0x2c2e0e22,
0xb83a8ab2, 0x6c2e4e62, 0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292,
0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0, 0x14150511, 0xf83bcbf3,
0x70304070, 0x74354571, 0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303,
0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, 0xd415c5d1, 0xb43484b0,
0xe82acae2, 0x08090901, 0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040,
0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501, 0xf83acaf2, 0x00010101,
0xf030c0f0, 0x282a0a22, 0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343,
0x84058581, 0x14140410, 0x88098981, 0x981b8b93, 0xb03080b0, 0xe425c5e1,
0x48084840, 0x78394971, 0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282,
0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53, 0x74374773, 0x54144450,
0xb03282b2, 0x1c1d0d11, 0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642,
0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, 0x7c3e4e72, 0xd81acad2,
0xc809c9c1, 0xfc3dcdf1, 0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30,
0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70, 0x0c0e0e02, 0x50104050,
0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393,
0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, 0xc80bcbc3, 0x50134353,
0x080a0a02, 0x84078783, 0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83,
0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3,
};
static const u32 SS2[256] = {
0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, 0x50541444, 0x111c1d0d,
0xa0ac2c8c, 0x21242505, 0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e,
0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343, 0x20282808, 0x40440444,
0x20202000, 0x919c1d8d, 0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707,
0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, 0xb3b83b8b, 0x13101303,
0xd2d012c2, 0xe2ec2ece, 0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888,
0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444, 0xe0ec2ccc, 0x91941585,
0x03080b0b, 0x53541747, 0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101,
0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, 0x10101000, 0xc0cc0ccc,
0xf2f032c2, 0xd1d819c9, 0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383,
0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9, 0x60602040, 0x50501040,
0xa3a02383, 0xe3e82bcb, 0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f,
0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, 0xa2a42686, 0x12101202,
0xa3ac2f8f, 0xd1d415c5, 0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141,
0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808, 0x131c1f0f, 0x91981989,
0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1,
0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, 0xb0b03080, 0x83880b8b,
0x020c0e0e, 0xa3a82b8b, 0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d,
0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a, 0xb3bc3f8f, 0xe3ec2fcf,
0xf3f033c3, 0xc1c405c5, 0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444,
0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, 0x02040606, 0x21202101,
0x63682b4b, 0x62642646, 0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a,
0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0, 0x72783a4a, 0x43440747,
0x92941686, 0xe1e425c5, 0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf,
0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, 0x32343606, 0x11141505,
0x22202202, 0x30383808, 0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c,
0x81800181, 0xe1e829c9, 0x80840484, 0x93941787, 0x31343505, 0xc3c80bcb,
0xc2cc0ece, 0x303c3c0c, 0x71703141, 0x11101101, 0xc3c407c7, 0x81880989,
0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, 0x90941484, 0x51581949,
0x82800282, 0xc0c404c4, 0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747,
0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888, 0x030c0f0f, 0x828c0e8e,
0x42400242, 0x23202303, 0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484,
0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, 0x636c2f4f, 0x313c3d0d,
0x212c2d0d, 0x40400040, 0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1,
0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545, 0x33383b0b, 0xd0dc1ccc,
0x60682848, 0x737c3f4f, 0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646,
0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, 0xb1b43585, 0x23282b0b,
0x61642545, 0xf2f83aca, 0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f,
0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282, 0x31303101, 0xe2e82aca,
0x616c2d4d, 0x535c1f4f, 0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888,
0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, 0x62602242, 0x21282909,
0x03040707, 0x33303303, 0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949,
0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a,
};
static const u32 SS3[256] = {
0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, 0xcfc3cc0f, 0xced2dc1e,
0x83b3b033, 0x88b0b838, 0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407,
0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b, 0xc3c3c003, 0x42626022,
0x03333033, 0x85b1b435, 0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427,
0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, 0x0c101c1c, 0x8cb0bc3c,
0x06323436, 0x4b43480b, 0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828,
0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434, 0xc2c2c002, 0x45414405,
0xc1e1e021, 0xc6d2d416, 0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818,
0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, 0x85a1a425, 0xc9f1f839,
0x0d010c0d, 0xcfd3dc1f, 0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a,
0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032, 0x42424002, 0xc4d0d414,
0x41414001, 0xc0c0c000, 0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b,
0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, 0xcac2c80a, 0x0c202c2c,
0x8aa2a82a, 0x04303434, 0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829,
0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838, 0x47535417, 0x8ea2ac2e,
0x08000808, 0xc5c1c405, 0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839,
0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, 0xc5f1f435, 0x8a82880a,
0x4a62682a, 0x81b1b031, 0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002,
0x02222022, 0x04000404, 0x48606828, 0x41717031, 0x07030407, 0xcbd3d81b,
0x8d919c1d, 0x89919819, 0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819,
0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, 0x8a92981a, 0x83a3a023,
0x8ba3a82b, 0xc0d0d010, 0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a,
0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f, 0x86929416, 0x4b73783b,
0x4c505c1c, 0x82a2a022, 0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d,
0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, 0x0c000c0c, 0x0e222c2e,
0x8ab2b83a, 0x4e626c2e, 0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012,
0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c, 0x05111415, 0xcbf3f83b,
0x40707030, 0x45717435, 0x4f737c3f, 0x05313435, 0x00101010, 0x03030003,
0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, 0xc5d1d415, 0x84b0b434,
0xcae2e82a, 0x09010809, 0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000,
0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405, 0xcaf2f83a, 0x01010001,
0xc0f0f030, 0x0a22282a, 0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003,
0x85818405, 0x04101414, 0x89818809, 0x8b93981b, 0x80b0b030, 0xc5e1e425,
0x48404808, 0x49717839, 0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002,
0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f, 0x47737437, 0x44505414,
0x82b2b032, 0x0d111c1d, 0x05212425, 0x4f434c0f, 0x00000000, 0x46424406,
0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, 0x4e727c3e, 0xcad2d81a,
0xc9c1c809, 0xcdf1fc3d, 0x00303030, 0x85919415, 0x45616425, 0x0c303c3c,
0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c, 0x0e020c0e, 0x40505010,
0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013,
0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, 0xcbc3c80b, 0x43535013,
0x0a02080a, 0x87838407, 0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f,
0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437,
};
static const u32 KC[NUMKC] = {
0x9e3779b9, 0x3c6ef373, 0x78dde6e6, 0xf1bbcdcc,
0xe3779b99, 0xc6ef3733, 0x8dde6e67, 0x1bbcdccf,
0x3779b99e, 0x6ef3733c, 0xdde6e678, 0xbbcdccf1,
0x779b99e3, 0xef3733c6, 0xde6e678d, 0xbcdccf1b,
};
/* Perform the key setup.
*/
static gcry_err_code_t
do_setkey (SEED_context *ctx, const byte *key, const unsigned keylen)
{
static int initialized = 0;
static const char *selftest_failed=0;
u32 x1, x2, x3, x4;
union wordbuf t0, t1;
u32 *keyout = ctx->keyschedule;
int i;
if (!initialized)
{
initialized = 1;
selftest_failed = selftest ();
if( selftest_failed )
log_error ("%s\n", selftest_failed );
}
if (selftest_failed)
return GPG_ERR_SELFTEST_FAILED;
if (keylen != 16)
return GPG_ERR_INV_KEYLEN;
x1 = GETU32 (key);
x2 = GETU32 (key+4);
x3 = GETU32 (key+8);
x4 = GETU32 (key+12);
for (i = 0; i < NUMKC; i++)
{
t0.w = x1 + x3 - KC[i];
t1.w = x2 + KC[i] - x4;
*(keyout++) = SS0[t0.b0] ^ SS1[t0.b1] ^ SS2[t0.b2] ^ SS3[t0.b3];
*(keyout++) = SS0[t1.b0] ^ SS1[t1.b1] ^ SS2[t1.b2] ^ SS3[t1.b3];
if (i % 2 == 0)
{
t0.w = x1;
x1 = (x1>>8) ^ (x2<<24);
x2 = (x2>>8) ^ (t0.w<<24);
}
else
{
t0.w = x3;
x3 = (x3<<8) ^ (x4>>24);
x4 = (x4<<8) ^ (t0.w>>24);
}
}
return 0;
}
static gcry_err_code_t
seed_setkey (void *context, const byte *key, const unsigned keylen)
{
SEED_context *ctx = context;
int rc = do_setkey (ctx, key, keylen);
_gcry_burn_stack (4*6 + sizeof(void*)*2 + sizeof(int)*2);
return rc;
}
#define OP(X1, X2, X3, X4, rbase) \
t0.w = X3 ^ ctx->keyschedule[rbase]; \
t1.w = X4 ^ ctx->keyschedule[rbase+1]; \
t1.w ^= t0.w; \
t1.w = SS0[t1.b0] ^ SS1[t1.b1] ^ SS2[t1.b2] ^ SS3[t1.b3]; \
t0.w += t1.w; \
t0.w = SS0[t0.b0] ^ SS1[t0.b1] ^ SS2[t0.b2] ^ SS3[t0.b3]; \
t1.w += t0.w; \
t1.w = SS0[t1.b0] ^ SS1[t1.b1] ^ SS2[t1.b2] ^ SS3[t1.b3]; \
t0.w += t1.w; \
X1 ^= t0.w; \
X2 ^= t1.w;
/* Encrypt one block. inbuf and outbuf may be the same. */
static void
do_encrypt (const SEED_context *ctx, byte *outbuf, const byte *inbuf)
{
u32 x1, x2, x3, x4;
union wordbuf t0, t1;
x1 = GETU32 (inbuf);
x2 = GETU32 (inbuf+4);
x3 = GETU32 (inbuf+8);
x4 = GETU32 (inbuf+12);
OP (x1, x2, x3, x4, 0);
OP (x3, x4, x1, x2, 2);
OP (x1, x2, x3, x4, 4);
OP (x3, x4, x1, x2, 6);
OP (x1, x2, x3, x4, 8);
OP (x3, x4, x1, x2, 10);
OP (x1, x2, x3, x4, 12);
OP (x3, x4, x1, x2, 14);
OP (x1, x2, x3, x4, 16);
OP (x3, x4, x1, x2, 18);
OP (x1, x2, x3, x4, 20);
OP (x3, x4, x1, x2, 22);
OP (x1, x2, x3, x4, 24);
OP (x3, x4, x1, x2, 26);
OP (x1, x2, x3, x4, 28);
OP (x3, x4, x1, x2, 30);
PUTU32 (outbuf, x3);
PUTU32 (outbuf+4, x4);
PUTU32 (outbuf+8, x1);
PUTU32 (outbuf+12, x2);
}
static unsigned int
seed_encrypt (void *context, byte *outbuf, const byte *inbuf)
{
SEED_context *ctx = context;
do_encrypt (ctx, outbuf, inbuf);
return /*burn_stack*/ (4*6);
}
/* Decrypt one block. inbuf and outbuf may be the same. */
static void
do_decrypt (SEED_context *ctx, byte *outbuf, const byte *inbuf)
{
u32 x1, x2, x3, x4;
union wordbuf t0, t1;
x1 = GETU32 (inbuf);
x2 = GETU32 (inbuf+4);
x3 = GETU32 (inbuf+8);
x4 = GETU32 (inbuf+12);
OP (x1, x2, x3, x4, 30);
OP (x3, x4, x1, x2, 28);
OP (x1, x2, x3, x4, 26);
OP (x3, x4, x1, x2, 24);
OP (x1, x2, x3, x4, 22);
OP (x3, x4, x1, x2, 20);
OP (x1, x2, x3, x4, 18);
OP (x3, x4, x1, x2, 16);
OP (x1, x2, x3, x4, 14);
OP (x3, x4, x1, x2, 12);
OP (x1, x2, x3, x4, 10);
OP (x3, x4, x1, x2, 8);
OP (x1, x2, x3, x4, 6);
OP (x3, x4, x1, x2, 4);
OP (x1, x2, x3, x4, 2);
OP (x3, x4, x1, x2, 0);
PUTU32 (outbuf, x3);
PUTU32 (outbuf+4, x4);
PUTU32 (outbuf+8, x1);
PUTU32 (outbuf+12, x2);
}
static unsigned int
seed_decrypt (void *context, byte *outbuf, const byte *inbuf)
{
SEED_context *ctx = context;
do_decrypt (ctx, outbuf, inbuf);
return /*burn_stack*/ (4*6);
}
/* Test a single encryption and decryption with each key size. */
static const char*
selftest (void)
{
SEED_context ctx;
byte scratch[16];
/* The test vector is taken from the appendix section B.3 of RFC4269.
*/
static const byte plaintext[16] = {
0x83, 0xA2, 0xF8, 0xA2, 0x88, 0x64, 0x1F, 0xB9,
0xA4, 0xE9, 0xA5, 0xCC, 0x2F, 0x13, 0x1C, 0x7D
};
static const byte key[16] = {
0x47, 0x06, 0x48, 0x08, 0x51, 0xE6, 0x1B, 0xE8,
0x5D, 0x74, 0xBF, 0xB3, 0xFD, 0x95, 0x61, 0x85
};
static const byte ciphertext[16] = {
0xEE, 0x54, 0xD1, 0x3E, 0xBC, 0xAE, 0x70, 0x6D,
0x22, 0x6B, 0xC3, 0x14, 0x2C, 0xD4, 0x0D, 0x4A,
};
seed_setkey (&ctx, key, sizeof(key));
seed_encrypt (&ctx, scratch, plaintext);
if (memcmp (scratch, ciphertext, sizeof (ciphertext)))
return "SEED test encryption failed.";
seed_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext, sizeof (plaintext)))
return "SEED test decryption failed.";
return NULL;
}
static gcry_cipher_oid_spec_t seed_oids[] =
{
{ "1.2.410.200004.1.3", GCRY_CIPHER_MODE_ECB },
{ "1.2.410.200004.1.4", GCRY_CIPHER_MODE_CBC },
{ "1.2.410.200004.1.5", GCRY_CIPHER_MODE_CFB },
{ "1.2.410.200004.1.6", GCRY_CIPHER_MODE_OFB },
{ NULL }
};
gcry_cipher_spec_t _gcry_cipher_spec_seed =
{
+ GCRY_CIPHER_SEED, {0, 0},
"SEED", NULL, seed_oids, 16, 128, sizeof (SEED_context),
seed_setkey, seed_encrypt, seed_decrypt,
};
diff --git a/cipher/serpent.c b/cipher/serpent.c
index 4720b9c6..c0898dcd 100644
--- a/cipher/serpent.c
+++ b/cipher/serpent.c
@@ -1,1212 +1,1215 @@
/* serpent.c - Implementation of the Serpent encryption algorithm.
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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 <string.h>
#include <stdio.h>
#include "types.h"
#include "g10lib.h"
#include "cipher.h"
#include "bithelp.h"
#include "bufhelp.h"
#include "cipher-selftest.h"
/* USE_SSE2 indicates whether to compile with AMD64 SSE2 code. */
#undef USE_SSE2
#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
# define USE_SSE2 1
#endif
/* USE_AVX2 indicates whether to compile with AMD64 AVX2 code. */
#undef USE_AVX2
#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
# if defined(ENABLE_AVX2_SUPPORT)
# define USE_AVX2 1
# endif
#endif
/* Number of rounds per Serpent encrypt/decrypt operation. */
#define ROUNDS 32
/* Magic number, used during generating of the subkeys. */
#define PHI 0x9E3779B9
/* Serpent works on 128 bit blocks. */
typedef u32 serpent_block_t[4];
/* Serpent key, provided by the user. If the original key is shorter
than 256 bits, it is padded. */
typedef u32 serpent_key_t[8];
/* The key schedule consists of 33 128 bit subkeys. */
typedef u32 serpent_subkeys_t[ROUNDS + 1][4];
/* A Serpent context. */
typedef struct serpent_context
{
serpent_subkeys_t keys; /* Generated subkeys. */
#ifdef USE_AVX2
int use_avx2;
#endif
} serpent_context_t;
#ifdef USE_SSE2
/* Assembler implementations of Serpent using SSE2. Process 8 block in
parallel.
*/
extern void _gcry_serpent_sse2_ctr_enc(serpent_context_t *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *ctr);
extern void _gcry_serpent_sse2_cbc_dec(serpent_context_t *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *iv);
extern void _gcry_serpent_sse2_cfb_dec(serpent_context_t *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *iv);
#endif
#ifdef USE_AVX2
/* Assembler implementations of Serpent using SSE2. Process 16 block in
parallel.
*/
extern void _gcry_serpent_avx2_ctr_enc(serpent_context_t *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *ctr);
extern void _gcry_serpent_avx2_cbc_dec(serpent_context_t *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *iv);
extern void _gcry_serpent_avx2_cfb_dec(serpent_context_t *ctx,
unsigned char *out,
const unsigned char *in,
unsigned char *iv);
#endif
/* A prototype. */
static const char *serpent_test (void);
/*
* These are the S-Boxes of Serpent from following research paper.
*
* D. A. Osvik, “Speeding up Serpent,” in Third AES Candidate Conference,
* (New York, New York, USA), p. 317–329, National Institute of Standards and
* Technology, 2000.
*
* Paper is also available at: http://www.ii.uib.no/~osvik/pub/aes3.pdf
*
*/
#define SBOX0(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r3 ^= r0; r4 = r1; \
r1 &= r3; r4 ^= r2; \
r1 ^= r0; r0 |= r3; \
r0 ^= r4; r4 ^= r3; \
r3 ^= r2; r2 |= r1; \
r2 ^= r4; r4 = ~r4; \
r4 |= r1; r1 ^= r3; \
r1 ^= r4; r3 |= r0; \
r1 ^= r3; r4 ^= r3; \
\
w = r1; x = r4; y = r2; z = r0; \
}
#define SBOX0_INVERSE(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r2 = ~r2; r4 = r1; \
r1 |= r0; r4 = ~r4; \
r1 ^= r2; r2 |= r4; \
r1 ^= r3; r0 ^= r4; \
r2 ^= r0; r0 &= r3; \
r4 ^= r0; r0 |= r1; \
r0 ^= r2; r3 ^= r4; \
r2 ^= r1; r3 ^= r0; \
r3 ^= r1; \
r2 &= r3; \
r4 ^= r2; \
\
w = r0; x = r4; y = r1; z = r3; \
}
#define SBOX1(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r0 = ~r0; r2 = ~r2; \
r4 = r0; r0 &= r1; \
r2 ^= r0; r0 |= r3; \
r3 ^= r2; r1 ^= r0; \
r0 ^= r4; r4 |= r1; \
r1 ^= r3; r2 |= r0; \
r2 &= r4; r0 ^= r1; \
r1 &= r2; \
r1 ^= r0; r0 &= r2; \
r0 ^= r4; \
\
w = r2; x = r0; y = r3; z = r1; \
}
#define SBOX1_INVERSE(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r4 = r1; r1 ^= r3; \
r3 &= r1; r4 ^= r2; \
r3 ^= r0; r0 |= r1; \
r2 ^= r3; r0 ^= r4; \
r0 |= r2; r1 ^= r3; \
r0 ^= r1; r1 |= r3; \
r1 ^= r0; r4 = ~r4; \
r4 ^= r1; r1 |= r0; \
r1 ^= r0; \
r1 |= r4; \
r3 ^= r1; \
\
w = r4; x = r0; y = r3; z = r2; \
}
#define SBOX2(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r4 = r0; r0 &= r2; \
r0 ^= r3; r2 ^= r1; \
r2 ^= r0; r3 |= r4; \
r3 ^= r1; r4 ^= r2; \
r1 = r3; r3 |= r4; \
r3 ^= r0; r0 &= r1; \
r4 ^= r0; r1 ^= r3; \
r1 ^= r4; r4 = ~r4; \
\
w = r2; x = r3; y = r1; z = r4; \
}
#define SBOX2_INVERSE(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r2 ^= r3; r3 ^= r0; \
r4 = r3; r3 &= r2; \
r3 ^= r1; r1 |= r2; \
r1 ^= r4; r4 &= r3; \
r2 ^= r3; r4 &= r0; \
r4 ^= r2; r2 &= r1; \
r2 |= r0; r3 = ~r3; \
r2 ^= r3; r0 ^= r3; \
r0 &= r1; r3 ^= r4; \
r3 ^= r0; \
\
w = r1; x = r4; y = r2; z = r3; \
}
#define SBOX3(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r4 = r0; r0 |= r3; \
r3 ^= r1; r1 &= r4; \
r4 ^= r2; r2 ^= r3; \
r3 &= r0; r4 |= r1; \
r3 ^= r4; r0 ^= r1; \
r4 &= r0; r1 ^= r3; \
r4 ^= r2; r1 |= r0; \
r1 ^= r2; r0 ^= r3; \
r2 = r1; r1 |= r3; \
r1 ^= r0; \
\
w = r1; x = r2; y = r3; z = r4; \
}
#define SBOX3_INVERSE(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r4 = r2; r2 ^= r1; \
r0 ^= r2; r4 &= r2; \
r4 ^= r0; r0 &= r1; \
r1 ^= r3; r3 |= r4; \
r2 ^= r3; r0 ^= r3; \
r1 ^= r4; r3 &= r2; \
r3 ^= r1; r1 ^= r0; \
r1 |= r2; r0 ^= r3; \
r1 ^= r4; \
r0 ^= r1; \
\
w = r2; x = r1; y = r3; z = r0; \
}
#define SBOX4(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r1 ^= r3; r3 = ~r3; \
r2 ^= r3; r3 ^= r0; \
r4 = r1; r1 &= r3; \
r1 ^= r2; r4 ^= r3; \
r0 ^= r4; r2 &= r4; \
r2 ^= r0; r0 &= r1; \
r3 ^= r0; r4 |= r1; \
r4 ^= r0; r0 |= r3; \
r0 ^= r2; r2 &= r3; \
r0 = ~r0; r4 ^= r2; \
\
w = r1; x = r4; y = r0; z = r3; \
}
#define SBOX4_INVERSE(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r4 = r2; r2 &= r3; \
r2 ^= r1; r1 |= r3; \
r1 &= r0; r4 ^= r2; \
r4 ^= r1; r1 &= r2; \
r0 = ~r0; r3 ^= r4; \
r1 ^= r3; r3 &= r0; \
r3 ^= r2; r0 ^= r1; \
r2 &= r0; r3 ^= r0; \
r2 ^= r4; \
r2 |= r3; r3 ^= r0; \
r2 ^= r1; \
\
w = r0; x = r3; y = r2; z = r4; \
}
#define SBOX5(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r0 ^= r1; r1 ^= r3; \
r3 = ~r3; r4 = r1; \
r1 &= r0; r2 ^= r3; \
r1 ^= r2; r2 |= r4; \
r4 ^= r3; r3 &= r1; \
r3 ^= r0; r4 ^= r1; \
r4 ^= r2; r2 ^= r0; \
r0 &= r3; r2 = ~r2; \
r0 ^= r4; r4 |= r3; \
r2 ^= r4; \
\
w = r1; x = r3; y = r0; z = r2; \
}
#define SBOX5_INVERSE(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r1 = ~r1; r4 = r3; \
r2 ^= r1; r3 |= r0; \
r3 ^= r2; r2 |= r1; \
r2 &= r0; r4 ^= r3; \
r2 ^= r4; r4 |= r0; \
r4 ^= r1; r1 &= r2; \
r1 ^= r3; r4 ^= r2; \
r3 &= r4; r4 ^= r1; \
r3 ^= r4; r4 = ~r4; \
r3 ^= r0; \
\
w = r1; x = r4; y = r3; z = r2; \
}
#define SBOX6(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r2 = ~r2; r4 = r3; \
r3 &= r0; r0 ^= r4; \
r3 ^= r2; r2 |= r4; \
r1 ^= r3; r2 ^= r0; \
r0 |= r1; r2 ^= r1; \
r4 ^= r0; r0 |= r3; \
r0 ^= r2; r4 ^= r3; \
r4 ^= r0; r3 = ~r3; \
r2 &= r4; \
r2 ^= r3; \
\
w = r0; x = r1; y = r4; z = r2; \
}
#define SBOX6_INVERSE(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r0 ^= r2; r4 = r2; \
r2 &= r0; r4 ^= r3; \
r2 = ~r2; r3 ^= r1; \
r2 ^= r3; r4 |= r0; \
r0 ^= r2; r3 ^= r4; \
r4 ^= r1; r1 &= r3; \
r1 ^= r0; r0 ^= r3; \
r0 |= r2; r3 ^= r1; \
r4 ^= r0; \
\
w = r1; x = r2; y = r4; z = r3; \
}
#define SBOX7(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r4 = r1; r1 |= r2; \
r1 ^= r3; r4 ^= r2; \
r2 ^= r1; r3 |= r4; \
r3 &= r0; r4 ^= r2; \
r3 ^= r1; r1 |= r4; \
r1 ^= r0; r0 |= r4; \
r0 ^= r2; r1 ^= r4; \
r2 ^= r1; r1 &= r0; \
r1 ^= r4; r2 = ~r2; \
r2 |= r0; \
r4 ^= r2; \
\
w = r4; x = r3; y = r1; z = r0; \
}
#define SBOX7_INVERSE(r0, r1, r2, r3, w, x, y, z) \
{ \
u32 r4; \
\
r4 = r2; r2 ^= r0; \
r0 &= r3; r4 |= r3; \
r2 = ~r2; r3 ^= r1; \
r1 |= r0; r0 ^= r2; \
r2 &= r4; r3 &= r4; \
r1 ^= r2; r2 ^= r0; \
r0 |= r2; r4 ^= r1; \
r0 ^= r3; r3 ^= r4; \
r4 |= r0; r3 ^= r2; \
r4 ^= r2; \
\
w = r3; x = r0; y = r1; z = r4; \
}
/* XOR BLOCK1 into BLOCK0. */
#define BLOCK_XOR(block0, block1) \
{ \
block0[0] ^= block1[0]; \
block0[1] ^= block1[1]; \
block0[2] ^= block1[2]; \
block0[3] ^= block1[3]; \
}
/* Copy BLOCK_SRC to BLOCK_DST. */
#define BLOCK_COPY(block_dst, block_src) \
{ \
block_dst[0] = block_src[0]; \
block_dst[1] = block_src[1]; \
block_dst[2] = block_src[2]; \
block_dst[3] = block_src[3]; \
}
/* Apply SBOX number WHICH to to the block found in ARRAY0 at index
INDEX, writing the output to the block found in ARRAY1 at index
INDEX. */
#define SBOX(which, array0, array1, index) \
SBOX##which (array0[index + 0], array0[index + 1], \
array0[index + 2], array0[index + 3], \
array1[index + 0], array1[index + 1], \
array1[index + 2], array1[index + 3]);
/* Apply inverse SBOX number WHICH to to the block found in ARRAY0 at
index INDEX, writing the output to the block found in ARRAY1 at
index INDEX. */
#define SBOX_INVERSE(which, array0, array1, index) \
SBOX##which##_INVERSE (array0[index + 0], array0[index + 1], \
array0[index + 2], array0[index + 3], \
array1[index + 0], array1[index + 1], \
array1[index + 2], array1[index + 3]);
/* Apply the linear transformation to BLOCK. */
#define LINEAR_TRANSFORMATION(block) \
{ \
block[0] = rol (block[0], 13); \
block[2] = rol (block[2], 3); \
block[1] = block[1] ^ block[0] ^ block[2]; \
block[3] = block[3] ^ block[2] ^ (block[0] << 3); \
block[1] = rol (block[1], 1); \
block[3] = rol (block[3], 7); \
block[0] = block[0] ^ block[1] ^ block[3]; \
block[2] = block[2] ^ block[3] ^ (block[1] << 7); \
block[0] = rol (block[0], 5); \
block[2] = rol (block[2], 22); \
}
/* Apply the inverse linear transformation to BLOCK. */
#define LINEAR_TRANSFORMATION_INVERSE(block) \
{ \
block[2] = ror (block[2], 22); \
block[0] = ror (block[0] , 5); \
block[2] = block[2] ^ block[3] ^ (block[1] << 7); \
block[0] = block[0] ^ block[1] ^ block[3]; \
block[3] = ror (block[3], 7); \
block[1] = ror (block[1], 1); \
block[3] = block[3] ^ block[2] ^ (block[0] << 3); \
block[1] = block[1] ^ block[0] ^ block[2]; \
block[2] = ror (block[2], 3); \
block[0] = ror (block[0], 13); \
}
/* Apply a Serpent round to BLOCK, using the SBOX number WHICH and the
subkeys contained in SUBKEYS. Use BLOCK_TMP as temporary storage.
This macro increments `round'. */
#define ROUND(which, subkeys, block, block_tmp) \
{ \
BLOCK_XOR (block, subkeys[round]); \
round++; \
SBOX (which, block, block_tmp, 0); \
LINEAR_TRANSFORMATION (block_tmp); \
BLOCK_COPY (block, block_tmp); \
}
/* Apply the last Serpent round to BLOCK, using the SBOX number WHICH
and the subkeys contained in SUBKEYS. Use BLOCK_TMP as temporary
storage. The result will be stored in BLOCK_TMP. This macro
increments `round'. */
#define ROUND_LAST(which, subkeys, block, block_tmp) \
{ \
BLOCK_XOR (block, subkeys[round]); \
round++; \
SBOX (which, block, block_tmp, 0); \
BLOCK_XOR (block_tmp, subkeys[round]); \
round++; \
}
/* Apply an inverse Serpent round to BLOCK, using the SBOX number
WHICH and the subkeys contained in SUBKEYS. Use BLOCK_TMP as
temporary storage. This macro increments `round'. */
#define ROUND_INVERSE(which, subkey, block, block_tmp) \
{ \
LINEAR_TRANSFORMATION_INVERSE (block); \
SBOX_INVERSE (which, block, block_tmp, 0); \
BLOCK_XOR (block_tmp, subkey[round]); \
round--; \
BLOCK_COPY (block, block_tmp); \
}
/* Apply the first Serpent round to BLOCK, using the SBOX number WHICH
and the subkeys contained in SUBKEYS. Use BLOCK_TMP as temporary
storage. The result will be stored in BLOCK_TMP. This macro
increments `round'. */
#define ROUND_FIRST_INVERSE(which, subkeys, block, block_tmp) \
{ \
BLOCK_XOR (block, subkeys[round]); \
round--; \
SBOX_INVERSE (which, block, block_tmp, 0); \
BLOCK_XOR (block_tmp, subkeys[round]); \
round--; \
}
/* Convert the user provided key KEY of KEY_LENGTH bytes into the
internally used format. */
static void
serpent_key_prepare (const byte *key, unsigned int key_length,
serpent_key_t key_prepared)
{
int i;
/* Copy key. */
key_length /= 4;
for (i = 0; i < key_length; i++)
key_prepared[i] = buf_get_le32 (key + i * 4);
if (i < 8)
{
/* Key must be padded according to the Serpent
specification. */
key_prepared[i] = 0x00000001;
for (i++; i < 8; i++)
key_prepared[i] = 0;
}
}
/* Derive the 33 subkeys from KEY and store them in SUBKEYS. */
static void
serpent_subkeys_generate (serpent_key_t key, serpent_subkeys_t subkeys)
{
u32 w_real[140]; /* The `prekey'. */
u32 k[132];
u32 *w = &w_real[8];
int i, j;
/* Initialize with key values. */
for (i = 0; i < 8; i++)
w[i - 8] = key[i];
/* Expand to intermediate key using the affine recurrence. */
for (i = 0; i < 132; i++)
w[i] = rol (w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11);
/* Calculate subkeys via S-Boxes, in bitslice mode. */
SBOX (3, w, k, 0);
SBOX (2, w, k, 4);
SBOX (1, w, k, 8);
SBOX (0, w, k, 12);
SBOX (7, w, k, 16);
SBOX (6, w, k, 20);
SBOX (5, w, k, 24);
SBOX (4, w, k, 28);
SBOX (3, w, k, 32);
SBOX (2, w, k, 36);
SBOX (1, w, k, 40);
SBOX (0, w, k, 44);
SBOX (7, w, k, 48);
SBOX (6, w, k, 52);
SBOX (5, w, k, 56);
SBOX (4, w, k, 60);
SBOX (3, w, k, 64);
SBOX (2, w, k, 68);
SBOX (1, w, k, 72);
SBOX (0, w, k, 76);
SBOX (7, w, k, 80);
SBOX (6, w, k, 84);
SBOX (5, w, k, 88);
SBOX (4, w, k, 92);
SBOX (3, w, k, 96);
SBOX (2, w, k, 100);
SBOX (1, w, k, 104);
SBOX (0, w, k, 108);
SBOX (7, w, k, 112);
SBOX (6, w, k, 116);
SBOX (5, w, k, 120);
SBOX (4, w, k, 124);
SBOX (3, w, k, 128);
/* Renumber subkeys. */
for (i = 0; i < ROUNDS + 1; i++)
for (j = 0; j < 4; j++)
subkeys[i][j] = k[4 * i + j];
}
/* Initialize CONTEXT with the key KEY of KEY_LENGTH bits. */
static void
serpent_setkey_internal (serpent_context_t *context,
const byte *key, unsigned int key_length)
{
serpent_key_t key_prepared;
serpent_key_prepare (key, key_length, key_prepared);
serpent_subkeys_generate (key_prepared, context->keys);
#ifdef USE_AVX2
context->use_avx2 = 0;
if ((_gcry_get_hw_features () & HWF_INTEL_AVX2))
{
context->use_avx2 = 1;
}
#endif
_gcry_burn_stack (272 * sizeof (u32));
}
/* Initialize CTX with the key KEY of KEY_LENGTH bytes. */
static gcry_err_code_t
serpent_setkey (void *ctx,
const byte *key, unsigned int key_length)
{
serpent_context_t *context = ctx;
static const char *serpent_test_ret;
static int serpent_init_done;
gcry_err_code_t ret = GPG_ERR_NO_ERROR;
if (! serpent_init_done)
{
/* Execute a self-test the first time, Serpent is used. */
serpent_init_done = 1;
serpent_test_ret = serpent_test ();
if (serpent_test_ret)
log_error ("Serpent test failure: %s\n", serpent_test_ret);
}
if (serpent_test_ret)
ret = GPG_ERR_SELFTEST_FAILED;
else
{
serpent_setkey_internal (context, key, key_length);
_gcry_burn_stack (sizeof (serpent_key_t));
}
return ret;
}
static void
serpent_encrypt_internal (serpent_context_t *context,
const byte *input, byte *output)
{
serpent_block_t b, b_next;
int round = 0;
b[0] = buf_get_le32 (input + 0);
b[1] = buf_get_le32 (input + 4);
b[2] = buf_get_le32 (input + 8);
b[3] = buf_get_le32 (input + 12);
ROUND (0, context->keys, b, b_next);
ROUND (1, context->keys, b, b_next);
ROUND (2, context->keys, b, b_next);
ROUND (3, context->keys, b, b_next);
ROUND (4, context->keys, b, b_next);
ROUND (5, context->keys, b, b_next);
ROUND (6, context->keys, b, b_next);
ROUND (7, context->keys, b, b_next);
ROUND (0, context->keys, b, b_next);
ROUND (1, context->keys, b, b_next);
ROUND (2, context->keys, b, b_next);
ROUND (3, context->keys, b, b_next);
ROUND (4, context->keys, b, b_next);
ROUND (5, context->keys, b, b_next);
ROUND (6, context->keys, b, b_next);
ROUND (7, context->keys, b, b_next);
ROUND (0, context->keys, b, b_next);
ROUND (1, context->keys, b, b_next);
ROUND (2, context->keys, b, b_next);
ROUND (3, context->keys, b, b_next);
ROUND (4, context->keys, b, b_next);
ROUND (5, context->keys, b, b_next);
ROUND (6, context->keys, b, b_next);
ROUND (7, context->keys, b, b_next);
ROUND (0, context->keys, b, b_next);
ROUND (1, context->keys, b, b_next);
ROUND (2, context->keys, b, b_next);
ROUND (3, context->keys, b, b_next);
ROUND (4, context->keys, b, b_next);
ROUND (5, context->keys, b, b_next);
ROUND (6, context->keys, b, b_next);
ROUND_LAST (7, context->keys, b, b_next);
buf_put_le32 (output + 0, b_next[0]);
buf_put_le32 (output + 4, b_next[1]);
buf_put_le32 (output + 8, b_next[2]);
buf_put_le32 (output + 12, b_next[3]);
}
static void
serpent_decrypt_internal (serpent_context_t *context,
const byte *input, byte *output)
{
serpent_block_t b, b_next;
int round = ROUNDS;
b_next[0] = buf_get_le32 (input + 0);
b_next[1] = buf_get_le32 (input + 4);
b_next[2] = buf_get_le32 (input + 8);
b_next[3] = buf_get_le32 (input + 12);
ROUND_FIRST_INVERSE (7, context->keys, b_next, b);
ROUND_INVERSE (6, context->keys, b, b_next);
ROUND_INVERSE (5, context->keys, b, b_next);
ROUND_INVERSE (4, context->keys, b, b_next);
ROUND_INVERSE (3, context->keys, b, b_next);
ROUND_INVERSE (2, context->keys, b, b_next);
ROUND_INVERSE (1, context->keys, b, b_next);
ROUND_INVERSE (0, context->keys, b, b_next);
ROUND_INVERSE (7, context->keys, b, b_next);
ROUND_INVERSE (6, context->keys, b, b_next);
ROUND_INVERSE (5, context->keys, b, b_next);
ROUND_INVERSE (4, context->keys, b, b_next);
ROUND_INVERSE (3, context->keys, b, b_next);
ROUND_INVERSE (2, context->keys, b, b_next);
ROUND_INVERSE (1, context->keys, b, b_next);
ROUND_INVERSE (0, context->keys, b, b_next);
ROUND_INVERSE (7, context->keys, b, b_next);
ROUND_INVERSE (6, context->keys, b, b_next);
ROUND_INVERSE (5, context->keys, b, b_next);
ROUND_INVERSE (4, context->keys, b, b_next);
ROUND_INVERSE (3, context->keys, b, b_next);
ROUND_INVERSE (2, context->keys, b, b_next);
ROUND_INVERSE (1, context->keys, b, b_next);
ROUND_INVERSE (0, context->keys, b, b_next);
ROUND_INVERSE (7, context->keys, b, b_next);
ROUND_INVERSE (6, context->keys, b, b_next);
ROUND_INVERSE (5, context->keys, b, b_next);
ROUND_INVERSE (4, context->keys, b, b_next);
ROUND_INVERSE (3, context->keys, b, b_next);
ROUND_INVERSE (2, context->keys, b, b_next);
ROUND_INVERSE (1, context->keys, b, b_next);
ROUND_INVERSE (0, context->keys, b, b_next);
buf_put_le32 (output + 0, b_next[0]);
buf_put_le32 (output + 4, b_next[1]);
buf_put_le32 (output + 8, b_next[2]);
buf_put_le32 (output + 12, b_next[3]);
}
static unsigned int
serpent_encrypt (void *ctx, byte *buffer_out, const byte *buffer_in)
{
serpent_context_t *context = ctx;
serpent_encrypt_internal (context, buffer_in, buffer_out);
return /*burn_stack*/ (2 * sizeof (serpent_block_t));
}
static unsigned int
serpent_decrypt (void *ctx, byte *buffer_out, const byte *buffer_in)
{
serpent_context_t *context = ctx;
serpent_decrypt_internal (context, buffer_in, buffer_out);
return /*burn_stack*/ (2 * sizeof (serpent_block_t));
}
/* Bulk encryption of complete blocks in CTR mode. This function is only
intended for the bulk encryption feature of cipher.c. CTR is expected to be
of size sizeof(serpent_block_t). */
void
_gcry_serpent_ctr_enc(void *context, unsigned char *ctr,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
serpent_context_t *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char tmpbuf[sizeof(serpent_block_t)];
int burn_stack_depth = 2 * sizeof (serpent_block_t);
int i;
#ifdef USE_AVX2
if (ctx->use_avx2)
{
int did_use_avx2 = 0;
/* Process data in 16 block chunks. */
while (nblocks >= 16)
{
_gcry_serpent_avx2_ctr_enc(ctx, outbuf, inbuf, ctr);
nblocks -= 16;
outbuf += 16 * sizeof(serpent_block_t);
inbuf += 16 * sizeof(serpent_block_t);
did_use_avx2 = 1;
}
if (did_use_avx2)
{
/* serpent-avx2 assembly code does not use stack */
if (nblocks == 0)
burn_stack_depth = 0;
}
/* Use generic/sse2 code to handle smaller chunks... */
/* TODO: use caching instead? */
}
#endif
#ifdef USE_SSE2
{
int did_use_sse2 = 0;
/* Process data in 8 block chunks. */
while (nblocks >= 8)
{
_gcry_serpent_sse2_ctr_enc(ctx, outbuf, inbuf, ctr);
nblocks -= 8;
outbuf += 8 * sizeof(serpent_block_t);
inbuf += 8 * sizeof(serpent_block_t);
did_use_sse2 = 1;
}
if (did_use_sse2)
{
/* serpent-sse2 assembly code does not use stack */
if (nblocks == 0)
burn_stack_depth = 0;
}
/* Use generic code to handle smaller chunks... */
/* TODO: use caching instead? */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* Encrypt the counter. */
serpent_encrypt_internal(ctx, ctr, tmpbuf);
/* XOR the input with the encrypted counter and store in output. */
buf_xor(outbuf, tmpbuf, inbuf, sizeof(serpent_block_t));
outbuf += sizeof(serpent_block_t);
inbuf += sizeof(serpent_block_t);
/* Increment the counter. */
for (i = sizeof(serpent_block_t); i > 0; i--)
{
ctr[i-1]++;
if (ctr[i-1])
break;
}
}
wipememory(tmpbuf, sizeof(tmpbuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CBC mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_serpent_cbc_dec(void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
serpent_context_t *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char savebuf[sizeof(serpent_block_t)];
int burn_stack_depth = 2 * sizeof (serpent_block_t);
#ifdef USE_AVX2
if (ctx->use_avx2)
{
int did_use_avx2 = 0;
/* Process data in 16 block chunks. */
while (nblocks >= 16)
{
_gcry_serpent_avx2_cbc_dec(ctx, outbuf, inbuf, iv);
nblocks -= 16;
outbuf += 16 * sizeof(serpent_block_t);
inbuf += 16 * sizeof(serpent_block_t);
did_use_avx2 = 1;
}
if (did_use_avx2)
{
/* serpent-avx2 assembly code does not use stack */
if (nblocks == 0)
burn_stack_depth = 0;
}
/* Use generic/sse2 code to handle smaller chunks... */
}
#endif
#ifdef USE_SSE2
{
int did_use_sse2 = 0;
/* Process data in 8 block chunks. */
while (nblocks >= 8)
{
_gcry_serpent_sse2_cbc_dec(ctx, outbuf, inbuf, iv);
nblocks -= 8;
outbuf += 8 * sizeof(serpent_block_t);
inbuf += 8 * sizeof(serpent_block_t);
did_use_sse2 = 1;
}
if (did_use_sse2)
{
/* serpent-sse2 assembly code does not use stack */
if (nblocks == 0)
burn_stack_depth = 0;
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* We need to save INBUF away because it may be identical to
OUTBUF. */
memcpy(savebuf, inbuf, sizeof(serpent_block_t));
serpent_decrypt_internal (ctx, inbuf, outbuf);
buf_xor(outbuf, outbuf, iv, sizeof(serpent_block_t));
memcpy(iv, savebuf, sizeof(serpent_block_t));
inbuf += sizeof(serpent_block_t);
outbuf += sizeof(serpent_block_t);
}
wipememory(savebuf, sizeof(savebuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CFB mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_serpent_cfb_dec(void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
serpent_context_t *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
int burn_stack_depth = 2 * sizeof (serpent_block_t);
#ifdef USE_AVX2
if (ctx->use_avx2)
{
int did_use_avx2 = 0;
/* Process data in 16 block chunks. */
while (nblocks >= 16)
{
_gcry_serpent_avx2_cfb_dec(ctx, outbuf, inbuf, iv);
nblocks -= 16;
outbuf += 16 * sizeof(serpent_block_t);
inbuf += 16 * sizeof(serpent_block_t);
did_use_avx2 = 1;
}
if (did_use_avx2)
{
/* serpent-avx2 assembly code does not use stack */
if (nblocks == 0)
burn_stack_depth = 0;
}
/* Use generic/sse2 code to handle smaller chunks... */
}
#endif
#ifdef USE_SSE2
{
int did_use_sse2 = 0;
/* Process data in 8 block chunks. */
while (nblocks >= 8)
{
_gcry_serpent_sse2_cfb_dec(ctx, outbuf, inbuf, iv);
nblocks -= 8;
outbuf += 8 * sizeof(serpent_block_t);
inbuf += 8 * sizeof(serpent_block_t);
did_use_sse2 = 1;
}
if (did_use_sse2)
{
/* serpent-sse2 assembly code does not use stack */
if (nblocks == 0)
burn_stack_depth = 0;
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
serpent_encrypt_internal(ctx, iv, iv);
buf_xor_n_copy(outbuf, iv, inbuf, sizeof(serpent_block_t));
outbuf += sizeof(serpent_block_t);
inbuf += sizeof(serpent_block_t);
}
_gcry_burn_stack(burn_stack_depth);
}
/* Run the self-tests for SERPENT-CTR-128, tests IV increment of bulk CTR
encryption. Returns NULL on success. */
static const char*
selftest_ctr_128 (void)
{
const int nblocks = 16+1;
const int blocksize = sizeof(serpent_block_t);
const int context_size = sizeof(serpent_context_t);
return _gcry_selftest_helper_ctr("SERPENT", &serpent_setkey,
&serpent_encrypt, &_gcry_serpent_ctr_enc, nblocks, blocksize,
context_size);
}
/* Run the self-tests for SERPENT-CBC-128, tests bulk CBC decryption.
Returns NULL on success. */
static const char*
selftest_cbc_128 (void)
{
const int nblocks = 16+2;
const int blocksize = sizeof(serpent_block_t);
const int context_size = sizeof(serpent_context_t);
return _gcry_selftest_helper_cbc("SERPENT", &serpent_setkey,
&serpent_encrypt, &_gcry_serpent_cbc_dec, nblocks, blocksize,
context_size);
}
/* Run the self-tests for SERPENT-CBC-128, tests bulk CBC decryption.
Returns NULL on success. */
static const char*
selftest_cfb_128 (void)
{
const int nblocks = 16+2;
const int blocksize = sizeof(serpent_block_t);
const int context_size = sizeof(serpent_context_t);
return _gcry_selftest_helper_cfb("SERPENT", &serpent_setkey,
&serpent_encrypt, &_gcry_serpent_cfb_dec, nblocks, blocksize,
context_size);
}
/* Serpent test. */
static const char *
serpent_test (void)
{
serpent_context_t context;
unsigned char scratch[16];
unsigned int i;
const char *r;
static struct test
{
int key_length;
unsigned char key[32];
unsigned char text_plain[16];
unsigned char text_cipher[16];
} test_data[] =
{
{
16,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\xD2\x9D\x57\x6F\xCE\xA3\xA3\xA7\xED\x90\x99\xF2\x92\x73\xD7\x8E",
"\xB2\x28\x8B\x96\x8A\xE8\xB0\x86\x48\xD1\xCE\x96\x06\xFD\x99\x2D"
},
{
24,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
"\xD2\x9D\x57\x6F\xCE\xAB\xA3\xA7\xED\x98\x99\xF2\x92\x7B\xD7\x8E",
"\x13\x0E\x35\x3E\x10\x37\xC2\x24\x05\xE8\xFA\xEF\xB2\xC3\xC3\xE9"
},
{
32,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\xD0\x95\x57\x6F\xCE\xA3\xE3\xA7\xED\x98\xD9\xF2\x90\x73\xD7\x8E",
"\xB9\x0E\xE5\x86\x2D\xE6\x91\x68\xF2\xBD\xD5\x12\x5B\x45\x47\x2B"
},
{
32,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00",
"\x20\x61\xA4\x27\x82\xBD\x52\xEC\x69\x1E\xC3\x83\xB0\x3B\xA7\x7C"
},
{
0
},
};
for (i = 0; test_data[i].key_length; i++)
{
serpent_setkey_internal (&context, test_data[i].key,
test_data[i].key_length);
serpent_encrypt_internal (&context, test_data[i].text_plain, scratch);
if (memcmp (scratch, test_data[i].text_cipher, sizeof (serpent_block_t)))
switch (test_data[i].key_length)
{
case 16:
return "Serpent-128 test encryption failed.";
case 24:
return "Serpent-192 test encryption failed.";
case 32:
return "Serpent-256 test encryption failed.";
}
serpent_decrypt_internal (&context, test_data[i].text_cipher, scratch);
if (memcmp (scratch, test_data[i].text_plain, sizeof (serpent_block_t)))
switch (test_data[i].key_length)
{
case 16:
return "Serpent-128 test decryption failed.";
case 24:
return "Serpent-192 test decryption failed.";
case 32:
return "Serpent-256 test decryption failed.";
}
}
if ( (r = selftest_ctr_128 ()) )
return r;
if ( (r = selftest_cbc_128 ()) )
return r;
if ( (r = selftest_cfb_128 ()) )
return r;
return NULL;
}
/* "SERPENT" is an alias for "SERPENT128". */
static const char *cipher_spec_serpent128_aliases[] =
{
"SERPENT",
NULL
};
gcry_cipher_spec_t _gcry_cipher_spec_serpent128 =
{
+ GCRY_CIPHER_SERPENT128, {0, 0},
"SERPENT128", cipher_spec_serpent128_aliases, NULL, 16, 128,
sizeof (serpent_context_t),
serpent_setkey, serpent_encrypt, serpent_decrypt
};
gcry_cipher_spec_t _gcry_cipher_spec_serpent192 =
{
+ GCRY_CIPHER_SERPENT192, {0, 0},
"SERPENT192", NULL, NULL, 16, 192,
sizeof (serpent_context_t),
serpent_setkey, serpent_encrypt, serpent_decrypt
};
gcry_cipher_spec_t _gcry_cipher_spec_serpent256 =
{
+ GCRY_CIPHER_SERPENT256, {0, 0},
"SERPENT256", NULL, NULL, 16, 256,
sizeof (serpent_context_t),
serpent_setkey, serpent_encrypt, serpent_decrypt
};
diff --git a/cipher/twofish.c b/cipher/twofish.c
index 17b3aa3f..993ad0f4 100644
--- a/cipher/twofish.c
+++ b/cipher/twofish.c
@@ -1,1317 +1,1319 @@
/* Twofish for GPG
* Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc.
* Written by Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
* 256-bit key length added March 20, 1999
* Some modifications to reduce the text size by Werner Koch, April, 1998
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
********************************************************************
*
* This code is a "clean room" implementation, written from the paper
* _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
* Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
* through http://www.counterpane.com/twofish.html
*
* For background information on multiplication in finite fields, used for
* the matrix operations in the key schedule, see the book _Contemporary
* Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
* Third Edition.
*
* Only the 128- and 256-bit key sizes are supported. This code is intended
* for GNU C on a 32-bit system, but it should work almost anywhere. Loops
* are unrolled, precomputation tables are used, etc., for maximum speed at
* some cost in memory consumption. */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for memcmp() */
#include "types.h" /* for byte and u32 typedefs */
#include "g10lib.h"
#include "cipher.h"
#include "bufhelp.h"
#include "cipher-selftest.h"
#define TWOFISH_BLOCKSIZE 16
/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
#undef USE_AMD64_ASM
#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
# define USE_AMD64_ASM 1
#endif
/* Prototype for the self-test function. */
static const char *selftest(void);
/* Structure for an expanded Twofish key. s contains the key-dependent
* S-boxes composed with the MDS matrix; w contains the eight "whitening"
* subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys. Note
* that k[i] corresponds to what the Twofish paper calls K[i+8]. */
typedef struct {
u32 s[4][256], w[8], k[32];
} TWOFISH_context;
/* These two tables are the q0 and q1 permutations, exactly as described in
* the Twofish paper. */
static const byte q0[256] = {
0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78,
0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30,
0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE,
0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45,
0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF,
0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED,
0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B,
0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F,
0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17,
0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68,
0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42,
0x4A, 0x5E, 0xC1, 0xE0
};
static const byte q1[256] = {
0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B,
0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B,
0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54,
0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7,
0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF,
0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D,
0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21,
0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E,
0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44,
0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B,
0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56,
0x55, 0x09, 0xBE, 0x91
};
/* These MDS tables are actually tables of MDS composed with q0 and q1,
* because it is only ever used that way and we can save some time by
* precomputing. Of course the main saving comes from precomputing the
* GF(2^8) multiplication involved in the MDS matrix multiply; by looking
* things up in these tables we reduce the matrix multiply to four lookups
* and three XORs. Semi-formally, the definition of these tables is:
* mds[0][i] = MDS (q1[i] 0 0 0)^T mds[1][i] = MDS (0 q0[i] 0 0)^T
* mds[2][i] = MDS (0 0 q1[i] 0)^T mds[3][i] = MDS (0 0 0 q0[i])^T
* where ^T means "transpose", the matrix multiply is performed in GF(2^8)
* represented as GF(2)[x]/v(x) where v(x)=x^8+x^6+x^5+x^3+1 as described
* by Schneier et al, and I'm casually glossing over the byte/word
* conversion issues. */
static const u32 mds[4][256] = {
{0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B,
0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B,
0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32,
0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA,
0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B,
0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1,
0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490,
0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154,
0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0,
0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228,
0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7,
0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3,
0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477,
0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF,
0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C,
0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA,
0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D,
0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72,
0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76,
0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321,
0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39,
0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D,
0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E,
0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5,
0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7,
0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544,
0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E,
0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A,
0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B,
0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2,
0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504,
0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756,
0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91},
{0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252,
0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A,
0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020,
0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444,
0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424,
0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A,
0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383,
0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A,
0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9,
0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1,
0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898,
0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414,
0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1,
0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989,
0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5,
0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E,
0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E,
0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202,
0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565,
0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A,
0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808,
0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A,
0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969,
0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505,
0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D,
0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343,
0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF,
0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F,
0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646,
0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6,
0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A,
0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7,
0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8},
{0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B,
0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F,
0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A,
0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70,
0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3,
0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB,
0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4,
0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41,
0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C,
0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622,
0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18,
0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035,
0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84,
0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E,
0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F,
0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558,
0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40,
0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA,
0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF,
0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773,
0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D,
0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C,
0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19,
0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086,
0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74,
0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755,
0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691,
0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4,
0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53,
0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E,
0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705,
0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7,
0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF},
{0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98,
0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866,
0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643,
0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9,
0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C,
0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3,
0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F,
0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25,
0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF,
0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4,
0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E,
0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA,
0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12,
0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A,
0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D,
0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A,
0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C,
0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B,
0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B,
0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3,
0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE,
0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85,
0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA,
0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E,
0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33,
0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC,
0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718,
0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8,
0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872,
0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882,
0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10,
0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6,
0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8}
};
/* The exp_to_poly and poly_to_exp tables are used to perform efficient
* operations in GF(2^8) represented as GF(2)[x]/w(x) where
* w(x)=x^8+x^6+x^3+x^2+1. We care about doing that because it's part of the
* definition of the RS matrix in the key schedule. Elements of that field
* are polynomials of degree not greater than 7 and all coefficients 0 or 1,
* which can be represented naturally by bytes (just substitute x=2). In that
* form, GF(2^8) addition is the same as bitwise XOR, but GF(2^8)
* multiplication is inefficient without hardware support. To multiply
* faster, I make use of the fact x is a generator for the nonzero elements,
* so that every element p of GF(2)[x]/w(x) is either 0 or equal to (x)^n for
* some n in 0..254. Note that that caret is exponentiation in GF(2^8),
* *not* polynomial notation. So if I want to compute pq where p and q are
* in GF(2^8), I can just say:
* 1. if p=0 or q=0 then pq=0
* 2. otherwise, find m and n such that p=x^m and q=x^n
* 3. pq=(x^m)(x^n)=x^(m+n), so add m and n and find pq
* The translations in steps 2 and 3 are looked up in the tables
* poly_to_exp (for step 2) and exp_to_poly (for step 3). To see this
* in action, look at the CALC_S macro. As additional wrinkles, note that
* one of my operands is always a constant, so the poly_to_exp lookup on it
* is done in advance; I included the original values in the comments so
* readers can have some chance of recognizing that this *is* the RS matrix
* from the Twofish paper. I've only included the table entries I actually
* need; I never do a lookup on a variable input of zero and the biggest
* exponents I'll ever see are 254 (variable) and 237 (constant), so they'll
* never sum to more than 491. I'm repeating part of the exp_to_poly table
* so that I don't have to do mod-255 reduction in the exponent arithmetic.
* Since I know my constant operands are never zero, I only have to worry
* about zero values in the variable operand, and I do it with a simple
* conditional branch. I know conditionals are expensive, but I couldn't
* see a non-horrible way of avoiding them, and I did manage to group the
* statements so that each if covers four group multiplications. */
static const byte poly_to_exp[255] = {
0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19,
0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A,
0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C,
0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B,
0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47,
0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D,
0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8,
0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C,
0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83,
0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48,
0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26,
0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E,
0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3,
0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9,
0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A,
0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D,
0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75,
0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84,
0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64,
0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49,
0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF,
0x85, 0xC8, 0xA1
};
static const byte exp_to_poly[492] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2,
0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03,
0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6,
0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A,
0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63,
0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C,
0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07,
0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88,
0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12,
0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7,
0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C,
0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8,
0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25,
0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A,
0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE,
0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC,
0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E,
0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92,
0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89,
0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB,
0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1,
0x8F, 0x53, 0xA6, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D,
0x9A, 0x79, 0xF2, 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC,
0xF5, 0xA7, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3,
0x8B, 0x5B, 0xB6, 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52,
0xA4, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0,
0xED, 0x97, 0x63, 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1,
0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A,
0xF4, 0xA5, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11,
0x22, 0x44, 0x88, 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51,
0xA2, 0x09, 0x12, 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66,
0xCC, 0xD5, 0xE7, 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB,
0x1B, 0x36, 0x6C, 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19,
0x32, 0x64, 0xC8, 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D,
0x5A, 0xB4, 0x25, 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56,
0xAC, 0x15, 0x2A, 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE,
0x91, 0x6F, 0xDE, 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9,
0x3F, 0x7E, 0xFC, 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE,
0xB1, 0x2F, 0x5E, 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41,
0x82, 0x49, 0x92, 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E,
0x71, 0xE2, 0x89, 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB
};
/* The table constants are indices of
* S-box entries, preprocessed through q0 and q1. */
static byte calc_sb_tbl[512] = {
0xA9, 0x75, 0x67, 0xF3, 0xB3, 0xC6, 0xE8, 0xF4,
0x04, 0xDB, 0xFD, 0x7B, 0xA3, 0xFB, 0x76, 0xC8,
0x9A, 0x4A, 0x92, 0xD3, 0x80, 0xE6, 0x78, 0x6B,
0xE4, 0x45, 0xDD, 0x7D, 0xD1, 0xE8, 0x38, 0x4B,
0x0D, 0xD6, 0xC6, 0x32, 0x35, 0xD8, 0x98, 0xFD,
0x18, 0x37, 0xF7, 0x71, 0xEC, 0xF1, 0x6C, 0xE1,
0x43, 0x30, 0x75, 0x0F, 0x37, 0xF8, 0x26, 0x1B,
0xFA, 0x87, 0x13, 0xFA, 0x94, 0x06, 0x48, 0x3F,
0xF2, 0x5E, 0xD0, 0xBA, 0x8B, 0xAE, 0x30, 0x5B,
0x84, 0x8A, 0x54, 0x00, 0xDF, 0xBC, 0x23, 0x9D,
0x19, 0x6D, 0x5B, 0xC1, 0x3D, 0xB1, 0x59, 0x0E,
0xF3, 0x80, 0xAE, 0x5D, 0xA2, 0xD2, 0x82, 0xD5,
0x63, 0xA0, 0x01, 0x84, 0x83, 0x07, 0x2E, 0x14,
0xD9, 0xB5, 0x51, 0x90, 0x9B, 0x2C, 0x7C, 0xA3,
0xA6, 0xB2, 0xEB, 0x73, 0xA5, 0x4C, 0xBE, 0x54,
0x16, 0x92, 0x0C, 0x74, 0xE3, 0x36, 0x61, 0x51,
0xC0, 0x38, 0x8C, 0xB0, 0x3A, 0xBD, 0xF5, 0x5A,
0x73, 0xFC, 0x2C, 0x60, 0x25, 0x62, 0x0B, 0x96,
0xBB, 0x6C, 0x4E, 0x42, 0x89, 0xF7, 0x6B, 0x10,
0x53, 0x7C, 0x6A, 0x28, 0xB4, 0x27, 0xF1, 0x8C,
0xE1, 0x13, 0xE6, 0x95, 0xBD, 0x9C, 0x45, 0xC7,
0xE2, 0x24, 0xF4, 0x46, 0xB6, 0x3B, 0x66, 0x70,
0xCC, 0xCA, 0x95, 0xE3, 0x03, 0x85, 0x56, 0xCB,
0xD4, 0x11, 0x1C, 0xD0, 0x1E, 0x93, 0xD7, 0xB8,
0xFB, 0xA6, 0xC3, 0x83, 0x8E, 0x20, 0xB5, 0xFF,
0xE9, 0x9F, 0xCF, 0x77, 0xBF, 0xC3, 0xBA, 0xCC,
0xEA, 0x03, 0x77, 0x6F, 0x39, 0x08, 0xAF, 0xBF,
0x33, 0x40, 0xC9, 0xE7, 0x62, 0x2B, 0x71, 0xE2,
0x81, 0x79, 0x79, 0x0C, 0x09, 0xAA, 0xAD, 0x82,
0x24, 0x41, 0xCD, 0x3A, 0xF9, 0xEA, 0xD8, 0xB9,
0xE5, 0xE4, 0xC5, 0x9A, 0xB9, 0xA4, 0x4D, 0x97,
0x44, 0x7E, 0x08, 0xDA, 0x86, 0x7A, 0xE7, 0x17,
0xA1, 0x66, 0x1D, 0x94, 0xAA, 0xA1, 0xED, 0x1D,
0x06, 0x3D, 0x70, 0xF0, 0xB2, 0xDE, 0xD2, 0xB3,
0x41, 0x0B, 0x7B, 0x72, 0xA0, 0xA7, 0x11, 0x1C,
0x31, 0xEF, 0xC2, 0xD1, 0x27, 0x53, 0x90, 0x3E,
0x20, 0x8F, 0xF6, 0x33, 0x60, 0x26, 0xFF, 0x5F,
0x96, 0xEC, 0x5C, 0x76, 0xB1, 0x2A, 0xAB, 0x49,
0x9E, 0x81, 0x9C, 0x88, 0x52, 0xEE, 0x1B, 0x21,
0x5F, 0xC4, 0x93, 0x1A, 0x0A, 0xEB, 0xEF, 0xD9,
0x91, 0xC5, 0x85, 0x39, 0x49, 0x99, 0xEE, 0xCD,
0x2D, 0xAD, 0x4F, 0x31, 0x8F, 0x8B, 0x3B, 0x01,
0x47, 0x18, 0x87, 0x23, 0x6D, 0xDD, 0x46, 0x1F,
0xD6, 0x4E, 0x3E, 0x2D, 0x69, 0xF9, 0x64, 0x48,
0x2A, 0x4F, 0xCE, 0xF2, 0xCB, 0x65, 0x2F, 0x8E,
0xFC, 0x78, 0x97, 0x5C, 0x05, 0x58, 0x7A, 0x19,
0xAC, 0x8D, 0x7F, 0xE5, 0xD5, 0x98, 0x1A, 0x57,
0x4B, 0x67, 0x0E, 0x7F, 0xA7, 0x05, 0x5A, 0x64,
0x28, 0xAF, 0x14, 0x63, 0x3F, 0xB6, 0x29, 0xFE,
0x88, 0xF5, 0x3C, 0xB7, 0x4C, 0x3C, 0x02, 0xA5,
0xB8, 0xCE, 0xDA, 0xE9, 0xB0, 0x68, 0x17, 0x44,
0x55, 0xE0, 0x1F, 0x4D, 0x8A, 0x43, 0x7D, 0x69,
0x57, 0x29, 0xC7, 0x2E, 0x8D, 0xAC, 0x74, 0x15,
0xB7, 0x59, 0xC4, 0xA8, 0x9F, 0x0A, 0x72, 0x9E,
0x7E, 0x6E, 0x15, 0x47, 0x22, 0xDF, 0x12, 0x34,
0x58, 0x35, 0x07, 0x6A, 0x99, 0xCF, 0x34, 0xDC,
0x6E, 0x22, 0x50, 0xC9, 0xDE, 0xC0, 0x68, 0x9B,
0x65, 0x89, 0xBC, 0xD4, 0xDB, 0xED, 0xF8, 0xAB,
0xC8, 0x12, 0xA8, 0xA2, 0x2B, 0x0D, 0x40, 0x52,
0xDC, 0xBB, 0xFE, 0x02, 0x32, 0x2F, 0xA4, 0xA9,
0xCA, 0xD7, 0x10, 0x61, 0x21, 0x1E, 0xF0, 0xB4,
0xD3, 0x50, 0x5D, 0x04, 0x0F, 0xF6, 0x00, 0xC2,
0x6F, 0x16, 0x9D, 0x25, 0x36, 0x86, 0x42, 0x56,
0x4A, 0x55, 0x5E, 0x09, 0xC1, 0xBE, 0xE0, 0x91
};
/* Macro to perform one column of the RS matrix multiplication. The
* parameters a, b, c, and d are the four bytes of output; i is the index
* of the key bytes, and w, x, y, and z, are the column of constants from
* the RS matrix, preprocessed through the poly_to_exp table. */
#define CALC_S(a, b, c, d, i, w, x, y, z) \
if (key[i]) { \
tmp = poly_to_exp[key[i] - 1]; \
(a) ^= exp_to_poly[tmp + (w)]; \
(b) ^= exp_to_poly[tmp + (x)]; \
(c) ^= exp_to_poly[tmp + (y)]; \
(d) ^= exp_to_poly[tmp + (z)]; \
}
/* Macros to calculate the key-dependent S-boxes for a 128-bit key using
* the S vector from CALC_S. CALC_SB_2 computes a single entry in all
* four S-boxes, where i is the index of the entry to compute, and a and b
* are the index numbers preprocessed through the q0 and q1 tables
* respectively. CALC_SB is simply a convenience to make the code shorter;
* it calls CALC_SB_2 four times with consecutive indices from i to i+3,
* using the remaining parameters two by two. */
#define CALC_SB_2(i, a, b) \
ctx->s[0][i] = mds[0][q0[(a) ^ sa] ^ se]; \
ctx->s[1][i] = mds[1][q0[(b) ^ sb] ^ sf]; \
ctx->s[2][i] = mds[2][q1[(a) ^ sc] ^ sg]; \
ctx->s[3][i] = mds[3][q1[(b) ^ sd] ^ sh]
#define CALC_SB(i, a, b, c, d, e, f, g, h) \
CALC_SB_2 (i, a, b); CALC_SB_2 ((i)+1, c, d); \
CALC_SB_2 ((i)+2, e, f); CALC_SB_2 ((i)+3, g, h)
/* Macros exactly like CALC_SB and CALC_SB_2, but for 256-bit keys. */
#define CALC_SB256_2(i, a, b) \
ctx->s[0][i] = mds[0][q0[q0[q1[(b) ^ sa] ^ se] ^ si] ^ sm]; \
ctx->s[1][i] = mds[1][q0[q1[q1[(a) ^ sb] ^ sf] ^ sj] ^ sn]; \
ctx->s[2][i] = mds[2][q1[q0[q0[(a) ^ sc] ^ sg] ^ sk] ^ so]; \
ctx->s[3][i] = mds[3][q1[q1[q0[(b) ^ sd] ^ sh] ^ sl] ^ sp];
#define CALC_SB256(i, a, b, c, d, e, f, g, h) \
CALC_SB256_2 (i, a, b); CALC_SB256_2 ((i)+1, c, d); \
CALC_SB256_2 ((i)+2, e, f); CALC_SB256_2 ((i)+3, g, h)
/* Macros to calculate the whitening and round subkeys. CALC_K_2 computes the
* last two stages of the h() function for a given index (either 2i or 2i+1).
* a, b, c, and d are the four bytes going into the last two stages. For
* 128-bit keys, this is the entire h() function and a and c are the index
* preprocessed through q0 and q1 respectively; for longer keys they are the
* output of previous stages. j is the index of the first key byte to use.
* CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2
* twice, doing the Pseudo-Hadamard Transform, and doing the necessary
* rotations. Its parameters are: a, the array to write the results into,
* j, the index of the first output entry, k and l, the preprocessed indices
* for index 2i, and m and n, the preprocessed indices for index 2i+1.
* CALC_K256_2 expands CALC_K_2 to handle 256-bit keys, by doing two
* additional lookup-and-XOR stages. The parameters a and b are the index
* preprocessed through q0 and q1 respectively; j is the index of the first
* key byte to use. CALC_K256 is identical to CALC_K but for using the
* CALC_K256_2 macro instead of CALC_K_2. */
#define CALC_K_2(a, b, c, d, j) \
mds[0][q0[a ^ key[(j) + 8]] ^ key[j]] \
^ mds[1][q0[b ^ key[(j) + 9]] ^ key[(j) + 1]] \
^ mds[2][q1[c ^ key[(j) + 10]] ^ key[(j) + 2]] \
^ mds[3][q1[d ^ key[(j) + 11]] ^ key[(j) + 3]]
#define CALC_K(a, j, k, l, m, n) \
x = CALC_K_2 (k, l, k, l, 0); \
y = CALC_K_2 (m, n, m, n, 4); \
y = (y << 8) + (y >> 24); \
x += y; y += x; ctx->a[j] = x; \
ctx->a[(j) + 1] = (y << 9) + (y >> 23)
#define CALC_K256_2(a, b, j) \
CALC_K_2 (q0[q1[b ^ key[(j) + 24]] ^ key[(j) + 16]], \
q1[q1[a ^ key[(j) + 25]] ^ key[(j) + 17]], \
q0[q0[a ^ key[(j) + 26]] ^ key[(j) + 18]], \
q1[q0[b ^ key[(j) + 27]] ^ key[(j) + 19]], j)
#define CALC_K256(a, j, k, l, m, n) \
x = CALC_K256_2 (k, l, 0); \
y = CALC_K256_2 (m, n, 4); \
y = (y << 8) + (y >> 24); \
x += y; y += x; ctx->a[j] = x; \
ctx->a[(j) + 1] = (y << 9) + (y >> 23)
/* Perform the key setup. Note that this works only with 128- and 256-bit
* keys, despite the API that looks like it might support other sizes. */
static gcry_err_code_t
do_twofish_setkey (TWOFISH_context *ctx, const byte *key, const unsigned keylen)
{
int i, j, k;
/* Temporaries for CALC_K. */
u32 x, y;
/* The S vector used to key the S-boxes, split up into individual bytes.
* 128-bit keys use only sa through sh; 256-bit use all of them. */
byte sa = 0, sb = 0, sc = 0, sd = 0, se = 0, sf = 0, sg = 0, sh = 0;
byte si = 0, sj = 0, sk = 0, sl = 0, sm = 0, sn = 0, so = 0, sp = 0;
/* Temporary for CALC_S. */
byte tmp;
/* Flags for self-test. */
static int initialized = 0;
static const char *selftest_failed=0;
/* Check key length. */
if( ( ( keylen - 16 ) | 16 ) != 16 )
return GPG_ERR_INV_KEYLEN;
/* Do self-test if necessary. */
if (!initialized)
{
initialized = 1;
selftest_failed = selftest ();
if( selftest_failed )
log_error("%s\n", selftest_failed );
}
if( selftest_failed )
return GPG_ERR_SELFTEST_FAILED;
/* Compute the first two words of the S vector. The magic numbers are
* the entries of the RS matrix, preprocessed through poly_to_exp. The
* numbers in the comments are the original (polynomial form) matrix
* entries. */
CALC_S (sa, sb, sc, sd, 0, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
CALC_S (sa, sb, sc, sd, 1, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
CALC_S (sa, sb, sc, sd, 2, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
CALC_S (sa, sb, sc, sd, 3, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
CALC_S (sa, sb, sc, sd, 4, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
CALC_S (sa, sb, sc, sd, 5, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
CALC_S (sa, sb, sc, sd, 6, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
CALC_S (sa, sb, sc, sd, 7, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
CALC_S (se, sf, sg, sh, 8, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
CALC_S (se, sf, sg, sh, 9, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
CALC_S (se, sf, sg, sh, 10, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
CALC_S (se, sf, sg, sh, 11, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
CALC_S (se, sf, sg, sh, 12, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
CALC_S (se, sf, sg, sh, 13, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
CALC_S (se, sf, sg, sh, 14, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
CALC_S (se, sf, sg, sh, 15, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
if (keylen == 32) /* 256-bit key */
{
/* Calculate the remaining two words of the S vector */
CALC_S (si, sj, sk, sl, 16, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
CALC_S (si, sj, sk, sl, 17, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
CALC_S (si, sj, sk, sl, 18, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
CALC_S (si, sj, sk, sl, 19, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
CALC_S (si, sj, sk, sl, 20, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
CALC_S (si, sj, sk, sl, 21, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
CALC_S (si, sj, sk, sl, 22, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
CALC_S (si, sj, sk, sl, 23, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
CALC_S (sm, sn, so, sp, 24, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
CALC_S (sm, sn, so, sp, 25, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
CALC_S (sm, sn, so, sp, 26, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
CALC_S (sm, sn, so, sp, 27, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
CALC_S (sm, sn, so, sp, 28, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
CALC_S (sm, sn, so, sp, 29, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
CALC_S (sm, sn, so, sp, 30, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
CALC_S (sm, sn, so, sp, 31, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
/* Compute the S-boxes. */
for(i=j=0,k=1; i < 256; i++, j += 2, k += 2 )
{
CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
}
/* Calculate whitening and round subkeys. The constants are
* indices of subkeys, preprocessed through q0 and q1. */
CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71);
CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F);
CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F);
CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00);
CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
}
else
{
/* Compute the S-boxes. */
for(i=j=0,k=1; i < 256; i++, j += 2, k += 2 )
{
CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
}
/* Calculate whitening and round subkeys. The constants are
* indices of subkeys, preprocessed through q0 and q1. */
CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3);
CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B);
CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD);
CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71);
CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F);
CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B);
CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA);
CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F);
CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00);
CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
}
return 0;
}
static gcry_err_code_t
twofish_setkey (void *context, const byte *key, unsigned int keylen)
{
TWOFISH_context *ctx = context;
int rc = do_twofish_setkey (ctx, key, keylen);
_gcry_burn_stack (23+6*sizeof(void*));
return rc;
}
#ifdef USE_AMD64_ASM
/* Assembly implementations of Twofish. */
extern void _gcry_twofish_amd64_encrypt_block(const TWOFISH_context *c,
byte *out, const byte *in);
extern void _gcry_twofish_amd64_decrypt_block(const TWOFISH_context *c,
byte *out, const byte *in);
/* These assembly implementations process three blocks in parallel. */
extern void _gcry_twofish_amd64_ctr_enc(const TWOFISH_context *c, byte *out,
const byte *in, byte *ctr);
extern void _gcry_twofish_amd64_cbc_dec(const TWOFISH_context *c, byte *out,
const byte *in, byte *iv);
extern void _gcry_twofish_amd64_cfb_dec(const TWOFISH_context *c, byte *out,
const byte *in, byte *iv);
#else /*!USE_AMD64_ASM*/
/* Macros to compute the g() function in the encryption and decryption
* rounds. G1 is the straight g() function; G2 includes the 8-bit
* rotation for the high 32-bit word. */
#define G1(a) \
(ctx->s[0][(a) & 0xFF]) ^ (ctx->s[1][((a) >> 8) & 0xFF]) \
^ (ctx->s[2][((a) >> 16) & 0xFF]) ^ (ctx->s[3][(a) >> 24])
#define G2(b) \
(ctx->s[1][(b) & 0xFF]) ^ (ctx->s[2][((b) >> 8) & 0xFF]) \
^ (ctx->s[3][((b) >> 16) & 0xFF]) ^ (ctx->s[0][(b) >> 24])
/* Encryption and decryption Feistel rounds. Each one calls the two g()
* macros, does the PHT, and performs the XOR and the appropriate bit
* rotations. The parameters are the round number (used to select subkeys),
* and the four 32-bit chunks of the text. */
#define ENCROUND(n, a, b, c, d) \
x = G1 (a); y = G2 (b); \
x += y; y += x + ctx->k[2 * (n) + 1]; \
(c) ^= x + ctx->k[2 * (n)]; \
(c) = ((c) >> 1) + ((c) << 31); \
(d) = (((d) << 1)+((d) >> 31)) ^ y
#define DECROUND(n, a, b, c, d) \
x = G1 (a); y = G2 (b); \
x += y; y += x; \
(d) ^= y + ctx->k[2 * (n) + 1]; \
(d) = ((d) >> 1) + ((d) << 31); \
(c) = (((c) << 1)+((c) >> 31)); \
(c) ^= (x + ctx->k[2 * (n)])
/* Encryption and decryption cycles; each one is simply two Feistel rounds
* with the 32-bit chunks re-ordered to simulate the "swap" */
#define ENCCYCLE(n) \
ENCROUND (2 * (n), a, b, c, d); \
ENCROUND (2 * (n) + 1, c, d, a, b)
#define DECCYCLE(n) \
DECROUND (2 * (n) + 1, c, d, a, b); \
DECROUND (2 * (n), a, b, c, d)
/* Macros to convert the input and output bytes into 32-bit words,
* and simultaneously perform the whitening step. INPACK packs word
* number n into the variable named by x, using whitening subkey number m.
* OUTUNPACK unpacks word number n from the variable named by x, using
* whitening subkey number m. */
#define INPACK(n, x, m) \
x = buf_get_le32(in + (n) * 4); \
x ^= ctx->w[m]
#define OUTUNPACK(n, x, m) \
x ^= ctx->w[m]; \
buf_put_le32(out + (n) * 4, x)
#endif /*!USE_AMD64_ASM*/
/* Encrypt one block. in and out may be the same. */
#ifdef USE_AMD64_ASM
static void
do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
{
_gcry_twofish_amd64_encrypt_block(ctx, out, in);
}
static unsigned int
twofish_encrypt (void *context, byte *out, const byte *in)
{
TWOFISH_context *ctx = context;
_gcry_twofish_amd64_encrypt_block(ctx, out, in);
return /*burn_stack*/ (4*sizeof (void*));
}
#else /*!USE_AMD64_ASM*/
static void
do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
{
/* The four 32-bit chunks of the text. */
u32 a, b, c, d;
/* Temporaries used by the round function. */
u32 x, y;
/* Input whitening and packing. */
INPACK (0, a, 0);
INPACK (1, b, 1);
INPACK (2, c, 2);
INPACK (3, d, 3);
/* Encryption Feistel cycles. */
ENCCYCLE (0);
ENCCYCLE (1);
ENCCYCLE (2);
ENCCYCLE (3);
ENCCYCLE (4);
ENCCYCLE (5);
ENCCYCLE (6);
ENCCYCLE (7);
/* Output whitening and unpacking. */
OUTUNPACK (0, c, 4);
OUTUNPACK (1, d, 5);
OUTUNPACK (2, a, 6);
OUTUNPACK (3, b, 7);
}
static unsigned int
twofish_encrypt (void *context, byte *out, const byte *in)
{
TWOFISH_context *ctx = context;
do_twofish_encrypt (ctx, out, in);
return /*burn_stack*/ (24+3*sizeof (void*));
}
#endif /*!USE_AMD64_ASM*/
/* Decrypt one block. in and out may be the same. */
#ifdef USE_AMD64_ASM
static void
do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
{
_gcry_twofish_amd64_decrypt_block(ctx, out, in);
}
static unsigned int
twofish_decrypt (void *context, byte *out, const byte *in)
{
TWOFISH_context *ctx = context;
_gcry_twofish_amd64_decrypt_block(ctx, out, in);
return /*burn_stack*/ (4*sizeof (void*));
}
#else /*!USE_AMD64_ASM*/
static void
do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
{
/* The four 32-bit chunks of the text. */
u32 a, b, c, d;
/* Temporaries used by the round function. */
u32 x, y;
/* Input whitening and packing. */
INPACK (0, c, 4);
INPACK (1, d, 5);
INPACK (2, a, 6);
INPACK (3, b, 7);
/* Encryption Feistel cycles. */
DECCYCLE (7);
DECCYCLE (6);
DECCYCLE (5);
DECCYCLE (4);
DECCYCLE (3);
DECCYCLE (2);
DECCYCLE (1);
DECCYCLE (0);
/* Output whitening and unpacking. */
OUTUNPACK (0, a, 0);
OUTUNPACK (1, b, 1);
OUTUNPACK (2, c, 2);
OUTUNPACK (3, d, 3);
}
static unsigned int
twofish_decrypt (void *context, byte *out, const byte *in)
{
TWOFISH_context *ctx = context;
do_twofish_decrypt (ctx, out, in);
return /*burn_stack*/ (24+3*sizeof (void*));
}
#endif /*!USE_AMD64_ASM*/
/* Bulk encryption of complete blocks in CTR mode. This function is only
intended for the bulk encryption feature of cipher.c. CTR is expected to be
of size TWOFISH_BLOCKSIZE. */
void
_gcry_twofish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg,
const void *inbuf_arg, unsigned int nblocks)
{
TWOFISH_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char tmpbuf[TWOFISH_BLOCKSIZE];
int burn_stack_depth = 24 + 3 * sizeof (void*);
int i;
#ifdef USE_AMD64_ASM
{
if (nblocks >= 3 && burn_stack_depth < 8 * sizeof(void*))
burn_stack_depth = 8 * sizeof(void*);
/* Process data in 3 block chunks. */
while (nblocks >= 3)
{
_gcry_twofish_amd64_ctr_enc(ctx, outbuf, inbuf, ctr);
nblocks -= 3;
outbuf += 3 * TWOFISH_BLOCKSIZE;
inbuf += 3 * TWOFISH_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
/* TODO: use caching instead? */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* Encrypt the counter. */
do_twofish_encrypt(ctx, tmpbuf, ctr);
/* XOR the input with the encrypted counter and store in output. */
buf_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE);
outbuf += TWOFISH_BLOCKSIZE;
inbuf += TWOFISH_BLOCKSIZE;
/* Increment the counter. */
for (i = TWOFISH_BLOCKSIZE; i > 0; i--)
{
ctr[i-1]++;
if (ctr[i-1])
break;
}
}
wipememory(tmpbuf, sizeof(tmpbuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CBC mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_twofish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
const void *inbuf_arg, unsigned int nblocks)
{
TWOFISH_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
unsigned char savebuf[TWOFISH_BLOCKSIZE];
int burn_stack_depth = 24 + 3 * sizeof (void*);
#ifdef USE_AMD64_ASM
{
if (nblocks >= 3 && burn_stack_depth < 9 * sizeof(void*))
burn_stack_depth = 9 * sizeof(void*);
/* Process data in 3 block chunks. */
while (nblocks >= 3)
{
_gcry_twofish_amd64_cbc_dec(ctx, outbuf, inbuf, iv);
nblocks -= 3;
outbuf += 3 * TWOFISH_BLOCKSIZE;
inbuf += 3 * TWOFISH_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
/* We need to save INBUF away because it may be identical to
OUTBUF. */
memcpy(savebuf, inbuf, TWOFISH_BLOCKSIZE);
do_twofish_decrypt (ctx, outbuf, inbuf);
buf_xor(outbuf, outbuf, iv, TWOFISH_BLOCKSIZE);
memcpy(iv, savebuf, TWOFISH_BLOCKSIZE);
inbuf += TWOFISH_BLOCKSIZE;
outbuf += TWOFISH_BLOCKSIZE;
}
wipememory(savebuf, sizeof(savebuf));
_gcry_burn_stack(burn_stack_depth);
}
/* Bulk decryption of complete blocks in CFB mode. This function is only
intended for the bulk encryption feature of cipher.c. */
void
_gcry_twofish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg,
const void *inbuf_arg, unsigned int nblocks)
{
TWOFISH_context *ctx = context;
unsigned char *outbuf = outbuf_arg;
const unsigned char *inbuf = inbuf_arg;
int burn_stack_depth = 24 + 3 * sizeof (void*);
#ifdef USE_AMD64_ASM
{
if (nblocks >= 3 && burn_stack_depth < 8 * sizeof(void*))
burn_stack_depth = 8 * sizeof(void*);
/* Process data in 3 block chunks. */
while (nblocks >= 3)
{
_gcry_twofish_amd64_cfb_dec(ctx, outbuf, inbuf, iv);
nblocks -= 3;
outbuf += 3 * TWOFISH_BLOCKSIZE;
inbuf += 3 * TWOFISH_BLOCKSIZE;
}
/* Use generic code to handle smaller chunks... */
}
#endif
for ( ;nblocks; nblocks-- )
{
do_twofish_encrypt(ctx, iv, iv);
buf_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE);
outbuf += TWOFISH_BLOCKSIZE;
inbuf += TWOFISH_BLOCKSIZE;
}
_gcry_burn_stack(burn_stack_depth);
}
/* Run the self-tests for TWOFISH-CTR, tests IV increment of bulk CTR
encryption. Returns NULL on success. */
static const char *
selftest_ctr (void)
{
const int nblocks = 3+1;
const int blocksize = TWOFISH_BLOCKSIZE;
const int context_size = sizeof(TWOFISH_context);
return _gcry_selftest_helper_ctr("TWOFISH", &twofish_setkey,
&twofish_encrypt, &_gcry_twofish_ctr_enc, nblocks, blocksize,
context_size);
}
/* Run the self-tests for TWOFISH-CBC, tests bulk CBC decryption.
Returns NULL on success. */
static const char *
selftest_cbc (void)
{
const int nblocks = 3+2;
const int blocksize = TWOFISH_BLOCKSIZE;
const int context_size = sizeof(TWOFISH_context);
return _gcry_selftest_helper_cbc("TWOFISH", &twofish_setkey,
&twofish_encrypt, &_gcry_twofish_cbc_dec, nblocks, blocksize,
context_size);
}
/* Run the self-tests for TWOFISH-CFB, tests bulk CBC decryption.
Returns NULL on success. */
static const char *
selftest_cfb (void)
{
const int nblocks = 3+2;
const int blocksize = TWOFISH_BLOCKSIZE;
const int context_size = sizeof(TWOFISH_context);
return _gcry_selftest_helper_cfb("TWOFISH", &twofish_setkey,
&twofish_encrypt, &_gcry_twofish_cfb_dec, nblocks, blocksize,
context_size);
}
/* Test a single encryption and decryption with each key size. */
static const char*
selftest (void)
{
TWOFISH_context ctx; /* Expanded key. */
byte scratch[16]; /* Encryption/decryption result buffer. */
const char *r;
/* Test vectors for single encryption/decryption. Note that I am using
* the vectors from the Twofish paper's "known answer test", I=3 for
* 128-bit and I=4 for 256-bit, instead of the all-0 vectors from the
* "intermediate value test", because an all-0 key would trigger all the
* special cases in the RS matrix multiply, leaving the math untested. */
static byte plaintext[16] = {
0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E,
0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19
};
static byte key[16] = {
0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32,
0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A
};
static const byte ciphertext[16] = {
0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85,
0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3
};
static byte plaintext_256[16] = {
0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F,
0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6
};
static byte key_256[32] = {
0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46,
0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B,
0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F
};
static const byte ciphertext_256[16] = {
0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97,
0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA
};
twofish_setkey (&ctx, key, sizeof(key));
twofish_encrypt (&ctx, scratch, plaintext);
if (memcmp (scratch, ciphertext, sizeof (ciphertext)))
return "Twofish-128 test encryption failed.";
twofish_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext, sizeof (plaintext)))
return "Twofish-128 test decryption failed.";
twofish_setkey (&ctx, key_256, sizeof(key_256));
twofish_encrypt (&ctx, scratch, plaintext_256);
if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256)))
return "Twofish-256 test encryption failed.";
twofish_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext_256, sizeof (plaintext_256)))
return "Twofish-256 test decryption failed.";
if ((r = selftest_ctr()) != NULL)
return r;
if ((r = selftest_cbc()) != NULL)
return r;
if ((r = selftest_cfb()) != NULL)
return r;
return NULL;
}
/* More complete test program. This does 1000 encryptions and decryptions
* with each of 250 128-bit keys and 2000 encryptions and decryptions with
* each of 125 256-bit keys, using a feedback scheme similar to a Feistel
* cipher, so as to be sure of testing all the table entries pretty
* thoroughly. We keep changing the keys so as to get a more meaningful
* performance number, since the key setup is non-trivial for Twofish. */
#ifdef TEST
#include <stdio.h>
#include <string.h>
#include <time.h>
int
main()
{
TWOFISH_context ctx; /* Expanded key. */
int i, j; /* Loop counters. */
const char *encrypt_msg; /* Message to print regarding encryption test;
* the printf is done outside the loop to avoid
* stuffing up the timing. */
clock_t timer; /* For computing elapsed time. */
/* Test buffer. */
byte buffer[4][16] = {
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
{0x0F, 0x1E, 0x2D, 0x3C, 0x4B, 0x5A, 0x69, 0x78,
0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2 ,0xE1, 0xF0},
{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54 ,0x32, 0x10},
{0x01, 0x23, 0x45, 0x67, 0x76, 0x54 ,0x32, 0x10,
0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98}
};
/* Expected outputs for the million-operation test */
static const byte test_encrypt[4][16] = {
{0xC8, 0x23, 0xB8, 0xB7, 0x6B, 0xFE, 0x91, 0x13,
0x2F, 0xA7, 0x5E, 0xE6, 0x94, 0x77, 0x6F, 0x6B},
{0x90, 0x36, 0xD8, 0x29, 0xD5, 0x96, 0xC2, 0x8E,
0xE4, 0xFF, 0x76, 0xBC, 0xE5, 0x77, 0x88, 0x27},
{0xB8, 0x78, 0x69, 0xAF, 0x42, 0x8B, 0x48, 0x64,
0xF7, 0xE9, 0xF3, 0x9C, 0x42, 0x18, 0x7B, 0x73},
{0x7A, 0x88, 0xFB, 0xEB, 0x90, 0xA4, 0xB4, 0xA8,
0x43, 0xA3, 0x1D, 0xF1, 0x26, 0xC4, 0x53, 0x57}
};
static const byte test_decrypt[4][16] = {
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
{0x0F, 0x1E, 0x2D, 0x3C, 0x4B, 0x5A, 0x69, 0x78,
0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2 ,0xE1, 0xF0},
{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54 ,0x32, 0x10},
{0x01, 0x23, 0x45, 0x67, 0x76, 0x54 ,0x32, 0x10,
0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98}
};
/* Start the timer ticking. */
timer = clock ();
/* Encryption test. */
for (i = 0; i < 125; i++)
{
twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]));
for (j = 0; j < 1000; j++)
twofish_encrypt (&ctx, buffer[2], buffer[2]);
twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]));
for (j = 0; j < 1000; j++)
twofish_encrypt (&ctx, buffer[3], buffer[3]);
twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2);
for (j = 0; j < 1000; j++) {
twofish_encrypt (&ctx, buffer[0], buffer[0]);
twofish_encrypt (&ctx, buffer[1], buffer[1]);
}
}
encrypt_msg = memcmp (buffer, test_encrypt, sizeof (test_encrypt)) ?
"encryption failure!\n" : "encryption OK!\n";
/* Decryption test. */
for (i = 0; i < 125; i++)
{
twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2);
for (j = 0; j < 1000; j++) {
twofish_decrypt (&ctx, buffer[0], buffer[0]);
twofish_decrypt (&ctx, buffer[1], buffer[1]);
}
twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]));
for (j = 0; j < 1000; j++)
twofish_decrypt (&ctx, buffer[3], buffer[3]);
twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]));
for (j = 0; j < 1000; j++)
twofish_decrypt (&ctx, buffer[2], buffer[2]);
}
/* Stop the timer, and print results. */
timer = clock () - timer;
printf (encrypt_msg);
printf (memcmp (buffer, test_decrypt, sizeof (test_decrypt)) ?
"decryption failure!\n" : "decryption OK!\n");
printf ("elapsed time: %.1f s.\n", (float) timer / CLOCKS_PER_SEC);
return 0;
}
#endif /* TEST */
gcry_cipher_spec_t _gcry_cipher_spec_twofish =
{
+ GCRY_CIPHER_TWOFISH, {0, 0},
"TWOFISH", NULL, NULL, 16, 256, sizeof (TWOFISH_context),
twofish_setkey, twofish_encrypt, twofish_decrypt
};
gcry_cipher_spec_t _gcry_cipher_spec_twofish128 =
{
+ GCRY_CIPHER_TWOFISH128, {0, 0},
"TWOFISH128", NULL, NULL, 16, 128, sizeof (TWOFISH_context),
twofish_setkey, twofish_encrypt, twofish_decrypt
};
diff --git a/src/cipher-proto.h b/src/cipher-proto.h
index 5b152b59..62bc8b97 100644
--- a/src/cipher-proto.h
+++ b/src/cipher-proto.h
@@ -1,205 +1,265 @@
/* cipher-proto.h - Internal declarations
* Copyright (C) 2008, 2011 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* This file has been factored out from cipher.h so that it can be
used standalone in visibility.c . */
#ifndef G10_CIPHER_PROTO_H
#define G10_CIPHER_PROTO_H
enum pk_encoding;
/* Definition of a function used to report selftest failures.
DOMAIN is a string describing the function block:
"cipher", "digest", "pubkey or "random",
ALGO is the algorithm under test,
WHAT is a string describing what has been tested,
DESC is a string describing the error. */
typedef void (*selftest_report_func_t)(const char *domain,
int algo,
const char *what,
const char *errdesc);
/* Definition of the selftest functions. */
typedef gpg_err_code_t (*selftest_func_t)
(int algo, int extended, selftest_report_func_t report);
/*
*
* Public key related definitions.
*
*/
/* Type for the pk_generate function. */
typedef gcry_err_code_t (*gcry_pk_generate_t) (int algo,
unsigned int nbits,
unsigned long evalue,
gcry_sexp_t genparms,
gcry_sexp_t *r_skey);
/* Type for the pk_check_secret_key function. */
typedef gcry_err_code_t (*gcry_pk_check_secret_key_t) (int algo,
gcry_mpi_t *skey);
/* Type for the pk_encrypt function. */
typedef gcry_err_code_t (*gcry_pk_encrypt_t) (int algo,
gcry_sexp_t *r_result,
gcry_mpi_t data,
gcry_mpi_t *pkey,
int flags);
/* Type for the pk_decrypt function. */
typedef gcry_err_code_t (*gcry_pk_decrypt_t) (int algo,
gcry_sexp_t *r_result,
gcry_mpi_t *data,
gcry_mpi_t *skey,
int flags,
enum pk_encoding encoding,
int hash_algo,
unsigned char *label,
size_t labellen);
/* Type for the pk_sign function. */
typedef gcry_err_code_t (*gcry_pk_sign_t) (int algo,
gcry_sexp_t *r_result,
gcry_mpi_t data,
gcry_mpi_t *skey,
int flags,
int hashalgo);
/* Type for the pk_verify function. */
typedef gcry_err_code_t (*gcry_pk_verify_t) (int algo,
gcry_mpi_t hash,
gcry_mpi_t *data,
gcry_mpi_t *pkey,
int (*cmp) (void *, gcry_mpi_t),
void *opaquev,
int flags,
int hashalgo);
/* Type for the pk_get_nbits function. */
typedef unsigned (*gcry_pk_get_nbits_t) (int algo,
gcry_mpi_t *pkey);
/* The type used to compute the keygrip. */
typedef gpg_err_code_t (*pk_comp_keygrip_t) (gcry_md_hd_t md,
gcry_sexp_t keyparm);
/* The type used to query ECC curve parameters. */
typedef gcry_err_code_t (*pk_get_param_t) (const char *name,
gcry_mpi_t *pkey);
/* The type used to query an ECC curve name. */
typedef const char *(*pk_get_curve_t)(gcry_mpi_t *pkey, int iterator,
unsigned int *r_nbits);
/* The type used to query ECC curve parameters by name. */
typedef gcry_sexp_t (*pk_get_curve_param_t)(const char *name);
/* Module specification structure for public key algoritms. */
typedef struct gcry_pk_spec
{
int algo;
struct {
unsigned int disabled:1;
unsigned int fips:1;
} flags;
int use;
const char *name;
const char **aliases;
const char *elements_pkey;
const char *elements_skey;
const char *elements_enc;
const char *elements_sig;
const char *elements_grip;
gcry_pk_generate_t generate;
gcry_pk_check_secret_key_t check_secret_key;
gcry_pk_encrypt_t encrypt;
gcry_pk_decrypt_t decrypt;
gcry_pk_sign_t sign;
gcry_pk_verify_t verify;
gcry_pk_get_nbits_t get_nbits;
selftest_func_t selftest;
pk_comp_keygrip_t comp_keygrip;
pk_get_param_t get_param;
pk_get_curve_t get_curve;
pk_get_curve_param_t get_curve_param;
} gcry_pk_spec_t;
+/*
+ *
+ * Symmetric cipher related definitions.
+ *
+ */
+
+/* Type for the cipher_setkey function. */
+typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c,
+ const unsigned char *key,
+ unsigned keylen);
+
+/* Type for the cipher_encrypt function. */
+typedef unsigned int (*gcry_cipher_encrypt_t) (void *c,
+ unsigned char *outbuf,
+ const unsigned char *inbuf);
+
+/* Type for the cipher_decrypt function. */
+typedef unsigned int (*gcry_cipher_decrypt_t) (void *c,
+ unsigned char *outbuf,
+ const unsigned char *inbuf);
+
+/* Type for the cipher_stencrypt function. */
+typedef void (*gcry_cipher_stencrypt_t) (void *c,
+ unsigned char *outbuf,
+ const unsigned char *inbuf,
+ unsigned int n);
+
+/* Type for the cipher_stdecrypt function. */
+typedef void (*gcry_cipher_stdecrypt_t) (void *c,
+ unsigned char *outbuf,
+ const unsigned char *inbuf,
+ unsigned int n);
+
/* The type used to convey additional information to a cipher. */
typedef gpg_err_code_t (*cipher_set_extra_info_t)
(void *c, int what, const void *buffer, size_t buflen);
/* The type used to set an IV directly in the algorithm module. */
typedef void (*cipher_setiv_func_t)(void *c,
const byte *iv, unsigned int ivlen);
-/* Extra module specification structures. These are used for internal
- modules which provide more functions than available through the
- public algorithm register APIs. */
-typedef struct cipher_extra_spec
+/* A structure to map OIDs to encryption modes. */
+typedef struct gcry_cipher_oid_spec
{
+ const char *oid;
+ int mode;
+} gcry_cipher_oid_spec_t;
+
+
+/* Module specification structure for ciphers. */
+typedef struct gcry_cipher_spec
+{
+ int algo;
+ struct {
+ unsigned int disabled:1;
+ unsigned int fips:1;
+ } flags;
+ const char *name;
+ const char **aliases;
+ gcry_cipher_oid_spec_t *oids;
+ size_t blocksize;
+ size_t keylen;
+ size_t contextsize;
+ gcry_cipher_setkey_t setkey;
+ gcry_cipher_encrypt_t encrypt;
+ gcry_cipher_decrypt_t decrypt;
+ gcry_cipher_stencrypt_t stencrypt;
+ gcry_cipher_stdecrypt_t stdecrypt;
selftest_func_t selftest;
cipher_set_extra_info_t set_extra_info;
cipher_setiv_func_t setiv;
-} cipher_extra_spec_t;
+} gcry_cipher_spec_t;
+
+
+
+/*
+ *
+ * Message digest related definitions.
+ *
+ */
typedef struct md_extra_spec
{
selftest_func_t selftest;
} md_extra_spec_t;
+
/* The private register functions. */
-gcry_error_t _gcry_cipher_register (gcry_cipher_spec_t *cipher,
- cipher_extra_spec_t *extraspec,
- int *algorithm_id,
- gcry_module_t *module);
gcry_error_t _gcry_md_register (gcry_md_spec_t *cipher,
md_extra_spec_t *extraspec,
unsigned int *algorithm_id,
gcry_module_t *module);
/* The selftest functions. */
gcry_error_t _gcry_cipher_selftest (int algo, int extended,
selftest_report_func_t report);
gcry_error_t _gcry_md_selftest (int algo, int extended,
selftest_report_func_t report);
gcry_error_t _gcry_pk_selftest (int algo, int extended,
selftest_report_func_t report);
gcry_error_t _gcry_hmac_selftest (int algo, int extended,
selftest_report_func_t report);
gcry_error_t _gcry_random_selftest (selftest_report_func_t report);
/*-- pubkey.c --*/
gcry_err_code_t _gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp,
int reserved, gcry_ctx_t ctx);
#endif /*G10_CIPHER_PROTO_H*/
diff --git a/src/cipher.h b/src/cipher.h
index 70b46fe2..d080e72d 100644
--- a/src/cipher.h
+++ b/src/cipher.h
@@ -1,247 +1,241 @@
/* cipher.h
* Copyright (C) 1998, 2002, 2003, 2009 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#ifndef G10_CIPHER_H
#define G10_CIPHER_H
#include "gcrypt-int.h"
#define DBG_CIPHER _gcry_get_debug_flag( 1 )
#include "../random/random.h"
#define PUBKEY_FLAG_NO_BLINDING (1 << 0)
#define PUBKEY_FLAG_RFC6979 (1 << 1)
#define PUBKEY_FLAG_EDDSA (1 << 2)
#define PUBKEY_FLAG_FIXEDLEN (1 << 3)
#define PUBKEY_FLAG_LEGACYRESULT (1 << 4)
enum pk_operation
{
PUBKEY_OP_ENCRYPT,
PUBKEY_OP_DECRYPT,
PUBKEY_OP_SIGN,
PUBKEY_OP_VERIFY
};
enum pk_encoding
{
PUBKEY_ENC_RAW,
PUBKEY_ENC_PKCS1,
PUBKEY_ENC_OAEP,
PUBKEY_ENC_PSS,
PUBKEY_ENC_UNKNOWN
};
struct pk_encoding_ctx
{
enum pk_operation op;
unsigned int nbits;
enum pk_encoding encoding;
int flags;
int hash_algo;
/* for OAEP */
unsigned char *label;
size_t labellen;
/* for PSS */
size_t saltlen;
int (* verify_cmp) (void *opaque, gcry_mpi_t tmp);
void *verify_arg;
};
#define CIPHER_INFO_NO_WEAK_KEY 1
#include "cipher-proto.h"
/*-- rmd160.c --*/
void _gcry_rmd160_hash_buffer (void *outbuf,
const void *buffer, size_t length);
/*-- sha1.c --*/
void _gcry_sha1_hash_buffer (void *outbuf,
const void *buffer, size_t length);
void _gcry_sha1_hash_buffers (void *outbuf,
const gcry_buffer_t *iov, int iovcnt);
/*-- rijndael.c --*/
void _gcry_aes_cfb_enc (void *context, unsigned char *iv,
void *outbuf, const void *inbuf,
unsigned int nblocks);
void _gcry_aes_cfb_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_aes_cbc_enc (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks, int cbc_mac);
void _gcry_aes_cbc_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_aes_ctr_enc (void *context, unsigned char *ctr,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
/*-- blowfish.c --*/
void _gcry_blowfish_cfb_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_blowfish_cbc_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_blowfish_ctr_enc (void *context, unsigned char *ctr,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
/*-- cast5.c --*/
void _gcry_cast5_cfb_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_cast5_cbc_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_cast5_ctr_enc (void *context, unsigned char *ctr,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
/*-- camellia-glue.c --*/
void _gcry_camellia_ctr_enc (void *context, unsigned char *ctr,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_camellia_cbc_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_camellia_cfb_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
/*-- serpent.c --*/
void _gcry_serpent_ctr_enc (void *context, unsigned char *ctr,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_serpent_cbc_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_serpent_cfb_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
/*-- twofish.c --*/
void _gcry_twofish_ctr_enc (void *context, unsigned char *ctr,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_twofish_cbc_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
void _gcry_twofish_cfb_dec (void *context, unsigned char *iv,
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks);
/*-- dsa.c --*/
void _gcry_register_pk_dsa_progress (gcry_handler_progress_t cbc, void *cb_data);
/*-- elgamal.c --*/
void _gcry_register_pk_elg_progress (gcry_handler_progress_t cb,
void *cb_data);
/*-- ecc.c --*/
void _gcry_register_pk_ecc_progress (gcry_handler_progress_t cbc,
void *cb_data);
/*-- primegen.c --*/
void _gcry_register_primegen_progress (gcry_handler_progress_t cb,
void *cb_data);
/*-- pubkey.c --*/
/* Declarations for the cipher specifications. */
extern gcry_cipher_spec_t _gcry_cipher_spec_blowfish;
extern gcry_cipher_spec_t _gcry_cipher_spec_des;
extern gcry_cipher_spec_t _gcry_cipher_spec_tripledes;
extern gcry_cipher_spec_t _gcry_cipher_spec_arcfour;
extern gcry_cipher_spec_t _gcry_cipher_spec_cast5;
extern gcry_cipher_spec_t _gcry_cipher_spec_aes;
extern gcry_cipher_spec_t _gcry_cipher_spec_aes192;
extern gcry_cipher_spec_t _gcry_cipher_spec_aes256;
extern gcry_cipher_spec_t _gcry_cipher_spec_twofish;
extern gcry_cipher_spec_t _gcry_cipher_spec_twofish128;
extern gcry_cipher_spec_t _gcry_cipher_spec_serpent128;
extern gcry_cipher_spec_t _gcry_cipher_spec_serpent192;
extern gcry_cipher_spec_t _gcry_cipher_spec_serpent256;
extern gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40;
extern gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128;
extern gcry_cipher_spec_t _gcry_cipher_spec_seed;
extern gcry_cipher_spec_t _gcry_cipher_spec_camellia128;
extern gcry_cipher_spec_t _gcry_cipher_spec_camellia192;
extern gcry_cipher_spec_t _gcry_cipher_spec_camellia256;
extern gcry_cipher_spec_t _gcry_cipher_spec_idea;
extern gcry_cipher_spec_t _gcry_cipher_spec_salsa20;
extern gcry_cipher_spec_t _gcry_cipher_spec_salsa20r12;
extern gcry_cipher_spec_t _gcry_cipher_spec_gost28147;
-extern cipher_extra_spec_t _gcry_cipher_extraspec_tripledes;
-extern cipher_extra_spec_t _gcry_cipher_extraspec_aes;
-extern cipher_extra_spec_t _gcry_cipher_extraspec_aes192;
-extern cipher_extra_spec_t _gcry_cipher_extraspec_aes256;
-extern cipher_extra_spec_t _gcry_cipher_extraspec_salsa20;
-
/* Declarations for the digest specifications. */
extern gcry_md_spec_t _gcry_digest_spec_crc32;
extern gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510;
extern gcry_md_spec_t _gcry_digest_spec_crc24_rfc2440;
extern gcry_md_spec_t _gcry_digest_spec_gost3411_94;
extern gcry_md_spec_t _gcry_digest_spec_stribog_256;
extern gcry_md_spec_t _gcry_digest_spec_stribog_512;
extern gcry_md_spec_t _gcry_digest_spec_md4;
extern gcry_md_spec_t _gcry_digest_spec_md5;
extern gcry_md_spec_t _gcry_digest_spec_rmd160;
extern gcry_md_spec_t _gcry_digest_spec_sha1;
extern gcry_md_spec_t _gcry_digest_spec_sha224;
extern gcry_md_spec_t _gcry_digest_spec_sha256;
extern gcry_md_spec_t _gcry_digest_spec_sha512;
extern gcry_md_spec_t _gcry_digest_spec_sha384;
extern gcry_md_spec_t _gcry_digest_spec_tiger;
extern gcry_md_spec_t _gcry_digest_spec_tiger1;
extern gcry_md_spec_t _gcry_digest_spec_tiger2;
extern gcry_md_spec_t _gcry_digest_spec_whirlpool;
extern md_extra_spec_t _gcry_digest_extraspec_sha1;
extern md_extra_spec_t _gcry_digest_extraspec_sha224;
extern md_extra_spec_t _gcry_digest_extraspec_sha256;
extern md_extra_spec_t _gcry_digest_extraspec_sha384;
extern md_extra_spec_t _gcry_digest_extraspec_sha512;
/* Declarations for the pubkey cipher specifications. */
extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
extern gcry_pk_spec_t _gcry_pubkey_spec_elg;
extern gcry_pk_spec_t _gcry_pubkey_spec_elg_e;
extern gcry_pk_spec_t _gcry_pubkey_spec_dsa;
extern gcry_pk_spec_t _gcry_pubkey_spec_ecc;
#endif /*G10_CIPHER_H*/
diff --git a/src/gcrypt-module.h b/src/gcrypt-module.h
index 9fcb8ab1..621a3a43 100644
--- a/src/gcrypt-module.h
+++ b/src/gcrypt-module.h
@@ -1,141 +1,88 @@
/* gcrypt-module.h - GNU Cryptographic Library Interface
Copyright (C) 2003, 2007 Free Software Foundation, Inc.
This file is part of Libgcrypt.
Libgcrypt is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
Libgcrypt 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/*
This file contains the necessary declarations/definitions for
working with Libgcrypt modules. Since 1.6 this is an internal
interface and will eventually be merged into another header or
entirely removed.
*/
#ifndef GCRYPT_MODULE_H
#define GCRYPT_MODULE_H
#ifdef __cplusplus
extern "C" {
#if 0 /* keep Emacsens's auto-indent happy */
}
#endif
#endif
/* The interfaces using the module system reserve a certain range of
IDs for application use. These IDs are not valid within Libgcrypt
but Libgcrypt makes sure never to allocate such a module ID. */
#define GCRY_MODULE_ID_USER 1024
#define GCRY_MODULE_ID_USER_LAST 4095
/* This type represents a `module'. */
typedef struct gcry_module *gcry_module_t;
-/* Check that the library fulfills the version requirement. */
-
-/* Type for the cipher_setkey function. */
-typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c,
- const unsigned char *key,
- unsigned keylen);
-
-/* Type for the cipher_encrypt function. */
-typedef unsigned int (*gcry_cipher_encrypt_t) (void *c,
- unsigned char *outbuf,
- const unsigned char *inbuf);
-
-/* Type for the cipher_decrypt function. */
-typedef unsigned int (*gcry_cipher_decrypt_t) (void *c,
- unsigned char *outbuf,
- const unsigned char *inbuf);
-
-/* Type for the cipher_stencrypt function. */
-typedef void (*gcry_cipher_stencrypt_t) (void *c,
- unsigned char *outbuf,
- const unsigned char *inbuf,
- unsigned int n);
-
-/* Type for the cipher_stdecrypt function. */
-typedef void (*gcry_cipher_stdecrypt_t) (void *c,
- unsigned char *outbuf,
- const unsigned char *inbuf,
- unsigned int n);
-
-typedef struct gcry_cipher_oid_spec
-{
- const char *oid;
- int mode;
-} gcry_cipher_oid_spec_t;
-
-/* Module specification structure for ciphers. */
-typedef struct gcry_cipher_spec
-{
- const char *name;
- const char **aliases;
- gcry_cipher_oid_spec_t *oids;
- size_t blocksize;
- size_t keylen;
- size_t contextsize;
- gcry_cipher_setkey_t setkey;
- gcry_cipher_encrypt_t encrypt;
- gcry_cipher_decrypt_t decrypt;
- gcry_cipher_stencrypt_t stencrypt;
- gcry_cipher_stdecrypt_t stdecrypt;
-} gcry_cipher_spec_t;
-
-
-/* ********************** */
/* ********************** */
/* Type for the md_init function. */
typedef void (*gcry_md_init_t) (void *c);
/* Type for the md_write function. */
typedef void (*gcry_md_write_t) (void *c, const void *buf, size_t nbytes);
/* Type for the md_final function. */
typedef void (*gcry_md_final_t) (void *c);
/* Type for the md_read function. */
typedef unsigned char *(*gcry_md_read_t) (void *c);
typedef struct gcry_md_oid_spec
{
const char *oidstring;
} gcry_md_oid_spec_t;
/* Module specification structure for message digests. */
typedef struct gcry_md_spec
{
const char *name;
unsigned char *asnoid;
int asnlen;
gcry_md_oid_spec_t *oids;
int mdlen;
gcry_md_init_t init;
gcry_md_write_t write;
gcry_md_final_t final;
gcry_md_read_t read;
size_t contextsize; /* allocate this amount of context */
} gcry_md_spec_t;
#if 0 /* keep Emacsens's auto-indent happy */
{
#endif
#ifdef __cplusplus
}
#endif
#endif /*GCRYPT_MODULE_H*/

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 4, 2:27 PM (1 d, 16 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
2f/d3/203b843b59cfdd865c35dcbb8e70

Event Timeline