/*- * Copyright (c) 2018 Taylor R. Campbell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define _POSIX_C_SOURCE 200809L #include #include #include #include "crypto_sign_ed25519.h" #include "hexdigit.h" #include "freadline.h" static int parsehex(const char *h, size_t hmax, void *dst, size_t len) { unsigned char *p = dst, hi, lo; size_t n = len; if (hmax < 2*len) return -1; while (n --> 0) { if (hexdigit(*h++, &hi) == -1) return -1; if (hexdigit(*h++, &lo) == -1) return -1; *p++ = (hi << 4) | lo; } return 0; } static void hexdump(FILE *f, const void *src, size_t len) { const char hex[16] = "0123456789abcdef"; const unsigned char *p = src; size_t n = len; while (n --> 0) { unsigned char x = *p++; fprintf(f, "%c%c", hex[x >> 4], hex[x & 0xf]); } } /* Like strtok_r, but don't skip empty fields. */ static char * strtok1_r(char *str, const char *sep, char **lastp) { char *start; char ch; if (str == NULL) str = *lastp; start = str; assert(strlen(sep) == 1); do { if ((ch = *str++) == '\0') return NULL; } while (ch != '\0' && ch != sep[0]); str[-1] = '\0'; *lastp = str; return start; } char buf[0x10000]; unsigned char seedpk[64], sk0[64]; unsigned char pk[32], pk0[32]; unsigned char m[2048], m0[2048]; unsigned char sm[2048], sm0[2048]; unsigned long long mlen, m0len; unsigned long long smlen, sm0len; int main(void) { size_t ln, len; char *h, *last; if (crypto_sign_ed25519_selftest() != 0) return 1; for (ln = 1; freadline(buf, sizeof buf, &len, stdin) != EOF; ln++) { if (buf[len - 1] != '\n') errx(1, "line %zu too long", ln); /* seedpk */ if ((h = strtok1_r(buf, ":", &last)) == NULL) errx(1, "missing seedpk colon on line %zu", ln); if (parsehex(h, strlen(h), seedpk, sizeof seedpk) == -1) errx(1, "malformed seedpk on line %zu", ln); /* pk */ if ((h = strtok1_r(NULL, ":", &last)) == NULL) errx(1, "missing pk colon on line %zu", ln); if (parsehex(h, strlen(h), pk, sizeof pk) == -1) errx(1, "malformed pk on line %zu", ln); /* m */ if ((h = strtok1_r(NULL, ":", &last)) == NULL) errx(1, "missing m colon on line %zu", ln); if (strlen(h) % 1) errx(1, "invalid hex length on line %zu", ln); if (strlen(h) >= 2*sizeof(m)) errx(1, "overlong message on line %zu", ln); mlen = strlen(h)/2; if (parsehex(h, strlen(h), m, mlen) == -1) errx(1, "malformed m on line %zu", ln); /* sm */ if ((h = strtok1_r(NULL, ":", &last)) == NULL) errx(1, "missing sm newline on line %zu", ln); if (strlen(h) % 1) errx(1, "invalid hex length on line %zu", ln); if (strlen(h) >= 2*sizeof(sm)) errx(1, "overlong signed message on line %zu", ln); smlen = strlen(h)/2; if (parsehex(h, strlen(h), sm, smlen) == -1) errx(1, "malformed sm on line %zu", ln); if ((h = strtok1_r(NULL, "\n", &last)) == NULL) errx(1, "missing line break on line %zu", ln); if (strlen(h) != 0) errx(1, "trailing garbage on line %zu", ln); if ((h = strtok1_r(NULL, "x", &last)) != NULL) errx(1, "trailing garbage after??? line %zu", ln); /* Test key generation from the seed. */ if (crypto_sign_ed25519_keypair_seed(pk0, sk0, seedpk) == -1) errx(1, "crypto_sign_ed25519_keypair_seed"); if (memcmp(pk0, pk, 32) != 0) { hexdump(stderr, pk, 32); fprintf(stderr, "\n"); hexdump(stderr, pk0, 32); fprintf(stderr, "\n"); errx(1, "pk0 =/= pk line %zu", ln); } /* Test signing. */ if (crypto_sign_ed25519(sm0, &sm0len, m, mlen, sk0) == -1) errx(1, "crypto_sign_ed25519 line %zu", ln); if (sm0len != smlen) errx(1, "sm0len %llu =/= smlen %llu", sm0len, smlen); if (memcmp(sm0, sm, smlen) != 0) { hexdump(stderr, sm, smlen); fprintf(stderr, "\n"); hexdump(stderr, sm0, sm0len); fprintf(stderr, "\n"); errx(1, "sm0 =/= sm line %zu", ln); } /* Test verifying. */ if (crypto_sign_ed25519_open(m0, &m0len, sm, smlen, pk) == -1) errx(1, "crypto_sign_ed25519_open line %zu", ln); if (m0len != mlen) errx(1, "m0len %llu =/= mlen %llu", m0len, mlen); if (memcmp(m0, m, mlen) != 0) { hexdump(stderr, m, mlen); fprintf(stderr, "\n"); hexdump(stderr, m0, m0len); fprintf(stderr, "\n"); errx(1, "m0 =/= m line %zu", ln); } hexdump(stdout, seedpk, 64); printf(":"); hexdump(stdout, pk0, 32); printf(":"); hexdump(stdout, m, mlen); printf(":"); hexdump(stdout, sm, smlen); printf(":\n"); } fflush(stdout); if (ferror(stdout)) errx(1, "stdout"); return 0; }