summaryrefslogtreecommitdiff
path: root/plugins/MirOTR/Libgcrypt/cipher/twofish.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/cipher/twofish.c')
-rw-r--r--plugins/MirOTR/Libgcrypt/cipher/twofish.c340
1 files changed, 326 insertions, 14 deletions
diff --git a/plugins/MirOTR/Libgcrypt/cipher/twofish.c b/plugins/MirOTR/Libgcrypt/cipher/twofish.c
index 5274c4001d..ecd76e359e 100644
--- a/plugins/MirOTR/Libgcrypt/cipher/twofish.c
+++ b/plugins/MirOTR/Libgcrypt/cipher/twofish.c
@@ -44,6 +44,27 @@
#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
+
+/* USE_ARM_ASM indicates whether to use ARM assembly code. */
+#undef USE_ARM_ASM
+#if defined(__ARMEL__)
+# if defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS)
+# define USE_ARM_ASM 1
+# endif
+#endif
+
/* Prototype for the self-test function. */
static const char *selftest(void);
@@ -522,7 +543,7 @@ static byte calc_sb_tbl[512] = {
* 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 Psuedo-Hadamard Transform, and doing the necessary
+ * 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.
@@ -575,10 +596,10 @@ do_twofish_setkey (TWOFISH_context *ctx, const byte *key, const unsigned keylen)
* 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;
@@ -668,7 +689,7 @@ do_twofish_setkey (TWOFISH_context *ctx, const byte *key, const unsigned keylen)
CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00);
CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
}
- else
+ else
{
/* Compute the S-boxes. */
for(i=j=0,k=1; i < 256; i++, j += 2, k += 2 )
@@ -714,6 +735,36 @@ twofish_setkey (void *context, const byte *key, unsigned int keylen)
+#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);
+
+#elif defined(USE_ARM_ASM)
+
+/* Assembly implementations of Twofish. */
+extern void _gcry_twofish_arm_encrypt_block(const TWOFISH_context *c,
+ byte *out, const byte *in);
+
+extern void _gcry_twofish_arm_decrypt_block(const TWOFISH_context *c,
+ byte *out, const byte *in);
+
+#else /*!USE_AMD64_ASM && !USE_ARM_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. */
@@ -764,16 +815,40 @@ twofish_setkey (void *context, const byte *key, unsigned int keylen)
* whitening subkey number m. */
#define INPACK(n, x, m) \
- x = in[4 * (n)] ^ (in[4 * (n) + 1] << 8) \
- ^ (in[4 * (n) + 2] << 16) ^ (in[4 * (n) + 3] << 24) ^ ctx->w[m]
+ x = buf_get_le32(in + (n) * 4); \
+ x ^= ctx->w[m]
#define OUTUNPACK(n, x, m) \
x ^= ctx->w[m]; \
- out[4 * (n)] = x; out[4 * (n) + 1] = x >> 8; \
- out[4 * (n) + 2] = x >> 16; out[4 * (n) + 3] = x >> 24
+ 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 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*));
+}
+
+#elif defined(USE_ARM_ASM)
+
+static unsigned int
+twofish_encrypt (void *context, byte *out, const byte *in)
+{
+ TWOFISH_context *ctx = context;
+ _gcry_twofish_arm_encrypt_block(ctx, out, in);
+ return /*burn_stack*/ (4*sizeof (void*));
+}
+
+#else /*!USE_AMD64_ASM && !USE_ARM_ASM*/
+
static void
do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
{
@@ -806,17 +881,41 @@ do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
OUTUNPACK (3, b, 7);
}
-static void
+static unsigned int
twofish_encrypt (void *context, byte *out, const byte *in)
{
TWOFISH_context *ctx = context;
do_twofish_encrypt (ctx, out, in);
- _gcry_burn_stack (24+3*sizeof (void*));
+ return /*burn_stack*/ (24+3*sizeof (void*));
}
+#endif /*!USE_AMD64_ASM && !USE_ARM_ASM*/
+
/* Decrypt one block. in and out may be the same. */
+#ifdef USE_AMD64_ASM
+
+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*));
+}
+
+#elif defined(USE_ARM_ASM)
+
+static unsigned int
+twofish_decrypt (void *context, byte *out, const byte *in)
+{
+ TWOFISH_context *ctx = context;
+ _gcry_twofish_arm_decrypt_block(ctx, out, in);
+ return /*burn_stack*/ (4*sizeof (void*));
+}
+
+#else /*!USE_AMD64_ASM && !USE_ARM_ASM*/
+
static void
do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
{
@@ -849,13 +948,216 @@ do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
OUTUNPACK (3, d, 3);
}
-static void
+static unsigned int
twofish_decrypt (void *context, byte *out, const byte *in)
{
TWOFISH_context *ctx = context;
do_twofish_decrypt (ctx, out, in);
- _gcry_burn_stack (24+3*sizeof (void*));
+ return /*burn_stack*/ (24+3*sizeof (void*));
+}
+
+#endif /*!USE_AMD64_ASM && !USE_ARM_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, size_t nblocks)
+{
+ TWOFISH_context *ctx = context;
+ unsigned char *outbuf = outbuf_arg;
+ const unsigned char *inbuf = inbuf_arg;
+ unsigned char tmpbuf[TWOFISH_BLOCKSIZE];
+ unsigned int burn, burn_stack_depth = 0;
+ int i;
+
+#ifdef USE_AMD64_ASM
+ {
+ /* 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;
+
+ burn = 8 * sizeof(void*);
+ if (burn > burn_stack_depth)
+ burn_stack_depth = burn;
+ }
+
+ /* Use generic code to handle smaller chunks... */
+ /* TODO: use caching instead? */
+ }
+#endif
+
+ for ( ;nblocks; nblocks-- )
+ {
+ /* Encrypt the counter. */
+ burn = twofish_encrypt(ctx, tmpbuf, ctr);
+ if (burn > burn_stack_depth)
+ burn_stack_depth = burn;
+
+ /* 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, size_t nblocks)
+{
+ TWOFISH_context *ctx = context;
+ unsigned char *outbuf = outbuf_arg;
+ const unsigned char *inbuf = inbuf_arg;
+ unsigned char savebuf[TWOFISH_BLOCKSIZE];
+ unsigned int burn, burn_stack_depth = 0;
+
+#ifdef USE_AMD64_ASM
+ {
+ /* 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;
+
+ burn = 9 * sizeof(void*);
+ if (burn > burn_stack_depth)
+ burn_stack_depth = burn;
+ }
+
+ /* Use generic code to handle smaller chunks... */
+ }
+#endif
+
+ for ( ;nblocks; nblocks-- )
+ {
+ /* INBUF is needed later and it may be identical to OUTBUF, so store
+ the intermediate result to SAVEBUF. */
+ burn = twofish_decrypt (ctx, savebuf, inbuf);
+ if (burn > burn_stack_depth)
+ burn_stack_depth = burn;
+
+ buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, 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, size_t nblocks)
+{
+ TWOFISH_context *ctx = context;
+ unsigned char *outbuf = outbuf_arg;
+ const unsigned char *inbuf = inbuf_arg;
+ unsigned int burn, burn_stack_depth = 0;
+
+#ifdef USE_AMD64_ASM
+ {
+ /* 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;
+
+ burn = 8 * sizeof(void*);
+ if (burn > burn_stack_depth)
+ burn_stack_depth = burn;
+ }
+
+ /* Use generic code to handle smaller chunks... */
+ }
+#endif
+
+ for ( ;nblocks; nblocks-- )
+ {
+ burn = twofish_encrypt(ctx, iv, iv);
+ if (burn > burn_stack_depth)
+ burn_stack_depth = burn;
+
+ 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);
}
@@ -866,6 +1168,7 @@ 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
@@ -915,6 +1218,13 @@ selftest (void)
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;
}
@@ -980,7 +1290,7 @@ main()
timer = clock ();
/* Encryption test. */
- for (i = 0; i < 125; i++)
+ for (i = 0; i < 125; i++)
{
twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]));
for (j = 0; j < 1000; j++)
@@ -998,7 +1308,7 @@ main()
"encryption failure!\n" : "encryption OK!\n";
/* Decryption test. */
- for (i = 0; i < 125; i++)
+ for (i = 0; i < 125; i++)
{
twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2);
for (j = 0; j < 1000; j++) {
@@ -1029,12 +1339,14 @@ main()
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
};