summaryrefslogtreecommitdiff
path: root/src/main.c
blob: c1836beaccc276f4b27cd42875c951627905e05d (plain)
    1 // upwgen generates random internationalized passwords
    2 // Copyright (C) 2019  Aaron Ball <nullspoon@oper.io>
    3 // 
    4 // This program is free software: you can redistribute it and/or modify
    5 // it under the terms of the GNU General Public License as published by
    6 // the Free Software Foundation, either version 3 of the License, or
    7 // (at your option) any later version.
    8 // 
    9 // This program is distributed in the hope that it will be useful,
   10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12 // GNU General Public License for more details.
   13 // 
   14 // You should have received a copy of the GNU General Public License
   15 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
   16 #include <stdlib.h>
   17 #include <stdio.h>
   18 #include <string.h>
   19 #include <time.h>
   20 #include <locale.h>
   21 
   22 
   23 // intrcat:
   24 // Integer range concatenate. Appends the specified integer range to an int
   25 // array.
   26 //
   27 // @arr    Array to cat range of ints to
   28 // @rstart Range start integer
   29 // @rend   Range end integer
   30 //
   31 // @return Number of integers appended to array
   32 int intrcat(unsigned int* arr, unsigned int rstart, unsigned int rend) {
   33   int i = 0;
   34   int total = rend - rstart; // Calculate our return count
   35 
   36   while(arr[i] != '\0')
   37     i++;
   38 
   39   while(rstart <= rend) {
   40     arr[i] = rstart;
   41     //printf("% -4d % -7d   %lc\n", i, rstart, rstart);
   42     rstart++;
   43     i++;
   44   }
   45 
   46   arr[i] = '\0';
   47   return total;
   48 }
   49 
   50 
   51 // populate_intl_arr:
   52 // Populates an unsigned integer array with common unicode (utf-8) language
   53 // alphabets and symbols.
   54 //
   55 // Some example unicode integer ranges:
   56 //   33 - 126      Standard english ascii
   57 //   256 - 383     Latin extended A block
   58 //   256 - 383     Latin extended B block
   59 //   913 - 969     Greek
   60 //   1040 - 1103   Russian
   61 //   1329 - 1414   Armenian
   62 //   1488 - 1514   Hebrew
   63 //   65166 - 65265 Arabic
   64 // 
   65 //   No/rare font support (boo!)
   66 //   2325 - 2373   Devanagari (Hindi)
   67 //   2437 - 2509   Bengali alphabet
   68 //   2949 - 3020   Tamil
   69 //   3585 - 3663   Thai
   70 //   5792 - 5880   Runic
   71 //   11392 - 11483 Coptic alphabet
   72 //   66560 - 66639 Deseret
   73 //
   74 // @out  Unsigned int array to be populated.
   75 //
   76 // @return Size of the array contents
   77 int populate_intl_arr(unsigned int* out) {
   78   int count = 0;
   79 
   80   // Populate the array
   81   count += intrcat(out, 33, 126);      // English
   82   count += intrcat(out, 256, 383);     // Latin A block
   83   count += intrcat(out, 399, 691);     // Latin B block
   84   count += intrcat(out, 913, 969);     // Greek
   85   count += intrcat(out, 1040, 1103);   // Russian
   86   count += intrcat(out, 1329, 1414);   // Armenian
   87   count += intrcat(out, 1488, 1514);   // Hebrew
   88   count += intrcat(out, 65166, 65265); // Arabic
   89 
   90   return count;
   91 }
   92 
   93 
   94 // print_intl_arr:
   95 // Prints array containing unsigned ints representing internal characters.
   96 // Outputs to STDOUT the unicode decimal, followed by the unicode character.
   97 //
   98 // @arr Unicode array to print
   99 void print_intl_arr(unsigned int* arr) {
  100   int i = 0; // cursor
  101 
  102   while(arr[i] != '\0') {
  103     printf("%5d: [%lc]\n", arr[i], arr[i]);
  104     i++;
  105   }
  106 }
  107 
  108 
  109 void usage() {
  110   printf(
  111     "Upwgen is a password generator with international support. If no length\n"
  112     "is specified, defaults to 32 characters output length\n\n"
  113     "Usage:\n  upwgen [options] [length]\n\n"
  114     "Options:\n"
  115     "  -c,--capitalize Include at least one capital letter in output\n"
  116     "  -l,--lower      Include at least one lower case letter in output\n"
  117     "  -n,--numerals   Include at least one numeral in output\n"
  118     "  -y,--symbols    Include at least one symbol in output\n"
  119     "  -i,--i18n       Include at least one international letter in output\n"
  120     "\n"
  121     "  -h,--help       Print this help text\n"
  122   );
  123 }
  124 
  125 
  126 int main(int argc, char* argv[]) {
  127   struct timespec ts; // Timespec for seeding rng
  128   int count;          // Number of chars to choose from
  129   int len;            // Password length
  130   int i;              // Arg index
  131   unsigned long seed; // Seed for the RNG (current seconds * nanoseconds)
  132   unsigned int chars[1024]; // Uint array to hold international chars
  133 
  134   // Initialize
  135   count    = 0;
  136   len      = 32;
  137   i        = 1;
  138   chars[0] = '\0';
  139   setlocale(LC_ALL, "en_US.UTF-8");
  140 
  141   while(i < argc) {
  142     if(strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--capitals") == 0) {
  143       count += intrcat(chars, 65, 90); // English uppercase
  144     } else if(strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--lower") == 0) {
  145       count += intrcat(chars, 97, 122); // English lower case
  146     } else if(strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--numerals") == 0) {
  147       count += intrcat(chars, 48, 57); // English numerals
  148     } else if(strcmp(argv[i], "-y") == 0 || strcmp(argv[i], "--symbols") == 0) {
  149       count += intrcat(chars, 33, 47);   // English symbols ! - /
  150       count += intrcat(chars, 58, 64);   // English symbols : - @
  151       count += intrcat(chars, 91, 96);   // English symbols [ - `
  152       count += intrcat(chars, 123, 126); // English symbols { - ~
  153     } else if(strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--i18n") == 0) {
  154       count += populate_intl_arr(chars);
  155     } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
  156       usage();
  157       return 0;
  158     } else {
  159       // If we reach this block, the user specified a custom length (or
  160       // fatfingered something). Test for ability to convert from str to int
  161       // and set length if possible.
  162       if(atoi(argv[i]) == 0) {
  163         printf("Invalid length \"%s\"\n", argv[i]);
  164         return 1;
  165       } else {
  166         len = atoi(argv[i]);
  167       }
  168     }
  169     i++;
  170   }
  171 
  172   // Ensure at least one character set was specified
  173   if(chars[0] == '\0') {
  174     printf("Must specify at least one character set\n");
  175     return 0;
  176   }
  177 
  178   // Get the random data seed
  179   clock_gettime(CLOCK_REALTIME, &ts);
  180   seed = ts.tv_sec + ts.tv_nsec;
  181   srand((unsigned)seed);
  182 
  183   while(len > 0) {
  184     int r = rand() % count;
  185     printf("%lc", chars[r]);
  186     len--;
  187   }
  188   printf("\n");
  189 
  190   return 0;
  191 }

Generated by cgit