+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Cryptographic challenges
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Trivial IP Encryption (TrIPE).
+ *
+ * TrIPE is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * TrIPE 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with TrIPE; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "tripe.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static gmac *mac;
+static uint32 oseq;
+static seqwin iseq;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @c_genkey@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Generates a new challenge key.
+ */
+
+static void c_genkey(void)
+{
+ if (mac && GM_CLASS(mac) == algs.m && oseq < 0x07ffffff) return;
+ if (mac) GM_DESTROY(mac);
+ assert(algs.mksz < sizeof(buf_t));
+ rand_get(RAND_GLOBAL, buf_t, algs.mksz);
+ mac = GM_KEY(algs.m, buf_t, algs.mksz);
+ oseq = 0;
+ seq_reset(&iseq);
+ IF_TRACING(T_CHAL, {
+ trace(T_CHAL, "chal: generated new challenge key");
+ trace_block(T_CRYPTO, "chal: new key", buf_t, algs.mksz);
+ })
+}
+
+/* --- @c_new@ --- *
+ *
+ * Arguments: @buf *b@ = where to put the challenge
+ *
+ * Returns: Zero if OK, nonzero on error.
+ *
+ * Use: Issues a new challenge.
+ */
+
+int c_new(buf *b)
+{
+ octet *p;
+ ghash *h;
+
+ c_genkey();
+ p = BCUR(b);
+ if (buf_putu32(b, oseq++)) return (-1);
+ h = GM_INIT(mac);
+ GH_HASH(h, p, BCUR(b) - p);
+ buf_put(b, GH_DONE(h, 0), algs.tagsz);
+ GH_DESTROY(h);
+ if (BBAD(b)) return (-1);
+ IF_TRACING(T_CHAL, {
+ trace(T_CHAL, "chal: issuing challenge %lu", (unsigned long)(oseq - 1));
+ trace_block(T_CRYPTO, "chal: challenge block", p, BCUR(b) - p);
+ })
+ return (0);
+}
+
+/* --- @c_check@ --- *
+ *
+ * Arguments: @buf *b@ = where to find the challenge
+ *
+ * Returns: Zero if OK, nonzero if it didn't work.
+ *
+ * Use: Checks a challenge. On failure, the buffer is broken.
+ */
+
+int c_check(buf *b)
+{
+ const octet *p;
+ size_t sz = 4 + algs.tagsz;
+ uint32 seq;
+ ghash *h;
+ int ok;
+
+ if ((p = buf_get(b, sz)) == 0) {
+ a_warn("CHAL invalid-challenge");
+ goto fail;
+ }
+ IF_TRACING(T_CHAL, trace_block(T_CRYPTO, "chal: check challenge", p, sz); )
+ if (!mac) {
+ a_warn("CHAL impossible-challenge");
+ goto fail;
+ }
+ h = GM_INIT(mac);
+ GH_HASH(h, p, 4);
+ ok = (memcmp(GH_DONE(h, 0), p + 4, algs.tagsz) == 0);
+ GH_DESTROY(h);
+ if (!ok) {
+ a_warn("CHAL incorrect-tag");
+ goto fail;
+ }
+ seq = LOAD32(p);
+ switch (seq_check(&iseq, LOAD32(p))) {
+ case SEQ_OK: break;
+ case SEQ_OLD: a_warn("CHAL replay old-sequence"); goto fail;
+ case SEQ_REPLAY: a_warn("CHAL replay duplicated-sequence"); goto fail;
+ default: abort();
+ }
+ T( trace(T_CHAL, "chal: checked challenge %lu", (unsigned long)seq); )
+ return (0);
+
+fail:
+ buf_break(b);
+ return (-1);
+}
+
+/*----- That's all, folks -------------------------------------------------*/