forked from btimby/py-radius
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tests.py
75 lines (61 loc) · 2.94 KB
/
tests.py
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
import unittest
import radius
TEST_SECRET = 's3cr3t'
TEST_HOST = 'localhost'
TEST_PORT = 1812
class RadcryptTestCase(unittest.TestCase):
"""
On transmission, the password is hidden. The password is first
padded at the end with nulls to a multiple of 16 octets. A one-
way MD5 hash is calculated over a stream of octets consisting of
the shared secret followed by the Request Authenticator. This
value is XORed with the first 16 octet segment of the password and
placed in the first 16 octets of the String field of the User-
Password Attribute.
If the password is longer than 16 characters, a second one-way MD5
hash is calculated over a stream of octets consisting of the
shared secret followed by the result of the first xor. That hash
is XORed with the second 16 octet segment of the password and
placed in the second 16 octets of the String field of the User-
Password Attribute.
If necessary, this operation is repeated, with each xor result
being used along with the shared secret to generate the next hash
to xor the next segment of the password, to no more than 128
characters.
The method is taken from the book "Network Security" by Kaufman,
Perlman and Speciner [9] pages 109-110. A more precise
explanation of the method follows:
Call the shared secret S and the pseudo-random 128-bit Request
Authenticator RA. Break the password into 16-octet chunks p1, p2,
etc. with the last one padded at the end with nulls to a 16-octet
boundary. Call the ciphertext blocks c(1), c(2), etc. We'll need
intermediate values b1, b2, etc.
b1 = MD5(S + RA) c(1) = p1 xor b1
b2 = MD5(S + c(1)) c(2) = p2 xor b2
. .
. .
. .
bi = MD5(S + c(i-1)) c(i) = pi xor bi
The String will contain c(1)+c(2)+...+c(i) where + denotes
concatenation.
"""
def setUp(self):
self.authenticator = '\xa0\xdb7\xe2\x1f1\x18-op\xff>&A\xb0g'
def test_radcrypt_small(self):
'Test a password shorter than 16 octets.'
SMALL_PASS = 'I3Zl@"42Xs%^[nk'
SMALL_CRYPT = '\xdc\xf7V\x82\xeb\xa8Zm\x1b\x92\xb3\xa3\x06\x02\xbc\x16'
r = radius.RADIUS(TEST_SECRET, TEST_HOST, TEST_PORT)
c = r.radcrypt(self.authenticator, SMALL_PASS)
self.assertEqual(c, SMALL_CRYPT)
def test_radcrypt_large(self):
'Test a password longer than 16 octets.'
LARGE_PASS = '`0T8/Ub\tojdP;\rc:L}#_hOF'
LARGE_CRYPT = '\xf5\xf4X\xd6\x84\xdf\x0cV,\x8b\xf2\xadfa\xb4,S\xef\x0f\x908\xfcH\x9a\xe9r\xcc\xd0\x07\x84\xdc\x98'
r = radius.RADIUS(TEST_SECRET, TEST_HOST, TEST_PORT)
c = r.radcrypt(self.authenticator, LARGE_PASS)
self.assertEqual(c, LARGE_CRYPT)
def main():
unittest.main()
if __name__ == '__main__':
main()