Ejemplo n.º 1
0
	def test_pbkdf(self):
		'''
		Test password based key derivation function
		'''
		expected_key = { 1000: "979d33c5e39bf7fc20ef",
						 10: "3c28a7f09aa19108a17d",
						 100: "303155b866685ad279fa" }
		for key_length in expected_key.keys():
			key = binascii.hexlify(pbkdf2("my password", "salt", 10, key_length))
			print key, expected_key[key_length]
			assert key == expected_key[key_length]
Ejemplo n.º 2
0
	def test_pbkdf(self):
		'''
		Test password based key derivation function
		'''
		expected_key = { 1000: "979d33c5e39bf7fc20ef",
						 10: "3c28a7f09aa19108a17d",
						 100: "303155b866685ad279fa" }
		for key_length in expected_key.keys():
			key = binascii.hexlify(pbkdf2("my password", "salt", 10, key_length))
			print key, expected_key[key_length]
			assert key == expected_key[key_length]
Ejemplo n.º 3
0
 def test_pbkdf(self):
     """
     Test password based key derivation function
     """
     expected_key = {
         1000: "979d33c5e39bf7fc20ef",
         10: "3c28a7f09aa19108a17d",
         100: "303155b866685ad279fa",
     }
     for key_length in list(expected_key.keys()):
         key = pbkdf2("my password", "salt", 10, key_length).hex()
         print(key, expected_key[key_length])
         assert key == expected_key[key_length]
