--- /dev/null
+/* -*-c-*-
+ *
+ * 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.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "dsa.h"
+#include "mp.h"
+#include "mpbarrett.h"
+#include "mpmont.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @dsa_mksig@ --- *
+ *
+ * Arguments: @const dsa_param *dp@ = pointer to DSA parameters
+ * @mp *a@ = secret signing key
+ * @mp *m@ = message to be signed
+ * @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, mp *a, mp *m, mp *k, mp **rr, mp **ss)
+{
+ mpmont pm;
+ mpbarrett qb;
+ mp *k1, *r;
+ mp *ar;
+
+ /* --- Compute %$r = (g^k \bmod p) \bmod q$% --- */
+
+ mpmont_create(&pm, dp->p);
+ r = mpmont_exp(&pm, MP_NEW, dp->g, k);
+ mpmont_destroy(&pm);
+ mp_div(0, &r, r, dp->q);
+
+ /* --- Compute %$k^{-1} \bmod q$% --- */
+
+ k1 = mp_modinv(MP_NEW, k, dp->q);
+
+ /* --- Now for %$k^{-1}(m + ar)$% --- */
+
+ mpbarrett_create(&qb, dp->q);
+ ar = mp_mul(MP_NEW, a, r);
+ ar = mp_add(ar, ar, m);
+ ar = mpbarrett_reduce(&qb, ar, ar);
+ ar = mp_mul(ar, ar, k1);
+ ar = mpbarrett_reduce(&qb, ar, ar);
+ mpbarrett_destroy(&qb);
+ MP_DROP(k1);
+ if (*rr) MP_DROP(*rr);
+ if (*ss) MP_DROP(*ss);
+ *rr = r;
+ *ss = ar;
+}
+
+/* --- @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 = dsa_h2n(MP_NEW, dp->q, m, msz);
+ mp *km = mp_loadb(MP_NEW, k, ksz);
+ mp *rm = MP_NEW, *sm = MP_NEW;
+ 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);
+ assert(mparena_count(MPARENA_GLOBAL) == 0);
+ 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 "/t/dsa");
+ return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/