[Seminarthemen WS08/09] [ < ] [ > ] [Übersicht]


A Kerberos String to Key Function in Python

StringToKey.py:

 
1#!/usr/bin/env python2.5 
2#Copyright (C) 1998 by the FundsXpress, INC. 
3# 
4#All rights reserved. 
5# 
6#Export of this software from the United States of America may require 
7#a specific license from the United States Government.  It is the 
8#responsibility of any person or organization contemplating export to 
9#obtain such a license before exporting. 
10# 
11#WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 
12#distribute this software and its documentation for any purpose and 
13#without fee is hereby granted, provided that the above copyright 
14#notice appear in all copies and that both that copyright notice and 
15#this permission notice appear in supporting documentation, and that 
16#the name of FundsXpress. not be used in advertising or publicity pertaining 
17#to distribution of the software without specific, written prior 
18#permission.  FundsXpress makes no representations about the suitability of 
19#this software for any purpose.  It is provided ~as is~ without express 
20#or implied warranty. 
21# 
22#THIS SOFTWARE IS PROVIDED ‘‘AS IS AND WITHOUT ANY EXPRESS OR 
23#IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
24#WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
25# 
26#Python port from MIT Kerberos lib/crypto/dk/stringtokey.c by Stefan Roggensack 
27 
28from nfold import krb5_nfold 
29from des3 import k5_des3_make_key 
30from derive import krb5_derive_key 
31 
32from array import array 
33from exceptions import Exception 
34 
35def krb5int_dk_string_to_key(password, salt, params): 
36    # construct input string ( = string + salt), fold it, make_key it 
37    if (params != ~~): 
38        raise Exception, ~invalid params~ 
39    keybytes = 21 
40    keylength = 24 
41 
42    foldkey = k5_des3_make_key(krb5_nfold(password + salt, keybytes) 
43                               , keylength) 
44    # now derive the key from this one 
45    key = krb5_derive_key(foldkey,kerberos) 
46    return key

nfold.py:

 
1#!/usr/bin/env python2.5 
2#Copyright (C) 1998 by the FundsXpress, INC. 
3# 
4#All rights reserved. 
5# 
6#Export of this software from the United States of America may require 
7#a specific license from the United States Government.  It is the 
8#responsibility of any person or organization contemplating export to 
9#obtain such a license before exporting. 
10# 
11#WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 
12#distribute this software and its documentation for any purpose and 
13#without fee is hereby granted, provided that the above copyright 
14#notice appear in all copies and that both that copyright notice and 
15#this permission notice appear in supporting documentation, and that 
16#the name of FundsXpress. not be used in advertising or publicity pertaining 
17#to distribution of the software without specific, written prior 
18#permission.  FundsXpress makes no representations about the suitability of 
19#this software for any purpose.  It is provided ~as is~ without express 
20#or implied warranty. 
21# 
22#THIS SOFTWARE IS PROVIDED ‘‘AS IS AND WITHOUT ANY EXPRESS OR 
23#IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
24#WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
25# 
26#Python port from MIT Kerberos lib/crypto/nfold.c by Stefan Roggensack 
27 
28from array import array 
29 
30def leastCommonMultiple(a,b): 
31    ~~~ 
32    Compute the Least Common Multiple (lcm) of two numbers. 
33    Using the euclidean algorithm 
34    ~~~ 
35    temp = a*b 
36    while(b != 0): 
37        c = b 
38        b = a%b 
39        a = c 
40    return temp/a 
41 
42def krb5_nfold(password, outlength): 
43    ~~~ 
44    n-fold(k-bits): 
45    l = lcm(n,k) 
46    r = l/k 
47    s = k-bits | k-bits rot 13 | k-bits rot 13*2 | ... | k-bits rot 13*(r-1) 
48    compute the 1’s complement sum: 
49    n-fold = s[0..n-1]+s[n..2n-1]+s[2n..3n-1]+..+s[(k-1)*n..k*n-1] 
50    ~~~ 
51 
52    if isinstance(password, str): 
53        # Use a Array of ordinal Numbers (this should only be lower then 256) 
54        password = array(B, map(ord, password)) 
55    inlength = len(password) 
56 
57    # first compute lcm(n,k) 
58    lcm = leastCommonMultiple(inlength,outlength) 
59    # now do the real work 
60 
61    byte = 0 
62    out = array(B, chr(0)*outlength) 
63 
64    # this will end up cycling through k lcm(k,n)/k times, which 
65    #   is correct 
66    for i in xrange(lcm-1,-1,-1): 
67        #compute the msbit in k which gets added into this byte 
68        msbit = (#first, start with the msbit in the first, unrotated byte 
69                ((inlength<<3)-1) 
70                # then, for each byte, shift to the right for each repetition 
71                + (((inlength<<3)+13)*(i/inlength)) 
72                # last, pick out the correct byte within that shifted repetition 
73                +((inlength-(i%inlength))<<3) 
74                )%(inlength<<3) 
75        # pull out the byte value itself 
76        byte += (((password[((inlength-1)-(msbit>>3))%inlength]<<8)| 
77                  (password[((inlength)-(msbit>>3))%inlength])) 
78                  >>((msbit&7)+1))&0xff 
79 
80        # do the addition 
81        byte += out[i%outlength] 
82        out[i%outlength] = byte&0xff 
83 
84        # keep around the carry bit, if any 
85        byte >>= 8 
86 
87    # if theres a carry bit left over, add it back in 
88    if byte != 0: 
89        for i in xrange(outlength-1,0,-1): 
90            # do the addition 
91            byte += out[i] 
92            out[i] = byte&0xff 
93 
94            #  keep around the carry bit, if any 
95            byte >>= 8 
96    return out.tostring()

