Python: simple elegance

pythonA little hobby-job took me down the Python route this weekend, and I have to say I’m impressed. So far, at least. It has a simple elegance, and seems to approach coding from the same angle I do. Feels very natural to me. Pascal is my native tongue, and I’ve coded there for so long I that the language itself doesn’t even seem to be there any more, the code almost flows out of my fingers. Every other environment I’ve dabbled in has felt foreign in some way, and that hasn’t happened here.

OK for sure I spend some time rifling through the various online references to look up a function or syntax I haven’t used yet (to be expected in any new language), but it seems more exciting than tedious. Perhaps because this is a hobby-job and not something I have to do? Maybe that’s a factor.

Want to see a sample? OK here goes. Some time ago I wrote a password-generator program, which would take five inputs:

and mash the first four together to create a random-looking, but predictably-reproducable (is that a word?) password of the requested length. I have a Windows desktop application (written in Delphi) and a Windows Mobile implementation (in VB) of this, and it has served me well. At least, until I upgraded my phone to a Symbian-based Nokia, at which point I lost the mobile version. And I miss that mobile one, so I decided to right this wrong. Python is available for just about every platform going, Java is so cliché, and although I can code in C/C++, I generally prefer not to (now there’s a foreign-feeling environment). Here’s the (very early pre-release-test-only-please-don’t-criticise-it) Python program:

"""Main executive for Ken's password generator.
Just a test shell at the moment, but will incorporate cross-platform
checking, ensuring the correct I/O bits are used.
"""
 
import PswGenCalc
 
a="myname"
b="anysite"
c="keyword"
d="1234"
 
print PswGenCalc.getPswGen(a,b,c,d,10)

Of course that’s useless unless we’ve actually got the PswGenCalc module:

"""The guts of Ken's password generator.
 
   Takes the four input strings:
     SiteName
     UserName
     KeyWord
     KeyNumber
   And generates a repeatably-derived but high-strength and random-looking password.
 
   Input strings are all upper-cased before hashing. Returned string is built from the
   collision-resistant constant named ANTICOL below. Note the omission of look-alike
   characters such as I, l and 1.
"""
 
ANTICOL = "234679ACDEFGHJKLMNPQRTUVWXYabcdefghijkmnpqrstuvwxyz!$^*()-+=@#.,~"
HEXDIGITS = "0123456789ABCDEF"
 
import hashlib
 
def getPswGen(SiteName, UserName, KeyWord, Number, Length=8):
    # first concatenate all inputs & bump to upper-case
    AllInOne = (SiteName + UserName + KeyWord + Number).upper()
    # and generate a hash on that lot.
    Hash = hashlib.sha512(AllInOne).hexdigest().upper()
    # The Hash just generated consists of a number of hex-pair values.
    # Now strip them out one at a time and use them as indexes to look up
    # password characters from the ANTICOL table.
    Passw = ""
    while (len(Hash) > 0):
        HexVal = Hash[:2]   # first two characters
        # Now convert that to a decimal.
        DecVal = (HEXDIGITS.find(HexVal[:1]) * 16) + HEXDIGITS.find(HexVal[1:])
        # Next use each value as an offset into the ANTICOL string, and look
        # up the next password character.
        Passw = Passw + ANTICOL[DecVal % len(ANTICOL)]
        # Drop the bit of the hash code we just used and loop around for the next.
        Hash = Hash[2:] # everything EXCEPT the first two characters
    # Return the requested length of password, but from the TAIL of the string.
    # Using the tail effectively includes the length in the "randomisation".
    return Passw[-Length:]

Yes, I know that I could have combined some of the statements above and made it perform a little faster, but I generally avoid doing that unless the performance gain is absoltely necessary – I’ll take readability over technical snobbery every time, thank you. And yes, I’m sure that there’s a library function somewhere to do the hex-to-decimal conversion for me too. When I come across it, I’ll update. For now it’s no hardship for me to write a one-line conversion calculation.

Back to the program in question: for the sample data supplied in the main program code above, the output password is “E^gTHm-&Tr”. As passwords go, this is pretty good. Ten characters is long enough for most personal uses, and the mixture of upper-case and lower-case letters along with digits and symbols makes it very strong. To demonstrate how good the SHA hashing process is, I changed the KeyNumber parameter from 1234 to 1235, and the resulting password was “^?< ]>i2KEh” – completely unrelated. This is a sign of a good hash – change one bit of input data and on average, half the bits of the output data will change. The neat thing is, the password looks like total garbage but isn’t actually random. Give the same set of inputs to this code – on ANY operating system – and you’ll get the same output every time. That makes it ideal for password generation – you don’t have to remember the passwords, just the input components. And the beauty of it, like any decent hashing or encryption process, is that the entire design can be made public (like I’ve just done) without weakening the value. It doesn’t matter if the bad guys know how this works, as long as I keep the inputs secret, the passwords are safe. In fact, I really only need to keep ONE of the inputs secret, but there’s no harm in taking it further.

Is that strong enough? Frankly, yes – for low-to-medium-risk applications. Since you don’t have to remember the passwords, make them longer if you’re worried. If you need more security strength than this, then you’re really outside the bounds of what a password can do for you, and should be looking into multi-factor authentication anyway.

So why do I like Python so very much?

  1. It is extremely portable, Python code can run just about anywhere. Any flavour of desktop you can think of (and possibly a couple you can’t), non-graphical UI environments (text-only consoles), mobile devices (including Windows Mobile and Symbian-based phones), web servers, you name it.
  2. The language seems to be implemented with the mind-set of programmers in mind. Rather than theoretical eggheads. I can’t explain what makes me think this, other than my immediate comfort-zone feeling.
  3. It runs both as a prepared-script program and interactively, making unit-testing and debugging extremely convenient.
  4. Silly issues like indenting conventions disappear – they are an integral part of how the language operates. If you get your indenting wrong, you’ll know all about it soon enough. Nudges the programmer into good design and coding habits.
  5. To a much larger extent than any other environment I’ve worked in, Python encourages code self-documentation. You noticed the triple-quoted headers on each file above? That’s a Python convention, and that text is picked up by the doc-generator utilities.
  6. Code is readable! You might have picked up from the above that Python is heavily object-oriented. Fortunately, this is object orientation done right. Simple dot notation, thank you very much. Again, this just encourages good habits.

And now if you’ll excuse me, I’m off to turn this into a functional application. A desktop one quickly for myself, then a Symbian one for the Nokia, followed by a web-based version for the rest of the world. Any other requests?

Link from your social page:
  • Facebook
  • MySpace
  • Twitter
  • Google Bookmarks

Did you enjoy this post? Why not leave a comment below and continue the conversation, or subscribe to my feed and get articles like this delivered automatically to your feed reader.

Comments

No comments yet.

Leave a comment

(required)

(required)