X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/ba6e6b64033b1f9de49feccb5c9cd438354481f7..0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a:/symm/idea.c?ds=sidebyside diff --git a/symm/idea.c b/symm/idea.c new file mode 100644 index 0000000..51edb2d --- /dev/null +++ b/symm/idea.c @@ -0,0 +1,273 @@ +/* -*-c-*- + * + * Implementation of the IDEA cipher + * + * (c) 1999 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include + +#include + +#include "blkc.h" +#include "gcipher.h" +#include "idea.h" + +/*----- Global variables --------------------------------------------------*/ + +const octet idea_keysz[] = { KSZ_SET, IDEA_KEYSZ }; + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @inv@ --- * + * + * Arguments: @uint16 n@ = number to invert + * + * Returns: Multiplicative inverse of @n@ %$\pmod{2^{16} + 1}$%. + * + * Use: Computes multiplicative inverses. This is handy for the + * decryption key scheduling. + */ + +static uint16 inv(uint16 n) +{ + uint32 m = 0x10001; + uint32 a = 1, b = 0; + uint32 nn = n; + + if (!nn) + nn = 0x10000; + for (;;) { + uint32 q, r, t; + if (!(r = m % nn)) + break; + q = m / nn; + m = nn; nn = r; + t = a; a = b - q * a; b = t; + } + if (a > MASK16) + a += 1; + return (U16(a)); +} + +/* --- @MUL@ --- * + * + * Arguments @x@ and @y@ are two 32-bit values to multiply. On exit, @x@ is + * the product of the two arguments. The result is not normalized back to 16 + * bits; the arguments are not expected to be normalized. + * + * This code is from `Side Channel Attack Hardening of the IDEA Cipher', + * published by Ascom Tech. + */ + +#define MUL(x, y) do { \ + unsigned _t; \ + uint32 _tt; \ + \ + x = U16(x - 1); \ + _t = U16(y - 1); \ + _tt = (uint32)x * (uint32)_t + (uint32)x + (uint32)_t + 1; \ + x = U16(_tt); \ + _t = U16(_tt >> 16); \ + x = x - _t + (x <= _t); \ +} while (0) + +/* --- @idea_init@ --- * + * + * Arguments: @idea_ctx *k@ = pointer to key block + * @const void *buf@ = pointer to key buffer + * @size_t sz@ = size of key material + * + * Returns: --- + * + * Use: Initializes an IDEA key buffer. The buffer must be exactly + * 16 bytes in size, because IDEA is only defined with a key + * size of 128 bits. + */ + +void idea_init(idea_ctx *k, const void *buf, size_t sz) +{ + KSZ_ASSERT(idea, sz); + + /* --- Unpack the encryption key --- */ + + { + const octet *p = buf; + uint16 *q = k->e; + uint32 a = LOAD32(p + 0); + uint32 b = LOAD32(p + 4); + uint32 c = LOAD32(p + 8); + uint32 d = LOAD32(p + 12); + int i; + + /* --- Main unpacking loop --- */ + + for (i = 0; i < 6; i++) { + + /* --- Spit out the next 8 subkeys --- */ + + q[0] = U16(a >> 16); + q[1] = U16(a >> 0); + q[2] = U16(b >> 16); + q[3] = U16(b >> 0); + q[4] = U16(c >> 16); + q[5] = U16(c >> 0); + q[6] = U16(d >> 16); + q[7] = U16(d >> 0); + q += 8; + + /* --- Rotate and permute the subkeys --- */ + + { + uint32 t = a; + a = U32((a << 25) | (b >> 7)); + b = U32((b << 25) | (c >> 7)); + c = U32((c << 25) | (d >> 7)); + d = U32((d << 25) | (t >> 7)); + } + } + + /* --- Write out the tail-enders --- */ + + q[0] = U16(a >> 16); + q[1] = U16(a >> 0); + q[2] = U16(b >> 16); + q[3] = U16(b >> 0); + } + + /* --- Convert this into the decryption key --- */ + + { + uint16 *p = k->e + 52; + uint16 *q = k->d; + int i; + + /* --- Translate the main round keys --- */ + + for (i = 0; i < 8; i++) { + p -= 6; + q[4] = p[0]; + q[5] = p[1]; + q[0] = inv(p[2]); + q[3] = inv(p[5]); + if (i) { + q[1] = 0x10000 - p[4]; + q[2] = 0x10000 - p[3]; + } else { + q[1] = 0x10000 - p[3]; + q[2] = 0x10000 - p[4]; + } + q += 6; + } + + /* --- Translate the tail-enders --- */ + + p -= 4; + q[0] = inv(p[0]); + q[1] = 0x10000 - p[1]; + q[2] = 0x10000 - p[2]; + q[3] = inv(p[3]); + } +} + +/* --- @ROUND@ --- */ + +#define MIX(k, a, b, c, d) do { \ + MUL(a, k[0]); \ + b += k[1]; \ + c += k[2]; \ + MUL(d, k[3]); \ +} while (0) + +#define MA(k, a, b, c, d) do { \ + unsigned _u = a ^ c; \ + unsigned _v = b ^ d; \ + MUL(_u, k[4]); \ + _v += _u; \ + MUL(_v, k[5]); \ + _u += _v; \ + a ^= _v; \ + b ^= _u; \ + c ^= _v; \ + d ^= _u; \ +} while (0); + +#define ROUND(k, a, b, c, d) do { \ + MIX(k, a, b, c, d); \ + MA(k, a, b, c, d); \ + (k) += 6; \ +} while (0) + +/* --- Encryption --- */ + +#define EBLK(k, a, b, c, d) do { \ + unsigned _a = U16(a >> 16); \ + unsigned _b = U16(a >> 0); \ + unsigned _c = U16(b >> 16); \ + unsigned _d = U16(b >> 0); \ + const uint16 *_k = (k); \ + \ + ROUND(_k, _a, _b, _c, _d); \ + ROUND(_k, _a, _c, _b, _d); \ + ROUND(_k, _a, _b, _c, _d); \ + ROUND(_k, _a, _c, _b, _d); \ + ROUND(_k, _a, _b, _c, _d); \ + ROUND(_k, _a, _c, _b, _d); \ + ROUND(_k, _a, _b, _c, _d); \ + ROUND(_k, _a, _c, _b, _d); \ + MIX (_k, _a, _c, _b, _d); \ + c = ((uint32)U16(_a) << 16) | (uint32)U16(_c); \ + d = ((uint32)U16(_b) << 16) | (uint32)U16(_d); \ +} while (0) + +#define DBLK(k, a, b) EBLK((k), (a), (b)) + +/* --- @idea_eblk@, @idea_dblk@ --- * + * + * Arguments: @const idea_ctx *k@ = pointer to a key block + * @const uint32 s[2]@ = pointer to source block + * @uint32 d[2]@ = pointer to destination block + * + * Returns: --- + * + * Use: Low-level block encryption and decryption. + */ + +void idea_eblk(const idea_ctx *k, const uint32 *s, uint32 *d) +{ + EBLK(k->e, s[0], s[1], d[0], d[1]); +} + +void idea_dblk(const idea_ctx *k, const uint32 *s, uint32 *d) +{ + EBLK(k->d, s[0], s[1], d[0], d[1]); +} + +BLKC_TEST(IDEA, idea) + +/*----- That's all, folks -------------------------------------------------*/