From: Mark Wooding Date: Mon, 20 Jul 2015 12:53:44 +0000 (+0100) Subject: Merge branch 'mdw/latin-dances' X-Git-Tag: 2.2.0~1 X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/commitdiff_plain/290ddb617fe530512a3496de61318a98ae623fe7?hp=965c4e7509499f0eef0694f129a819bc28d5fe56 Merge branch 'mdw/latin-dances' * mdw/latin-dances: progs/rspit.c: Include Salsa20 and ChaCha (and their variants). symm: Implement Bernstein's ChaCha stream cipher. symm: Implement Bernstein's Salsa20 stream cipher and its variants. --- diff --git a/math/ec-raw.c b/math/ec-raw.c index acee1b66..497e191b 100644 --- a/math/ec-raw.c +++ b/math/ec-raw.c @@ -54,6 +54,9 @@ * @EC_EXPLY@ is set, then an explicit %$y$%-coordinate is * output in full. Otherwise the %$y$%-coordinate is * suppressed. + * + * Returns failure (@-1@) if the flags are invalid, or if there + * isn't enough space in the output buffer. */ int ec_ec2osp(ec_curve *c, unsigned f, buf *b, const ec *p) @@ -62,15 +65,22 @@ int ec_ec2osp(ec_curve *c, unsigned f, buf *b, const ec *p) size_t n; ec t = EC_INIT; + /* --- Check the requested flags for sanity --- */ + + if (!f) f = EC_XONLY; + if (f & ~((f & EC_XONLY) ? EC_XONLY : + (f & EC_CMPR) ? (EC_CMPR | EC_EXPLY | EC_SORT) : + (f & EC_EXPLY) ? EC_EXPLY : + 0u)) + return (-1); + /* --- Point at infinity --- */ if (EC_ATINF(p)) return (buf_putbyte(b, 0)); /* --- Fix up the format byte, compressing the %$y$%-coordinate --- */ - if (!f) - f = EC_XONLY; - else if (f & EC_CMPR) { + if (f & EC_CMPR) { if (!(f & EC_SORT)) f |= EC_COMPR(c, p) ? EC_YBIT : 0; else { diff --git a/math/ec-raw.h b/math/ec-raw.h index 0ceadd63..df8d1ab4 100644 --- a/math/ec-raw.h +++ b/math/ec-raw.h @@ -74,6 +74,9 @@ * @EC_EXPLY@ is set, then an explicit %$y$%-coordinate is * output in full. Otherwise the %$y$%-coordinate is * suppressed. + * + * Returns failure (@-1@) if the flags are invalid, or if there + * isn't enough space in the output buffer. */ extern int ec_ec2osp(ec_curve */*c*/, unsigned /*f*/, diff --git a/math/t/ec b/math/t/ec index 9b57d6c4..9af65c8d 100644 --- a/math/t/ec +++ b/math/t/ec @@ -462,6 +462,32 @@ mul { } ec2osp { + ## Make sure some things which I expect to fail actually do. + "prime: 6277101735386680763835789423207666416102355444464034512659; prime: -3, 6" + 3 "0x4a4edd749b4e809ddf0ecdb0cddd64b64f4558816ef243f5, 0xb3cef6f7f891a23d823aa01e96a74a3890cf71f4032d49d" + FAIL; + "prime: 6277101735386680763835789423207666416102355444464034512659; prime: -3, 6" + 5 "0x4a4edd749b4e809ddf0ecdb0cddd64b64f4558816ef243f5, 0xb3cef6f7f891a23d823aa01e96a74a3890cf71f4032d49d" + FAIL; + "prime: 6277101735386680763835789423207666416102355444464034512659; prime: -3, 6" + 7 "0x4a4edd749b4e809ddf0ecdb0cddd64b64f4558816ef243f5, 0xb3cef6f7f891a23d823aa01e96a74a3890cf71f4032d49d" + FAIL; + "prime: 6277101735386680763835789423207666416102355444464034512659; prime: -3, 6" + 8 "0x4a4edd749b4e809ddf0ecdb0cddd64b64f4558816ef243f5, 0xb3cef6f7f891a23d823aa01e96a74a3890cf71f4032d49d" + FAIL; + "prime: 6277101735386680763835789423207666416102355444464034512659; prime: -3, 6" + 9 "0x4a4edd749b4e809ddf0ecdb0cddd64b64f4558816ef243f5, 0xb3cef6f7f891a23d823aa01e96a74a3890cf71f4032d49d" + FAIL; + "prime: 6277101735386680763835789423207666416102355444464034512659; prime: -3, 6" + 11 "0x4a4edd749b4e809ddf0ecdb0cddd64b64f4558816ef243f5, 0xb3cef6f7f891a23d823aa01e96a74a3890cf71f4032d49d" + FAIL; + "prime: 6277101735386680763835789423207666416102355444464034512659; prime: -3, 6" + 13 "0x4a4edd749b4e809ddf0ecdb0cddd64b64f4558816ef243f5, 0xb3cef6f7f891a23d823aa01e96a74a3890cf71f4032d49d" + FAIL; + "prime: 6277101735386680763835789423207666416102355444464034512659; prime: -3, 6" + 15 "0x4a4edd749b4e809ddf0ecdb0cddd64b64f4558816ef243f5, 0xb3cef6f7f891a23d823aa01e96a74a3890cf71f4032d49d" + FAIL; + ## Some automated tests, from `ec-compr-test.sage'. "prime: 6277101735386680763835789423207666416102355444464034512659; prime: -3, 6" 1 "0x4a4edd749b4e809ddf0ecdb0cddd64b64f4558816ef243f5, 0xb3cef6f7f891a23d823aa01e96a74a3890cf71f4032d49d" diff --git a/progs/key.1 b/progs/key.1 index f301391f..a2ac3376 100644 --- a/progs/key.1 +++ b/progs/key.1 @@ -117,6 +117,8 @@ is one of: .B fingerprint .RB [ \-f .IR filter ] +.RB [ \-p +.IR style ] .RB [ \-a .IR hash ] .RI [ tag ...] @@ -124,6 +126,8 @@ is one of: .B verify .RB [ \-f .IR filter ] +.RB [ \-p +.IR style ] .RB [ \-a .IR hash ] .I tag @@ -340,6 +344,13 @@ The pseudorandom generators which are acceptable to the option of the .B add command. +.TP +.B fpres +Fingerprint presentation styles, as used by the +.B fingerprint +and +.B verify +commands. .SS add The .B add @@ -919,6 +930,11 @@ Specifies a filter. Only keys and key components which match the filter are fingerprinted. The default is to only fingerprint nonsecret components. .TP +.BI "\-p, \-\-presentation " style +Write fingerprints in the given +.IR style . +See below for a list of presentation styles. +.TP .BI "\-a, \-\-algorithm " hash Names the hashing algorithm. Run .B key show hash @@ -930,6 +946,18 @@ command line arguments. If no key tags are given, all keys which match the filter are fingerprinted. See .BR keyring (5) for a description of how key fingerprints are computed. +.PP +The fingerprint may be shown in the following styles. +.TP +.B hex +Lowercase hexadecimal, with groups of eight digits separated by hyphens +(`\-'). This is the default presentation style. (On input, colons are +also permitted as separators.) +.TP +.B base32 +Lowercase Base32 encoding, without `=' padding, with groups of six +digits separated by colons (`:'). (On input, padding characters are +ignored.) .SS "verify" Check a key's fingerprint against a reference copy. The following options are supported: @@ -939,15 +967,29 @@ Specifies a filter. Only key components which match the filter are hashed. The default is to only fingerprint nonsecret components. An error is reported if no part of the key matches. .TP +.BI "\-p, \-\-presentation " style +Expect the +.I fingerprint +to be in the given presentation +.IR style . +These match the styles produced by the +.B fingerprint +command described above. +.TP .BI "\-a, \-\-algorithm " hash Names the hashing algorithm. Run .B key show hash for a list of hashing algorithms. The default is .BR rmd160 . .PP -The reference fingerprint is given as hex, in upper or lower case. The -hash may contain hyphens, colons and whitespace. Other characters are -not permitted. +The fingerprint should be provided in the form printed by the +.B fingerprint +command, using the same presentation +.IR style . +A little flexibility is permitted: separators may be placed anywhere (or +not at all) and are ignored; whitespace is permitted and ignored; and +case is ignored in presentation styles which don't make use of both +upper- and lower-case characters. .SS "tidy" Simply reads the keyring from file and writes it back again. This has the effect of removing any deleted keys from the file. diff --git a/progs/key.c b/progs/key.c index fe5f3137..05494691 100644 --- a/progs/key.c +++ b/progs/key.c @@ -38,7 +38,10 @@ #include #include +#include +#include #include +#include #include #include #include @@ -100,8 +103,10 @@ static const char *keyfile = "keyring"; static void doopen(key_file *f, unsigned how) { - if (key_open(f, keyfile, how, key_moan, 0)) - die(1, "couldn't open keyring `%s': %s", keyfile, strerror(errno)); + if (key_open(f, keyfile, how, key_moan, 0)){ + die(EXIT_FAILURE, "couldn't open keyring `%s': %s", + keyfile, strerror(errno)); + } } /* --- @doclose@ --- * @@ -472,7 +477,7 @@ static void alg_dsaparam(keyopts *k) octet *p; size_t sz; dstr d = DSTR_INIT; - base64_ctx c; + codec *c; key_data *kd; dsa_seed ds; @@ -509,11 +514,9 @@ static void alg_dsaparam(keyopts *k) /* --- Store the seed for future verification --- */ - base64_init(&c); - c.maxline = 0; - c.indent = ""; - base64_encode(&c, ds.p, ds.sz, &d); - base64_encode(&c, 0, 0, &d); + c = base64_class.encoder(0, "", 0); + c->ops->code(c, ds.p, ds.sz, &d); c->ops->code(c, 0, 0, &d); + c->ops->destroy(c); DPUTZ(&d); key_putattr(k->kf, k->k, "seed", d.buf); DRESET(&d); @@ -1097,19 +1100,22 @@ static int cmd_add(int argc, char *argv[]) } break; case 's': { - base64_ctx b; + codec *c; + int rc; dstr d = DSTR_INIT; if (seed) die(EXIT_FAILURE, "seed already set"); - base64_init(&b); - base64_decode(&b, optarg, strlen(optarg), &d); - base64_decode(&b, 0, 0, &d); + c = base64_class.decoder(CDCF_IGNEQPAD); + if ((rc = c->ops->code(c, optarg, strlen(optarg), &d)) != 0 || + (rc = c->ops->code(c, 0, 0, &d)) != 0) + die(EXIT_FAILURE, "invalid seed base64: %s", codec_strerror(rc)); + c->ops->destroy(c); k.r = sa->gen(d.buf, d.len); seed = optarg; dstr_destroy(&d); } break; case 'n': { - base64_ctx b; + codec *c; dstr d = DSTR_INIT; char *p; unsigned n = strtoul(optarg, &p, 0); @@ -1119,9 +1125,9 @@ static int cmd_add(int argc, char *argv[]) n /= 8; p = xmalloc(n); rand_get(RAND_GLOBAL, p, n); - base64_init(&b); - base64_encode(&b, p, n, &d); - base64_encode(&b, 0, 0, &d); + c = base64_class.encoder(0, "", 0); + c->ops->code(c, p, n, &d); c->ops->code(c, 0, 0, &d); + c->ops->destroy(c); seed = d.buf; k.r = sa->gen(p, n); } break; @@ -1678,42 +1684,67 @@ static int cmd_getattr(int argc, char *argv[]) /* --- @cmd_finger@ --- */ -static void fingerprint(key *k, const gchash *ch, const key_filter *kf) +static const struct fpres { + const char *name; + const codec_class *cdc; + unsigned short ival; + const char *sep; +} fprestab[] = { + { "hex", &hex_class, 8, "-:" }, + { "base32", &base32_class, 6, ":" }, + { 0, 0 } +}; + +static void fingerprint(key *k, const struct fpres *fpres, + const gchash *ch, const key_filter *kf) { ghash *h; - dstr d = DSTR_INIT; + dstr d = DSTR_INIT, dd = DSTR_INIT; const octet *p; size_t i; + codec *c; h = GH_INIT(ch); if (key_fingerprint(k, h, kf)) { p = GH_DONE(h, 0); - key_fulltag(k, &d); - for (i = 0; i < ch->hashsz; i++) { - if (i && i % 4 == 0) - putchar('-'); - printf("%02x", p[i]); + c = fpres->cdc->encoder(CDCF_LOWERC | CDCF_NOEQPAD, "", 0); + c->ops->code(c, p, ch->hashsz, &dd); c->ops->code(c, 0, 0, &dd); + c->ops->destroy(c); + for (i = 0; i < dd.len; i++) { + if (i && i%fpres->ival == 0) dstr_putc(&d, fpres->sep[0]); + dstr_putc(&d, dd.buf[i]); } - printf(" %s\n", d.buf); + dstr_putc(&d, ' '); key_fulltag(k, &d); dstr_putc(&d, '\n'); + dstr_write(&d, stdout); } - dstr_destroy(&d); + dstr_destroy(&d); dstr_destroy(&dd); GH_DESTROY(h); } +static const struct fpres *lookup_fpres(const char *name) +{ + const struct fpres *fpres; + for (fpres = fprestab; fpres->name; fpres++) + if (strcmp(fpres->name, name) == 0) return (fpres); + die(EXIT_FAILURE, "unknown presentation syle `%s'", name); +} + static int cmd_finger(int argc, char *argv[]) { key_file f; int rc = 0; + const struct fpres *fpres = fprestab; const gchash *ch = &rmd160; key_filter kf = { KF_NONSECRET, KF_NONSECRET }; for (;;) { static struct option opt[] = { { "filter", OPTF_ARGREQ, 0, 'f' }, + { "presentation", OPTF_ARGREQ, 0, 'p' }, { "algorithm", OPTF_ARGREQ, 0, 'a' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "+f:a:", opt, 0, 0, 0); + int i = mdwopt(argc, argv, "+f:a:p:", opt, 0, 0, 0); if (i < 0) break; switch (i) { @@ -1723,6 +1754,9 @@ static int cmd_finger(int argc, char *argv[]) if (err || *p) die(EXIT_FAILURE, "bad filter string `%s'", optarg); } break; + case 'p': + fpres = lookup_fpres(optarg); + break; case 'a': if ((ch = ghash_byname(optarg)) == 0) die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg); @@ -1734,8 +1768,10 @@ static int cmd_finger(int argc, char *argv[]) } argv += optind; argc -= optind; - if (rc) - die(EXIT_FAILURE, "Usage: fingerprint [-f FILTER] [TAG...]"); + if (rc) { + die(EXIT_FAILURE, + "Usage: fingerprint [-a HASHALG] [-p STYLE] [-f FILTER] [TAG...]"); + } doopen(&f, KOPEN_READ); @@ -1744,7 +1780,7 @@ static int cmd_finger(int argc, char *argv[]) for (i = 0; i < argc; i++) { key *k = key_bytag(&f, argv[i]); if (k) - fingerprint(k, ch, &kf); + fingerprint(k, fpres, ch, &kf); else { rc = 1; moan("key `%s' not found", argv[i]); @@ -1754,50 +1790,13 @@ static int cmd_finger(int argc, char *argv[]) key_iter i; key *k; for (key_mkiter(&i, &f); (k = key_next(&i)) != 0; ) - fingerprint(k, ch, &kf); + fingerprint(k, fpres, ch, &kf); } return (rc); } /* --- @cmd_verify@ --- */ -static unsigned xdigit(char c) -{ - if ('A' <= c && c <= 'Z') return (c + 10 - 'A'); - if ('a' <= c && c <= 'z') return (c + 10 - 'a'); - if ('0' <= c && c <= '9') return (c - '0'); - return (~0u); -} - -static void unhexify(octet *q, char *p, size_t n) -{ - unsigned a = 0; - int i = 0; - - for (;;) { - if (*p == '-' || *p == ':' || isspace((unsigned char)*p)) { - p++; - continue; - } - if (!n && !*p) - break; - if (!*p) - die(EXIT_FAILURE, "hex string too short"); - if (!isxdigit((unsigned char)*p)) - die(EXIT_FAILURE, "bad hex string"); - if (!n) - die(EXIT_FAILURE, "hex string too long"); - a = (a << 4) | xdigit(*p++); - i++; - if (i == 2) { - *q++ = U8(a); - a = 0; - i = 0; - n--; - } - } -} - static int cmd_verify(int argc, char *argv[]) { key_file f; @@ -1805,17 +1804,21 @@ static int cmd_verify(int argc, char *argv[]) const gchash *ch = &rmd160; ghash *h; key *k; - octet *buf; const octet *fpr; + dstr d = DSTR_INIT, dd = DSTR_INIT; + codec *c; + const char *p; + const struct fpres *fpres = fprestab; key_filter kf = { KF_NONSECRET, KF_NONSECRET }; for (;;) { static struct option opt[] = { { "filter", OPTF_ARGREQ, 0, 'f' }, + { "presentation", OPTF_ARGREQ, 0, 'p' }, { "algorithm", OPTF_ARGREQ, 0, 'a' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "+f:a:", opt, 0, 0, 0); + int i = mdwopt(argc, argv, "+f:a:p:", opt, 0, 0, 0); if (i < 0) break; switch (i) { @@ -1825,6 +1828,9 @@ static int cmd_verify(int argc, char *argv[]) if (err || *p) die(EXIT_FAILURE, "bad filter string `%s'", optarg); } break; + case 'p': + fpres = lookup_fpres(optarg); + break; case 'a': if ((ch = ghash_byname(optarg)) == 0) die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg); @@ -1836,21 +1842,36 @@ static int cmd_verify(int argc, char *argv[]) } argv += optind; argc -= optind; - if (rc || argc != 2) - die(EXIT_FAILURE, "Usage: verify [-f FILTER] TAG FINGERPRINT"); + if (rc || argc != 2) { + die(EXIT_FAILURE, + "Usage: verify [-a HASHALG] [-p STYLE] [-f FILTER] TAG FINGERPRINT"); + } doopen(&f, KOPEN_READ); if ((k = key_bytag(&f, argv[0])) == 0) die(EXIT_FAILURE, "key `%s' not found", argv[0]); - buf = xmalloc(ch->hashsz); - unhexify(buf, argv[1], ch->hashsz); + for (p = argv[1]; *p; p++) { + if (strchr(fpres->sep, *p)) continue; + dstr_putc(&dd, *p); + } + c = fpres->cdc->decoder(CDCF_IGNCASE | CDCF_IGNEQPAD | + CDCF_IGNSPC | CDCF_IGNNEWL); + if ((rc = c->ops->code(c, dd.buf, dd.len, &d)) != 0 || + (rc = c->ops->code(c, 0, 0, &d)) != 0) + die(EXIT_FAILURE, "invalid fingerprint: %s", codec_strerror(rc)); + c->ops->destroy(c); + if (d.len != ch->hashsz) { + die(EXIT_FAILURE, "incorrect fingerprint length (%lu != %lu)", + (unsigned long)d.len, (unsigned long)ch->hashsz); + } h = GH_INIT(ch); if (!key_fingerprint(k, h, &kf)) die(EXIT_FAILURE, "key has no fingerprintable components (as filtered)"); fpr = GH_DONE(h, 0); - if (memcmp(fpr, buf, ch->hashsz) != 0) + if (memcmp(fpr, d.buf, ch->hashsz) != 0) die(EXIT_FAILURE, "key fingerprint mismatch"); + dstr_destroy(&d); dstr_destroy(&dd); doclose(&f); return (0); } @@ -2086,7 +2107,9 @@ static int cmd_merge(int argc, char *argv[]) LI("Key-generation algorithms", keygen, \ algtab[i].name, algtab[i].name) \ LI("Random seeding algorithms", seed, \ - seedtab[i].p, seedtab[i].p) + seedtab[i].p, seedtab[i].p) \ + LI("Fingerprint presentation styles", fpres, \ + fprestab[i].name, fprestab[i].name) MAKELISTTAB(listtab, LISTS) @@ -2109,17 +2132,21 @@ Options:\n\ -q, --quiet Show less information.\n\ -v, --verbose Show more information.\n\ " }, - { "fingerprint", cmd_finger, "fingerprint [-f FILTER] [TAG...]", "\ + { "fingerprint", cmd_finger, + "fingerprint [-a HASHALG] [-p STYLE] [-f FILTER] [TAG...]", "\ Options:\n\ \n\ -f, --filter=FILT Only hash key components matching FILT.\n\ +-p, --presentation=STYLE Use STYLE for presenting fingerprints.\n\ -a, --algorithm=HASH Use the named HASH algorithm.\n\ ($ show hash for list.)\n\ " }, - { "verify", cmd_verify, "verify [-f FILTER] TAG FINGERPRINT", "\ + { "verify", cmd_verify, + "verify [-a HASH] [-p STYLE] [-f FILTER] TAG FINGERPRINT", "\ Options:\n\ \n\ -f, --filter=FILT Only hash key components matching FILT.\n\ +-p, --presentation=STYLE Expect FINGERPRINT in the given STYLE.\n\ -a, --algorithm=HASH Use the named HASH algorithm.\n\ ($ show hash for list.)\n\ " }, diff --git a/rand/rand.c b/rand/rand.c index ab00e893..e0bebbfa 100644 --- a/rand/rand.c +++ b/rand/rand.c @@ -327,7 +327,7 @@ void rand_stretch(rand_pool *r) /* --- Now mangle the buffer based on the hash --- */ - assert(CIPHER_KEYSZ < HASH_SZ); + assert(CIPHER_KEYSZ <= HASH_SZ); CIPHER_INIT(&cc, h, CIPHER_KEYSZ, 0); CIPHER_ENCRYPT(&cc, r->buf, r->buf, RAND_BUFSZ); BURN(cc);