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 // If no charset was specified, use standard ascii 33 - 126 chars, which
173 // includes english lower case, upper case, numbers, and some symbols.
174 if(chars[0] == '\0')
175 count += intrcat(chars, 33, 126);
176
177 // Get the random data seed
178 clock_gettime(CLOCK_REALTIME, &ts);
179 seed = ts.tv_sec + ts.tv_nsec;
180 srand((unsigned)seed);
181
182 while(len > 0) {
183 int r = rand() % count;
184 printf("%lc", chars[r]);
185 len--;
186 }
187 printf("\n");
188
189 return 0;
190 }
|