Rearrange the file tree.
[u/mdw/catacomb] / symm / des.c
diff --git a/symm/des.c b/symm/des.c
new file mode 100644 (file)
index 0000000..06400a1
--- /dev/null
@@ -0,0 +1,279 @@
+/* -*-c-*-
+ *
+ * The Data Encryption Standard
+ *
+ * (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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#include "blkc.h"
+#include "des-base.h"
+#include "des.h"
+#include "gcipher.h"
+
+/*----- Global variables --------------------------------------------------*/
+
+const octet des_keysz[] = { KSZ_SET, 7, 8, 0 };
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @permute@ --- *
+ *
+ * Arguments:  @const char *p@ = pointer to permutation table
+ *             @uint32 a, b@ = source value to permute
+ *             @uint32 *d@ = destination for value
+ *
+ * Returns:    ---
+ *
+ * Use:                Performs a 64-bit permutation.  The table is given in the
+ *             normal (but bizarre) DES bit numbering system.  That's not to
+ *             say that the tables in this source file are like the normal
+ *             DES tables, because they're not.
+ */
+
+static void permute(const char *p, uint32 a, uint32 b, uint32 *d)
+{
+  uint32 x = 0, y = 0;
+  int i;
+
+  for (i = 0; i < 32; i++) {
+    int q = p[i];
+    uint32 t;
+    if (!q)
+      continue;
+    else if (q <= 32)
+      t = a;
+    else {
+      t = b;
+      q -= 32;
+    }
+    if (t & (1 << (32 - q)))
+      x |= (1 << (31 - i));
+  }
+
+  p += 32;
+
+  for (i = 0; i < 32; i++) {
+    int q = p[i];
+    uint32 t;
+    if (!q)
+      continue;
+    else if (q <= 32)
+      t = a;
+    else {
+      t = b;
+      q -= 32;
+    }
+    if (t & (1 << (32 - q)))
+      y |= (1 << (31 - i));
+  }
+
+  d[0] = x;
+  d[1] = y;
+}
+
+/* --- @des_expand@ --- *
+ *
+ * Arguments:  @const octet *k@ = pointer to key material
+ *             @size_t n@ = number of octets of key material (7 or 8)
+ *             @uint32 *xx, *yy@ = where to put the results
+ *
+ * Returns:    ---
+ *
+ * Use:                Extracts 64 bits of key material from the given buffer,
+ *             possibly expanding it from 56 to 64 bits on the way.
+ *             Parity is set correctly if the key is expanded.
+ */
+
+void des_expand(const octet *k, size_t n, uint32 *xx, uint32 *yy)
+{
+  uint32 x, y, z;
+
+  if (n == 8) {
+    x = LOAD32(k + 0);
+    y = LOAD32(k + 4);
+  } else {
+    x = LOAD32(k + 0);
+    x = (x & 0xfe000000) | ((x & 0x01fffff0) >> 1);
+    x = (x & 0xfffe0000) | ((x & 0x0001fff8) >> 1);
+    x = (x & 0xfffffe00) | ((x & 0x000001fc) >> 1);
+    z = x; z ^= z >> 4; z ^= z >> 2; z ^= z >> 1;
+    x |= (z & 0x01010101) ^ 0x01010101;
+    y = LOAD32(k + 3) << 1; /* Note: misaligned */
+    y = (y & 0x000000fe) | ((y & 0x1fffff00) << 1);
+    y = (y & 0x0000fefe) | ((y & 0x3fff0000) << 1);
+    y = (y & 0x00fefefe) | ((y & 0x7f000000) << 1);
+    z = y; z ^= z >> 4; z ^= z >> 2; z ^= z >> 1;
+    y |= (z & 0x01010101) ^ 0x01010101;
+  }
+  *xx = x; *yy = y;
+}
+
+/* --- @des_init@ --- *
+ *
+ * Arguments:  @des_ctx *k@ = pointer to key block
+ *             @const void *buf@ = pointer to key buffer
+ *             @size_t sz@ = size of key material
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes a DES key buffer.  The key buffer may be either 7
+ *             or 8 bytes long.  If it's 8 bytes, the key is assumed to be
+ *             padded with parity bits in the low order bit of each octet.
+ *             These are stripped out without checking prior to the actual
+ *             key scheduling.
+ */
+
+void des_init(des_ctx *k, const void *buf, size_t sz)
+{
+  uint32 x, y;
+  uint32 *kp = k->k;
+  uint32 ka[2];
+  int i;
+
+  /* --- @pc1@ --- *
+   *
+   * This cryptographically useless permutation is used to mangle the key
+   * before it's subjected to the key schedule proper.  I've not actually
+   * messed it about much except for inserting padding at the beginning of
+   * the two halves of the key.
+   */
+
+  static const char pc1[] = {
+     0,         0,  0,  0,
+    57, 49, 41, 33, 25, 17,  9,
+     1, 58, 50, 42, 34, 26, 18,
+    10,         2, 59, 51, 43, 35, 27,
+    19, 11,  3, 60, 52, 44, 36,
+     0,         0,  0,  0,
+    63, 55, 47, 39, 31, 23, 15,
+     7, 62, 54, 46, 38, 30, 22,
+    14,         6, 61, 53, 45, 37, 29,
+    21, 13,  5, 28, 20, 12,  4
+  };
+
+  /* --- @pc2@ --- *
+   *
+   * This irritating but necessary permutation mangles the key between the
+   * simple rotation-based schedule and the actual XOR with which it modifies
+   * the behaviour of the cipher.
+   *
+   * This version of the table doesn't look much like the original.  This is
+   * because some parts of the world have been permuted in order to make
+   * things simpler for the round function.  In particular, everything is
+   * rotated left one place to avoid problems with the wraparound of the
+   * expansion permutation, and the key is split between odd and even S-boxes
+   * rather than high and low ones.  That's without the complication of the
+   * padding bits in the representation of the 56-bit proto-key.
+   */
+
+  static const char pc2[] = {
+     0,         0,  3 + 4, 28 + 4, 15 + 4,  6 + 4, 21 + 4, 10 + 4, /* S-box 2 */
+     0,         0, 16 + 4,  7 + 4, 27 + 4, 20 + 4, 13 + 4,  2 + 4, /* S-box 4 */
+     0,         0, 30 + 8, 40 + 8, 51 + 8, 45 + 8, 33 + 8, 48 + 8, /* S-box 6 */
+     0,         0, 46 + 8, 42 + 8, 50 + 8, 36 + 8, 29 + 8, 32 + 8, /* S-box 8 */
+     0,         0, 14 + 4, 17 + 4, 11 + 4, 24 + 4,  1 + 4,  5 + 4, /* S-box 1 */
+     0,         0, 23 + 4, 19 + 4, 12 + 4,  4 + 4, 26 + 4,  8 + 4, /* S-box 3 */
+     0,         0, 41 + 8, 52 + 8, 31 + 8, 37 + 8, 47 + 8, 55 + 8, /* S-box 5 */
+     0,         0, 44 + 8, 49 + 8, 39 + 8, 56 + 8, 34 + 8, 53 + 8  /* S-box 7 */
+  };
+
+  /* --- @v@ --- *
+   *
+   * Contains the rotation amounts for the key halves.
+   */
+
+  static const char v[] = {
+    1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+  };
+
+  /* --- Extract the key into my registers --- *
+   *
+   * The 7 byte case is rather horrible.  It expands the key to the 8 byte
+   * case before going any further.  It could probably do with its own @pc1@
+   * table.
+   */
+
+  KSZ_ASSERT(des, sz);
+  des_expand(buf, sz, &x, &y);
+
+  /* --- Permute using the pointless PC1 --- */
+
+  permute(pc1, x, y, ka);
+  x = ka[0]; y = ka[1];
+
+  /* --- Now for the key schedule proper --- */
+
+  for (i = 0; i < 16; i++) {
+    if (v[i] == 1) {
+      x = ((x << 1) | (x >> 27)) & 0x0fffffff;
+      y = ((y << 1) | (y >> 27)) & 0x0fffffff;
+    } else {
+      x = ((x << 2) | (x >> 26)) & 0x0fffffff;
+      y = ((y << 2) | (y >> 26)) & 0x0fffffff;
+    }
+    permute(pc2, x, y, kp);
+    kp += 2;
+  }
+}
+
+/* --- @des_eblk@, @des_dblk@ --- *
+ *
+ * Arguments:  @const des_ctx *k@ = pointer to 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 des_eblk(const des_ctx *k, const uint32 *s, uint32 *d)
+{
+  uint32 x = s[0], y = s[1];
+  DES_IP(x, y);
+  DES_EBLK(k->k, x, y, x, y);
+  DES_IPINV(x, y);
+  d[0] = x, d[1] = y;
+}
+
+void des_dblk(const des_ctx *k, const uint32 *s, uint32 *d)
+{
+  uint32 x = s[0], y = s[1];
+  DES_IP(x, y);
+  DES_DBLK(k->k, x, y, x, y);
+  DES_IPINV(x, y);
+  d[0] = x, d[1] = y;
+}
+
+BLKC_TEST(DES, des)
+
+/*----- That's all, folks -------------------------------------------------*/