Ejemplo n.º 4
0
def parsePSKCdata(xml,
                  preshared_key_hex=None,
                  password=None,
                  do_checkserial=True,
                  do_feitian=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

    It returns a dictionary of
        serial : { hmac_key , counter, .... }
    '''
    TAG_NAME_KEYPACKAGE = "KeyPackage"
    TAG_TOKEN_ID = "Id"
    # Feitian Fix
    if do_feitian:
        TAG_NAME_KEYPACKAGE = "Device"
        TAG_TOKEN_ID = "KeyId"
        do_checkserial = False

    TOKENS = {}
    elem_keycontainer = etree.fromstring(xml)
    ENCRYPTION_KEY_hex = preshared_key_hex

    if getTagName(elem_keycontainer).lower() != "keycontainer":
        raise ImportException("No toplevel element KeyContainer")

    tag = elem_keycontainer.tag
    match = re.match("^({.*?})Key[Cc]ontainer$", tag)
    namespace = ""
    if match:
        namespace = match.group(1)
        log.debug("Found namespace %s" % namespace)

    PSKC_VERSION = elem_keycontainer.get("Version")
    KEYNAME = None
    MACKEY_bin = None
    ENC_ALGO = None
    ENC_MODE = None

    PBE_DERIVE_ALGO = None
    PBE_SALT = None
    PBE_ITERATION_COUNT = None
    PBE_KEY_LENGTH = None

    # check for any encryption method 6.1, 6.2
    ### Do the Encryption Key
    elem_encKey = elem_keycontainer.find(namespace + "EncryptionKey")

    if elem_encKey:

        # Check for AES-128-CBC, preshared key (chapter 6.1)
        enckeyTag = getTagName(list(elem_encKey)[0])
        # This will hold the name of the preshared key
        if "KeyName" == enckeyTag:
            ENC_MODE = "AES128"
            KEYNAME = list(elem_encKey)[0].text
            log.debug("The keyname of preshared encryption is <<%s>>" %
                      KEYNAME)
        # check for PasswordBasedEncyprion (chapter 6.2)
        elif "DerivedKey" == enckeyTag:
            ENC_MODE = "PBE"
            log.debug("We found PBE.")
            # Now we check for KeyDerivationMethod
            elem_keyderivation = list(list(elem_encKey)[0])
            for e in elem_keyderivation:
                if "KeyDerivationMethod" == getTagName(e):

                    deriv_algo = e.get("Algorithm")
                    m = re.search("\#(.*)$", deriv_algo)
                    PBE_DERIVE_ALGO = m.group(1)
                    log.debug("Algorithm of the PBE: %s" % PBE_DERIVE_ALGO)
                    if "pbkdf2" == PBE_DERIVE_ALGO:
                        for p in list(e):
                            if "PBKDF2-params" == getTagName(p):
                                for sp in list(p):
                                    spTag = getTagName(sp)
                                    if "Salt" == spTag:
                                        for salt in list(sp):
                                            if "Specified" == getTagName(salt):
                                                PBE_SALT = salt.text
                                            else:
                                                log.warning(
                                                    "Unknown element in element Salt: %s"
                                                    % getTagName(salt))
                                    elif "IterationCount" == spTag:
                                        PBE_ITERATION_COUNT = sp.text
                                    elif "KeyLength" == spTag:
                                        PBE_KEY_LENGTH = sp.text
                    else:
                        # probably pbkdf1
                        log.error(
                            "We do not support key derivation method %s" %
                            deriv_algo)
                        raise ImportException(
                            "We do not support key derivation method %s" %
                            deriv_algo)
                log.debug("found the salt <<%s>>" % PBE_SALT)

            if password and len(password) > 5 and len(password) <= 64:
                log.debug(
                    "calculation encryption key from password [%s], salt: [%s] and length: [%s], count: [%s]"
                    %
                    (password, PBE_SALT, PBE_KEY_LENGTH, PBE_ITERATION_COUNT))
                ENCRYPTION_KEY_bin = pbkdf2.pbkdf2(password.encode('ascii'),
                                                   base64.b64decode(PBE_SALT),
                                                   int(PBE_KEY_LENGTH),
                                                   int(PBE_ITERATION_COUNT))
                ENCRYPTION_KEY_hex = binascii.hexlify(ENCRYPTION_KEY_bin)
                log.debug("calculated encryption key: %s" % ENCRYPTION_KEY_hex)
            else:
                log.error(
                    "You must provide a password that is longer than 5 characters and up to 64 characters long."
                )
                raise ImportException(
                    "You must provide a password that is longer than 5 characters and up to 64 characters long."
                )

        ### Do the MAC Key
        # This will hold the MAC key
        macmethod = elem_keycontainer.find(namespace + "MACMethod")
        MAC_Method = getMacMethod(macmethod)
        elem_mackey = macmethod.find(namespace + "MACKey")

        # Find the MAC: ENC_ALGO and MAC_bin
        for e in list(elem_mackey):
            tag = getTagName(e)
            if "CipherData" == tag:
                for c in list(e):
                    cipher_tag = getTagName(c)
                    if "CipherValue" == cipher_tag:
                        cipherValue = c.text.strip()
                        log.debug("Found this MAC Key cipherValue: <<%s>>" %
                                  cipherValue)
                        MACKEY_bin = aes_decrypt(cipherValue,
                                                 ENCRYPTION_KEY_hex)
                    else:
                        log.error("Found unsupported child in CipherData: %s" %
                                  cipher_tag)
                        raise ImportException(
                            "Found unsupported child in CipherData: %s" %
                            cipher_tag)
            elif "EncryptionMethod" == tag:
                ENC_ALGO = getEncMethod(e)
            else:
                log.warning("Found unknown tag: %s" % tag)

    ## End of Encryption Key
    # There is a keypackage per key
    # Now we get the list of keypackages

    elem_KeyPackageList = elem_keycontainer.findall(namespace +
                                                    TAG_NAME_KEYPACKAGE)
    if 0 == len(elem_KeyPackageList):
        raise ImportException("No element %s contained!" % TAG_NAME_KEYPACKAGE)

    # Now parsing all the keys
    for elem_package in elem_KeyPackageList:

        ### Do the keys

        elem_key = elem_package.find(namespace + "Key")

        serial = elem_key.get(TAG_TOKEN_ID)
        log.info("Processing token with serial (Key Id=%s)" % serial)

        elem_deviceInfo = elem_package.find(namespace + "DeviceInfo")
        if elem_deviceInfo:
            # Try to find the real serial number
            elem_serial = elem_deviceInfo.find(namespace + "SerialNo")
            serial = elem_serial.text
            log.info("Processing token with the real SerialNo %s" % serial)

        algorithm = elem_key.get("Algorithm")
        if algorithm:
            # <Key Id="12345678" Algorithm="urn:ietf:params:xml:ns:keyprov:pskc:hotp">
            algorithm = algorithm.split(":")[-1]
        else:
            # Some draft say, this would be KeyAlgorithm
            algorithm = elem_key.get("KeyAlgorithm")
            # <Key KeyAlgorithm="http://www.ietf.org/keyprov/pskc#totp"
            algorithm = algorithm.split("#")[-1]

        TOKEN_TYPE = None

        if algorithm:
            if 'hotp' == algorithm.lower():
                TOKEN_TYPE = "hmac"
            elif 'totp' == algorithm.lower():
                TOKEN_TYPE = "totp"
            elif 'ocra' == algorithm.lower():
                TOKEN_TYPE = "ocra"

        if do_checkserial and not checkSerial(serial):
            log.warning("serial %s is not a valid OATH serial" % serial)
        else:
            # Now we do the Parameters, which can hold
            # the number of the digits :
            # <pskc:AlgorithmParameters>
            #   <Suite>OCRA-1:HOTP-SHA1-6:C-QN08-PSHA1</Suite>
            #   <pskc:ResponseFormat Length="6" Encoding="DECIMAL"/>
            # </pskc:AlgorithmParameters>
            KD_otplen = 6
            KD_hashlib = None
            KD_Suite = None
            elem_algoParam = elem_key.find(namespace + "AlgorithmParameters")
            for e in list(elem_algoParam):
                eTag = getTagName(e)
                log.debug("Evaluating element <<%s>>" % eTag)
                if "ResponseFormat" == eTag:
                    KD_otplen = int(e.get("Length"))
                    log.debug("Found length = %s" % e.get("Length"))
                elif "Suite" == eTag:
                    if TOKEN_TYPE == "ocra":
                        KD_Suite = e.text
                        log.debug("Found OCRA Suite = %s" % KD_Suite)
                    else:
                        # This can be HMAC-SHA256
                        KD_hashlib = e.text
                        if KD_hashlib.lower() == "hmac-sha256":
                            KD_hashlib = "sha256"
                        if KD_hashlib.lower() == "hmac-sha1":
                            KD_hashlib = "sha1"
                        log.debug("Found hashlib = %s" % KD_hashlib)

            # Now we do all the Key Data: <pskc:Data>
            elem_keydata = elem_key.find(namespace + "Data")
            # Parse through the data of the Key
            KD_hmac_key_b64 = None
            KD_cipher_b64 = None
            KD_mac_b64 = None
            KD_algo = None
            KD_counter = None
            KD_TimeInterval = None
            KD_TimeOffset = None
            for e in list(elem_keydata):
                eTag = getTagName(e)
                log.debug("Evaluating element <<%s>>" % eTag)
                if "Secret" == eTag:
                    for se in list(e):
                        seTag = getTagName(se)
                        if "EncryptedValue" == seTag:
                            for ev in list(se):
                                evTag = getTagName(ev)
                                if "EncryptionMethod" == evTag:
                                    KD_algo = getEncMethod(ev)
                                elif "CipherData" == evTag:
                                    for ciph in list(ev):
                                        ciphTag = getTagName(ciph)
                                        if "CipherValue" == ciphTag:
                                            KD_cipher_b64 = ciph.text.strip()

                        elif "PlainValue" == seTag:
                            KD_hmac_key_b64 = se.text.strip()
                        elif "ValueMAC" == seTag:
                            KD_mac_b64 = se.text.strip()

                elif "Counter" == eTag:
                    for se in list(e):
                        seTag = getTagName(se)
                        if "PlainValue" == seTag:
                            KD_counter = se.text
                        else:
                            log.warning(
                                "We do only support PlainValue counters")
                elif "TimeInterval" == eTag:
                    for se in list(e):
                        seTag = getTagName(se)
                        if "PlainValue" == seTag:
                            KD_TimeInterval = se.text
                            log.debug("Found TimeInterval = %s" %
                                      KD_TimeInterval)
                        else:
                            log.warning(
                                "We do only support PlainValue for TimeInterval"
                            )
                elif "Time" == eTag:
                    for se in list(e):
                        seTag = getTagName(se)
                        if "PlainValue" == seTag:
                            KD_Time = se.text
                            log.debug("Found Time offset = %s" % KD_Time)
                        else:
                            log.warning(
                                "We do only support PlainValue for Time")

                else:
                    log.warning("Unparsed Tag in Key: %s" % eTag)

            if KD_algo and KD_hmac_key_b64:
                log.warning(
                    "The key %s contained a secret with PlainValue and EncryptedValue!"
                    % serial)
            else:
                if "aes128-cbc" == ENC_ALGO:
                    #
                    #   Verifiy the MAC Value
                    #
                    if "hmac-sha1" == MAC_Method:

                        MAC_digest_bin = hmac.new(
                            MACKEY_bin, base64.b64decode(KD_cipher_b64),
                            sha).digest()
                        MAC_digest_b64 = base64.b64encode(MAC_digest_bin)
                        log.debug("AES128-CBC secret cipher: %s" %
                                  KD_cipher_b64)
                        log.debug("calculated MAC value    : %s" %
                                  MAC_digest_b64)
                        log.debug("read MAC value          : %s" % KD_mac_b64)

                        # decrypt key
                        HMAC_KEY_bin = aes_decrypt(KD_cipher_b64,
                                                   ENCRYPTION_KEY_hex, serial)

                        if MAC_digest_b64 == KD_mac_b64:
                            TOKENS[serial] = {
                                'hmac_key': binascii.hexlify(HMAC_KEY_bin),
                                'counter': KD_counter,
                                'type': TOKEN_TYPE,
                                'timeStep': KD_TimeInterval,
                                'otplen': KD_otplen,
                                'hashlib': KD_hashlib,
                                'ocrasuite': KD_Suite
                            }
                        else:
                            log.error(
                                "The MAC value for %s does not fit. The HMAC secrets could be compromised!"
                                % serial)
                            raise ImportException(
                                "The MAC value for %s does not fit. The HMAC secrets could be compromised!"
                                % serial)
                            #TOKENS[serial] = { 'hmac_key' : binascii.hexlify(HMAC_KEY_bin),
                            #            'counter' : KD_counter, 'type' : TOKEN_TYPE,
                            #            'timeStep' : KD_TimeInterval, 'otplen' : KD_otplen,
                            #            'hashlib' : KD_hashlib }
                    else:
                        log.warning(
                            "At the moment we only support hmac-sha1. We found %s"
                            % MAC_Method)

                elif KD_hmac_key_b64:
                    TOKENS[serial] = {
                        'hmac_key':
                        binascii.hexlify(base64.b64decode(KD_hmac_key_b64)),
                        'counter':
                        KD_counter,
                        'type':
                        TOKEN_TYPE,
                        'timeStep':
                        KD_TimeInterval,
                        'otplen':
                        KD_otplen,
                        'hashlib':
                        KD_hashlib,
                        'ocrasuite':
                        KD_Suite
                    }
                else:
                    log.warning(
                        "neither a PlainValue nor an EncryptedValue was found for the secret of key %s"
                        % serial)

    return TOKENS
Ejemplo n.º 5
0
def parsePSKCdata(xml , preshared_key_hex=None, password=None,
                    do_checkserial=True,
                    do_feitian=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

    It returns a dictionary of
        serial : { hmac_key , counter, .... }
    '''
    TAG_NAME_KEYPACKAGE = "KeyPackage"
    TAG_TOKEN_ID = "Id"
    # Feitian Fix
    if do_feitian:
        TAG_NAME_KEYPACKAGE = "Device"
        TAG_TOKEN_ID = "KeyId"
        do_checkserial = False


    TOKENS = {}
    elem_keycontainer = etree.fromstring(xml)
    ENCRYPTION_KEY_hex = preshared_key_hex

    if getTagName(elem_keycontainer).lower() != "keycontainer":
        raise ImportException("No toplevel element KeyContainer")

    tag = elem_keycontainer.tag
    match = re.match("^({.*?})Key[Cc]ontainer$", tag)
    namespace = ""
    if match:
        namespace = match.group(1)
        log.debug("Found namespace %s" % namespace)

    PSKC_VERSION = elem_keycontainer.get("Version")
    KEYNAME = None
    MACKEY_bin = None
    ENC_ALGO = None
    ENC_MODE = None

    PBE_DERIVE_ALGO = None
    PBE_SALT = None
    PBE_ITERATION_COUNT = None
    PBE_KEY_LENGTH = None

    # check for any encryption method 6.1, 6.2
    ### Do the Encryption Key
    elem_encKey = elem_keycontainer.find(namespace + "EncryptionKey")

    if elem_encKey:

        # Check for AES-128-CBC, preshared key (chapter 6.1)
        enckeyTag = getTagName(list(elem_encKey)[0])
        # This will hold the name of the preshared key
        if "KeyName" == enckeyTag:
            ENC_MODE = "AES128"
            KEYNAME = list(elem_encKey)[0].text
            log.debug("The keyname of preshared encryption is <<%s>>" % KEYNAME)
        # check for PasswordBasedEncyprion (chapter 6.2)
        elif "DerivedKey" == enckeyTag:
            ENC_MODE = "PBE"
            log.debug("We found PBE.")
            # Now we check for KeyDerivationMethod
            elem_keyderivation = list(list(elem_encKey)[0])
            for e in elem_keyderivation:
                if "KeyDerivationMethod" == getTagName(e):

                    deriv_algo = e.get("Algorithm")
                    m = re.search("\#(.*)$", deriv_algo)
                    PBE_DERIVE_ALGO = m.group(1)
                    log.debug("Algorithm of the PBE: %s" % PBE_DERIVE_ALGO)
                    if "pbkdf2" == PBE_DERIVE_ALGO:
                        for p in list(e):
                            if "PBKDF2-params" == getTagName(p):
                                for sp in list(p):
                                    spTag = getTagName(sp)
                                    if "Salt" == spTag:
                                        for salt in list(sp):
                                            if "Specified" == getTagName(salt):
                                                PBE_SALT = salt.text
                                            else:
                                                log.warning("Unknown element in element Salt: %s" % getTagName(salt))
                                    elif "IterationCount" == spTag:
                                        PBE_ITERATION_COUNT = sp.text
                                    elif "KeyLength" == spTag:
                                        PBE_KEY_LENGTH = sp.text
                    else:
                        # probably pbkdf1
                        log.error("We do not support key derivation method %s" % deriv_algo)
                        raise ImportException("We do not support key derivation method %s" % deriv_algo)
                log.debug("found the salt <<%s>>" % PBE_SALT)

            if password and len(password) > 5 and len(password) <= 64:
                log.debug("calculation encryption key from password [%s], salt: [%s] and length: [%s], count: [%s]" %
                    (password, PBE_SALT, PBE_KEY_LENGTH, PBE_ITERATION_COUNT))
                ENCRYPTION_KEY_bin = pbkdf2.pbkdf2(password.encode('ascii'), base64.b64decode(PBE_SALT),
                    int(PBE_KEY_LENGTH), int(PBE_ITERATION_COUNT))
                ENCRYPTION_KEY_hex = binascii.hexlify(ENCRYPTION_KEY_bin)
                log.debug("calculated encryption key: %s" % ENCRYPTION_KEY_hex)
            else:
                log.error("You must provide a password that is longer than 5 characters and up to 64 characters long.")
                raise ImportException("You must provide a password that is longer than 5 characters and up to 64 characters long.")


        ### Do the MAC Key
        # This will hold the MAC key
        macmethod = elem_keycontainer.find(namespace + "MACMethod")
        MAC_Method = getMacMethod(macmethod)
        elem_mackey = macmethod.find(namespace + "MACKey")


        # Find the MAC: ENC_ALGO and MAC_bin
        for e in list(elem_mackey):
            tag = getTagName(e)
            if "CipherData" == tag:
                for c in list(e):
                    cipher_tag = getTagName(c)
                    if "CipherValue" == cipher_tag:
                        cipherValue = c.text.strip()
                        log.debug("Found this MAC Key cipherValue: <<%s>>" % cipherValue)
                        MACKEY_bin = aes_decrypt(cipherValue, ENCRYPTION_KEY_hex)
                    else:
                        log.error("Found unsupported child in CipherData: %s" % cipher_tag)
                        raise ImportException("Found unsupported child in CipherData: %s" % cipher_tag)
            elif "EncryptionMethod" == tag:
                ENC_ALGO = getEncMethod(e)
            else:
                log.warning("Found unknown tag: %s" % tag)


    ## End of Encryption Key
    # There is a keypackage per key
    # Now we get the list of keypackages

    elem_KeyPackageList = elem_keycontainer.findall(namespace + TAG_NAME_KEYPACKAGE)
    if 0 == len(elem_KeyPackageList):
        raise ImportException("No element %s contained!" % TAG_NAME_KEYPACKAGE)

    # Now parsing all the keys
    for elem_package in elem_KeyPackageList:

        ### Do the keys

        elem_key = elem_package.find(namespace + "Key")

        serial = elem_key.get(TAG_TOKEN_ID)
        log.info("Processing token with serial (Key Id=%s)" % serial)

        elem_deviceInfo = elem_package.find(namespace + "DeviceInfo")
        if elem_deviceInfo:
            # Try to find the real serial number
            elem_serial = elem_deviceInfo.find(namespace + "SerialNo")
            serial = elem_serial.text
            log.info("Processing token with the real SerialNo %s" % serial)

        algorithm = elem_key.get("Algorithm")
        if algorithm:
            # <Key Id="12345678" Algorithm="urn:ietf:params:xml:ns:keyprov:pskc:hotp">
            algorithm = algorithm.split(":")[-1]
        else:
            # Some draft say, this would be KeyAlgorithm
            algorithm = elem_key.get("KeyAlgorithm")
            # <Key KeyAlgorithm="http://www.ietf.org/keyprov/pskc#totp"
            algorithm = algorithm.split("#")[-1]

        TOKEN_TYPE = None

        if algorithm:
            if 'hotp' == algorithm.lower():
                TOKEN_TYPE = "hmac"
            elif 'totp' == algorithm.lower():
                TOKEN_TYPE = "totp"
            elif 'ocra' == algorithm.lower():
                TOKEN_TYPE = "ocra"

        if do_checkserial and not checkSerial(serial):
            log.warning("serial %s is not a valid OATH serial" % serial)
        else:
            # Now we do the Parameters, which can hold
            # the number of the digits :
            # <pskc:AlgorithmParameters>
            #   <Suite>OCRA-1:HOTP-SHA1-6:C-QN08-PSHA1</Suite>
            #   <pskc:ResponseFormat Length="6" Encoding="DECIMAL"/>
            # </pskc:AlgorithmParameters>
            KD_otplen = 6
            KD_hashlib = None
            KD_Suite = None
            elem_algoParam = elem_key.find(namespace + "AlgorithmParameters")
            for e in list(elem_algoParam):
                eTag = getTagName(e)
                log.debug("Evaluating element <<%s>>" % eTag)
                if "ResponseFormat" == eTag:
                    KD_otplen = int (e.get("Length"))
                    log.debug("Found length = %s" % e.get("Length"))
                elif "Suite" == eTag:
                    if TOKEN_TYPE == "ocra":
                        KD_Suite = e.text
                        log.debug("Found OCRA Suite = %s" % KD_Suite)
                    else:
                        # This can be HMAC-SHA256
                        KD_hashlib = e.text
                        if KD_hashlib.lower() == "hmac-sha256":
                            KD_hashlib = "sha256"
                        if KD_hashlib.lower() == "hmac-sha1":
                            KD_hashlib = "sha1"
                        log.debug("Found hashlib = %s" % KD_hashlib)


            # Now we do all the Key Data: <pskc:Data>
            elem_keydata = elem_key.find(namespace + "Data")
            # Parse through the data of the Key
            KD_hmac_key_b64 = None
            KD_cipher_b64 = None
            KD_mac_b64 = None
            KD_algo = None
            KD_counter = None
            KD_TimeInterval = None
            KD_TimeOffset = None
            for e in list(elem_keydata):
                eTag = getTagName(e)
                log.debug("Evaluating element <<%s>>" % eTag)
                if "Secret" == eTag:
                    for se in list(e):
                        seTag = getTagName(se)
                        if "EncryptedValue" == seTag:
                            for ev in list(se):
                                evTag = getTagName(ev)
                                if "EncryptionMethod" == evTag:
                                    KD_algo = getEncMethod(ev)
                                elif "CipherData" == evTag:
                                    for ciph in list(ev):
                                        ciphTag = getTagName(ciph)
                                        if "CipherValue" == ciphTag:
                                            KD_cipher_b64 = ciph.text.strip()


                        elif "PlainValue" == seTag:
                            KD_hmac_key_b64 = se.text.strip()
                        elif "ValueMAC" == seTag:
                            KD_mac_b64 = se.text.strip()

                elif "Counter" == eTag:
                    for se in list(e):
                        seTag = getTagName(se)
                        if "PlainValue" == seTag:
                            KD_counter = se.text
                        else:
                            log.warning("We do only support PlainValue counters")
                elif "TimeInterval" == eTag:
                    for se in list(e):
                        seTag = getTagName(se)
                        if "PlainValue" == seTag:
                            KD_TimeInterval = se.text
                            log.debug("Found TimeInterval = %s" % KD_TimeInterval)
                        else:
                            log.warning("We do only support PlainValue for TimeInterval")
                elif "Time" == eTag:
                    for se in list(e):
                        seTag = getTagName(se)
                        if "PlainValue" == seTag:
                            KD_Time = se.text
                            log.debug("Found Time offset = %s" % KD_Time)
                        else:
                            log.warning("We do only support PlainValue for Time")

                else:
                    log.warning("Unparsed Tag in Key: %s" % eTag)

            if KD_algo and KD_hmac_key_b64:
                log.warning("The key %s contained a secret with PlainValue and EncryptedValue!" % serial)
            else:
                if "aes128-cbc" == ENC_ALGO:
                    #
                    #   Verifiy the MAC Value
                    #
                    if "hmac-sha1" == MAC_Method:

                        MAC_digest_bin = hmac.new(MACKEY_bin, base64.b64decode(KD_cipher_b64), sha).digest()
                        MAC_digest_b64 = base64.b64encode(MAC_digest_bin)
                        log.debug("AES128-CBC secret cipher: %s" % KD_cipher_b64)
                        log.debug("calculated MAC value    : %s" % MAC_digest_b64)
                        log.debug("read MAC value          : %s" % KD_mac_b64)

                        # decrypt key
                        HMAC_KEY_bin = aes_decrypt(KD_cipher_b64, ENCRYPTION_KEY_hex, serial)

                        if MAC_digest_b64 == KD_mac_b64:
                            TOKENS[serial] = { 'hmac_key' : binascii.hexlify(HMAC_KEY_bin),
                                        'counter' : KD_counter, 'type' : TOKEN_TYPE,
                                        'timeStep' : KD_TimeInterval, 'otplen' : KD_otplen,
                                        'hashlib' : KD_hashlib,
                                        'ocrasuite' : KD_Suite }
                        else:
                            log.error("The MAC value for %s does not fit. The HMAC secrets could be compromised!" % serial)
                            raise ImportException("The MAC value for %s does not fit. The HMAC secrets could be compromised!" % serial)
                            #TOKENS[serial] = { 'hmac_key' : binascii.hexlify(HMAC_KEY_bin),
                            #            'counter' : KD_counter, 'type' : TOKEN_TYPE,
                            #            'timeStep' : KD_TimeInterval, 'otplen' : KD_otplen,
                            #            'hashlib' : KD_hashlib }
                    else:
                        log.warning("At the moment we only support hmac-sha1. We found %s" % MAC_Method)

                elif KD_hmac_key_b64:
                    TOKENS[serial] = { 'hmac_key' : binascii.hexlify(base64.b64decode(KD_hmac_key_b64)),
                                        'counter' : KD_counter, 'type' : TOKEN_TYPE,
                                        'timeStep' : KD_TimeInterval, 'otplen' : KD_otplen,
                                        'hashlib' : KD_hashlib,
                                        'ocrasuite' : KD_Suite  }
                else:
                    log.warning("neither a PlainValue nor an EncryptedValue was found for the secret of key %s" % serial)

    return TOKENS
Ejemplo n.º 6
0
    def test_vectors(self):
        """
        test the pbkdf2 function agains the rfc test vectors

        from https://www.ietf.org/rfc/rfc6070.txt
        """

        testvectors = [{
            "P": "password", # (8 octets)
            "S": "salt", # (4 octets)
            "c": 1,
            "dkLen": 20,
            "DK": ("0c" "60" "c8" "0f" "96" "1f" "0e" "71" # (20 octets)
                   "f3" "a9" "b5" "24" "af" "60" "12" "06"
                   "2f" "e0" "37" "a6")},
            {
             "P": "password", #(8 octets)
             "S": "salt", #(4 octets)
             "c": 2,
             "dkLen": 20,
             "DK": ("ea" "6c" "01" "4d" "c7" "2d" "6f" "8c" #(20 octets)
                    "cd" "1e" "d9" "2a" "ce" "1d" "41" "f0"
                    "d8" "de" "89" "57"),},
            {
            "P": "password", # (8 octets)
            "S": "salt", # (4 octets)
            "c": 4096,
            "dkLen": 20,
            "DK": ("4b" "00" "79" "01" "b7" "65" "48" "9a" #(20 octets)
                   "be" "ad" "49" "d9" "26" "f7" "21" "d0"
                   "65" "a4" "29" "c1"),},
#             { # this is a long running test and as we test
#               # against a std lib, this might not be required
#             "P": "password", # (8 octets)
#             "S": "salt", # (4 octets)
#             "c": 16777216,
#             "dkLen": 20,
#             "DK": ( "ee" "fe" "3d" "61" "cd" "4d" "a4" "e4" # (20 octets)
#                     "e9" "94" "5b" "3d" "6b" "a2" "15" "8c"
#                     "26" "34" "e9" "84")},
            {
            "P": "passwordPASSWORDpassword",  # (24 octets)
            "S": "saltSALTsaltSALTsaltSALTsaltSALTsalt",  # (36 octets)
            "c": 4096,
            "dkLen": 25,
            "DK" : ("3d" "2e" "ec" "4f" "e4" "1c" "84" "9b"  # (25 octets)
                    "80" "c8" "d8" "36" "62" "c0" "e4" "4a"
                    "8b" "29" "1a" "96" "4c" "f2" "f0" "70"
                    "38")},
            {
             "P": "pass\0word",  # (9 octets)
             "S": "sa\0lt",  # (5 octets)
             "c" : 4096,
             "dkLen" : 16,
             "DK" : ("56" "fa" "6a" "a7" "55" "48" "09" "9d"  #  (16 octets)
                     "cc" "37" "d7" "f0" "34" "25" "e0" "c3")},
        ]

        hashfunc = sha1

        for testvector in testvectors:

            password = testvector['P']
            salt = testvector['S']
            iterations = testvector['c']
            dk_length = testvector['dkLen']
            expected_result = testvector['DK']

            rawhash1 = pbkdf2(password, salt, dk_length, iterations, hashfunc)
            assert(expected_result == binascii.hexlify(rawhash1))

        return
Ejemplo n.º 7
0
    def test_vectors(self):
        """
        test the pbkdf2 function agains the rfc test vectors

        from https://www.ietf.org/rfc/rfc6070.txt
        """

        testvectors = [
            {
                "P":
                "password",  # (8 octets)
                "S":
                "salt",  # (4 octets)
                "c":
                1,
                "dkLen":
                20,
                "DK": (
                    "0c"
                    "60"
                    "c8"
                    "0f"
                    "96"
                    "1f"
                    "0e"
                    "71"  # (20 octets)
                    "f3"
                    "a9"
                    "b5"
                    "24"
                    "af"
                    "60"
                    "12"
                    "06"
                    "2f"
                    "e0"
                    "37"
                    "a6"),
            },
            {
                "P":
                "password",  # (8 octets)
                "S":
                "salt",  # (4 octets)
                "c":
                2,
                "dkLen":
                20,
                "DK": (
                    "ea"
                    "6c"
                    "01"
                    "4d"
                    "c7"
                    "2d"
                    "6f"
                    "8c"  # (20 octets)
                    "cd"
                    "1e"
                    "d9"
                    "2a"
                    "ce"
                    "1d"
                    "41"
                    "f0"
                    "d8"
                    "de"
                    "89"
                    "57"),
            },
            {
                "P":
                "password",  # (8 octets)
                "S":
                "salt",  # (4 octets)
                "c":
                4096,
                "dkLen":
                20,
                "DK": (
                    "4b"
                    "00"
                    "79"
                    "01"
                    "b7"
                    "65"
                    "48"
                    "9a"  # (20 octets)
                    "be"
                    "ad"
                    "49"
                    "d9"
                    "26"
                    "f7"
                    "21"
                    "d0"
                    "65"
                    "a4"
                    "29"
                    "c1"),
            },
            #             { # this is a long running test and as we test
            #               # against a std lib, this might not be required
            #             "P": "password", # (8 octets)
            #             "S": "salt", # (4 octets)
            #             "c": 16777216,
            #             "dkLen": 20,
            #             "DK": ( "ee" "fe" "3d" "61" "cd" "4d" "a4" "e4" # (20 octets)
            #                     "e9" "94" "5b" "3d" "6b" "a2" "15" "8c"
            #                     "26" "34" "e9" "84")},
            {
                "P":
                "passwordPASSWORDpassword",  # (24 octets)
                "S":
                "saltSALTsaltSALTsaltSALTsaltSALTsalt",  # (36 octets)
                "c":
                4096,
                "dkLen":
                25,
                "DK": (
                    "3d"
                    "2e"
                    "ec"
                    "4f"
                    "e4"
                    "1c"
                    "84"
                    "9b"  # (25 octets)
                    "80"
                    "c8"
                    "d8"
                    "36"
                    "62"
                    "c0"
                    "e4"
                    "4a"
                    "8b"
                    "29"
                    "1a"
                    "96"
                    "4c"
                    "f2"
                    "f0"
                    "70"
                    "38"),
            },
            {
                "P":
                "pass\0word",  # (9 octets)
                "S":
                "sa\0lt",  # (5 octets)
                "c":
                4096,
                "dkLen":
                16,
                "DK": (
                    "56"
                    "fa"
                    "6a"
                    "a7"
                    "55"
                    "48"
                    "09"
                    "9d"  # (16 octets)
                    "cc"
                    "37"
                    "d7"
                    "f0"
                    "34"
                    "25"
                    "e0"
                    "c3"),
            },
        ]

        hashfunc = sha1

        for testvector in testvectors:

            password = testvector["P"]
            salt = testvector["S"]
            iterations = testvector["c"]
            dk_length = testvector["dkLen"]
            expected_result = testvector["DK"].encode("utf-8")

            rawhash1 = pbkdf2(password, salt, dk_length, iterations, hashfunc)
            assert expected_result == binascii.hexlify(rawhash1)

        return