def SignDeviceToken(idKeyHashAlg):
    # MaxInputBuffer = TpmHelpers.getTpmProperty(tpm, TPM_PT.INPUT_BUFFER)
    caps = tpm.GetCapability(TPM_CAP.TPM_PROPERTIES, TPM_PT.INPUT_BUFFER, 1)
    props = caps.capabilityData  # : TPML_TAGGED_TPM_PROPERTY
    if len(props.tpmProperty
           ) != 1 or props.tpmProperty[0].property != TPM_PT.INPUT_BUFFER:
        raise (Exception(
            'Unexpected result of TPM2_GetCapability(TPM_PT.INPUT_BUFFER)'))
    MaxInputBuffer = props.tpmProperty[0].value

    # First, the code for a short (<= MaxInputBuffer) token signing
    deviceIdToken = crypto.randomBytes(800)
    if len(deviceIdToken) > MaxInputBuffer:
        raise (Exception('Too long token to HMAC'))

    signature = tpm.HMAC(ID_KEY_PersHandle, deviceIdToken, idKeyHashAlg)
    print('HMAC() returned {0}; signature size {1}'.format(
        str(tpm.lastResponseCode), len(signature)))

    if TEST_MODE:
        # Verify the signature correctness
        sigOK = drsVerifyIdSignature(tpm, deviceIdToken, signature)
        print('Signature over short token: ' + ('OK' if sigOK else 'FAILED'))

        signature[16] ^= 0xCC
        sigOK = drsVerifyIdSignature(tpm, deviceIdToken, signature)
        print('Bad signature over short token: ' +
              ('OK' if sigOK else 'FAILED'))

    # Now the code for long token (> MaxInputBuffer) signing
    deviceIdToken = crypto.randomBytes(5500)

    hSequence = tpm.HMAC_Start(ID_KEY_PersHandle, None, idKeyHashAlg)
    print('HMAC_Start() returned ' + str(tpm.lastResponseCode))

    curPos = 0
    bytesLeft = len(deviceIdToken)
    while bytesLeft > MaxInputBuffer:
        tpm.SequenceUpdate(hSequence,
                           deviceIdToken[curPos:curPos + MaxInputBuffer])
        print('SequenceUpdate() returned {0} for slice [{1}, {2}]'.format(str(tpm.lastResponseCode), \
                                                                          curPos, curPos + MaxInputBuffer))
        bytesLeft -= MaxInputBuffer
        curPos += MaxInputBuffer

    resp = tpm.SequenceComplete(hSequence, deviceIdToken[-bytesLeft:],
                                TPM_HANDLE(TPM_RH.NULL))
    print('SequenceComplete() returned {0}. Signature size {1}'.format(
        str(tpm.lastResponseCode), len(signature)))

    if TEST_MODE:
        sigOK = drsVerifyIdSignature(tpm, deviceIdToken, resp.result)
        print('Signature over long token: ' + ('OK' if sigOK else 'FAILED'))
