commit ffe25f1f65e93981b34007bfe33975fca37f6512 from: Alexander Arkhipov date: Sun Aug 21 16:40:54 2022 UTC minimise the number of passes through the file commit - 97049080a945e564b80d1a8c51173ed1fb45e22c commit + ffe25f1f65e93981b34007bfe33975fca37f6512 blob - d029531700282a908e6b9331bf7d3e2f4ac17cf1 blob + 80b7c7bc08e2d02a159da7caccd5a3655eaba3f7 --- gpass.c +++ gpass.c @@ -12,9 +12,12 @@ #define PREFIX "/usr/local" #endif -char *pgen, *dict = NULL; -int npass = 1, minent = 70; +char *pgen, *dictname = NULL; +int plen = 70, nlines = 0, npass = 1; +FILE *dictfp; +#define RANDLINE (int)randombytes_uniform(nlines)+1 + int usage(void) { @@ -38,46 +41,27 @@ err(char *fmt, ...) void gen(void) { - int nlines = 0; - FILE *fp; - if (!(fp = fopen(dict, "r"))) { - err("could not open the dictionary file %s", dict); - exit(EXIT_FAILURE); - return; - } - for (char c = getc(fp); c != EOF; c = getc(fp)) - nlines += (c == '\n'); - - int plen = minent / log2(nlines) + 1; - if (plen > nlines) { - err("dictionary is too short"); - exit(EXIT_FAILURE); - } - if (plen >= MAXWORDS) { - err("required passphrase length is too big"); - exit(EXIT_FAILURE); - } - int nums[MAXWORDS]; - for (int i = 0; i < plen; i++) - nums[i] = (int)randombytes_uniform(nlines)+1; - - rewind(fp); - nlines = 1; - char c = getc(fp); - for(int i = 0; i < plen; c = getc(fp)) { - if (nlines == nums[i]) { - for (; c != '\n' && c != EOF && c != '\0'; c = getc(fp)) + rewind(dictfp); + char c; + int left = plen, cur = 1, sought = RANDLINE; + for (;;) { + c = getc(dictfp); + if (cur == sought) { + for (; c != '\n' && c != EOF; c = getc(dictfp)) putchar(c); - putchar(' '); - if (++i < plen && nums[i] <= nlines) { - rewind(fp); - nlines = 0; - } + if (--left) { + putchar(' '); + sought = RANDLINE; + if (sought <= cur) { + rewind(dictfp); + cur = 0; + } + } else + break; } - nlines += (c == '\n' || c == EOF || c == '\0'); + cur += (c == '\n' || c == EOF || c == '\0'); } putchar('\n'); - fclose(fp); } int @@ -86,35 +70,45 @@ main(int argc, char *argv[]) pgen = argv[0]; if (sodium_init() < 0) { err("could not initialise libsodium"); - return 1; + exit(EXIT_FAILURE); } int c; while ((c = getopt(argc, argv, "d:e:n:")) != -1) { switch (c) { case 'd': - dict = optarg; + dictname = optarg; break; case 'e': - minent = strtonum(optarg, 1, INT_MAX, NULL); - if (!minent) { + plen = strtonum(optarg, 1, INT_MAX, NULL); + if (!plen) { err("invalid entropy: use 1-%d", INT_MAX); - return 1; + exit(EXIT_FAILURE); } break; case 'n': npass = strtonum(optarg, 1, INT_MAX, NULL); if (!npass) { err("invalid number of passphrases: use 1-%d", - INT_MAX); - return 1; + INT_MAX); + exit(EXIT_FAILURE); } break; default: usage(); } } - if (!dict && !(dict = getenv("GPASS_DIC"))) - dict = PREFIX "/share/gpass/eff.long"; + + if (!dictname && !(dictname = getenv("GPASS_DIC"))) + dictname = PREFIX "/share/gpass/eff.long"; + if (!(dictfp = fopen(dictname, "r"))) { + err("could not open the dictionary file %s", dictfp); + exit(EXIT_FAILURE); + } + for (char c = getc(dictfp); c != EOF; c = getc(dictfp)) + nlines += (c == '\n'); + plen = plen / log2(nlines) + 1; + for (int i = 0; i < npass; i++) gen(); + fclose(dictfp); }