re-organized source, added Makefile, better Readme, added manpage

This commit is contained in:
TLINDEN
2015-08-01 20:54:10 +02:00
parent 7187bc3e0a
commit 414cb2bec5
11 changed files with 900 additions and 361 deletions

49
Makefile Normal file
View File

@@ -0,0 +1,49 @@
#
# This file is part of dicepwgen
#
# Copyright (C) 2015 T.v.Dein.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# You can contact me by mail: <tom AT vondein DOT org>.
CFLAGS = -Wall -Wextra -Werror -O1 -g
LDFLAGS=
OBJS = dicepwgen.o dictfile.o tossing.o
DST = dicepwgen
PREFIX = /usr/local
UID = root
GID = 0
MAN = dicepwgen.1
POD = dicepwgen.pod
all: $(DST)
$(DST): $(OBJS)
gcc $(OBJS) -o $(DST)
%.o: %.c
gcc -c $(CFLAGS) $*.c -o $*.o
clean:
rm -f *.o $(DST)
man:
pod2man $(POD) > $(MAN)
install: $(DST)
install -d -o $(UID) -g $(GID) $(PREFIX)/sbin
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
install -o $(UID) -g $(GID) -m 555 $(DST) $(PREFIX)/sbin/
install -o $(UID) -g $(GID) -m 444 $(MAN) $(PREFIX)/man/man1/

View File

@@ -1,11 +1,46 @@
# diceware
A diceware password generator
## dicepwgen - A diceware password generator
# build
This is the README file for the password generator dicepwgen.
gcc dice.c -o dice
## Documentation
# use
You can read the documentation without installing the
software:
perldoc udpxd.pod
If it is already installed, you can read the manual page:
man udpxd
## Installation
This software doesn't have eny external dependencies, but
you need either BSD make or GNU make installed to build it.
First you need to check out the source code. Skip this, if
you have already done so:
git clone git@github.com:TLINDEN/diceware.git
Next, change into the newly created directory 'diceware' and
compile the source code:
cd diceware
make
To install, type this command:
sudo make install
This will install the binary to `$PREFIX/sbin/dicepwgen` and
the manual page to `$PREFIX/man/man1/dicepwgen.1`. You can
modify `$PREFIX` during installation time like this:
make install PREFIX=/opt
## Usage
```
Usage: dice [-tcfvh]
@@ -18,9 +53,23 @@ Options:
-h Print this help screen
```
# license
## Getting help
GPLv3
Although I'm happy to hear from udpxd users in private email,
that's the best way for me to forget to do something.
# author
Thomas von Dein
In order to report a bug, unexpected behavior, feature requests
or to submit a patch, please open an issue on github:
https://github.com/TLINDEN/diceware/issues.
## License
This software is licensed under the GNU GENERAL PUBLIC LICENSE version 3.
## Author
T.v.Dein <tom AT vondein DOT org>
## Project homepage
https://github.com/TLINDEN/diceware

352
dice.c
View File

