Initial commit of a word-based password generator.
The diceware algorithm is a password generation algorithm where users roll dice several times (around 7) to generate a random number. This random number is then used to index into a word list and select a word. This process is repeated until between 3 and 12 words are selected. With dozens to hundreds of dice rolls, this can get very tedious. The passgen program performs this work in C++. It uses the /dev/urandom device on all modern UNIX systems to get randomness. This randomness is used to index into a word list. It uses 18 bits of randomness per word. The word list is more than 262144 words long and thus is suitable for this use. Before running a random sample of the words are discarded from the list. The list is also randomly reshuffled before beginning the process to ensure that a random selection of words are removed. The reshuffling also means that the same stream of bits from /dev/urandom will not generate the same password. It will, however, be slightly dependent upon the randomness in the pre-shuffle. This randomness does not improve the security of those passwords. Words smaller than 4 letters are also removed. 18 bits requires 3 bytes to store cleanly, and more than 3 bytes in base32 (which is kind of like what we're generating these passwords in). Thus those shorter words represent a compression -- this lowers the minimum number of bytes necessary to encode the password and reduces the search surface slightly. (The worst case would be 4 words having two letters -- 8 bytes, at 5 bits per byte is 40 bits of search space. 4 words at 18 bits per word is 72 bits of search space. You lose 32 bits of total search space there, alone!) (Note: This is a commit of the latest passgen, but using sha256 object store.)
This commit is contained in:
114
pingen.cc
Normal file
114
pingen.cc
Normal file
@ -0,0 +1,114 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <random>
|
||||
#include <cstdint>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
#include <cassert>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#undef BITS
|
||||
#undef DOMAIN
|
||||
#undef SKIP
|
||||
#undef DOIT
|
||||
#undef DEBUG
|
||||
|
||||
#define DEBUG SKIP
|
||||
#define DOIT if( true )
|
||||
#define SKIP if( false )
|
||||
|
||||
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace C
|
||||
{
|
||||
const std::size_t bits= 4;
|
||||
const std::size_t domain= 16;
|
||||
}
|
||||
|
||||
class Failure : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit Failure() : std::runtime_error( "Failure" ) {}
|
||||
explicit Failure( const std::string &s ) : std::runtime_error( "Failure: " + s ) {}
|
||||
};
|
||||
|
||||
auto
|
||||
openRandom()
|
||||
{
|
||||
std::ifstream r( "/dev/urandom" );
|
||||
if( r.bad() || r.fail() ) throw Failure();
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
class safe_vector : public std::vector< T >
|
||||
{
|
||||
public:
|
||||
using std::vector< T >::vector;
|
||||
template< typename Idx >
|
||||
auto operator []( const Idx &i ) const { return this->at( i ); }
|
||||
|
||||
template< typename Idx >
|
||||
auto operator []( const Idx &i ) { return this->at( i ); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main( const int argcnt, const char *const *const argvec )
|
||||
try
|
||||
{
|
||||
auto rnd= openRandom();
|
||||
|
||||
const int digitsDesired = ( argcnt == 1 ) ? 8 : boost::lexical_cast< int >( argvec[ 1 ] );
|
||||
|
||||
std::cout << "We are going to make a pin that has " << digitsDesired << " digits." << std::endl;
|
||||
|
||||
uint64_t randomness;
|
||||
std::string digits;
|
||||
std::size_t bitsInRnd= 0;
|
||||
|
||||
do
|
||||
{
|
||||
if( bitsInRnd < C::bits )
|
||||
{
|
||||
rnd.read( reinterpret_cast< char * >( &randomness ), sizeof( randomness ) );
|
||||
if( rnd.bad() || rnd.fail() || rnd.eof() ) throw Failure();
|
||||
bitsInRnd= sizeof( randomness ) * CHAR_BIT;
|
||||
}
|
||||
|
||||
const auto digit= randomness % ( C::domain );
|
||||
randomness>>= C::bits;
|
||||
bitsInRnd-= C::bits;
|
||||
|
||||
if( digit > 9 ) continue;
|
||||
|
||||
DEBUG std::cout << digit << std::endl;
|
||||
|
||||
digits.push_back( digit + '0' );
|
||||
}
|
||||
while( digits.size() < digitsDesired );
|
||||
|
||||
std::cout << "[32m" << digits << "[0m" << std::endl;
|
||||
std::cout << "Your pin has " << digits.size() << " words in its makeup." << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch( const std::exception &ex )
|
||||
{
|
||||
std::cerr << "Error: " << ex.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
Reference in New Issue
Block a user