Finish port to PyCA cryptography

* add missing default_backend
* unpad encrypted data
* use cryptography's hashes and HMAC construct
* remove hard dependency on python-nss from setup.py

Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
This commit is contained in:
Christian Heimes
2017-02-25 11:06:04 +01:00
committed by Martin Basti
parent d00ae870dd
commit 135d0b5dd1
3 changed files with 60 additions and 36 deletions

View File

@@ -20,20 +20,18 @@
import abc import abc
import base64 import base64
import datetime import datetime
import hashlib
import hmac
import os import os
import uuid import uuid
import struct
from lxml import etree from lxml import etree
import dateutil.parser import dateutil.parser
import dateutil.tz import dateutil.tz
import gssapi import gssapi
import six import six
from six.moves import xrange
from cryptography.hazmat.primitives import hashes from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.hazmat.primitives.padding import PKCS7
from cryptography.hazmat.primitives.kdf import pbkdf2 from cryptography.hazmat.primitives.kdf import pbkdf2
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
@@ -111,25 +109,32 @@ def convertHMACType(value):
"Converts HMAC URI to hashlib object." "Converts HMAC URI to hashlib object."
return { return {
"http://www.w3.org/2000/09/xmldsig#hmac-sha1": hashlib.sha1, "http://www.w3.org/2000/09/xmldsig#hmac-sha1": hashes.SHA1,
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha224": hashlib.sha224, "http://www.w3.org/2001/04/xmldsig-more#hmac-sha224": hashes.SHA224,
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256": hashlib.sha256, "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256": hashes.SHA256,
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha384": hashlib.sha384, "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384": hashes.SHA384,
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha512": hashlib.sha512, "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512": hashes.SHA512,
}.get(value.lower(), hashlib.sha1) }.get(value.lower(), hashes.SHA1)
def convertAlgorithm(value): def convertAlgorithm(value):
"Converts encryption URI to (mech, ivlen)." "Converts encryption URI to (mech, ivlen)."
return { return {
"http://www.w3.org/2001/04/xmlenc#aes128-cbc": (algorithms.AES, modes.CBC, 128), "http://www.w3.org/2001/04/xmlenc#aes128-cbc": (
"http://www.w3.org/2001/04/xmlenc#aes192-cbc": (algorithms.AES, modes.CBC, 192), algorithms.AES, modes.CBC, 128),
"http://www.w3.org/2001/04/xmlenc#aes256-cbc": (algorithms.AES, modes.CBC, 256), "http://www.w3.org/2001/04/xmlenc#aes192-cbc": (
"http://www.w3.org/2001/04/xmlenc#tripledes-cbc": (algorithms.TripleDES, modes.CBC, 64), algorithms.AES, modes.CBC, 192),
"http://www.w3.org/2001/04/xmldsig-more#camellia128": (algorithms.Camellia, modes.CBC, 128), "http://www.w3.org/2001/04/xmlenc#aes256-cbc": (
"http://www.w3.org/2001/04/xmldsig-more#camellia192": (algorithms.Camellia, modes.CBC, 192), algorithms.AES, modes.CBC, 256),
"http://www.w3.org/2001/04/xmldsig-more#camellia256": (algorithms.Camellia, modes.CBC, 256), "http://www.w3.org/2001/04/xmlenc#tripledes-cbc": (
algorithms.TripleDES, modes.CBC, 64),
"http://www.w3.org/2001/04/xmldsig-more#camellia128": (
algorithms.Camellia, modes.CBC, 128),
"http://www.w3.org/2001/04/xmldsig-more#camellia192": (
algorithms.Camellia, modes.CBC, 192),
"http://www.w3.org/2001/04/xmldsig-more#camellia256": (
algorithms.Camellia, modes.CBC, 256),
# TODO: add support for these formats. # TODO: add support for these formats.
# "http://www.w3.org/2001/04/xmlenc#kw-aes128": "kw-aes128", # "http://www.w3.org/2001/04/xmlenc#kw-aes128": "kw-aes128",
@@ -174,10 +179,14 @@ class PBKDF2KeyDerivation(XMLKeyDerivation):
if params is None: if params is None:
raise ValueError("XML file is missing PBKDF2 parameters!") raise ValueError("XML file is missing PBKDF2 parameters!")
salt = fetch(params, "./xenc11:Salt/xenc11:Specified/text()", base64.b64decode) salt = fetch(
itrs = fetch(params, "./xenc11:IterationCount/text()", int) params, "./xenc11:Salt/xenc11:Specified/text()", base64.b64decode)
klen = fetch(params, "./xenc11:KeyLength/text()", int) itrs = fetch(
hmod = fetch(params, "./xenc11:PRF/@Algorithm", convertHMACType, hashlib.sha1) params, "./xenc11:IterationCount/text()", int)
klen = fetch(
params, "./xenc11:KeyLength/text()", int)
hmod = fetch(
params, "./xenc11:PRF/@Algorithm", convertHMACType, hashes.SHA1)
if salt is None: if salt is None:
raise ValueError("XML file is missing PBKDF2 salt!") raise ValueError("XML file is missing PBKDF2 salt!")
@@ -189,10 +198,11 @@ class PBKDF2KeyDerivation(XMLKeyDerivation):
raise ValueError("XML file is missing PBKDF2 key length!") raise ValueError("XML file is missing PBKDF2 key length!")
self.kdf = pbkdf2.PBKDF2HMAC( self.kdf = pbkdf2.PBKDF2HMAC(
algorithm=hmod, algorithm=hmod(),
length=klen, length=klen,
salt=salt, salt=salt,
iterations=itrs iterations=itrs,
backend=default_backend()
) )
def derive(self, masterkey): def derive(self, masterkey):
@@ -217,8 +227,13 @@ class XMLDecryptor(object):
self.__hmac = hmac self.__hmac = hmac
def __call__(self, element, mac=None): def __call__(self, element, mac=None):
(algo, mode, klen) = fetch(element, "./xenc:EncryptionMethod/@Algorithm", convertAlgorithm) algo, mode, klen = fetch(
data = fetch(element, "./xenc:CipherData/xenc:CipherValue/text()", base64.b64decode) element, "./xenc:EncryptionMethod/@Algorithm", convertAlgorithm)
data = fetch(
element,
"./xenc:CipherData/xenc:CipherValue/text()",
base64.b64decode
)
# Make sure the key is the right length. # Make sure the key is the right length.
if len(self.__key) * 8 != klen: if len(self.__key) * 8 != klen:
@@ -228,17 +243,24 @@ class XMLDecryptor(object):
if mac: if mac:
tmp = self.__hmac.copy() tmp = self.__hmac.copy()
tmp.update(data) tmp.update(data)
if tmp.digest() != mac: try:
raise ValidationError("MAC validation failed!") tmp.verify(mac)
except InvalidSignature as e:
raise ValidationError("MAC validation failed!", e)
iv = data[:algo.block_size / 8] iv = data[:algo.block_size // 8]
data = data[len(iv):] data = data[len(iv):]
cipher = Cipher(algo(self.__key), mode(iv)) algorithm = algo(self.__key)
cipher = Cipher(algorithm, mode(iv), default_backend())
decryptor = cipher.decryptor() decryptor = cipher.decryptor()
padded = decryptor.update(data)
padded += decryptor.finalize()
unpadder = PKCS7(algorithm.block_size).unpadder()
out = unpadder.update(padded)
out += unpadder.finalize()
out = decryptor.update(data)
out += decryptor.finalize()
return out return out
@@ -441,7 +463,11 @@ class PSKCDocument(object):
# Load the decryptor. # Load the decryptor.
self.__decryptor = XMLDecryptor(key) self.__decryptor = XMLDecryptor(key)
if self.__mkey is not None and self.__algo is not None: if self.__mkey is not None and self.__algo is not None:
tmp = hmac.HMAC(self.__decryptor(self.__mkey), digestmod=self.__algo) tmp = hmac.HMAC(
self.__decryptor(self.__mkey),
self.__algo(),
backend=default_backend()
)
self.__decryptor = XMLDecryptor(key, tmp) self.__decryptor = XMLDecryptor(key, tmp)
def getKeyPackages(self): def getKeyPackages(self):

View File

@@ -58,7 +58,6 @@ if __name__ == '__main__':
"netaddr", "netaddr",
"pyasn1", "pyasn1",
"pyldap", "pyldap",
"python-nss",
"six", "six",
# not available on PyPI # not available on PyPI
# "python-libipa_hbac", # "python-libipa_hbac",

View File

@@ -71,12 +71,11 @@ if __name__ == '__main__':
"pyldap", "pyldap",
"pytest", "pytest",
"pytest_multihost", "pytest_multihost",
"python-nss",
"six", "six",
], ],
extras_require={ extras_require={
"integration": ["dbus-python", "pyyaml", "ipaserver"], "integration": ["dbus-python", "pyyaml", "ipaserver"],
"ipaserver": ["ipaserver"], "ipaserver": ["ipaserver", "python-nss"],
"webui": ["selenium", "pyyaml", "ipaserver"], "webui": ["selenium", "pyyaml", "ipaserver"],
"xmlrpc": ["ipaserver"], "xmlrpc": ["ipaserver"],
} }