56
52
def parse(self, encrypted_value):
57
53
"""Read encrypted data from the <EncryptedValue> XML tree."""
58
from pskc.parse import g_e_v, namespaces
54
from pskc.parse import find, findbin
59
55
if encrypted_value is None:
61
encryption_method = encrypted_value.find(
62
'xenc:EncryptionMethod', namespaces=namespaces)
63
self.algorithm = encryption_method.attrib.get('Algorithm')
64
value = g_e_v(encrypted_value, 'xenc:CipherData/xenc:CipherValue')
66
self.cipher_value = base64.b64decode(value)
57
encryption_method = find(encrypted_value, 'xenc:EncryptionMethod')
58
if encryption_method is not None:
59
self.algorithm = encryption_method.attrib.get('Algorithm')
60
self.cipher_value = findbin(
61
encrypted_value, 'xenc:CipherData/xenc:CipherValue')
69
64
"""Decrypt the linked value and return the plaintext value."""
65
from pskc.exceptions import DecryptionError
66
if self.cipher_value is None:
70
68
key = self.encryption.key
71
ciphertext = self.cipher_value
72
if key is None or ciphertext is None:
74
if self.algorithm == AES128_CBC:
75
iv = ciphertext[:AES.block_size]
70
raise DecryptionError('No key available')
71
if self.algorithm is None:
72
raise DecryptionError('No algorithm specified')
73
if self.algorithm.endswith('#aes128-cbc') or \
74
self.algorithm.endswith('#aes192-cbc') or \
75
self.algorithm.endswith('#aes256-cbc'):
76
from Crypto.Cipher import AES
77
if len(key) * 8 != int(self.algorithm[-7:-4]) or \
78
len(key) not in AES.key_size:
79
raise DecryptionError('Invalid key length')
80
iv = self.cipher_value[:AES.block_size]
81
ciphertext = self.cipher_value[AES.block_size:]
76
82
cipher = AES.new(key, AES.MODE_CBC, iv)
77
plaintext = cipher.decrypt(ciphertext[AES.block_size:])
78
return plaintext[0:-ord(plaintext[-1])]
82
'http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5#pbkdf2',
83
'http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5v2-0#pbkdf2',
84
'http://www.w3.org/2009/xmlenc11#pbkdf2',
83
return unpad(cipher.decrypt(ciphertext))
84
elif self.algorithm.endswith('#tripledes-cbc'):
85
from Crypto.Cipher import DES3
86
if len(key) not in DES3.key_size:
87
raise DecryptionError('Invalid key length')
88
iv = self.cipher_value[:DES3.block_size]
89
ciphertext = self.cipher_value[DES3.block_size:]
90
cipher = DES3.new(key, DES3.MODE_CBC, iv)
91
return unpad(cipher.decrypt(ciphertext))
92
elif self.algorithm.endswith('#kw-aes128') or \
93
self.algorithm.endswith('#kw-aes192') or \
94
self.algorithm.endswith('#kw-aes256'):
95
from pskc.aeskw import unwrap
96
from Crypto.Cipher import AES
97
if len(key) * 8 != int(self.algorithm[-3:]) or \
98
len(key) not in AES.key_size:
99
raise DecryptionError('Invalid key length')
100
return unwrap(self.cipher_value, key)
101
elif self.algorithm.endswith('#kw-tripledes'):
102
from pskc.tripledeskw import unwrap
103
from Crypto.Cipher import DES3
104
if len(key) not in DES3.key_size:
105
raise DecryptionError('Invalid key length')
106
return unwrap(self.cipher_value, key)
108
raise DecryptionError('Unsupported algorithm: %r' % self.algorithm)
88
111
class KeyDerivation(object):
109
132
def parse(self, key_deriviation):
110
133
"""Read derivation parameters from a <KeyDerivationMethod> element."""
111
from pskc.parse import g_e_v, g_e_i, namespaces
134
from pskc.parse import find, findint, findbin
112
135
if key_deriviation is None:
114
self.algorithm = key_deriviation.attrib.get('Algorithm')
137
self.algorithm = key_deriviation.get('Algorithm')
115
138
# PBKDF2 properties
116
pbkdf2 = key_deriviation.find(
117
'xenc11:PBKDF2-params', namespaces=namespaces)
139
pbkdf2 = find(key_deriviation, 'xenc11:PBKDF2-params')
118
140
if pbkdf2 is None:
119
pbkdf2 = key_deriviation.find(
120
'pkcs5:PBKDF2-params', namespaces=namespaces)
141
pbkdf2 = find(key_deriviation, 'pkcs5:PBKDF2-params')
121
142
if pbkdf2 is not None:
123
value = g_e_v(pbkdf2, 'Salt/Specified')
124
if value is not None:
125
self.pbkdf2_salt = base64.b64decode(value)
144
self.pbkdf2_salt = findbin(pbkdf2, 'Salt/Specified')
126
145
# required number of iterations
127
self.pbkdf2_iterations = g_e_i(pbkdf2, 'IterationCount')
146
self.pbkdf2_iterations = findint(pbkdf2, 'IterationCount')
129
self.pbkdf2_key_length = g_e_i(pbkdf2, 'KeyLength')
148
self.pbkdf2_key_length = findint(pbkdf2, 'KeyLength')
130
149
# pseudorandom function used
131
prf = pbkdf2.find('PRF', namespaces=namespaces)
150
prf = find(pbkdf2, 'PRF')
132
151
if prf is not None:
133
self.pbkdf2_prf = prf.attrib.get('Algorithm')
152
self.pbkdf2_prf = prf.get('Algorithm')
135
def generate(self, password):
154
def derive(self, password):
136
155
"""Derive a key from the password."""
137
if self.algorithm in PBKDF2_URIS:
138
# TODO: support pseudorandom function (prf)
156
from pskc.exceptions import KeyDerivationError
157
if self.algorithm is None:
158
raise KeyDerivationError('No algorithm specified')
159
if self.algorithm.endswith('#pbkdf2'):
160
from Crypto.Protocol.KDF import PBKDF2
161
from pskc.mac import get_hmac
164
prf = get_hmac(self.pbkdf2_prf)
166
raise KeyDerivationError(
167
'Pseudorandom function unsupported: %r' %
140
170
password, self.pbkdf2_salt, dkLen=self.pbkdf2_key_length,
141
count=self.pbkdf2_iterations, prf=None)
171
count=self.pbkdf2_iterations, prf=prf)
173
raise KeyDerivationError(
174
'Unsupported algorithm: %r' % self.algorithm)
144
177
class Encryption(object):
167
200
def parse(self, key_info):
168
201
"""Read encryption information from the <EncryptionKey> XML tree."""
169
from pskc.parse import g_e_v, namespaces
202
from pskc.parse import find, findall, findtext
170
203
if key_info is None:
172
self.id = key_info.attrib.get('Id')
173
for name in key_info.findall('ds:KeyName', namespaces=namespaces):
174
self.key_names.append(g_e_v(name, '.'))
175
for name in key_info.findall(
176
'xenc11:DerivedKey/xenc11:MasterKeyName',
177
namespaces=namespaces):
178
self.key_names.append(g_e_v(name, '.'))
179
self.derivation.parse(key_info.find(
180
'xenc11:DerivedKey/xenc11:KeyDerivationMethod',
181
namespaces=namespaces))
205
self.id = key_info.get('Id')
206
for name in findall(key_info, 'ds:KeyName'):
207
self.key_names.append(findtext(name, '.'))
209
key_info, 'xenc11:DerivedKey/xenc11:MasterKeyName'):
210
self.key_names.append(findtext(name, '.'))
211
self.derivation.parse(find(
212
key_info, 'xenc11:DerivedKey/xenc11:KeyDerivationMethod'))
184
215
def key_name(self):