-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathhsub.py
More file actions
84 lines (75 loc) · 3.06 KB
/
hsub.py
File metadata and controls
84 lines (75 loc) · 3.06 KB
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
79
80
81
82
83
#!/usr/bin/python
#
# vim: tabstop=4 expandtab shiftwidth=4 autoindent
#
# Copyright (C) 2010 Steve Crook
#
# 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, 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 MERCHANTIBILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
from hashlib import sha256
from os import urandom
HSUBLEN = 48
def hash(text, iv = None, hsublen = HSUBLEN):
"""Create an hSub (Hashed Subject). This is constructed as:
--------------------------------------
| 64bit iv | 256bit SHA2 'iv + text' |
--------------------------------------"""
# Generate a 64bit random IV if none is provided.
if iv is None: iv = cryptorandom()
# Concatenate our IV with a SHA256 hash of text + IV.
hsub = iv + sha256(iv + text).digest()
return hsub.encode('hex')[:hsublen]
def check(text, hsub):
"""Create an hSub using a known iv, (stripped from a passed hSub). If
the supplied and generated hSub's collide, the message is probably for
us."""
# We are prepared to check variable length hsubs within boundaries.
# The low bound is the current Type-I esub length. The high bound
# is the 256 bits within SHA2-256.
hsublen = len(hsub)
# 48 digits = 192 bit hsub, the smallest we allow.
# 80 digits = 320 bit hsub, the full length of SHA256 + 64 bit IV
if hsublen < 48 or hsublen > 80: return False
iv = hexiv(hsub)
if not iv: return False
# Return True if our generated hSub collides with the supplied
# sample.
return hash(text, iv, hsublen) == hsub
def cryptorandom(bytes = 8):
"""Return a string of random bytes. By default we return the default
IV length (64bits)."""
return urandom(bytes)
def hexiv(hsub, digits = 16):
"""Return the decoded IV from an hsub. By default the IV is the first
64bits of the hsub. As it's hex encoded, this equates to 16 digits."""
# We don't want to process IVs of inadequate length.
if len(hsub) < digits: return False
try:
iv = hsub[:digits].decode('hex')
except TypeError:
# Not all Subjects are hSub'd so just bail out if it's non-hex.
return False
return iv
def main():
"""Only used for testing purposes. We Generate an hSub and then check it
using the same input text."""
passphrase = "91c5dc4d604c9dee4a4074bbaef4f0fe94d92f406da5aee04d414400dd6d9f42"
# hsub = hash(passphrase)
hsub = '0b07815eac0b4631e8814855af5bf9f5c691f36ddd47c7b4'
iv = hexiv(hsub)
print "Passphrase: " + passphrase
print "IV: %s" % iv.encode('hex')
print "hsub: " + hsub
print "hsub length: %d bytes" % len(hsub)
print "Should return True: %s" % check(passphrase, hsub)
print "Should return False: %s" % check('false', hsub)
# Call main function.
if (__name__ == "__main__"):
main()