des3.py:

 
1#!/usr/bin/env python2.5 
2#Copyright (C) 1998 by the FundsXpress, INC. 
3# 
4#All rights reserved. 
5# 
6#Export of this software from the United States of America may require 
7#a specific license from the United States Government.  It is the 
8#responsibility of any person or organization contemplating export to 
9#obtain such a license before exporting. 
10# 
11#WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 
12#distribute this software and its documentation for any purpose and 
13#without fee is hereby granted, provided that the above copyright 
14#notice appear in all copies and that both that copyright notice and 
15#this permission notice appear in supporting documentation, and that 
16#the name of FundsXpress. not be used in advertising or publicity pertaining 
17#to distribution of the software without specific, written prior 
18#permission.  FundsXpress makes no representations about the suitability of 
19#this software for any purpose.  It is provided ~as is~ without express 
20#or implied warranty. 
21# 
22#THIS SOFTWARE IS PROVIDED ‘‘AS IS AND WITHOUT ANY EXPRESS OR 
23#IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
24#WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
25# 
26#Python port from MIT Kerberos lib/crypto/enc_provider/des3.c by Stefan Roggensack 
27 
28from array import array 
29from exceptions import Exception 
30from ncrypt.cipher import EncryptCipher, DecryptCipher, CipherType 
31 
32from f_parity import mit_des_fixup_key_parity 
33 
34def k5_des3_make_key(random, keylength): 
35    if (keylength != 24): 
36        raise Exception, KRB5_BAD_KEYSIZE 
37    if (len(random) != 21): 
38        raise Exception, KRB5_CRYPTO_INTERNAL 
39    key = array(B, [0]*keylength) 
40    if isinstance(random, str): 
41        # Use a Array of ordinal Numbers (this should only be lower then 256) 
42        random = array(B, map(ord, random)) 
43    # take the seven bytes, move them around into the top 7 bits of the 
44    # 8 key bytes, then compute the parity bits.  Do this three times. 
45    for i in xrange(0,3): 
46        key[i*8:i*8+7] = random[i*7:i*7+7] 
47        key[i*8+7] = (((key[i*8]&1)<<1) | 
48                      ((key[i*8+1]&1)<<2) | 
49                      ((key[i*8+2]&1)<<3) | 
50                      ((key[i*8+3]&1)<<4) | 
51                      ((key[i*8+4]&1)<<5) | 
52                      ((key[i*8+5]&1)<<6) | 
53                      ((key[i*8+6]&1)<<7)) 
54        mit_des_fixup_key_parity(key) 
55    return key.tostring() 
56 
57def encrypt(key, iv, plain_text): 
58    cipherType = CipherType(DES-EDE3, CBC) 
59    enc = EncryptCipher(cipherType, key, iv) 
60    cipher_text = enc.finish(plain_text) 
61    return cipher_text

