Python Forum
mkpw: rewriting in python 3 - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: General (https://python-forum.io/forum-1.html)
+--- Forum: News and Discussions (https://python-forum.io/forum-31.html)
+--- Thread: mkpw: rewriting in python 3 (/thread-2360.html)

Pages: 1 2


mkpw: rewriting in python 3 - Skaperen - Mar-10-2017

i have this command originally written in C that i would like to rewrite in python 3.  anyone want to join in?  it takes a length as the only argument then outputs a candidate password randomly generated with letters, numbers, and special characters.

here is my original C code, untabified:
//-----------------------------------------------------------------------------
// Copyright © 2012 - Phil D. Howard - All rights reserved
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//-----------------------------------------------------------------------------
// license      ISC (BSD)
//-----------------------------------------------------------------------------
// author       Philip Howard
// email        echo L3I2rF5kYaIvnz5ypHO0rz52rF5jLabX|rot13|mimencode -u|rot13
//-----------------------------------------------------------------------------
// This file is best viewed using a fixed spaced font such as Courier and in a
// display at least 144 columns wide.
//-----------------------------------------------------------------------------
// compile      gcc -O3 -o mkpw mkpw.c && strip mkpw && ldd mkpw && ls -dl mkpw
//-----------------------------------------------------------------------------

#include <alloca.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define ARCHBITS        64
#define ARCHINT_T       uint64_t

#define DEFPWLEN        10
#define MAXPWLEN        32768
#define MINPWLEN        6

static unsigned long long       limit   = 5631351470947265625ULL;       /* 75^10 */
// static unsigned long         maxrn   = 33554432;
static unsigned long            maxrn   = 65536;

static char     rname[]         = "/dev/urandom";
static char     chset[75]       = "%&+,-./0123456789:=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~";
static char     class[75]       = "000000011111111110000333333333333333333333333330222222222222222222222222220";

static int      maxcount[4]     = { MAXPWLEN, MAXPWLEN, MAXPWLEN, MAXPWLEN };
static int      mincount[4]     = { 1, 1, 1, 20 };

int
main ( int argc, char ** argv )
{
    union {
        ARCHINT_T       number  ;
        unsigned char   buffer  [ARCHBITS/8];
    } numbuf;

    FILE                *rfile          ;
    char                *pw,*ptr,*pn,*pwend     ;
    unsigned long       cntrn           ;
    int                 counts[4]       ;
    int                 len,n,r         ;

    unsigned char       table   [256];

    //-- Get our own program name.
    pn = argv[0];
    while ( * pn ) ++ pn;
    while ( pn > argv[0] && * pn != '/' ) -- pn;
    if ( * pn == '/' ) ++ pn;

    //-- Get desired password length.
    len = DEFPWLEN;
    if ( -- argc && * ++ argv ) {
        len = strtoul( * argv, NULL, 0 );
        if ( len > MAXPWLEN ) len = MAXPWLEN;
        if ( len < MINPWLEN ) len = MINPWLEN;
    }

    //-- Open the random bit source.
    rfile = fopen( rname, "r" );
    if ( ! rfile ) {
        fprintf( stderr, "%s: unable to open \"%s\" to read random bits: %s\n", pn, rname, strerror( errno ) );
        return 1;
    }

    //-- Build character class lookup table.
    memset( table, 0, sizeof table );
    for ( n = 0; n < 75; ++ n ) {
        table[ chset[n] ] = class[n] - '0';
    }

    //-- Convert character class lookup to binary values.
    for ( ptr = class; * ptr; ++ ptr ) * ptr = * ptr - '0';

    //-- Get automatic space sized for the requested length.
    pw = alloca( len + 1 );
    if ( ! pw ) {
        fprintf( stderr, "%s: unable to allocate %llu bytes for password string\n", pn,
                 (unsigned long long) ( len + 1 ) );
        return 1;
    }
    pwend = pw + len;
    * pwend = 0;

    cntrn = 0;

    //-- Repeat until a password that meets requirements is generated.
    for (;;) {

        counts[0] = 0;
        counts[1] = 0;
        counts[2] = 0;
        counts[3] = 0;

        //-- Repeat until a password of sufficient length is generated.
        for ( ptr = pw; ptr < pwend; ) {

            //-- Check for max tries.
            if ( ++ cntrn > maxrn ) {
                fprintf( stderr, "%s: exceeded %lu random values without valid password\n", pn, maxrn );
                return 1;
            }

            //-- Read random bits
            r = fread( numbuf.buffer, 1, ARCHBITS/8, rfile );
            if ( feof( rfile ) ) {
                fprintf( stderr, "%s: unexpected EOF from \"%s\"\n", pn, rname );
                fclose( rfile );
                return 1;
            }
            if ( r < 8 ) {
                fprintf( stderr, "%s: error reading 8 bytes from \"%s\": %s\n", pn, rname, strerror( errno ) );
                fclose( rfile );
                return 1;
            }

            //-- Reject values that can lead to an uneven distribution of characters.
            if ( numbuf.number > limit ) continue;

            //-- Encode some characters.
            for ( n = 0; ptr < pwend && n < (ARCHBITS/6); ++ ptr, ++ n ) {
                r = numbuf.number % 75ULL;
                numbuf.number /= 75ULL;
                *ptr = chset[r];
                counts[ table[ *ptr ] ]++;
            }
        }

//      printf( "%2u %2u %2u %2u %s\n", counts[0], counts[1], counts[2], counts[3], pw );

        if ( counts[0] >= mincount[0] && counts[0] <= maxcount[0] &&
             counts[1] >= mincount[1] && counts[1] <= maxcount[1] &&
             counts[2] >= mincount[2] && counts[2] <= maxcount[2] &&
             counts[3] >= mincount[3] && counts[3] <= maxcount[3] ) break;
    }

    fclose( rfile );
    puts( pw );

    return 0;
}



RE: mkpw: rewriting in python 3 - varung1985 - Mar-16-2017

I would suggest using random module here, however, the code seems a bit complex than just giving a random password. Can you help me understand, after that we can work on python module for this?


RE: mkpw: rewriting in python 3 - Ofnuts - Mar-16-2017

https://blog.codinghorror.com/password-rules-are-bullshit/


RE: mkpw: rewriting in python 3 - Skaperen - Mar-17-2017

(Mar-16-2017, 10:07 AM)varung1985 Wrote: I would suggest using random module here, however, the code seems a bit complex than just giving a random password. Can you help me understand, after that we can work on python module for this?

yeah, the random module makes sense.  i'm thinking about using random.SystemRandom().choice() over the set of characters to be used.  

much of the complexity in that older version is making sure the random selection hits specific characters and is statistically consistent (so that no one character has lesser or greater chance of being chosen than any other).  it also has to do that for a variable length.

i think this will be simpler in Python given the tools it has.  i suspect most complexity will be cli option parsing.  this is not cryptography.


RE: mkpw: rewriting in python 3 - wavic - Mar-17-2017

Anyway, you have to specify a range os acceptable characters if you use SystemRandom. I've not played with this and don't know what comes out of the pool.


RE: mkpw: rewriting in python 3 - Larz60+ - Mar-17-2017

Save yourself some time, pick one of these: https://pypi.python.org/pypi?%3Aaction=search&term=make+password&submit=search


RE: mkpw: rewriting in python 3 - nilamo - Mar-17-2017

Here's something basic:

import random, string, sys

rand = random.SystemRandom()
chars = string.ascii_letters + string.digits + string.punctuation
length = int(sys.argv[1])

# if the entire password needs to be unique, just set this to 0
allowed_repetition = 2
min_unique = length - allowed_repetition

pword = ""
while not len(set(pword)) >= min_unique:
   pword = "".join(rand.choice(chars) for _ in range(length))
print(pword)



RE: mkpw: rewriting in python 3 - snippsat - Mar-17-2017

Can trow something together in a line.
>>> import random, string
>>> ''.join(random.SystemRandom().choice(string.ascii_uppercase+string.ascii_lowercase+string.digits+string.punctuation) for _ in range(10))
'x:92c~tL.u'
>>> ''.join(random.SystemRandom().choice(string.ascii_uppercase+string.ascii_lowercase+string.digits+string.punctuation) for _ in range(10))
'X$fv@Xd"hv'

>>> # Without punctuation
>>> ''.join(random.SystemRandom().choice(string.ascii_uppercase+string.ascii_lowercase+string.digits) for _ in range(10))
'6bS19nSJj4'
>>> ''.join(random.SystemRandom().choice(string.ascii_uppercase+string.ascii_lowercase+string.digits) for _ in range(10))
'bdcNqnxJjH'
The correct horse is better Wink


RE: mkpw: rewriting in python 3 - nilamo - Mar-17-2017

I agree that horses power the batteries of the future, but in our current level of faux security addled society, most people think obfuscation == security. ...including the people in charge of deciding what passwords should look like, who set rules that dictate what passwords must contain. Living within that framework, sometimes we need to do things that don't feel very good.

Or, you can use something like http://keepass.info/, and let it auto-generate 256 bits of insane passwords you'll never remember. Satisfy the rules, without melting your mind. Win/Win!


RE: mkpw: rewriting in python 3 - Skaperen - Mar-18-2017

(Mar-17-2017, 01:37 PM)Larz60+ Wrote: Save yourself some time, pick one of these: https://pypi.python.org/pypi?%3Aaction=search&term=make+password&submit=search

too many to choose from.  the issue with that is the most of them will have the code i need deeply embedded in code doing other stuff.  at best i'll need to extract it, which is not a time savings.  or what chance is there to find code that does the basic simple outputting of the desired kind of password i want at that time of running ... in a cli.

one of the things i have found i need to do is make passwords that can "lifted" off the screen by double-click highlighting and then pasting into another form somewhere.  that means excluding many special characters or only using a certain limited set.  and different users may be using different systems that behave differently and thus need different sets.  i also prefer to avoid mixed case in certain situation, or maybe avoid a lot of things.  so this could end up with a lot of options. both at the command line layer and at the function call layer.  careful option design is needed.

and did i mention password length?