Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 118 lines (88 sloc) 3.386 kB
767facb @lirazsiri cleanup whitespace
lirazsiri authored
1 #
8be343d @lirazsiri updated copyright year to 2013
lirazsiri authored
2 # Copyright (c) 2010-2013 Liraz Siri <liraz@turnkeylinux.org>
767facb @lirazsiri cleanup whitespace
lirazsiri authored
3 #
32b1e9e @lirazsiri TurnKey Linux => TurnKey GNU/Linux
lirazsiri authored
4 # This file is part of TKLBAM (TurnKey GNU/Linux BAckup and Migration).
767facb @lirazsiri cleanup whitespace
lirazsiri authored
5 #
e34925a @lirazsiri free software => open source software
lirazsiri authored
6 # TKLBAM is open source software; you can redistribute it and/or
0c11ee9 @lirazsiri added copyright notices to everything
lirazsiri authored
7 # modify it under the terms of the GNU General Public License as
8 # published by the Free Software Foundation; either version 3 of
9 # the License, or (at your option) any later version.
767facb @lirazsiri cleanup whitespace
lirazsiri authored
10 #
2ca97b9 @lirazsiri first implementation of key encryption
lirazsiri authored
11 import os
12 import hashlib
55d3ee0 @lirazsiri key API refactoring + store the secret as a null encrypted key
lirazsiri authored
13 import base64
e5e7400 @lirazsiri add computation complexity to encrypt/decrypt itself
lirazsiri authored
14 import struct
2ca97b9 @lirazsiri first implementation of key encryption
lirazsiri authored
15
16 from Crypto.Cipher import AES
b141a4a @lirazsiri increase x100,000 the computational cost of calculating a cipher key
lirazsiri authored
17
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
18 KEY_VERSION = 1
e5e7400 @lirazsiri add computation complexity to encrypt/decrypt itself
lirazsiri authored
19
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
20 SALT_LEN = 4
21 KILO_REPEATS_HASH = 80
22 KILO_REPEATS_CIPHER = 80
2ca97b9 @lirazsiri first implementation of key encryption
lirazsiri authored
23
682efd6 @lirazsiri increased fingerprint from 32-bits to 48-bits and refactored
lirazsiri authored
24 FINGERPRINT_LEN = 6
25
2ca97b9 @lirazsiri first implementation of key encryption
lirazsiri authored
26 class Error(Exception):
27 pass
28
e5e7400 @lirazsiri add computation complexity to encrypt/decrypt itself
lirazsiri authored
29 def _pad(s):
30 padded_len = ((len(s) + 2 - 1) | 0xF) + 1
31 padding_len = padded_len - len(s) - 2
32 return os.urandom(padding_len) + s + struct.pack("!H", len(s))
33
34 def _unpad(padded):
35 len, = struct.unpack("!H", padded[-2:])
36 return padded[-(2 + len) :-2]
37
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
38 def _repeat(f, input, count):
e5e7400 @lirazsiri add computation complexity to encrypt/decrypt itself
lirazsiri authored
39 for x in xrange(count):
40 input = f(input)
41 return input
42
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
43 def _cipher_key(passphrase, repeats):
767facb @lirazsiri cleanup whitespace
lirazsiri authored
44 cipher_key = _repeat(lambda k: hashlib.sha256(k).digest(),
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
45 passphrase, repeats)
b141a4a @lirazsiri increase x100,000 the computational cost of calculating a cipher key
lirazsiri authored
46 return cipher_key
47
022ffee @lirazsiri use AES.MODE_CBC instead of the less secure AES.MODE_OFB
lirazsiri authored
48 def _cipher(cipher_key):
f95e31e @lirazsiri keypacket: set a null-IV explicitly when initializing the AES cipher
lirazsiri authored
49 return AES.new(cipher_key, mode=AES.MODE_CBC, IV='\0' * 16)
2ca97b9 @lirazsiri first implementation of key encryption
lirazsiri authored
50
55d3ee0 @lirazsiri key API refactoring + store the secret as a null encrypted key
lirazsiri authored
51 def fmt(secret, passphrase):
2ca97b9 @lirazsiri first implementation of key encryption
lirazsiri authored
52 salt = os.urandom(SALT_LEN)
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
53
54 if not passphrase:
55 hash_repeats = cipher_repeats = 1
56 else:
57 hash_repeats = KILO_REPEATS_HASH * 1000 + 1
58 cipher_repeats = KILO_REPEATS_CIPHER * 1000 + 1
59
60 cipher_key = _cipher_key(passphrase, hash_repeats)
e5e7400 @lirazsiri add computation complexity to encrypt/decrypt itself
lirazsiri authored
61 plaintext = salt + hashlib.sha1(secret).digest() + secret
022ffee @lirazsiri use AES.MODE_CBC instead of the less secure AES.MODE_OFB
lirazsiri authored
62
767facb @lirazsiri cleanup whitespace
lirazsiri authored
63 ciphertext = _repeat(lambda v: _cipher(cipher_key).encrypt(v),
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
64 _pad(plaintext), cipher_repeats)
65
682efd6 @lirazsiri increased fingerprint from 32-bits to 48-bits and refactored
lirazsiri authored
66 fingerprint = hashlib.sha1(secret).digest()[:FINGERPRINT_LEN]
767facb @lirazsiri cleanup whitespace
lirazsiri authored
67 packet = struct.pack("!BHH", KEY_VERSION,
68 hash_repeats / 1000,
78b272c @lirazsiri added fingerprint of secret to keypacket
lirazsiri authored
69 cipher_repeats / 1000) + fingerprint + ciphertext
e5e7400 @lirazsiri add computation complexity to encrypt/decrypt itself
lirazsiri authored
70
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
71 return base64.b64encode(packet)
2ca97b9 @lirazsiri first implementation of key encryption
lirazsiri authored
72
406ff8d @lirazsiri refactored raw keypacket parsing out of parse() to _parse()
lirazsiri authored
73 def _parse(packet):
4849362 @lirazsiri more robust error handling in keypacket.parse
lirazsiri authored
74 try:
75 packet = base64.b64decode(packet)
76 version, khr, kcr = struct.unpack("!BHH", packet[:5])
77 except (TypeError, struct.error), e:
78 raise Error("can't parse key packet: " + str(e))
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
79
406ff8d @lirazsiri refactored raw keypacket parsing out of parse() to _parse()
lirazsiri authored
80 minimum_len = (5 + FINGERPRINT_LEN + 16)
81 if len(packet) < minimum_len:
82 raise Error("key packet length (%d) smaller than minimum (%d)" % (len(packet), minimum_len))
83
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
84 if version != KEY_VERSION:
85 raise Error("unknown key version (%d)" % version)
86
406ff8d @lirazsiri refactored raw keypacket parsing out of parse() to _parse()
lirazsiri authored
87 fingerprint = packet[5:5 + FINGERPRINT_LEN]
88 ciphertext = packet[5 + FINGERPRINT_LEN:]
89
90 return khr, kcr, fingerprint, ciphertext
91
92 def parse(packet, passphrase):
93 khr, kcr, fingerprint, ciphertext = _parse(packet)
94
f427a55 @lirazsiri keypacket optimization: if passphrase is "", hardwire 1 repeat
lirazsiri authored
95 if not passphrase:
96 hash_repeats = cipher_repeats = 1
97 else:
98 hash_repeats = khr * 1000 + 1
99 cipher_repeats = kcr * 1000 + 1
100
92647af @lirazsiri embed key version, and variable hash/cipher repeat parameters
lirazsiri authored
101 cipher_key = _cipher_key(passphrase, hash_repeats)
102 decrypted = _repeat(lambda v: _cipher(cipher_key).decrypt(v),
103 ciphertext,
104 cipher_repeats)
105
e5e7400 @lirazsiri add computation complexity to encrypt/decrypt itself
lirazsiri authored
106 decrypted = _unpad(decrypted)
107
2ca97b9 @lirazsiri first implementation of key encryption
lirazsiri authored
108 digest = decrypted[SALT_LEN:SALT_LEN+20]
55d3ee0 @lirazsiri key API refactoring + store the secret as a null encrypted key
lirazsiri authored
109 secret = decrypted[SALT_LEN+20:]
110
111 if digest != hashlib.sha1(secret).digest():
112 raise Error("error decrypting key")
2ca97b9 @lirazsiri first implementation of key encryption
lirazsiri authored
113
55d3ee0 @lirazsiri key API refactoring + store the secret as a null encrypted key
lirazsiri authored
114 return secret
78b272c @lirazsiri added fingerprint of secret to keypacket
lirazsiri authored
115
116 def fingerprint(packet):
406ff8d @lirazsiri refactored raw keypacket parsing out of parse() to _parse()
lirazsiri authored
117 return base64.b16encode(_parse(packet)[2])
Something went wrong with that request. Please try again.