derive.py:

 
1#!/usr/bin/env python2.5 
2#Copyright (C) 1998 by the FundsXpress, INC. 
3# 
4#All rights reserved. 
5# 
6#Export of this software from the United States of America may require 
7#a specific license from the United States Government.  It is the 
8#responsibility of any person or organization contemplating export to 
9#obtain such a license before exporting. 
10# 
11#WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 
12#distribute this software and its documentation for any purpose and 
13#without fee is hereby granted, provided that the above copyright 
14#notice appear in all copies and that both that copyright notice and 
15#this permission notice appear in supporting documentation, and that 
16#the name of FundsXpress. not be used in advertising or publicity pertaining 
17#to distribution of the software without specific, written prior 
18#permission.  FundsXpress makes no representations about the suitability of 
19#this software for any purpose.  It is provided ~as is~ without express 
20#or implied warranty. 
21# 
22#THIS SOFTWARE IS PROVIDED ‘‘AS IS AND WITHOUT ANY EXPRESS OR 
23#IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
24#WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
25# 
26#Python port from MIT Kerberos lib/crypto/enc_provider/des3.c by Stefan Roggensack 
27 
28from array import array 
29from exceptions import Exception 
30 
31from nfold import krb5_nfold 
32from des3 import encrypt, k5_des3_make_key 
33 
34def krb5_derive_key(inkey, in_constant): 
35    blocksize = 8 
36    keybytes = 21 
37    keylength = 24 
38    rawkey = array(B) 
39 
40    if len(inkey) != keylength: 
41        raise Exception, KRB5_CRYPTO_INTERNAL 
42 
43    # initialize the input block 
44    out = in_constant if (len(in_constant) == blocksize) else krb5_nfold(in_constant, blocksize) 
45 
46    # loop encrypting the blocks until enough key bytes are generated 
47    for n in xrange(0,keybytes,blocksize): 
48        out = encrypt(inkey, chr(0)*8, out)[:blocksize] 
49 
50        if ((keybytes - n) <= 8): 
51            rawkey.fromstring(out[:keybytes - n]) 
52        else: 
53            rawkey.fromstring(out) 
54 
55    # postprocess the key 
56    return k5_des3_make_key(rawkey, keylength)

fparity.py:

 
1#!/usr/bin/env python2.5 
2#These routines check and fix parity of encryption keys for the DES 
3#algorithm. 
4# 
5#They are a replacement for routines in key_parity.c, that dont require 
6#the table building that they do. 
7#Mark Eichin -- Cygnus Support 
8# 
9#Python port from MIT Kerberos lib/crypto/des/f_parity.c by Stefan Roggensack 
10 
11def mit_des_fixup_key_parity(key): 
12    ~~~ 
13    des_fixup_key_parity: Forces odd parity per byte; parity is bits 
14    8,16,...64 in des order, implies 0, 8, 16, ... vax order. 
15    ~~~ 
16    for i in xrange(0,len(key)): 
17        key[i] &= 0xfe 
18        key[i] |= 1^pstep(pstep(pstep((key[i]),4),2),1) 
19 
20    return key 
21def parity_char(x): 
22    return pstep(pstep(pstep((x),4),2),1) 
23def pstep(x,step): 
24    return (((x)&smask(step))^(((x)>>step)&smask(step))) 
25def smask(step): 
26    return ((1<<step)-1)