@@ -1,352 +0,0 @@
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#define DICTFILE "/usr/share/dict/american-english"
#define VERSION "1.0"
#define RLEN 1024
int humantoss = 0;
int WMIN = 5;
int WMAX = 10;
int usage() {
fprintf(stderr,
"Generate a random diceware passphrase\n"
"Usage: dice [-cfvh]\n"
"Options: \n"
"-t --humantoss Asks interactively for tossed dices\n"
"-c --wordcount <count> Number of words (default: 4)\n"
"-f --dictfile <dictfile> Dictionary file to use (default:\n"
" /usr/share/dict/american-english)\n"
"-l --minlen <count> Minimum word len (default: 5)\n"
"-m --maxlen <count> Maximum word len (default: 10)\n"
"-v --version Print program version\n"
"-h -? --help Print this help screen\n"
);
return 1;
}
unsigned char *toss(int count) {
/*
toss <count> dices. if the global humandice is enabled (option -t),
then ask the human to toss dices and enter the numbers interactively.
otherwise generate tosses from /dev/random.
*/
FILE *RAND;
int i;
int pos = 0;
uint8_t onedice;
unsigned char *tosses = NULL;
unsigned char *rand = NULL;
size_t len;
ssize_t linelen;
if(humantoss) {
char *line = NULL;
char digit[2];
digit[1] = '\0';
RETRY:
fprintf(stderr, "enter 5 digits, each between 1-6\n");
linelen = getline(&line, &len, stdin);
tosses = malloc((size_t)count);
if(linelen < 6) /* 5 digits max allowed */
goto RETRY;
for(i=0; i<count; i++) { /* only digits allowed */
if(isdigit(line[i]) == 0)
goto RETRY;
digit[0] = line[i];
onedice = atoi(digit);
if (onedice < 1 || onedice > 6) /* no dice digit */
goto RETRY;
tosses[i] = onedice;
}
free(line);
}
else {
rand = malloc(RLEN);
if((RAND = fopen("/dev/urandom", "rb")) == NULL) {
perror("Could not open /dev/urandom");
}
fread(rand, RLEN, 1, RAND);
fclose(RAND);
tosses = malloc((size_t)count);
for(i=0; i<RLEN; i++) {
onedice = rand[i];
onedice &= 7; /* only use the last 3 bits, 0-7 */
onedice %= 6; /* 6 is the max */
if(onedice >= 1 && onedice <= 6) {
tosses[pos] = onedice;
pos++;
}
if(pos == count)
break;
}
free(rand);
}
return tosses;
}
int rand_lim(int limit) {
/*
return a random number in the range [0..limit)
*/
int divisor = RAND_MAX/limit;
int retval;
do {
retval = rand() / divisor;
} while (retval == limit);
return retval;
}
int *incr_dicedigit(int *digits) {
/*
increment an array of dice digits, we expect the first to
be a multiple of 10000, the 2nd a multiple of 1000 and so on.
*/
if(digits[4] == 6) {
digits[4] = 1;
if(digits[3] == 60) {
digits[3] = 10;
if(digits[2] == 600) {
digits[2] = 100;
if(digits[1] == 6000) {
digits[1] = 1000;
digits[0] += 10000; /* may overflow to 71111, must be catched by caller */
}
else
digits[1] += 1000;
}
else
digits[2] += 100;
}
else
digits[3] += 10;
}
else
digits[4]++;
return digits;
}
int get_dicenum(int *digits) {
/*
get the actual number of an array of dice digits
*/
int i = 0;
int pos = 0;
for(i=0; i<5; i++)
pos += digits[i];
return pos;
}
char **fetch_dict(char *dictfile) {
/*
read in the dictionary file. we generate an array of max
66666 entries from the dictionary, each entry's index will
be a dice number (1 <=> 6). to enhance randomness, we jump
over a number of lines (1-32 lines) and start from the beginning
of the file if we reach the end before our array is full.
*/
char **words;
int pos, i, next, jump;
char *line = NULL;
size_t len = 0;
ssize_t linelen;
FILE *DICT;
int *digits;
if((DICT = fopen(dictfile, "rb")) == NULL) {
perror("Could not open dictfile");
}
words = malloc(66666 * sizeof(char *));
digits = malloc(5);
jump = rand_lim(32);
digits[0] = 10000;
digits[1] = 1000;
digits[2] = 100;
digits[3] = 10;
digits[4] = 1;
pos = 11111;
next = 0;
for(i=0; i<6666; i++)
words[i] = NULL;
LOOP:
while ((linelen = getline(&line, &len, DICT)) != -1) {
if(jump > 0) {
jump--;
continue;
}
else {
jump = rand_lim(32);
}
if(linelen >= WMIN+1 && linelen <= WMAX+1) {
line[linelen-1] = '\0'; /* remove newline */
for(i=0; i<linelen-1; i++) {
if(isalpha((int)line[i]) == 0) {
next = 1;
break;
}
}
if(next) {
next = 0;
continue;
}
words[pos] = malloc(linelen);
strncpy( words[pos], line, linelen);
//fprintf(stdout, "%d: %s\n", pos, line);
digits = incr_dicedigit(digits);
pos = get_dicenum(digits);
/* this is what pos gets next after 66666, which is max reachable with 5 dices */
if(pos == 71111)
break;
} /* endif word 4<=>10 */
} /* while read */
if(pos < 66666) {
fseek(DICT, 0L, SEEK_SET);
goto LOOP;
}
fclose(DICT);
free(line);
free(digits);
return words;
}
void getwords(char *dictfile, int count) {
/*
initiate dice tossing, extract matching number of words
froom the wordlist and print it.
*/
char **words;
int i, pos, one, two, three, four, five;
int *tossed;
unsigned char *tosses;
words = fetch_dict(dictfile);
tossed = malloc(count * sizeof(int));
for(i=0; i<count; i++) {
tosses = toss(5);
one = tosses[0] * 10000;
two = tosses[1] * 1000;
three = tosses[2] * 100;
four = tosses[3] * 10;
five = tosses[4];
pos = one + two + three + four + five;
tossed[i] = pos;
free(tosses);
}
for(i=0; i<count; i++) {
fprintf(stdout, "%s ", words[tossed[i]]);
}
fprintf(stdout, "\n");
free(tossed);
for(i=0; i<6666; i++)
if(words[i] != NULL)
free(words[i]);
free(words);
}
int main (int argc, char **argv) {
int count = 4;
char *dictfile = NULL;
unsigned char *tosses = NULL;
int opt;
static struct option longopts[] = {
{ "wordcount", required_argument, NULL, 'c' },
{ "minlen", required_argument, NULL, 'l' },
{ "maxlen", required_argument, NULL, 'm' },
{ "humantoss", required_argument, NULL, 't' },
{ "dictfile", required_argument, NULL, 'f' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
};
while ((opt = getopt_long(argc, argv, "l:m:tf:c:vh?", longopts, NULL)) != -1) {
switch (opt) {
case 'v':
fprintf(stderr, "This is %s version %s\n", argv[0], VERSION);
return 1;
break;
case 'h':
case '?':
return usage();
break;
case 'c':
count = atoi(optarg);
break;
case 'l':
WMIN = atoi(optarg);
break;
case 'm':
WMAX = atoi(optarg);
break;
case 't':
humantoss = 1;
break;
case 'f':
dictfile = malloc(strlen(optarg));
strncpy(dictfile, optarg, strlen(optarg));
break;
default:
return usage();
break;
}
}
if(dictfile == NULL) {
dictfile = DICTFILE;
}
getwords(dictfile, count);
return 0;
}

193
dicepwgen.1 Normal file
View File

@@ -0,0 +1,193 @@
.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
. ds C`
. ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\"
.\" If the F register is turned on, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.nr rF 0
.if \n(.g .if rF .nr rF 1
.if (\n(rF:(\n(.g==0)) \{
. if \nF \{
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. if !\nF==2 \{
. nr % 0
. nr F 2
. \}
. \}
.\}
.rr rF
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear. Run. Save yourself. No user-serviceable parts.
. \" fudge factors for nroff and troff
.if n \{\
. ds #H 0
. ds #V .8m
. ds #F .3m
. ds #[ \f1
. ds #] \fP
.\}
.if t \{\
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
. ds #V .6m
. ds #F 0
. ds #[ \&
. ds #] \&
.\}
. \" simple accents for nroff and troff
.if n \{\
. ds ' \&
. ds ` \&
. ds ^ \&
. ds , \&
. ds ~ ~
. ds /
.\}
.if t \{\
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
. \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
. \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
. \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
. ds : e
. ds 8 ss
. ds o a
. ds d- d\h'-1'\(ga
. ds D- D\h'-1'\(hy
. ds th \o'bp'
. ds Th \o'LP'
. ds ae ae
. ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ========================================================================
.\"
.IX Title "DICEPWGEN 1"
.TH DICEPWGEN 1 "2015-08-01" "perl v5.18.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
dicepwgen \- A diceware password generator
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
.Vb 10
\& Usage: dice [\-cfvh]
\& Options:
\& \-t \-\-humantoss Asks interactively for tossed dices
\& \-c \-\-wordcount <count> Number of words (default: 4)
\& \-f \-\-dictfile <dictfile> Dictionary file to use (default:
\& /usr/share/dict/american\-english)
\& \-l \-\-minlen <count> Minimum word len (default: 5)
\& \-m \-\-maxlen <count> Maximum word len (default: 10)
\& \-v \-\-version Print program version
\& \-h \-? \-\-help Print this help screen
.Ve
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
dicepwgen generates a diceware password using a dictionary
file. By default it uses pseudo random dice tosses, but
it is also possible to use real dices and enter the numbers
by using the option \fB\-t\fR.
.PP
The option \fB\-c\fR can be used to tweak the number of words
to output. The options \fB\-l\fR and \fB\-m\fR can be used to tweak
minimum and maximum word length.
.PP
You can tell dicepwgen to use another dictionary file with
the option \fB\-f\fR.
.PP
The program only uses words which contain 7bit \s-1ASCII\s0 letters
(a\-zA-Z), which are easier for password usage anyway.
.SH "FILES"
.IX Header "FILES"
\&\fB/usr/share/dict/american\-english\fR: default dictionary file.
.SH "SEE ALSO"
.IX Header "SEE ALSO"
<http://world.std.com/~reinhold/diceware.html>
.PP
<https://xkcd.com/936/>.
.SH "BUGS"
.IX Header "BUGS"
In order to report a bug, unexpected behavior, feature requests
or to submit a patch, please open an issue on github:
<https://github.com/TLINDEN/diceware/issues>.
.SH "LICENSE"
.IX Header "LICENSE"
This software is licensed under the \s-1GNU GENERAL PUBLIC LICENSE\s0 version 3.
.PP
Copyright (c) 2015 by T. v. Dein.
.SH "AUTHORS"
.IX Header "AUTHORS"
T.v.Dein \fBtom \s-1AT\s0 vondein \s-1DOT\s0 org\fR

146
dicepwgen.c Normal file
View File

@@ -0,0 +1,146 @@
/*
* This file is part of dicepwgen
*
* Copyright (C) 2015 T.v.Dein.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can contact me by mail: <tom AT vondein DOT org>.
*/
#include "dicepwgen.h"
int usage() {
fprintf(stderr,
"Generate a random diceware passphrase\n"
"Usage: dice [-tcfvh]\n"
"Options: \n"
"-t --humantoss Asks interactively for tossed dices\n"
"-c --wordcount <count> Number of words (default: 4)\n"
"-f --dictfile <dictfile> Dictionary file to use (default:\n"
" /usr/share/dict/american-english)\n"
"-l --minlen <count> Minimum word len (default: 5)\n"
"-m --maxlen <count> Maximum word len (default: 10)\n"
"-v --version Print program version\n"
"-h -? --help Print this help screen\n"
);
return 1;
}
int main (int argc, char **argv) {
int count = 4;
char *dictfile = NULL;
unsigned char *tosses = NULL;
int opt;
WMIN = 6;
WMAX = 10;
humantoss = 0;
static struct option longopts[] = {
{ "wordcount", required_argument, NULL, 'c' },
{ "minlen", required_argument, NULL, 'l' },
{ "maxlen", required_argument, NULL, 'm' },
{ "humantoss", required_argument, NULL, 't' },
{ "dictfile", required_argument, NULL, 'f' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
};
while ((opt = getopt_long(argc, argv, "l:m:tf:c:vh?", longopts, NULL)) != -1) {
switch (opt) {
case 'v':
fprintf(stderr, "This is %s version %s\n", argv[0], VERSION);
return 1;
break;
case 'h':
case '?':
return usage();
break;
case 'c':
count = atoi(optarg);
break;
case 'l':
WMIN = atoi(optarg);
break;
case 'm':
WMAX = atoi(optarg);
break;
case 't':
humantoss = 1;
break;
case 'f':
dictfile = malloc(strlen(optarg));
strncpy(dictfile, optarg, strlen(optarg));
break;
default:
return usage();
break;
}
}
if(dictfile == NULL) {
dictfile = DICTFILE;
}
getwords(dictfile, count);
return 0;
}
void getwords(char *dictfile, int count) {
/*
initiate dice tossing, extract matching number of words
froom the wordlist and print it.
*/
char **words;
int i, pos, one, two, three, four, five;
int *tossed;
unsigned char *tosses;
words = fetch_dict(dictfile);
tossed = malloc(count * sizeof(int));
for(i=0; i<count; i++) {
tosses = toss(5);
one = tosses[0] * 10000;
two = tosses[1] * 1000;
three = tosses[2] * 100;
four = tosses[3] * 10;
five = tosses[4];
pos = one + two + three + four + five;
tossed[i] = pos;
free(tosses);
}
for(i=0; i<count; i++) {
fprintf(stdout, "%s ", words[tossed[i]]);
}
fprintf(stdout, "\n");
free(tossed);
for(i=0; i<6666; i++)
if(words[i] != NULL)
free(words[i]);
free(words);
}

48
dicepwgen.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* This file is part of dicepwgen
*
* Copyright (C) 2015 T.v.Dein.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can contact me by mail: <tom AT vondein DOT org>.
*/
#ifndef HAVE_DICE_H
#define HAVE_DICE_H
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include "dictfile.h"
#include "tossing.h"
#define DICTFILE "/usr/share/dict/american-english"
#define VERSION "1.0"
#define RLEN 1024
int humantoss;
int WMIN;
int WMAX;
int usage();
int main (int argc, char **argv);
void getwords(char *dictfile, int count);
#endif

61
dicepwgen.pod Normal file
View File

@@ -0,0 +1,61 @@
=head1 NAME
dicepwgen - A diceware password generator
=head1 SYNOPSIS
Usage: dice [-cfvh]
Options:
-t --humantoss Asks interactively for tossed dices
-c --wordcount <count> Number of words (default: 4)
-f --dictfile <dictfile> Dictionary file to use (default:
/usr/share/dict/american-english)
-l --minlen <count> Minimum word len (default: 5)
-m --maxlen <count> Maximum word len (default: 10)
-v --version Print program version
-h -? --help Print this help screen
=head1 DESCRIPTION
dicepwgen generates a diceware password using a dictionary
file. By default it uses pseudo random dice tosses, but
it is also possible to use real dices and enter the numbers
by using the option B<-t>.
The option B<-c> can be used to tweak the number of words
to output. The options B<-l> and B<-m> can be used to tweak
minimum and maximum word length.
You can tell dicepwgen to use another dictionary file with
the option B<-f>.
The program only uses words which contain 7bit ASCII letters
(a-zA-Z), which are easier for password usage anyway.
=head1 FILES
B</usr/share/dict/american-english>: default dictionary file.
=head1 SEE ALSO
L<http://world.std.com/~reinhold/diceware.html>
L<https://xkcd.com/936/>.
=head1 BUGS
In order to report a bug, unexpected behavior, feature requests
or to submit a patch, please open an issue on github:
L<https://github.com/TLINDEN/diceware/issues>.
=head1 LICENSE
This software is licensed under the GNU GENERAL PUBLIC LICENSE version 3.
Copyright (c) 2015 by T. v. Dein.
=head1 AUTHORS
T.v.Dein B<tom AT vondein DOT org>
=cut

139
dictfile.c Normal file
View File

@@ -0,0 +1,139 @@
/*
* This file is part of dicepwgen
*
* Copyright (C) 2015 T.v.Dein.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can contact me by mail: <tom AT vondein DOT org>.
*/
#include "dictfile.h"
int *incr_dicedigit(int *digits) {
/*
increment an array of dice digits, we expect the first to
be a multiple of 10000, the 2nd a multiple of 1000 and so on.
*/
if(digits[4] == 6) {
digits[4] = 1;
if(digits[3] == 60) {
digits[3] = 10;
if(digits[2] == 600) {
digits[2] = 100;
if(digits[1] == 6000) {
digits[1] = 1000;
digits[0] += 10000; /* may overflow to 71111, must be catched by caller */
}
else
digits[1] += 1000;
}
else
digits[2] += 100;
}
else
digits[3] += 10;
}
else
digits[4]++;
return digits;
}
char **fetch_dict(char *dictfile) {
/*
read in the dictionary file. we generate an array of max
66666 entries from the dictionary, each entry's index will
be a dice number (1 <=> 6). to enhance randomness, we jump
over a number of lines (1-32 lines) and start from the beginning
of the file if we reach the end before our array is full.
*/
char **words;
int pos, i, next, jump;
char *line = NULL;
size_t len = 0;
ssize_t linelen;
FILE *DICT;
int *digits;
if((DICT = fopen(dictfile, "rb")) == NULL) {
perror("Could not open dictfile");
}
words = malloc(66666 * sizeof(char *));
digits = malloc(5);
jump = rand_lim(32);
digits[0] = 10000;
digits[1] = 1000;
digits[2] = 100;
digits[3] = 10;
digits[4] = 1;
pos = 11111;
next = 0;
for(i=0; i<6666; i++)
words[i] = NULL;
LOOP:
while ((linelen = getline(&line, &len, DICT)) != -1) {
if(jump > 0) {
jump--;
continue;
}
else {
jump = rand_lim(32);
}
if(linelen >= WMIN+1 && linelen <= WMAX+1) {
line[linelen-1] = '\0'; /* remove newline */
for(i=0; i<linelen-1; i++) {
if(isalpha((int)line[i]) == 0) {
next = 1;
break;
}
}
if(next) {
next = 0;
continue;
}
words[pos] = malloc(linelen);
strncpy( words[pos], line, linelen);
//fprintf(stdout, "%d: %s\n", pos, line);
digits = incr_dicedigit(digits);
pos = get_dicenum(digits);
/* this is what pos gets next after 66666, which is max reachable with 5 dices */
if(pos == 71111)
break;
} /* endif word 4<=>10 */
} /* while read */
if(pos < 66666) {
fseek(DICT, 0L, SEEK_SET);
goto LOOP;
}
fclose(DICT);
free(line);
free(digits);
return words;
}

40
dictfile.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* This file is part of dicepwgen
*
* Copyright (C) 2015 T.v.Dein.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can contact me by mail: <tom AT vondein DOT org>.
*/
#ifndef HAVE_DICTFILE_H
#define HAVE_DICTFILE_H
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include "tossing.h"
extern int WMIN;
extern int WMAX;
int *incr_dicedigit(int *digits);
char **fetch_dict(char *dictfile);
#endif

124
tossing.c Normal file
View File

@@ -0,0 +1,124 @@
/*
* This file is part of dicepwgen
*
* Copyright (C) 2015 T.v.Dein.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can contact me by mail: <tom AT vondein DOT org>.
*/
#include "tossing.h"
unsigned char *toss(int count) {
/*
toss <count> dices. if the global humandice is enabled (option -t),
then ask the human to toss dices and enter the numbers interactively.
otherwise generate tosses from /dev/random.
*/
FILE *RAND;
int i;
int pos = 0;
uint8_t onedice;
unsigned char *tosses = NULL;
unsigned char *rand = NULL;
size_t len;
ssize_t linelen;
if(humantoss) {
char *line = NULL;
char digit[2];
digit[1] = '\0';
RETRY:
fprintf(stderr, "enter 5 digits, each between 1-6\n");
linelen = getline(&line, &len, stdin);
tosses = malloc((size_t)count);
if(linelen < 6) /* 5 digits max allowed */
goto RETRY;
for(i=0; i<count; i++) { /* only digits allowed */
if(isdigit(line[i]) == 0)
goto RETRY;
digit[0] = line[i];
onedice = atoi(digit);
if (onedice < 1 || onedice > 6) /* no dice digit */
goto RETRY;
tosses[i] = onedice;
}
free(line);
}
else {
rand = malloc(RLEN);
if((RAND = fopen("/dev/urandom", "rb")) == NULL)
perror("Could not open /dev/urandom");
if(fread(rand, RLEN, 1, RAND) != 1)
perror("Could not read from /dev/urandom");
fclose(RAND);
tosses = malloc((size_t)count);
for(i=0; i<RLEN; i++) {
onedice = rand[i];
onedice &= 7; /* only use the last 3 bits, 0-7 */
onedice %= 6; /* 6 is the max */
if(onedice >= 1 && onedice <= 6) {
tosses[pos] = onedice;
pos++;
}
if(pos == count)
break;
}
free(rand);
}
return tosses;
}
int rand_lim(int limit) {
/*
return a random number in the range [0..limit)
*/
int divisor = RAND_MAX/limit;
int retval;
do {
retval = rand() / divisor;
} while (retval == limit);
return retval;
}
int get_dicenum(int *digits) {
/*
get the actual number of an array of dice digits
*/
int i = 0;
int pos = 0;
for(i=0; i<5; i++)
pos += digits[i];
return pos;
}

42
tossing.h Normal file
View File

@@ -0,0 +1,42 @@
/*
* This file is part of dicepwgen
*
* Copyright (C) 2015 T.v.Dein.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can contact me by mail: <tom AT vondein DOT org>.
*/
#ifndef HAVE_TOSSING_H
#define HAVE_TOSSING_H
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#define RLEN 1024
extern int humantoss;
extern int WMIN;
extern int WMAX;
unsigned char *toss(int count);
int rand_lim(int limit);
int get_dicenum(int *digits);
#endif