symm/des.c: Introduce a function to fix or check key parity.
[catacomb] / symm / des.c
index 06400a1..19407bc 100644 (file)
@@ -100,6 +100,49 @@ static void permute(const char *p, uint32 a, uint32 b, uint32 *d)
   d[1] = y;
 }
 
+/* --- @des_fixparity@ --- *
+ *
+ * Arguments:  @octet *z@ = output buffer pointer, or null
+ *             @const octet *p@ = input buffer pointer
+ *             @size_t sz@ = size of the buffers
+ *
+ * Returns:    Zero if the input already had correct parity, @-1@ if changes
+ *             were necessary (in constant time).
+ *
+ * Use:                Check the @sz@ bytes at @p@ for odd parity (as used in DES
+ *             keys); if @z@ is not null, then copy a parity-fixed version
+ *             of @p@ to @z@.  The two buffers at @p@ and @z@ may coincide,
+ *             or be disjoint, but not otherwise overlap.
+ */
+
+int des_fixparity(octet *z, const octet *p, size_t sz)
+{
+  int a = 0, t, u;
+
+  while (sz--) {
+
+    /* Collect the byte. */
+    t = *p++;
+
+    /* Compute the parity.  Specifically, this will determine the overall
+     * parity of the byte: 0 for odd, and 1 for even (since we complement
+     * the result).  This is therefore the change which needs to be applied
+     * to the incoming byte to ensure that it has odd parity.
+     */
+    u = t; u ^= u >> 4; u ^= u >> 2; u ^= u >> 1; u ^= 1; u &= 1;
+
+    /* Accumulate the difference.  If any bytes had even parity, then this
+     * will equal 1. */
+    a |= u;
+
+    /* Maybe write out the fixed value. */
+    if (z) *z++ = t ^ u;
+  }
+
+  /* Done. */
+  return (-a);
+}
+
 /* --- @des_expand@ --- *
  *
  * Arguments:  @const octet *k@ = pointer to key material