nfoldtests.py:

 
1#!/usr/bin/env python2.5 
2from nfold import krb5_nfold 
3import binascii 
4import unittest 
5 
6class rfc3961_nfold(unittest.TestCase): 
7    def test1(self): 
8    #      64-fold(~012345~) = 
9    #      64-fold(303132333435) = be072631276b1955 
10        self.assertEqual(krb5_nfold(unicode.encode(u012345), 64/8), binascii.unhexlify(be072631276b1955)) 
11 
12    def test2(self): 
13    #      56-fold(~password~) = 
14    #      56-fold(70617373776f7264) = 78a07b6caf85fa 
15        self.assertEqual(krb5_nfold(unicode.encode(upassword), 56/8), binascii.unhexlify(78a07b6caf85fa)) 
16 
17    def test3(self): 
18    #      64-fold(~Rough Consensus, and Running Code~) = 
19    #      64-fold(526f75676820436f6e73656e7375732c20616e642052756e 
20    #              6e696e6720436f6465) = bb6ed30870b7f0e0 
21        self.assertEqual(krb5_nfold(unicode.encode(uRough Consensus, and Running Code), 64/8), binascii.unhexlify(bb6ed30870b7f0e0)) 
22 
23    def test4(self): 
24    #      168-fold(~password~) = 
25    #      168-fold(70617373776f7264) = 
26    #               59e4a8ca7c0385c3c37b3f6d2000247cb6e6bd5b3e 
27        self.assertEqual(krb5_nfold(unicode.encode(upassword), 168/8), binascii.unhexlify(59e4a8ca7c0385c3c37b3f6d2000247cb6e6bd5b3e)) 
28 
29    def test5(self): 
30    #      192-fold(~MASSACHVSETTS INSTITVTE OF TECHNOLOGY~) 
31    #      192-fold(4d41535341434856534554545320494e5354495456544520 
32    #               4f4620544543484e4f4c4f4759) = 
33    #               db3b0d8f0b061e603282b308a50841229ad798fab9540c1b 
34        self.assertEqual(krb5_nfold(unicode.encode(uMASSACHVSETTS INSTITVTE OF TECHNOLOGY), 192/8), binascii.unhexlify(db3b0d8f0b061e603282b308a50841229ad798fab9540c1b)) 
35 
36    def test6(self): 
37    #      168-fold(~Q~) = 
38    #      168-fold(51) = 
39    #               518a54a2 15a8452a 518a54a2 15a8452a 
40    #               518a54a2 15 
41        self.assertEqual(krb5_nfold(unicode.encode(uQ), 168/8), binascii.unhexlify(518a54a215a8452a518a54a215a8452a518a54a215)) 
42 
43    def test7(self): 
44    #      168-fold(~ba~) = 
45    #      168-fold(6261) = 
46    #               fb25d531 ae897449 9f52fd92 ea9857c4 
47    #               ba24cf29 7e 
48        self.assertEqual(krb5_nfold(unicode.encode(uba), 168/8), binascii.unhexlify(fb25d531ae8974499f52fd92ea9857c4ba24cf297e)) 
49 
50    def test8(self): 
51    #      64-fold(~kerberos~) = 
52    #               6b657262 65726f73 
53        self.assertEqual(krb5_nfold(unicode.encode(ukerberos), 64/8), binascii.unhexlify(6b65726265726f73)) 
54 
55    def test9(self): 
56    #      128-fold(~kerberos~) = 
57    #               6b657262 65726f73 7b9b5b2b 93132b93 
58        self.assertEqual(krb5_nfold(unicode.encode(ukerberos), 128/8), binascii.unhexlify(6b65726265726f737b9b5b2b93132b93)) 
59 
60    def test10(self): 
61    #      168-fold(~kerberos~) = 
62    #               8372c236 344e5f15 50cd0747 e15d62ca 
63    #               7a5a3bce a4 
64        self.assertEqual(krb5_nfold(unicode.encode(ukerberos), 168/8), binascii.unhexlify(8372c236344e5f1550cd0747e15d62ca7a5a3bcea4)) 
65 
66    def test11(self): 
67    #      256-fold(~kerberos~) = 
68    #               6b657262 65726f73 7b9b5b2b 93132b93 
69    #               5c9bdcda d95c9899 c4cae4de e6d6cae4 
70        self.assertEqual(krb5_nfold(unicode.encode(ukerberos), 256/8), binascii.unhexlify(6b65726265726f737b9b5b2b93132b935c9bdcdad95c9899c4cae4dee6d6cae4)) 
71 
72 
73if __name__==~__main__~: 
74    unittest.main()

