Implementation of the Digital Signature Algorithm.
[catacomb] / dsa-sign.c
diff --git a/dsa-sign.c b/dsa-sign.c
new file mode 100644 (file)
index 0000000..8e5c997
--- /dev/null
@@ -0,0 +1,213 @@
+/* -*-c-*-
+ *
+ * $Id: dsa-sign.c,v 1.1 1999/11/19 19:28:00 mdw Exp $
+ *
+ * DSA signing operation
+ *
+ * (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.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: dsa-sign.c,v $
+ * Revision 1.1  1999/11/19 19:28:00  mdw
+ * Implementation of the Digital Signature Algorithm.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "dsa.h"
+#include "mp.h"
+#include "mpmont.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @dsa_mksig@ --- *
+ *
+ * Arguments:  @const dsa_param *dp@ = pointer to DSA parameters
+ *             @const mp *a@ = secret signing key
+ *             @const mp *m@ = message to be signed
+ *             @const mp *k@ = random data
+ *             @mp **rr, **ss@ = where to put output parameters
+ *
+ * Returns:    ---
+ *
+ * Use:                Computes a DSA signature of a message.
+ */
+
+void dsa_mksig(const dsa_param *dp, const mp *a, const mp *m, const mp *k,
+              mp **rr, mp **ss)
+{
+  mpmont pm, qm;
+  mp *k1, *r;
+  mp *rrr, *ar;
+
+  /* --- Create the Montgomery contexts --- */
+
+  mpmont_create(&pm, dp->p);
+  mpmont_create(&qm, dp->q);
+
+  /* --- Compute %$r = (g^k \bmod p) \bmod q$% --- */
+
+  r = mpmont_exp(&pm, dp->g, k);
+  mp_div(0, &r, r, dp->q);
+  *rr = r;
+
+  /* --- Compute %$k^{-1} \bmod q$% --- */
+
+  mp_gcd(0, 0, &k1, dp->q, (mp *)k);
+
+  /* --- Now for %$k^{-1}(m + ar)$% --- */
+
+  rrr = mpmont_mul(&qm, MP_NEW, r, qm.r2);
+  ar = mpmont_mul(&qm, MP_NEW, a, rrr);
+  ar = mp_add(ar, ar, m);
+  if (MP_CMP(ar, >=, dp->q))
+    ar = mp_sub(ar, ar, dp->q);
+  rrr = mpmont_mul(&qm, rrr, ar, qm.r2);
+  ar = mpmont_mul(&qm, ar, rrr, k1);
+  *ss = ar;
+
+  /* --- Tidy things up a little --- */
+
+  mp_drop(rrr);
+  mp_drop(k1);
+  mpmont_destroy(&pm);
+  mpmont_destroy(&qm);
+}
+
+/* --- @dsa_sign@ --- *
+ *
+ * Arguments:  @dsa_param *dp@ = pointer to DSA parameters
+ *             @mp *a@ = pointer to secret signing key
+ *             @const void *m@ = pointer to message
+ *             @size_t msz@ = size of the message
+ *             @const void *k@ = secret random data for securing signature
+ *             @size_t ksz@ = size of secret data
+ *             @void *r@ = pointer to output space for @r@
+ *             @size_t rsz@ = size of output space for @r@
+ *             @void *s@ = pointer to output space for @s@
+ *             @size_t ssz@ = size of output space for @s@
+ *
+ * Returns:    ---
+ *
+ * Use:                Signs a message, storing the results in a big-endian binary
+ *             form.
+ */
+
+void dsa_sign(dsa_param *dp, mp *a,
+             const void *m, size_t msz, const void *k, size_t ksz,
+             void *r, size_t rsz, void *s, size_t ssz)
+{
+  mp *mm = mp_loadb(MP_NEW, m, msz);
+  mp *km = mp_loadb(MP_NEW, k, ksz);
+  mp *rm, *sm;
+  dsa_mksig(dp, a, mm, km, &rm, &sm);
+  mp_storeb(rm, r, rsz);
+  mp_storeb(sm, s, ssz);
+  mp_drop(mm); mp_drop(km);
+  mp_drop(rm); mp_drop(sm);
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/testrig.h>
+
+#include "sha.h"
+
+static int verify(dstr *v)
+{
+  dsa_param dp;
+  mp *x;
+  sha_ctx c;
+  octet hash[SHA_HASHSZ];
+  dsa_sig s;
+  int ok = 1;
+
+  dp.q = *(mp **)v[0].buf;
+  dp.p = *(mp **)v[1].buf;
+  dp.g = *(mp **)v[2].buf;
+  x = *(mp **)v[3].buf;
+
+  sha_init(&c);
+  sha_hash(&c, v[4].buf, v[4].len);
+  sha_done(&c, hash);
+
+  dsa_sign(&dp, x, hash, sizeof(hash), v[5].buf, v[5].len,
+          s.r, sizeof(s.r), s.s, sizeof(s.s));
+
+  if (v[6].len != sizeof(s.r) || v[7].len != sizeof(s.s) ||
+      memcmp(s.r, v[6].buf, sizeof(s.r)) != 0 ||
+      memcmp(s.s, v[7].buf, sizeof(s.s)) != 0) {
+    fputs("\n*** signature failed", stderr);
+    fputs("\nq = ", stderr); mp_writefile(dp.q, stderr, 16);
+    fputs("\np = ", stderr); mp_writefile(dp.p, stderr, 16);
+    fputs("\ng = ", stderr); mp_writefile(dp.g, stderr, 16);
+    fputs("\nx = ", stderr); mp_writefile(x, stderr, 16);
+    fprintf(stderr, "\nmessage = `%s'", v[4].buf);
+    fputs("\nk = ", stderr); type_hex.dump(&v[5], stderr);
+    fputs("\nR = ", stderr); type_hex.dump(&v[6], stderr);
+    fputs("\nS = ", stderr); type_hex.dump(&v[7], stderr);
+
+    {
+      mp *m = MP_NEW;
+      m = mp_loadb(m, hash, sizeof(hash));
+      fputs("\nm = ", stderr); mp_writefile(m, stderr, 16);
+      m = mp_loadb(m, s.r, sizeof(s.r));
+      fputs("\nr = ", stderr); mp_writefile(m, stderr, 16);
+      m = mp_loadb(m, s.s, sizeof(s.s));
+      fputs("\ns = ", stderr); mp_writefile(m, stderr, 16);
+      mp_drop(m);
+    }
+      
+    fputc('\n', stderr);
+    ok = 0;
+  }
+
+  mp_drop(dp.p);
+  mp_drop(dp.q);
+  mp_drop(dp.g);
+  mp_drop(x);
+  return (ok);
+}
+
+static test_chunk tests[] = {
+  { "sign", verify,
+    { &type_mp, &type_mp, &type_mp, &type_mp,
+      &type_string, &type_hex, &type_hex, &type_hex, 0 } },
+  { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+  sub_init();
+  test_run(argc, argv, tests, SRCDIR "/tests/dsa");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/