def doActivation(rawActBlob):
    print('Raw Activation Blob size: {0}'.format(len(rawActBlob)))

    # Unmarshal components of the activation blob received from the DRS
    actBlob = DrsActivationBlob(rawActBlob)

    # Start a policy session to be used with ActivateCredential()
    nonceCaller = crypto.randomBytes(20)
    resp = tpm.StartAuthSession(None, None, nonceCaller, None, TPM_SE.POLICY,
                                NullSymDef, TPM_ALG_ID.SHA256)
    print('StartAuthSession(POLICY_SESS) returned ' +
          str(tpm.lastResponseCode) + '; sess handle: ' + str(resp.handle))
    policySess = Session(resp.handle, resp.nonceTPM)

    # Apply the policy necessary to authorize an EK on Windows
    resp = tpm.PolicySecret(Endorsement, policySess.SessIn.sessionHandle, None,
                            None, None, 0)
    print('PolicySecret() returned ' + str(tpm.lastResponseCode))

    # Use ActivateCredential() to decrypt symmetric key that is used as an inner protector
    # of the duplication blob of the new Device ID key generated by DRS.
    innerWrapKey = tpm.withSessions(None, policySess)   \
                      .ActivateCredential(SRK_PersHandle, EK_PersHandle, actBlob.credBlob, actBlob.encSecret.secret)
    print('ActivateCredential() returned {0}; innerWrapKey size {1}'.format(
        str(tpm.lastResponseCode), len(innerWrapKey)))

    # Initialize parameters of the symmetric key used by DRS
    # Note that the client uses the key size chosen by DRS, but other parameters are fixes (an AES key in CFB mode).
    symDef = TPMT_SYM_DEF_OBJECT(TPM_ALG_ID.AES,
                                 len(innerWrapKey) * 8, TPM_ALG_ID.CFB)

    # Import the new Device ID key issued by DRS to the device's TPM
    idKeyPriv = tpm.Import(SRK_PersHandle, innerWrapKey, actBlob.idKeyPub,
                           actBlob.idKeyDupBlob, actBlob.encWrapKey.secret,
                           symDef)
    print('Import() returned {0}; idKeyPriv size {1}'.format(
        str(tpm.lastResponseCode), len(idKeyPriv.buffer)))

    # Load the imported key into the TPM
    hIdKey = tpm.Load(SRK_PersHandle, idKeyPriv, actBlob.idKeyPub)
    print('Load() returned {0}; ID key handle: {1}'.format(
        str(tpm.lastResponseCode), str(hIdKey.handle)))

    # Remove possibly existing persistent instance of the previous Device ID key
    tpm.allowErrors().EvictControl(Owner, ID_KEY_PersHandle, ID_KEY_PersHandle)

    # Persist the new Device ID key
    tpm.EvictControl(Owner, hIdKey, ID_KEY_PersHandle)
    print('EvictControl({0}, {1}) returned {2}'.format(
        str(hIdKey.handle), str(ID_KEY_PersHandle.handle),
        str(tpm.lastResponseCode)))

    # Free the ID Key transient handle
    tpm.FlushContext(hIdKey)
    print('FlushContext(TRANS_ID_KEY) returned ' + str(tpm.lastResponseCode))

    # Free the session object
    tpm.FlushContext(policySess.SessIn.sessionHandle)
    print('FlushContext(POLICY_SESS) returned ' + str(tpm.lastResponseCode))

    #
    # Decrypt the secret URI data sent by the DRS
    #
    """
    symAlg = 'AES-' + str(len(innerWrapKey) * 8) + '-CFB'
    iv = buffer(16)
    iv.fill(0)

    dec: crypto.Decipher = crypto.createDecipheriv(symAlg, innerWrapKey, iv)
    decUriData: Buffer = dec.update(actBlob.encUriData.buffer)
    print('Decipher.update returned ' + len(decUriData) + ' bytes: ' + decUriData)
    decFinal: Buffer = dec.final()
    print('Decipher.final returned ' + len(decFinal) + ' bytes: ' + decFinal)
    """

    #
    # Example of signing a device token using the new Device ID key
    #
    idKeyHashAlg = actBlob.idKeyPub.parameters.scheme.hashAlg  # ((TPMS_SCHEME_HMAC)((TPMS_KEYEDHASH_PARMS)actBlob.idKeyPub.parameters).scheme).hashAlg
    SignDeviceToken(idKeyHashAlg)