StringToKeyTests.py:

 
1#!/usr/bin/env python2.5 
2import unittest 
3import binascii 
4from StringToKey import krb5int_dk_string_to_key, krb5_derive_key 
5 
6class rfc3961_StringToKey(unittest.TestCase): 
7    # A.4.  DES3string_to_key 
8    def test1(self): 
9        salt=   ~ATHENA.MIT.EDUraeburn~ 
10        passwd= ~password~ 
11        key=    ~850bb51358548cd05e86768c313e3bfef7511937dcf72c3e~ 
12        self.assertEqual(krb5int_dk_string_to_key(passwd,salt,), 
13                         binascii.unhexlify(key)) 
14    def test2(self): 
15        salt=   ~WHITEHOUSE.GOVdanny~ 
16        passwd= ~potatoe~ 
17        key=    ~dfcd233dd0a43204ea6dc437fb15e061b02979c1f74f377a~ 
18        self.assertEqual(krb5int_dk_string_to_key(passwd,salt,), 
19                         binascii.unhexlify(key)) 
20    def test3(self): 
21        salt=   ~EXAMPLE.COMbuckaroo~ 
22        passwd= ~penny~ 
23        key=    ~6d2fcdf2d6fbbc3ddcadb5da5710a23489b0d3b69d5d9d4a~ 
24        self.assertEqual(krb5int_dk_string_to_key(passwd,salt,), 
25                         binascii.unhexlify(key)) 
26    def test4(self): 
27        salt=   u~ATHENA.MIT.EDUJuri\u0161i\u0107~.encode(utf8) 
28        passwd= u~\u00DF~.encode(utf8) 
29        key=    ~16d5a40e1ce3bacb61b9dce00470324c831973a7b952feb0~ 
30        self.assertEqual(krb5int_dk_string_to_key(passwd,salt,), 
31                         binascii.unhexlify(key)) 
32    def test5(self): 
33        salt=   ~EXAMPLE.COMpianist~.encode(utf8) 
34        passwd= u~\uD834\uDD1E~.encode(utf8) 
35        key=    ~85763726585dbc1cce6ec43e1f751f07f1c4cbb098f40b19~ 
36        self.assertEqual(krb5int_dk_string_to_key(passwd,salt,), 
37                         binascii.unhexlify(key)) 
38 
39    # A.3.  DES3 DR and DK 
40    def test6(self): 
41        key=                 ~dce06b1f64c857a11c3db57c51899b2cc1791008ce973b92~ 
42        usage=               ~0000000155~ 
43        DR=                  ~935079d14490a75c3093c4a6e8c3b049c71e6ee705~ 
44        DK=                  ~925179d04591a79b5d3192c4a7e9c289b049c71f6ee604cd~ 
45 
46        self.assertEqual(krb5_derive_key(binascii.unhexlify(key), binascii.unhexlify(usage)), 
47                         binascii.unhexlify(DK)) 
48 
49    def test7(self): 
50        key=                 ~5e13d31c70ef765746578531cb51c15bf11ca82c97cee9f2~ 
51        usage=               ~00000001aa~ 
52        DR=                  ~9f58e5a047d894101c469845d67ae3c5249ed812f2~ 
53        DK=                  ~9e58e5a146d9942a101c469845d67a20e3c4259ed913f207~ 
54 
55        self.assertEqual(krb5_derive_key(binascii.unhexlify(key), binascii.unhexlify(usage)), 
56                         binascii.unhexlify(DK)) 
57 
58    def test8(self): 
59        key=                 ~98e6fd8a04a4b6859b75a176540b9752bad3ecd610a252bc~ 
60        usage=               ~0000000155~ 
61        DR=                  ~12fff90c773f956d13fc2ca0d0840349dbd39908eb~ 
62        DK=                  ~13fef80d763e94ec6d13fd2ca1d085070249dad39808eabf~ 
63        self.assertEqual(krb5_derive_key(binascii.unhexlify(key), binascii.unhexlify(usage)), 
64                         binascii.unhexlify(DK)) 
65 
66    def test9(self): 
67        key=                 ~622aec25a2fe2cad7094680b7c64940280084c1a7cec92b5~ 
68        usage=               ~00000001aa~ 
69        DR=                  ~f8debf05b097e7dc0603686aca35d91fd9a5516a70~ 
70        DK=                  ~f8dfbf04b097e6d9dc0702686bcb3489d91fd9a4516b703e~ 
71 
72        self.assertEqual(krb5_derive_key(binascii.unhexlify(key), binascii.unhexlify(usage)), 
73                         binascii.unhexlify(DK)) 
74 
75    def test10(self): 
76        key=                 ~d3f8298ccb166438dcb9b93ee5a7629286a491f838f802fb~ 
77        usage=               ~6b65726265726f73~ 
78        DR=                  ~2270db565d2a3d64cfbfdc5305d4f778a6de42d9da~ 
79        DK=                  ~2370da575d2a3da864cebfdc5204d56df779a7df43d9da43~ 
80 
81        self.assertEqual(krb5_derive_key(binascii.unhexlify(key), binascii.unhexlify(usage)), 
82                         binascii.unhexlify(DK)) 
83 
84    def test11(self): 
85        key=                 ~c1081649ada74362e6a1459d01dfd30d67c2234c940704da~ 
86        usage=               ~0000000155~ 
87        DR=                  ~348056ec98fcc517171d2b4d7a9493af482d999175~ 
88        DK=                  ~348057ec98fdc48016161c2a4c7a943e92ae492c989175f7~ 
89 
90        self.assertEqual(krb5_derive_key(binascii.unhexlify(key), binascii.unhexlify(usage)), 
91                         binascii.unhexlify(DK)) 
92 
93    def test12(self): 
94        key=                 ~5d154af238f46713155719d55e2f1f790dd661f279a7917c~ 
95        usage=               ~00000001aa~ 
96        DR=                  ~a8818bc367dadacbe9a6c84627fb60c294b01215e5~ 
97        DK=                  ~a8808ac267dada3dcbe9a7c84626fbc761c294b01315e5c1~ 
98 
99        self.assertEqual(krb5_derive_key(binascii.unhexlify(key), binascii.unhexlify(usage)), 
100                         binascii.unhexlify(DK)) 
101 
102    def test13(self): 
103        key=                 ~798562e049852f57dc8c343ba17f2ca1d97394efc8adc443~ 
104        usage=               ~0000000155~ 
105        DR=                  ~c813f88b3be2b2f75424ce9175fbc8483b88c8713a~ 
106        DK=                  ~c813f88a3be3b334f75425ce9175fbe3c8493b89c8703b49~ 
107 
108        self.assertEqual(krb5_derive_key(binascii.unhexlify(key), binascii.unhexlify(usage)), 
109                         binascii.unhexlify(DK)) 
110 
111    def test14(self): 
112        key=                 ~26dce334b545292f2feab9a8701a89a4b99eb9942cecd016~ 
113        usage=               ~00000001aa~ 
114        DR=                  ~f58efc6f83f93e55e695fd252cf8fe59f7d5ba37ec~ 
115        DK=                  ~f48ffd6e83f83e7354e694fd252cf83bfe58f7d5ba37ec5d~ 
116 
117        self.assertEqual(krb5_derive_key(binascii.unhexlify(key), binascii.unhexlify(usage)), 
118                         binascii.unhexlify(DK)) 
119 
120if __name__==~__main__~: 
121    unittest.main()

Tests.py:

 
1import unittest 
2 
3from StringToKeyTests import rfc3961_StringToKey 
4from nfoldtests import rfc3961_nfold 
5 
6suite1 = unittest.makeSuite(rfc3961_StringToKey,test) 
7suite2 = unittest.makeSuite(rfc3961_nfold,test) 
8alltests = unittest.TestSuite((suite1, suite2)) 
9unittest.main()

[Seminarthemen WS08/09] [ < ] [ > ] [Übersicht]