% Simple GNU Prolog password generator % Author: Detlef Sax % $Log: prld.pl,v $ % Revision 1.1 2002/07/03 09:36:50 sax % Initial revision % % % Copyright (c) 1999, Detlef Sax % All rights reserved. % % 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 2 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, write to the Free Software Foundation, Inc., 675 % Mass Ave, Cambridge, MA 02139, USA. /* I have two devices on my FreeBSD/Linux Box, called /dev/random and * /dev/urandom. It gives somewhat better results, but they are * slow, especially /dev/random. You can use these devices for all * your random needs, but they're only necessary for setting the * seed via set_seed/1. My five Cent. */ q :- dev_random, cmdline, halt. % If /dev/random exist grab 2 bytes for setting the random seed. % Gives at least better results than randomize/0 on my boxes. dev_random :- file_exists('/dev/random'), make_seed. dev_random :- randomize. %-------------------W-A-R-N-I-N-G---------------------------------------| % You'll get errors if you increase the +Amount too much and other | % processes also want some randoms from /dev/{u}random. | % Use it only for setting the seed (set_seed/1) of the random builtin | % and you're on the secure side. | %-------------------W-A-R-N-I-N-G---------------------------------------| % Take two bytes from /dev/random and set seed for builtin random functions. make_seed :- ggs(2, SeedList), sum_list(SeedList, C), set_seed(C). %Get a good seed ggs(+Amount, -Seed) ggs(N, Seed) :- open('/dev/random', read, Stream, [reposition(false),alias(al)]), !, get_seed(N, Seed), close(Stream). % get_seed(+Amount, -ListOfRandomCharcodes) get_seed(0, []) :- !. get_seed(N, [H|T]) :- N < 4,% I said: "Read the WARNING" get_code(al, S), number(S), H is abs(S), N1 is dec(N), get_seed(N1,T). cmdline :- argument_list(List), length(List, 2), do_cmdln(List, Length, Amount), do_passwd(Length, Amount). cmdline :- argument_list([]), do_passwd. cmdline :- argument_list(X), do_cmdln(X, _, _). do_cmdln([A, B], Length, Amount) :- number_atom(Length, A), number_atom(Amount, B), limit_keys(Length, Amount). do_cmdln(X, _, _) :- nl, write('parse error: '), write_list_sp(X), nl, write('usage: propass L A'), nl, write('L is an integer and the length of an key,'), nl, write('A is an integer and the amount of keys you need.'), nl, halt. % Even the memory of your computer is limited: limit_keys(Length, Amount) :- hardware_limit(L, A), Length =< L, Amount =< A. limit_keys(_, _) :- hardware_limit(L, A), write('error: values are out of range '), nl, write(L), write(' the limit of key length'), nl, write(A), write(' the limit of key amount'), nl, write('read the source and change hardware_limit/2'), nl, halt. do_passwd(L, A) :- L >= 1, A >= 1, make_passwd(L, A, Passwords), write_list(Passwords). do_passwd(L, A) :- ( L =< 0 ; A =< 0 ), write(L),write(' '),write(A), nl, write('You\'re kidding'), nl, halt. do_passwd :- default_args(L, A), make_passwd(L, A, Passwords), write_list(Passwords). %make_passwd(+LengthKey, +Amount, -Passwords) make_passwd(_, 0, []) :- !. make_passwd(L, N, [NPw|Rest]) :- differ_limit(DIFFLIMIT), L =< DIFFLIMIT, N1 is dec(N), length(Pass, L), make_passwd(L, N1, Rest), one_password(Pass, NPass), atom_chars(NPw, NPass). make_passwd(L, N, [NPw|Rest]) :- N1 is dec(N), length(Pass, L), make_passwd(L, N1, Rest), get_one(Pass), atom_chars(NPw, Pass). one_password(Pass, NPass) :- get_one(Pass), all_differ(Pass, NPass). %get_one(-Password) get_one([]). get_one([L|Rest]) :- repeat, random(48, 122, Rand), word_char(Rand), char_code(L, Rand), get_one(Rest). all_differ(Pass, NPass) :- length(Pass, L), sort(Pass, SPass), length(SPass, L), NPass = Pass. all_differ(Pass, NNPass) :- length(Pass, L), length(NPass, L), true, one_password(NPass, NNPass). write_list([]) :- !. write_list([H|T]) :- write(H), nl, write_list(T). write_list_sp([]) :- !. write_list_sp([H|T]) :- write(H), write(' '), write_list_sp(T). % character codes: see "man ascii" word_char(C) :- 97 =< C, C =< 122. % [a-z] word_char(C) :- 65 =< C, C =< 90. % [A-Z] word_char(C) :- 48 =< C, C =< 57. % [0-9] % Try more if you're an experimentalist: % hardware_limit(L, A) hardware_limit(80, 1000). % default_args(L, A). default_args(8, 20). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Experimental, % no duplicate chars per key under this limit % Segfaults on my machine (i386 sufficent RAM) at L 14 A 500. % Try more: differ_limit(10). :- initialization(q).