def drsGetActivationBlob(tpm, ekPubBlob, srkPubBlob):
    ekPub = TpmBuffer(ekPubBlob).createFromTpm(TPM2B_PUBLIC).publicArea
    srkPub = TpmBuffer(srkPubBlob).createFromTpm(TPM2B_PUBLIC).publicArea

    # Start a policy session to be used with ActivateCredential()
    nonceCaller = crypto.randomBytes(20)
    respSas = tpm.StartAuthSession(None, None, nonceCaller, None,
                                   TPM_SE.POLICY, NullSymDef,
                                   TPM_ALG_ID.SHA256)
    hSess = respSas.handle
    print('DRS >> StartAuthSession(POLICY_SESS) returned ' +
          str(tpm.lastResponseCode) + '; sess handle: ' + str(hSess.handle))
    sess = Session(hSess, respSas.nonceTPM)

    # Run the policy command necessary for key duplication
    respPcc = tpm.PolicyCommandCode(hSess, TPM_CC.Duplicate)
    print('DRS >> PolicyCommandCode() returned ' + str(tpm.lastResponseCode))

    # Retrieve the policy digest computed by the TPM
    dupPolicyDigest = tpm.PolicyGetDigest(hSess)
    print('DRS >> PolicyGetDigest() returned ' + str(tpm.lastResponseCode))

    idKeyTemplate.authPolicy = dupPolicyDigest

    idKey = tpm.withSession(NullPwSession)  \
               .CreatePrimary(Owner, idKeySens, idKeyTemplate, None, [])

    print('DRS >> CreatePrimary(idKey) returned ' + str(tpm.lastResponseCode))

    hSrkPub = tpm.LoadExternal(None, srkPub, Owner)
    print('DRS >> LoadExternal(SRKpub) returned ' + str(tpm.lastResponseCode))

    symWrapperDef = TPMT_SYM_DEF_OBJECT(TPM_ALG_ID.AES, 128, TPM_ALG_ID.CFB)
    respDup = tpm.withSession(sess)   \
                 .Duplicate(idKey.handle, hSrkPub, None, symWrapperDef)
    print('DRS >> Duplicate(...) returned ' + str(tpm.lastResponseCode))

    tpm.FlushContext(hSrkPub)

    hEkPub = tpm.LoadExternal(None, ekPub, Endorsement)
    print('DRS >> LoadExternal(EKpub) returned ' + str(tpm.lastResponseCode))

    cred = tpm.MakeCredential(hEkPub, respDup.encryptionKeyOut,
                              srkPub.getName())
    print('DRS >> MakeCredential(...) returned ' + str(tpm.lastResponseCode))

    # Delete the key and session handles
    tpm.FlushContext(hEkPub)
    tpm.FlushContext(idKey.handle)
    tpm.FlushContext(hSess)
    print('DRS >> Cleanup done')

    #
    # Encrypt URI data to be passed to the client device
    #
    symWrapperTemplate = TPMT_PUBLIC(
        TPM_ALG_ID.SHA256,
        TPMA_OBJECT.decrypt | TPMA_OBJECT.encrypt | TPMA_OBJECT.userWithAuth,
        None, TPMS_SYMCIPHER_PARMS(symWrapperDef), TPM2B_DIGEST())
    sens = TPMS_SENSITIVE_CREATE(None, respDup.encryptionKeyOut)
    symWrapperKey = tpm.withSession(NullPwSession)  \
                       .CreatePrimary(Owner, sens, symWrapperTemplate, None, [])
    print('DRS >> CreatePrimary(SymWrapperKey) returned ' +
          str(tpm.lastResponseCode))

    uriData = "http:#my.test.url/TestDeviceID=F4ED90771DAA7C0B3230FF675DF8A61104AE7C8BB0093FD6A".encode(
        'utf8')
    if (Py3):
        iv = bytes(len(respDup.encryptionKeyOut))
    else:
        iv = bytes(b'\0' * len(respDup.encryptionKeyOut))
    respEnc = tpm.withSession(NullPwSession)    \
                 .EncryptDecrypt(symWrapperKey.handle, 0, TPM_ALG_ID.CFB, iv, uriData)
    print('DRS >> EncryptDecrypt() returned ' + str(tpm.lastResponseCode))
    encryptedUri = respEnc.outData

    # Delete the key and session handles
    tpm.FlushContext(symWrapperKey.handle)
    print('DRS >> Final cleanup done')

    #
    # Prepare data to send back to the DRS client
    #
    actBlob = TpmBuffer(4096)

    actBlob.sizedToTpm(cred.credentialBlob, 2)
    actBlob.toTpm2B(cred.secret)
    respDup.duplicate.toTpm(actBlob)
    actBlob.toTpm2B(respDup.outSymSeed)
    actBlob.sizedToTpm(idKey.outPublic, 2)
    actBlob.toTpm2B(encryptedUri)
    print('DRS >> Activation blob of {0} bytes generated'.format(
        actBlob.curPos))

    return actBlob.trim().buffer
    decUriData: Buffer = dec.update(actBlob.encUriData.buffer)
    print('Decipher.update returned ' + len(decUriData) + ' bytes: ' + decUriData)
    decFinal: Buffer = dec.final()
    print('Decipher.final returned ' + len(decFinal) + ' bytes: ' + decFinal)
    """

    #
    # Example of signing a device token using the new Device ID key
    #
    idKeyHashAlg = actBlob.idKeyPub.parameters.scheme.hashAlg  # ((TPMS_SCHEME_HMAC)((TPMS_KEYEDHASH_PARMS)actBlob.idKeyPub.parameters).scheme).hashAlg
    SignDeviceToken(idKeyHashAlg)


# doActivation()

keyBytes = crypto.randomBytes(32)
idKeySens = TPMS_SENSITIVE_CREATE(None, keyBytes)
idKeyTemplate = TPMT_PUBLIC(
    TPM_ALG_ID.SHA256,
    TPMA_OBJECT.sign | TPMA_OBJECT.userWithAuth | TPMA_OBJECT.noDA,
    None,  # Will be filled by getActivationBlob
    TPMS_KEYEDHASH_PARMS(TPMS_SCHEME_HMAC(TPM_ALG_ID.SHA256)),
    TPM2B_DIGEST_Keyedhash())


def drsGetActivationBlob(tpm, ekPubBlob, srkPubBlob):
    ekPub = TpmBuffer(ekPubBlob).createFromTpm(TPM2B_PUBLIC).publicArea
    srkPub = TpmBuffer(srkPubBlob).createFromTpm(TPM2B_PUBLIC).publicArea

    # Start a policy session to be used with ActivateCredential()
    nonceCaller = crypto.randomBytes(20)