Commit b8bfdf63 authored by George Kadianakis's avatar George Kadianakis
Browse files

Introduce ed25519_{sign,checksig}_prefixed functions().

parent 261f4c3f
Loading
Loading
Loading
Loading
+95 −0
Original line number Diff line number Diff line
@@ -184,9 +184,43 @@ ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong)
  return 0;
}

/* Return a heap-allocated array that contains <b>msg</b> prefixed by the
 * string <b>prefix_str</b>. Set <b>final_msg_len_out</b> to the size of the
 * final array. If an error occured, return NULL. It's the resonsibility of the
 * caller to free the returned array. */
static uint8_t *
get_prefixed_msg(const uint8_t *msg, size_t msg_len,
                 const char *prefix_str,
                 size_t *final_msg_len_out)
{
  size_t prefixed_msg_len, prefix_len;
  uint8_t *prefixed_msg;

  tor_assert(prefix_str);
  tor_assert(final_msg_len_out);

  prefix_len = strlen(prefix_str);

  /* msg_len + strlen(prefix_str) must not overflow. */
  if (msg_len > SIZE_T_CEILING - prefix_len) {
    return NULL;
  }

  prefixed_msg_len = msg_len + prefix_len;
  prefixed_msg = tor_malloc_zero(prefixed_msg_len);

  memcpy(prefixed_msg, prefix_str, prefix_len);
  memcpy(prefixed_msg + prefix_len, msg, msg_len);

  *final_msg_len_out = prefixed_msg_len;
  return prefixed_msg;
}

/**
 * Set <b>signature_out</b> to a signature of the <b>len</b>-byte message
 * <b>msg</b>, using the secret and public key in <b>keypair</b>.
 *
 * Return 0 if we successfuly signed the message, otherwise return -1.
 */
int
ed25519_sign(ed25519_signature_t *signature_out,
@@ -202,6 +236,37 @@ ed25519_sign(ed25519_signature_t *signature_out,
  return 0;
}

/**
 * Like ed25519_sign(), but also prefix <b>msg</b> with <b>prefix_str</b>
 * before signing. <b>prefix_str</b> must be a NUL-terminated string.
 */
int
ed25519_sign_prefixed(ed25519_signature_t *signature_out,
                      const uint8_t *msg, size_t msg_len,
                      const char *prefix_str,
                      const ed25519_keypair_t *keypair)
{
  int retval;
  size_t prefixed_msg_len;
  uint8_t *prefixed_msg;

  tor_assert(prefix_str);

  prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str,
                                  &prefixed_msg_len);
  if (!prefixed_msg) {
    log_warn(LD_GENERAL, "Failed to get prefixed msg.");
    return -1;
  }

  retval = ed25519_sign(signature_out,
                        prefixed_msg, prefixed_msg_len,
                        keypair);
  tor_free(prefixed_msg);

  return retval;
}

/**
 * Check whether if <b>signature</b> is a valid signature for the
 * <b>len</b>-byte message in <b>msg</b> made with the key <b>pubkey</b>.
@@ -217,6 +282,36 @@ ed25519_checksig(const ed25519_signature_t *signature,
    get_ed_impl()->open(signature->sig, msg, len, pubkey->pubkey) < 0 ? -1 : 0;
}

/**
 * Like ed2519_checksig(), but also prefix <b>msg</b> with <b>prefix_str</b>
 * before verifying signature. <b>prefix_str</b> must be a NUL-terminated
 * string.
 */
int
ed25519_checksig_prefixed(const ed25519_signature_t *signature,
                          const uint8_t *msg, size_t msg_len,
                          const char *prefix_str,
                          const ed25519_public_key_t *pubkey)
{
  int retval;
  size_t prefixed_msg_len;
  uint8_t *prefixed_msg;

  prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str,
                                  &prefixed_msg_len);
  if (!prefixed_msg) {
    log_warn(LD_GENERAL, "Failed to get prefixed msg.");
    return -1;
  }

  retval = ed25519_checksig(signature,
                            prefixed_msg, prefixed_msg_len,
                            pubkey);
  tor_free(prefixed_msg);

  return retval;
}

/** Validate every signature among those in <b>checkable</b>, which contains
 * exactly <b>n_checkable</b> elements.  If <b>okay_out</b> is non-NULL, set
 * the i'th element of <b>okay_out</b> to 1 if the i'th element of
+11 −0
Original line number Diff line number Diff line
@@ -55,6 +55,17 @@ int ed25519_checksig(const ed25519_signature_t *signature,
                     const uint8_t *msg, size_t len,
                     const ed25519_public_key_t *pubkey);

int
ed25519_sign_prefixed(ed25519_signature_t *signature_out,
                      const uint8_t *msg, size_t len,
                      const char *prefix_str,
                      const ed25519_keypair_t *keypair);
int
ed25519_checksig_prefixed(const ed25519_signature_t *signature,
                          const uint8_t *msg, size_t len,
                          const char *prefix_str,
                          const ed25519_public_key_t *pubkey);

/**
 * A collection of information necessary to check an Ed25519 signature. Used
 * for batch verification.
+35 −0
Original line number Diff line number Diff line
@@ -2242,6 +2242,41 @@ test_crypto_ed25519_simple(void *arg)
    tt_int_op(0, OP_EQ, ed25519_checksig_batch(NULL, ch, 2));
  }

  /* Test the string-prefixed sign/checksig functions */
  {
    ed25519_signature_t manual_sig;
    char *prefixed_msg;

    /* Generate a signature with a prefixed msg. */
    tt_int_op(0, OP_EQ, ed25519_sign_prefixed(&sig1, msg, msg_len,
                                              "always in the mood",
                                              &kp1));

    /* First, check that ed25519_sign_prefixed() returns the exact same sig as
       if we had manually prefixed the msg ourselves. */
    tor_asprintf(&prefixed_msg, "%s%s", "always in the mood", msg);
    tt_int_op(0, OP_EQ, ed25519_sign(&manual_sig, (uint8_t *)prefixed_msg,
                                     strlen(prefixed_msg), &kp1));
    tor_free(prefixed_msg);
    tt_assert(!memcmp(sig1.sig, manual_sig.sig, sizeof(sig1.sig)));

    /* Test that prefixed checksig verifies it properly. */
    tt_int_op(0, OP_EQ, ed25519_checksig_prefixed(&sig1, msg, msg_len,
                                                  "always in the mood",
                                                  &pub1));

    /* Test that checksig with wrong prefix fails. */
    tt_int_op(-1, OP_EQ, ed25519_checksig_prefixed(&sig1, msg, msg_len,
                                                   "always in the moo",
                                                   &pub1));
    tt_int_op(-1, OP_EQ, ed25519_checksig_prefixed(&sig1, msg, msg_len,
                                                   "always in the moon",
                                                   &pub1));
    tt_int_op(-1, OP_EQ, ed25519_checksig_prefixed(&sig1, msg, msg_len,
                                                   "always in the mood!",
                                                   &pub1));
  }

 done:
  ;
}