def test_02_encrypt_decrypt_eas_base64(self): import os key = os.urandom(16) data = b"This is so secret!" s = aes_encrypt_b64(key, data) d = aes_decrypt_b64(key, s) self.assertEqual(data, d) otp_seed = os.urandom(20) s = aes_encrypt_b64(key, otp_seed) d = aes_decrypt_b64(key, s) self.assertEqual(otp_seed, d) otp_seed = os.urandom(32) s = aes_encrypt_b64(key, otp_seed) d = aes_decrypt_b64(key, s) self.assertEqual(otp_seed, d) # check some data generated with 2.23 hex_key = 'f84c2ddb09dee2a88194d5ac2156a8e4' data = b'secret data' enc_data = 'WNfUSNBNZF5kaPfujW8ueUi5Afas47pQ/3FHc3VymWM=' d = aes_decrypt_b64(binascii.unhexlify(hex_key), enc_data) self.assertEqual(data, d) enc_data = 'RDDvdAJhCnw/tlYscTxv+6idHAQnQFY5VpUK8SFflYQ=' d = aes_decrypt_b64(binascii.unhexlify(hex_key), enc_data) self.assertEqual(data, d)
def test_02_encrypt_decrypt_eas_base64(self): import os key = os.urandom(16) data = b"This is so secret!" s = aes_encrypt_b64(key, data) d = aes_decrypt_b64(key, s) self.assertEqual(data, d) otp_seed = os.urandom(20) s = aes_encrypt_b64(key, otp_seed) d = aes_decrypt_b64(key, s) self.assertEqual(otp_seed, d) otp_seed = os.urandom(32) s = aes_encrypt_b64(key, otp_seed) d = aes_decrypt_b64(key, s) self.assertEqual(otp_seed, d)
def test_02_encrypt_decrypt_eas_base64(self): import os key = os.urandom(16) data = "This is so secret!" s = aes_encrypt_b64(key, data) d = aes_decrypt_b64(key, s) self.assertEqual(data, d) otp_seed = os.urandom(20) s = aes_encrypt_b64(key, otp_seed) d = aes_decrypt_b64(key, s) self.assertEqual(otp_seed, d) otp_seed = os.urandom(32) s = aes_encrypt_b64(key, otp_seed) d = aes_decrypt_b64(key, s) self.assertEqual(otp_seed, d)
def parsePSKCdata(xml_data, preshared_key_hex=None, password=None, do_checkserial=False): """ This function parses XML data of a PSKC file, (RFC6030) It can read * AES-128-CBC encrypted (preshared_key_bin) data * password based encrypted data * plain text data :param xml_data: The XML data :type xml_data: basestring :param preshared_key_hex: The preshared key, hexlified :param password: The password that encrypted the keys :param do_checkserial: Check if the serial numbers conform to the OATH specification (not yet implemented) :return: a dictionary of token dictionaries { serial : { otpkey , counter, .... }} """ tokens = {} #xml = BeautifulSoup(xml_data, "lxml") xml = strip_prefix_from_soup(BeautifulSoup(xml_data, "lxml")) if xml.keycontainer.encryptionkey and \ xml.keycontainer.encryptionkey.derivedkey: # If we have a password we also need a tag EncryptionKey in the # KeyContainer preshared_key_hex = derive_key(xml, password) key_packages = xml.keycontainer.findAll("keypackage") for key_package in key_packages: token = {} key = key_package.key try: token["description"] = key_package.deviceinfo.manufacturer.string except Exception as exx: log.debug("Can not get manufacturer string {0!s}".format(exx)) serial = key["id"] try: serial = key_package.deviceinfo.serialno.string.strip() except Exception as exx: log.debug("Can not get serial string from device info {0!s}".format(exx)) algo = key["algorithm"] token["type"] = algo.split(":")[-1].lower() parameters = key.algorithmparameters token["otplen"] = parameters.responseformat["length"] or 6 try: token["hashlib"] = parameters.suite["hashalgo"] or "sha1" except Exception as exx: log.warning("No compatible suite contained.") try: if key.data.secret.plainvalue: secret = key.data.secret.plainvalue.string token["otpkey"] = hexlify_and_unicode(base64.b64decode(secret)) elif key.data.secret.encryptedvalue: encryptionmethod = key.data.secret.encryptedvalue.encryptionmethod enc_algorithm = encryptionmethod["algorithm"].split("#")[-1] if enc_algorithm.lower() != "aes128-cbc": raise ImportException("We only import PSKC files with " "AES128-CBC.") enc_data = key.data.secret.encryptedvalue.ciphervalue.text enc_data = enc_data.strip() secret = aes_decrypt_b64(binascii.unhexlify(preshared_key_hex), enc_data) if token["type"].lower() in ["hotp", "totp"]: token["otpkey"] = hexlify_and_unicode(secret) elif token["type"].lower() in ["pw"]: token["otpkey"] = to_unicode(secret) else: token["otpkey"] = to_unicode(secret) except Exception as exx: log.error("Failed to import tokendata: {0!s}".format(exx)) log.debug(traceback.format_exc()) raise ImportException("Failed to import tokendata. Wrong " "encryption key? %s" % exx) if token["type"] in ["hotp", "totp"] and key.data.counter: token["counter"] = key.data.counter.text.strip() if token["type"] == "totp": if key.data.timeinterval: token["timeStep"] = key.data.timeinterval.text.strip() if key.data.timedrift: token["timeShift"] = key.data.timedrift.text.strip() tokens[serial] = token return tokens
def parsePSKCdata(xml_data, preshared_key_hex=None, password=None, do_checkserial=False): """ This function parses XML data of a PSKC file, (RFC6030) It can read * AES-128-CBC encrypted (preshared_key_bin) data * password based encrypted data * plain text data :param xml_data: The XML data :type xml_data: basestring :param preshared_key_hex: The preshared key, hexlified :param password: The password that encrypted the keys :param do_checkserial: Check if the serial numbers conform to the OATH specification (not yet implemented) :return: a dictionary of token dictionaries { serial : { otpkey , counter, .... }} """ tokens = {} #xml = BeautifulSoup(xml_data, "lxml") xml = strip_prefix_from_soup(BeautifulSoup(xml_data, "lxml")) if xml.keycontainer.encryptionkey and \ xml.keycontainer.encryptionkey.derivedkey: # If we have a password we also need a tag EncryptionKey in the # KeyContainer preshared_key_hex = derive_key(xml, password) key_packages = xml.keycontainer.findAll("keypackage") for key_package in key_packages: token = {} key = key_package.key try: token["description"] = key_package.deviceinfo.manufacturer.string except Exception as exx: log.debug("Can not get manufacturer string {0!s}".format(exx)) serial = key["id"] try: serial = key_package.deviceinfo.serialno.string.strip() except Exception as exx: log.debug( "Can not get serial string from device info {0!s}".format(exx)) algo = key["algorithm"] token["type"] = algo.split(":")[-1].lower() parameters = key.algorithmparameters token["otplen"] = parameters.responseformat["length"] or 6 try: token["hashlib"] = parameters.suite["hashalgo"] or "sha1" except Exception as exx: log.warning("No compatible suite contained.") try: if key.data.secret.plainvalue: secret = key.data.secret.plainvalue.string token["otpkey"] = binascii.hexlify(base64.b64decode(secret)) elif key.data.secret.encryptedvalue: encryptionmethod = key.data.secret.encryptedvalue.encryptionmethod enc_algorithm = encryptionmethod["algorithm"].split("#")[-1] if enc_algorithm.lower() != "aes128-cbc": raise ImportException("We only import PSKC files with " "AES128-CBC.") enc_data = key.data.secret.encryptedvalue.ciphervalue.text enc_data = enc_data.strip() secret = aes_decrypt_b64(binascii.unhexlify(preshared_key_hex), enc_data) token["otpkey"] = binascii.hexlify(secret) except Exception as exx: log.error("Failed to import tokendata: {0!s}".format(exx)) log.debug(traceback.format_exc()) raise ImportException("Failed to import tokendata. Wrong " "encryption key? %s" % exx) if token["type"] in ["hotp", "totp"] and key.data.counter: token["counter"] = key.data.counter.text.strip() if token["type"] == "totp": if key.data.timeinterval: token["timeStep"] = key.data.timeinterval.text.strip() if key.data.timedrift: token["timeShift"] = key.data.timedrift.text.strip() tokens[serial] = token return tokens
def parsePSKCdata(xml_data, preshared_key_hex=None, password=None, validate_mac='check_fail_hard', do_checkserial=False): """ This function parses XML data of a PSKC file, (RFC6030) It can read * AES-128-CBC encrypted (preshared_key_bin) data * password based encrypted data * plain text data :param xml_data: The XML data :type xml_data: basestring :param preshared_key_hex: The preshared key, hexlified :param password: The password that encrypted the keys :param do_checkserial: Check if the serial numbers conform to the OATH specification (not yet implemented) :param validate_mac: Operation mode of hmac validation. Possible values: - 'check_fail_hard' : If an invalid hmac is encountered no token gets parsed. - 'check_fail_soft' : Skip tokens with invalid MAC. - 'no_check' : Hmac of tokens are not checked, every token is parsed. :return: tuple of a dictionary of token dictionaries and a list of serial of not imported tokens { serial : { otpkey , counter, .... }}, [serial, serial, ...] """ abort = False not_imported_serials = [] tokens = {} xml = strip_prefix_from_soup(BeautifulSoup(xml_data, "lxml")) if not xml.keycontainer: raise ImportException("No KeyContainer found in PSKC data. Could not " "import any tokens.") if xml.keycontainer.encryptionkey and \ xml.keycontainer.encryptionkey.derivedkey: # If we have a password we also need a tag EncryptionKey in the # KeyContainer preshared_key_hex = derive_key(xml, password) key_packages = xml.keycontainer.findAll("keypackage") for key_package in key_packages: token = {} key = key_package.key try: token["description"] = key_package.deviceinfo.manufacturer.string except Exception as exx: log.debug("Can not get manufacturer string {0!s}".format(exx)) serial = key["id"] try: serial = key_package.deviceinfo.serialno.string.strip() except Exception as exx: log.debug( "Can not get serial string from device info {0!s}".format(exx)) algo = key["algorithm"] token["type"] = algo.split(":")[-1].lower() parameters = key.algorithmparameters token["otplen"] = parameters.responseformat["length"] or 6 try: token["hashlib"] = parameters.suite["hashalgo"] or "sha1" except Exception as exx: log.warning("No compatible suite contained.") try: if key.data.secret.plainvalue: secret = key.data.secret.plainvalue.string token["otpkey"] = hexlify_and_unicode(base64.b64decode(secret)) elif key.data.secret.encryptedvalue: encryptionmethod = key.data.secret.encryptedvalue.encryptionmethod enc_algorithm = encryptionmethod["algorithm"].split("#")[-1] if enc_algorithm.lower() != "aes128-cbc": raise ImportException("We only import PSKC files with " "AES128-CBC.") enc_data = key.data.secret.encryptedvalue.ciphervalue.text enc_data = enc_data.strip() preshared_key = binascii.unhexlify(preshared_key_hex) secret = aes_decrypt_b64(preshared_key, enc_data) if token["type"].lower() in ["hotp", "totp"]: token["otpkey"] = hexlify_and_unicode(secret) elif token["type"].lower() in ["pw"]: token["otpkey"] = to_unicode(secret) else: token["otpkey"] = to_unicode(secret) if validate_mac != 'no_check': # Validate MAC: encrypted_mac_key = xml.keycontainer.find("mackey").text mac_key = aes_decrypt_b64(preshared_key, encrypted_mac_key) enc_data_bin = base64.b64decode(enc_data) hm = hmac.new(key=mac_key, msg=enc_data_bin, digestmod=hashlib.sha1) mac_value_calculated = b64encode_and_unicode(hm.digest()) mac_value_xml = key.data.find('valuemac').text.strip() is_invalid = not hmac.compare_digest( mac_value_xml, mac_value_calculated) if is_invalid and validate_mac == 'check_fail_hard': abort = True elif is_invalid and validate_mac == 'check_fail_soft': not_imported_serials.append(serial) continue except Exception as exx: log.error("Failed to import tokendata: {0!s}".format(exx)) log.debug(traceback.format_exc()) raise ImportException("Failed to import tokendata. Wrong " "encryption key? %s" % exx) if token["type"] in ["hotp", "totp"] and key.data.counter: token["counter"] = key.data.counter.text.strip() if token["type"] == "totp": if key.data.timeinterval: token["timeStep"] = key.data.timeinterval.text.strip() if key.data.timedrift: token["timeShift"] = key.data.timedrift.text.strip() tokens[serial] = token if abort: not_imported_serials = tokens.keys() tokens = {} # reset tokens return tokens, not_imported_serials