X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/f0c52873e4c1e3a16bb2d5a086df2526f698e4ac..cd6eca4375f46a35b93e2fea4b0428a23b451aa3:/catcrypt.c diff --git a/catcrypt.c b/catcrypt.c index d10739d..08fb7e0 100644 --- a/catcrypt.c +++ b/catcrypt.c @@ -29,6 +29,8 @@ /*----- Header files ------------------------------------------------------*/ +#define _FILE_OFFSET_BITS 64 + #include "config.h" #include @@ -126,10 +128,11 @@ err: static int encrypt(int argc, char *argv[]) { - const char *of = 0, *kn = "ccrypt", *skn = 0; + const char *fn, *of = 0, *kn = "ccrypt", *skn = 0; FILE *ofp = 0; FILE *fp = 0; const char *ef = "binary"; + fprogress ff; const char *err; int i; int en; @@ -153,6 +156,7 @@ static int encrypt(int argc, char *argv[]) #define f_bogus 1u #define f_nocheck 2u +#define f_progress 4u for (;;) { static const struct option opt[] = { @@ -162,10 +166,11 @@ static int encrypt(int argc, char *argv[]) { "armor", 0, 0, 'a' }, { "format", OPTF_ARGREQ, 0, 'f' }, { "output", OPTF_ARGREQ, 0, 'o' }, + { "progress", 0, 0, 'p' }, { "nocheck", 0, 0, 'C' }, { 0, 0, 0, 0 } }; - i = mdwopt(argc, argv, "k:s:af:o:C", opt, 0, 0, 0); + i = mdwopt(argc, argv, "k:s:af:o:pC", opt, 0, 0, 0); if (i < 0) break; switch (i) { case 'k': kn = optarg; break; @@ -173,6 +178,7 @@ static int encrypt(int argc, char *argv[]) case 'a': ef = "pem"; break; case 'f': ef = optarg; break; case 'o': of = optarg; break; + case 'p': f |= f_progress; break; case 'C': f |= f_nocheck; break; default: f |= f_bogus; break; } @@ -190,16 +196,13 @@ static int encrypt(int argc, char *argv[]) if ((eo = getenc(ef)) == 0) die(EXIT_FAILURE, "encoding `%s' not found", ef); - if (optind == argc) - fp = stdin; - else if (strcmp(argv[optind], "-") == 0) { + fn = optind < argc ? argv[optind++] : "-"; + if (strcmp(fn, "-") == 0) fp = stdin; - optind++; - } else if ((fp = fopen(argv[optind], "rb")) == 0) { + else if ((fp = fopen(fn, "rb")) == 0) { die(EXIT_FAILURE, "couldn't open file `%s': %s", - argv[optind], strerror(errno)); - } else - optind++; + fn, strerror(errno)); + } if (!of || strcmp(of, "-") == 0) ofp = stdout; @@ -258,6 +261,13 @@ static int encrypt(int argc, char *argv[]) /* --- Now do the main crypto --- */ + if (f & f_progress) { + if (fprogress_init(&ff, fn, fp)) { + die(EXIT_FAILURE, "failed to initialize progress display: %s", + strerror(errno)); + } + } + assert(GC_CLASS(c)->blksz <= sizeof(bb)); dstr_ensure(&d, sizeof(bb) + GM_CLASS(m)->hashsz); seq = 0; @@ -272,6 +282,7 @@ static int encrypt(int argc, char *argv[]) } n = fread(bb, 1, chsz, fp); if (!n) break; + if (f & f_progress) fprogress_update(&ff, n); buf_init(&b, d.buf, d.sz); tag = buf_get(&b, GM_CLASS(m)->hashsz); ct = buf_get(&b, n); @@ -294,6 +305,7 @@ static int encrypt(int argc, char *argv[]) /* --- All done --- */ + if (f & f_progress) fprogress_done(&ff); e->ops->encdone(e); GM_DESTROY(m); GC_DESTROY(c); @@ -309,16 +321,18 @@ static int encrypt(int argc, char *argv[]) #undef f_bogus #undef f_nocheck +#undef f_progress } /*---- Decryption ---------------------------------------------------------*/ static int decrypt(int argc, char *argv[]) { - const char *of = 0; + const char *fn, *of = 0; FILE *ofp = 0, *rfp = 0; FILE *fp = 0; const char *ef = "binary"; + fprogress ff; int i; size_t n; dstr d = DSTR_INIT; @@ -344,6 +358,7 @@ static int decrypt(int argc, char *argv[]) #define f_bogus 1u #define f_buffer 2u #define f_nocheck 4u +#define f_progress 8u for (;;) { static const struct option opt[] = { @@ -355,9 +370,10 @@ static int decrypt(int argc, char *argv[]) { "nocheck", 0, 0, 'C' }, { "format", OPTF_ARGREQ, 0, 'f' }, { "output", OPTF_ARGREQ, 0, 'o' }, + { "progress", 0, 0, 'p' }, { 0, 0, 0, 0 } }; - i = mdwopt(argc, argv, "abf:o:qvC", opt, 0, 0, 0); + i = mdwopt(argc, argv, "abf:o:pqvC", opt, 0, 0, 0); if (i < 0) break; switch (i) { case 'a': ef = "pem"; break; @@ -367,6 +383,7 @@ static int decrypt(int argc, char *argv[]) case 'C': f |= f_nocheck; break; case 'f': ef = optarg; break; case 'o': of = optarg; break; + case 'p': f |= f_progress; break; default: f |= f_bogus; break; } } @@ -376,44 +393,55 @@ static int decrypt(int argc, char *argv[]) if ((eo = getenc(ef)) == 0) die(EXIT_FAILURE, "encoding `%s' not found", ef); - if (optind == argc) - fp = stdin; - else if (strcmp(argv[optind], "-") == 0) { + fn = optind < argc ? argv[optind++] : "-"; + if (strcmp(fn, "-") == 0) fp = stdin; - optind++; - } else if ((fp = fopen(argv[optind], eo->rmode)) == 0) { + else if ((fp = fopen(fn, eo->rmode)) == 0) { die(EXIT_FAILURE, "couldn't open file `%s': %s", - argv[optind], strerror(errno)); - } else - optind++; + fn, strerror(errno)); + } if (key_open(&kf, keyring, KOPEN_READ, key_moan, 0)) die(EXIT_FAILURE, "can't open keyring `%s'", keyring); e = initdec(eo, fp, checkbdry, "CATCRYPT ENCRYPTED MESSAGE"); + if (f & f_progress) { + if (fprogress_init(&ff, fn, fp)) { + die(EXIT_FAILURE, "failed to initialize progress display: %s", + strerror(errno)); + } + } + /* --- Read the header chunk --- */ chunk_read(e, &d, &b); + if (f & f_progress) + fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw); if (buf_getu32(&b, &id)) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL malformed header: missing keyid\n"); exit(EXIT_FAILURE); } if ((k = key_byid(&kf, id)) == 0) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id); exit(EXIT_FAILURE); } if (BLEFT(&b)) { if (buf_getu32(&b, &id)) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL malformed header: missing signature keyid\n"); exit(EXIT_FAILURE); } if ((sk = key_byid(&kf, id)) == 0) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id); exit(EXIT_FAILURE); } } if (BLEFT(&b)) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL malformed header: junk at end\n"); exit(EXIT_FAILURE); } @@ -434,7 +462,10 @@ static int decrypt(int argc, char *argv[]) /* --- Read the KEM chunk --- */ chunk_read(e, &d, &b); + if (f & f_progress) + fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw); if (setupkem(km, &d, &cx, &c, &m)) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL failed to decapsulate key\n"); exit(EXIT_FAILURE); } @@ -448,18 +479,24 @@ static int decrypt(int argc, char *argv[]) GC_ENCRYPT(cx, 0, d.buf, 1024); GH_HASH(s->h, d.buf, 1024); chunk_read(e, &d, &b); + if (f & f_progress) + fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw); if (s->ops->doit(s, &d)) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL signature verification failed\n"); exit(EXIT_FAILURE); } if (verb) { dstr_reset(&d); key_fulltag(sk, &d); + if (f & f_progress) fprogress_clear(&ff); printf("INFO good-signature %s\n", d.buf); } freesig(s); - } else if (verb) + } else if (verb) { + if (f & f_progress) fprogress_clear(&ff); printf("INFO no-signature\n"); + } /* --- Now decrypt the main body --- */ @@ -469,12 +506,15 @@ static int decrypt(int argc, char *argv[]) } if (!(f & f_buffer)) { if ((ofp = fopen(of, "wb")) == 0) { + if (f & f_progress) fprogress_done(&ff); die(EXIT_FAILURE, "couldn't open file `%s' for output: %s", ofp, strerror(errno)); } rfp = ofp; - } else if ((rfp = tmpfile()) == 0) + } else if ((rfp = tmpfile()) == 0) { + if (f & f_progress) fprogress_done(&ff); die(EXIT_FAILURE, "couldn't create temporary file: %s", strerror(errno)); + } seq = 0; dstr_ensure(&d, GC_CLASS(c)->blksz); @@ -488,12 +528,16 @@ static int decrypt(int argc, char *argv[]) GH_HASHU32(h, seq); seq++; chunk_read(e, &d, &b); + if (f & f_progress) + fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw); if ((tag = buf_get(&b, GM_CLASS(m)->hashsz)) == 0) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL bad ciphertext chunk: no tag\n"); exit(EXIT_FAILURE); } GH_HASH(h, BCUR(&b), BLEFT(&b)); if (memcmp(tag, GH_DONE(h, 0), GM_CLASS(m)->hashsz) != 0) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL bad ciphertext chunk: authentication failure\n"); exit(EXIT_FAILURE); @@ -503,11 +547,13 @@ static int decrypt(int argc, char *argv[]) break; GC_DECRYPT(c, BCUR(&b), BCUR(&b), BLEFT(&b)); if (fwrite(BCUR(&b), 1, BLEFT(&b), rfp) != BLEFT(&b)) { + if (f & f_progress) fprogress_done(&ff); if (verb) printf("FAIL error writing output: %s\n", strerror(errno)); exit(EXIT_FAILURE); } } + if (f & f_progress) fprogress_done(&ff); if (fflush(rfp) || ferror(rfp)) { if (verb) printf("FAIL error writing output: %s\n", strerror(errno)); exit(EXIT_FAILURE); @@ -518,15 +564,20 @@ static int decrypt(int argc, char *argv[]) of, strerror(errno)); } rewind(rfp); + if (f & f_progress) fprogress_init(&ff, "copying buffer", rfp); dstr_reset(&d); dstr_ensure(&d, 65536); if (verb && ofp == stdout) printf("DATA\n"); for (;;) { n = fread(d.buf, 1, d.sz, rfp); if (!n) break; - if (fwrite(d.buf, 1, n, ofp) < n) + if (f & f_progress) fprogress_update(&ff, n); + if (fwrite(d.buf, 1, n, ofp) < n) { + if (f & f_progress) fprogress_done(&ff); die(EXIT_FAILURE, "error writing output: %s", strerror(errno)); + } } + if (f & f_progress) fprogress_done(&ff); if (ferror(rfp) || fclose(rfp)) die(EXIT_FAILURE, "error unbuffering output: %s", strerror(errno)); } @@ -549,6 +600,7 @@ static int decrypt(int argc, char *argv[]) #undef f_bogus #undef f_buffer #undef f_nocheck +#undef f_progress } /*----- Main code ---------------------------------------------------------*/ @@ -584,7 +636,7 @@ static cmd cmdtab[] = { CMD_ENCODE, CMD_DECODE, { "encrypt", encrypt, - "encrypt [-aC] [-k TAG] [-s TAG] [-f FORMAT]\n\t\ + "encrypt [-apC] [-k TAG] [-s TAG] [-f FORMAT]\n\t\ [-o OUTPUT] [FILE]", "\ Options:\n\ \n\ @@ -593,20 +645,22 @@ Options:\n\ -k, --key=TAG Use public encryption key named by TAG.\n\ -s, --sign-key=TAG Use private signature key named by TAG.\n\ -o, --output=FILE Write output to FILE.\n\ +-p, --progress Show progress on large files.\n\ -C, --nocheck Don't check the public key.\n\ " }, { "decrypt", decrypt, - "decrypt [-abqvC] [-f FORMAT] [-o OUTPUT] [FILE]", "\ + "decrypt [-abpqvC] [-f FORMAT] [-o OUTPUT] [FILE]", "\ Options:\n\ \n\ -a, --armour Same as `-f pem'.\n\ -b, --buffer Buffer output until we're sure we have it all.\n\ -f, --format=FORMAT Decode as FORMAT.\n\ -o, --output=FILE Write output to FILE.\n\ +-p, --progress Show progress on large files.\n\ -q, --quiet Produce fewer messages.\n\ -v, --verbose Produce more verbose messages.\n\ -C, --nocheck Don't check the private key.\n\ -" }, /* ' emacs is confused */ +" }, { 0, 0, 0 } };