Welcome, guest | Sign In | My Account | Store | Cart

Generate hashes and compare them, with a very secure hash generation function.

Python, 78 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
##################################################################################################################
##################################################################################################################
##
## RAS- Riddle's Authentication System (04/08/2006)
## This Python file contains the skeleton functions for RAS.
## If you want to use it, that's fine with the author, Riddle.
## But if you want to edit the code, comment out the parts you don't want and add
## comments telling where your code was added.
## If you examine the source code and read the comments, it should be easy to use without much headache.
## If you do need help, however, here are contacts for the author:
## email: J.Riddle.x@gmail.com
## aim: J Riddle x
##
##################################################################################################################
##################################################################################################################
 
import md5,sha; from random import choice; from os import access,F_OK

##################################################################################################################
#repeat line generator: prints random replacement lines in a config file, 'cfgfile'
def repgen(cfgfile): #cfgfile= config file to which you want to write the generated replace lines (WILL OVERWRITE)
  num= 0; reps= []
  chars='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%\&\'()*+,-./:;<=>?@[\\]^_`{|}~'
  for num in range(0,len(chars)):
    reps.append('replace %s:%s\n' % (chars[num],chars[choice(range(0,len(chars)))]))
  cfg= file(cfgfile,'w')
  for num in range(0,len(reps)):
    cfg.write(reps[num]); cfg.close
##################################################################################################################

##################################################################################################################
#replacement loop function- does replacements on strob as cfgtxt tells to; return the modified strob
def reploop(strob,cfgtxt): #strob= string object (target of the replacements); cfgtxt= list object with rep lines
  for num in range(0,len(cfgtxt)):
    if cfgtxt[num].startswith('replace '):
      tmpline= cfgtxt[num].strip('replace ')
      strob= strob.replace(tmpline.split(':')[0],tmpline.split(':')[1])
  return strob
##################################################################################################################

##################################################################################################################
#hash generator- either writes the hash to a specified config file, or just returns it (as used by hashcmp())
#if you want to write to the file, the third argument should be 1; the fourth argument should be the hash name

def hashgen(tmppass,cfgfile,*writedata):    #tmppass= password to gen a hash for; cfgfile= config file to use
  if access(cfgfile,F_OK):                  #writedata= tells us if to write, and if so, the hash name
    cfg= file(cfgfile,'r'); cfgtxt= cfg.readlines(); cfg.close()
    tmppass= reploop(tmppass,cfgtxt);
      #coders: if you know what you are doing, you can make the md5/sha hash(es) go through the reploop function too
      #(which would add some extra confusion in any attempt to decrypt the hashes)
    hash= sha.sha(md5.md5(tmppass).hexdigest()).hexdigest()
    if writedata[0]:
      cfg= file(cfgfile,'a'); cfg.write('hash %s %s\n' % (writedata[1],hash)); cfg.close()
    else:
      return hash
###################################################################################################################

###################################################################################################################
#hash comparing function- a function used to compare two hashes
#third argument should be 1 if you want to load a hash from the config file (if so, fourth argument= hash name)
#third argument should be 0 if you want to compare with a hash which you will supply (if so, fourth argument= hash)
#returns 1 if they're the same, returns 0 otherwise

def hashcmp(tmppass,cfgfile,*cmphash):    #tmppass= password to compare the saved password to
  if cmphash[0]:                          #cfgfile= file to generate the hash with
    if access(cfgfile,F_OK):              #         and load the fourth argument, the hash name, from (but only if the third argument= 1)
      cfg= file(cfgfile,'r'); cfgtxt= cfg.readlines(); cfg.close()
      for num in range(0,len(cfgtxt)):
        if cfgtxt[num].startswith('hash %s ' % cmphash[1]):
          if hashgen(tmppass,cfgfile,0,0) == cfgtxt[num].split(cmphash[1]+' ')[1].strip('\n'):
            return 1
      return 0
  else:
    if hashgen(tmppass,cfgfile,0) == cmphash[1]:
      return 1
    else:
      return 0
##################################################################################################################

Hashes are very secure (that is to say, quite hard to decrypt):

A password has certain letters replaced with other certain letters (as defined in the config file), then has an MD5 hash generated for it. Then, the MD5 hash is turned into a SHA hash.

If you were to modify the code, you could make one or both of the hashes go through the reploop() function (which is the same function with which the password's original letters are modified).

When generating a hash, you have the option of writing it to the config file (this is convenient, because you can have the hashes in the same config files with which they were created).

If a client and server are both running RAS, the client can generate a hash and then the server can compare it to a hash on record- this way, the password is encrypted before transfer, and programs such as packet scanners would get only the encrypted hash (which would do them little good as far as finding out the password goes).

04/09: Edited code to make the function's syntax easier (with tuple argument objects, so that you don't have to have arguments which won't be used).

2 comments

Josiah Carlson 15 years, 7 months ago  # | flag

This method is no more secure than plain md5. As the subject says, this method is no more secure than plain md5. If there are collisions in md5, then your method will also produce collisions. Even worse; if there were collisions in sha1 of input strings of 16 bytes (combinatorically this is far more likely than not), then your method will have worse security than md5.

Josiah Carlson 15 years, 4 months ago  # | flag

I suppose I should add that MD5 is effectively broken (one can generate collisions in seconds on a modern machine), so this "secure" scheme is actually quite insecure.

Created by J.Riddle.x on Sat, 8 Apr 2006 (PSF)
Python recipes (4591)
J.Riddle.x's recipes (1)

Required Modules

Other Information and Tasks