Commit message: Fix vulnerabilities found and reported by Mark Dowd

- limit length of memcpy
- limit number of offered algorithms in Hello packet
- length check in PING packet
- fix a small coding error
CVE: CVE-2013-2221
CWE: CWE-119
Vulnerability description: Heap-based buffer overflow in the ZRtp::storeMsgTemp function in GNU ZRTPCPP before 3.2.0 allows remote attackers to cause a denial of service (crash) and possibly execute arbitrary code via a large packet.

Project: ZRTPCPP
File: ZRtp.cpp

AlgorithmEnum* ZRtp::getStrongHashOffered(ZrtpPacketHello *hello) {

    int numHash = hello->getNumHashes();
    for (int i = 0; i < numHash; i++) {
        if (*(int32_t*)(hello->getHashType(i)) == *(int32_t*)s384) {
            return &zrtpHashes.getByName((const char*)hello->getHashType(i));
        }
    }
    return NULL;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

int32_t ZrtpQueue::activateTimer(int32_t time) {
    std::string s("ZRTP");
    if (staticTimeoutProvider != NULL) {
        staticTimeoutProvider->requestTimeout(time, this, s);
    }
    return 1;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

int32_t ZrtpQueue::getNumberSupportedVersions() {
    if (zrtpEngine != NULL)
        return zrtpEngine->getNumberSupportedVersions();

    return 0;
}

Project: ZRTPCPP
File: ZRtp.cpp

ZRtp::~ZRtp() {
    stopZrtp();
    if (DHss != NULL) {
        delete DHss;
        DHss = NULL;
    }
    if (stateEngine != NULL) {
        delete stateEngine;
        stateEngine = NULL;
    }
    if (dhContext != NULL) {
        delete dhContext;
        dhContext = NULL;
    }
    if (msgShaContext != NULL) {
        closeHashCtx(msgShaContext, NULL);
        msgShaContext = NULL;
    }
    if (auxSecret != NULL) {
        delete auxSecret;
        auxSecret = NULL;
        auxSecretLength = 0;
    }
    if (zidRec != NULL) {
        delete zidRec;
        zidRec = NULL;
    }
    memset(hmacKeyI, 0, MAX_DIGEST_LENGTH);
    memset(hmacKeyR, 0, MAX_DIGEST_LENGTH);

    memset(zrtpKeyI, 0, MAX_DIGEST_LENGTH);
    memset(zrtpKeyR, 0, MAX_DIGEST_LENGTH);
    /*
     * Clear the Initiator's srtp key and salt
     */
    memset(srtpKeyI, 0, MAX_DIGEST_LENGTH);
    memset(srtpSaltI, 0,  MAX_DIGEST_LENGTH);
    /*
     * Clear he Responder's srtp key and salt
     */
    memset(srtpKeyR, 0, MAX_DIGEST_LENGTH);
    memset(srtpSaltR, 0, MAX_DIGEST_LENGTH);

    memset(zrtpSession, 0, MAX_DIGEST_LENGTH);
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::inState(int32_t state)
{
    if (stateEngine != NULL) {
        return stateEngine->inState(state);
    }
    else {
        return false;
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::computeSRTPKeys() {

    // allocate the maximum size, compute real size to use
    uint8_t KDFcontext[sizeof(peerZid)+sizeof(ownZid)+sizeof(messageHash)];
    int32_t kdfSize = sizeof(peerZid)+sizeof(ownZid)+hashLength;

    int32_t keyLen = cipher->getKeylen() * 8;

    if (myRole == Responder) {
        memcpy(KDFcontext, peerZid, sizeof(peerZid));
        memcpy(KDFcontext+sizeof(peerZid), ownZid, sizeof(ownZid));
    }
    else {
        memcpy(KDFcontext, ownZid, sizeof(ownZid));
        memcpy(KDFcontext+sizeof(ownZid), peerZid, sizeof(peerZid));
    }
    memcpy(KDFcontext+sizeof(ownZid)+sizeof(peerZid), messageHash, hashLength);

    // Inititiator key and salt
    KDF(s0, hashLength, (unsigned char*)iniMasterKey, strlen(iniMasterKey)+1, KDFcontext, kdfSize, keyLen, srtpKeyI);
    KDF(s0, hashLength, (unsigned char*)iniMasterSalt, strlen(iniMasterSalt)+1, KDFcontext, kdfSize, 112, srtpSaltI);

    // Responder key and salt
    KDF(s0, hashLength, (unsigned char*)respMasterKey, strlen(respMasterKey)+1, KDFcontext, kdfSize, keyLen, srtpKeyR);
    KDF(s0, hashLength, (unsigned char*)respMasterSalt, strlen(respMasterSalt)+1, KDFcontext, kdfSize, 112, srtpSaltR);

    // The HMAC keys for GoClear
    KDF(s0, hashLength, (unsigned char*)iniHmacKey, strlen(iniHmacKey)+1, KDFcontext, kdfSize, hashLength*8, hmacKeyI);
    KDF(s0, hashLength, (unsigned char*)respHmacKey, strlen(respHmacKey)+1, KDFcontext, kdfSize, hashLength*8, hmacKeyR);

    // The keys for Confirm messages
    KDF(s0, hashLength, (unsigned char*)iniZrtpKey, strlen(iniZrtpKey)+1, KDFcontext, kdfSize, keyLen, zrtpKeyI);
    KDF(s0, hashLength, (unsigned char*)respZrtpKey, strlen(respZrtpKey)+1, KDFcontext, kdfSize, keyLen, zrtpKeyR);

    detailInfo.pubKey = detailInfo.sasType = NULL;
    if (!multiStream) {
        // Compute the new Retained Secret
        KDF(s0, hashLength, (unsigned char*)retainedSec, strlen(retainedSec)+1, KDFcontext, kdfSize, SHA256_DIGEST_LENGTH*8, newRs1);

        // Compute the ZRTP Session Key
        KDF(s0, hashLength, (unsigned char*)zrtpSessionKey, strlen(zrtpSessionKey)+1, KDFcontext, kdfSize, hashLength*8, zrtpSession);

        // perform  generation according to chapter 5.5 and 8.
        // we don't need a speciai sasValue filed. sasValue are the first
        // (leftmost) 32 bits (4 bytes) of sasHash
        uint8_t sasBytes[4];
        KDF(s0, hashLength, (unsigned char*)sasString, strlen(sasString)+1, KDFcontext, kdfSize, SHA256_DIGEST_LENGTH*8, sasHash);

        // according to chapter 8 only the leftmost 20 bits of sasValue (aka
        //  sasHash) are used to create the character SAS string of type SAS
        // base 32 (5 bits per character)
        sasBytes[0] = sasHash[0];
        sasBytes[1] = sasHash[1];
        sasBytes[2] = sasHash[2] & 0xf0;
        sasBytes[3] = 0;
        if (*(int32_t*)b32 == *(int32_t*)(sasType->getName())) {
            SAS = Base32(sasBytes, 20).getEncoded();
        }
        else {
            SAS.assign(sas256WordsEven[sasBytes[0]]).append(":").append(sas256WordsOdd[sasBytes[1]]);
        }

        if (signSasSeen)
            callback->signSAS(sasHash);

        detailInfo.pubKey = pubKey->getReadable();
        detailInfo.sasType = sasType->getReadable();
    }
    // set algorithm names into detailInfo structure
    detailInfo.authLength = authLength->getReadable();
    detailInfo.cipher = cipher->getReadable();
    detailInfo.hash = hash->getReadable();

    memset(KDFcontext, 0, sizeof(KDFcontext));
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evAckDetected(void) {

    DEBUGOUT((cout << "Checking for match in AckDetected.\n"));

    char *msg, first, last;
    uint8_t *pkt;
    uint32_t errorCode = 0;

    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));

#if 1
        /*
         * Implementation for choice 1)
         * Hello:
         * - Acknowledge peer's Hello, sending HelloACK (F4)
         * - switch to state WaitCommit, wait for peer's Commit
         * - we are going to be in the Responder role
         */

        if (first == 'h' && last ==' ') {
            // Parse Hello packet and build an own Commit packet even if the
            // Commit is not send to the peer. We need to do this to check the
            // Hello packet and prepare the shared secret stuff.
            ZrtpPacketHello hpkt(pkt);
            ZrtpPacketCommit* commit = parent->prepareCommit(&hpkt, &errorCode);

            // Something went wrong during processing of the Hello packet, for
            // example wrong version, duplicate ZID.
            if (commit == NULL) {
                sendErrorPacket(errorCode);
                return;
            }
            ZrtpPacketHelloAck *helloAck = parent->prepareHelloAck();
            nextState(WaitCommit);

            // remember packet for easy resend
            sentPacket = static_cast<ZrtpPacketBase *>(helloAck);
            if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(helloAck))) {
                sendFailed();
            }
        }
#else
        /*
         * Implementation for choice 2)
         * Hello:
         * - Acknowledge peer's Hello by sending Commit (F5)
         *   instead of HelloAck (F4)
         * - switch to state CommitSent
         * - Initiator role, thus start timer T2 to monitor timeout for Commit
         */

        if (first == 'h' && last == ' ') {
            // Parse peer's packet data into a Hello packet
            ZrtpPacketHello hpkt(pkt);
            ZrtpPacketCommit* commit = parent->prepareCommit(&hpkt, &errorCode);
            // Something went wrong during processing of the Hello packet  
            if (commit == NULL) {
                sendErrorPacket(errorCode);
                return;
            }
            nextState(CommitSent);

            // remember packet for easy resend in case timer triggers
            // Timer trigger received in new state CommitSend
            sentPacket = static_cast<ZrtpPacketBase *>(commit);
            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();
                return;
            }
            if (startTimer(&T2) <= 0) {
                timerFailed(SevereNoTimer);
            }
        }
#endif
    }
    else {  // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        nextState(Initial);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketConf2Ack* ZRtp::prepareConf2Ack(ZrtpPacketConfirm *confirm2, uint32_t* errMsg) {

    sendInfo(Info, InfoRespConf2Received);

    uint8_t confMac[MAX_DIGEST_LENGTH];
    uint32_t macLen;

    // Use the Initiator's keys here because we are Responder here and
    // reveice packets from Initiator
    int16_t hmlen = (confirm2->getLength() - 9) * ZRTP_WORD_SIZE;

    // Use negotiated HMAC (hash)
    hmacFunction(hmacKeyI, hashLength,
                 (unsigned char*)confirm2->getHashH0(),
                 hmlen, confMac, &macLen);

    if (memcmp(confMac, confirm2->getHmac(), HMAC_SIZE) != 0) {
        *errMsg = ConfirmHMACWrong;
        return NULL;
    }
    // Cast away the const for the IV - the standalone AES CFB modifies IV on return
    cipher->getDecrypt()(zrtpKeyI, cipher->getKeylen(), (uint8_t*)confirm2->getIv(), confirm2->getHashH0(), hmlen);

    if (!multiStream) {
        // Check HMAC of DHPart2 packet stored in temporary buffer. The
        // HMAC key of the DHPart2 packet is peer's H0 that is contained in
        // Confirm2. Refer to chapter 9.1 and chapter 10.
        if (!checkMsgHmac(confirm2->getHashH0())) {
            sendInfo(Severe, SevereDH2HMACFailed);
            *errMsg = CriticalSWError;
            return NULL;
        }
        signatureLength = confirm2->getSignatureLength();
        if (signSasSeen && signatureLength > 0) {
            signatureData = confirm2->getSignatureData();
            callback->checkSASSignature(sasHash);
            // TODO: error handling if checkSASSignature returns false.
        }
        /*
        * The Confirm2 is ok, handle the Retained secret stuff and inform
        * GUI about state.
        */
        bool sasFlag = confirm2->isSASFlag();
        // Our peer did not confirm the SAS in last session, thus reset
        // our SAS flag too. Reset the flag also if paranoidMode is true.
        if (!sasFlag || paranoidMode) {
            zidRec->resetSasVerified();
        }

        // save new RS1, this inherits the verified flag from old RS1
        zidRec->setNewRs1((const uint8_t*)newRs1);
        getZidCacheInstance()->saveRecord(zidRec);

        // Ask for enrollment only if enabled via configuration and the
        // confirm packet contains the enrollment flag. The enrolling user
        // agent stores the MitM key only if the user accepts the enrollment
        // request.
        if (enableMitmEnrollment && confirm2->isPBXEnrollment()) {
            computePBXSecret();
            // As clarification to RFC6189: if already enrolled (having a matching PBX secret)
            // ask for reconfirmation.
            if (!peerIsEnrolled) {
                callback->zrtpAskEnrollment(EnrollmentRequest);
            }
            else {
                callback->zrtpAskEnrollment(EnrollmentReconfirm);
            }
        }
    }
    else {
        // Check HMAC of Commit packet stored in temporary buffer. The
        // HMAC key of the Commit packet is initiator's H1
        // use implicit hash function.
        uint8_t tmpHash[IMPL_MAX_DIGEST_LENGTH];
        hashFunctionImpl(confirm2->getHashH0(), HASH_IMAGE_SIZE, tmpHash); // Compute initiator's H1 in tmpHash

        if (!checkMsgHmac(tmpHash)) {
            sendInfo(Severe, SevereCommitHMACFailed);
            *errMsg = CriticalSWError;
            return NULL;
        }
    }
    return &zrtpConf2Ack;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::zrtpNegotiationFailed(MessageSeverity severity, int32_t subCode) {
    if (zrtpUserCallback != NULL) {
        zrtpUserCallback->zrtpNegotiationFailed(severity, subCode);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

std::string ZrtpQueue::getSasType() {
    if (zrtpEngine != NULL)
        return zrtpEngine->getSasType();
    else
        return NULL;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::generateKeysInitiator(ZrtpPacketDHPart *dhPart, ZIDRecord *zidRec) {
    const uint8_t* setD[3];
    int32_t rsFound = 0;

    setD[0] = setD[1] = setD[2] = NULL;

    detailInfo.secretsMatchedDH = 0;
    if (memcmp(rs1IDr, dhPart->getRs1Id(), HMAC_SIZE) == 0 || memcmp(rs1IDr, dhPart->getRs2Id(), HMAC_SIZE) == 0)
        detailInfo.secretsMatchedDH |= Rs1;
    if (memcmp(rs2IDr, dhPart->getRs1Id(), HMAC_SIZE) == 0 || memcmp(rs2IDr, dhPart->getRs2Id(), HMAC_SIZE) == 0)
        detailInfo.secretsMatchedDH |= Rs2;
    /*
     * Select the real secrets into setD. The dhPart is DHpart1 message
     * received from responder. rs1IDr and rs2IDr are the expected ids using
     * the initator's cached retained secrets.
     */
    // Check which RS we shall use for first place (s1)
    detailInfo.secretsMatched = 0;
    if (memcmp(rs1IDr, dhPart->getRs1Id(), HMAC_SIZE) == 0) {
        setD[0] = zidRec->getRs1();
        rsFound = 0x1;
        detailInfo.secretsMatched = Rs1;
    }
    else if (memcmp(rs1IDr, dhPart->getRs2Id(), HMAC_SIZE) == 0) {
        setD[0] = zidRec->getRs1();
        rsFound = 0x2;
        detailInfo.secretsMatched = Rs1;
    }
    else if (memcmp(rs2IDr, dhPart->getRs1Id(), HMAC_SIZE) == 0) {
        setD[0] = zidRec->getRs2();
        rsFound = 0x4;
        detailInfo.secretsMatched = Rs2;
    }
    else if (memcmp(rs2IDr, dhPart->getRs2Id(), HMAC_SIZE) == 0) {
        setD[0] = zidRec->getRs2();
        rsFound = 0x8;
        detailInfo.secretsMatched = Rs2;
    }
    /* *** Not yet supported
    if (memcmp(auxSecretIDr, dhPart->getAuxSecretId(), 8) == 0) {
    DEBUGOUT((fprintf(stdout, "%c: Match for aux secret found\n", zid[0])));
        setD[1] = auxSecret;
    }
    */
    // check if we have a matching PBX secret and place it third (s3)
    if (memcmp(pbxSecretIDr, dhPart->getPbxSecretId(), HMAC_SIZE) == 0) {
        DEBUGOUT((fprintf(stdout, "%c: Match for Other_secret found\n", zid[0])));
        setD[2] = zidRec->getMiTMData();
        detailInfo.secretsMatched |= Pbx;
        detailInfo.secretsMatchedDH |= Pbx;
        // Flag to record that fact that we have a MitM key of the other peer.
        peerIsEnrolled = true;
    }
    // Check if some retained secrets found
    if (rsFound == 0) {                        // no RS matches found
        if (rs1Valid || rs2Valid) {            // but valid RS records in cache
            sendInfo(Warning, WarningNoExpectedRSMatch);
            zidRec->resetSasVerified();
        }
        else {                                 // No valid RS record in cache
            sendInfo(Warning, WarningNoRSMatch);
        }
    }
    else {                                     // at least one RS matches
        sendInfo(Info, InfoRSMatchFound);
    }
    /*
     * Ready to generate s0 here.
     * The formular to compute S0 (Refer to ZRTP specification 5.4.4):
     *
      s0 = hash( counter | DHResult | "ZRTP-HMAC-KDF" | ZIDi | ZIDr | \
      total_hash | len(s1) | s1 | len(s2) | s2 | len(s3) | s3)
     *
     * Note: in this function we are Initiator, thus ZIDi is our zid
     * (zid), ZIDr is the peer's zid (peerZid).
     */

    /*
     * These arrays hold the pointers and lengths of the data that must be
     * hashed to create S0.  According to the formula the max number of
     * elements to hash is 12, add one for the terminating "NULL"
     */
    unsigned char* data[13];
    unsigned int   length[13];
    uint32_t pos = 0;                  // index into the array

    // we need a number of length data items, so define them here
    uint32_t counter, sLen[3];

    //Very first element is a fixed counter, big endian
    counter = 1;
    counter = zrtpHtonl(counter);
    data[pos] = (unsigned char*)&counter;
    length[pos++] = sizeof(uint32_t);

    // Next is the DH result itself
    data[pos] = DHss;
    length[pos++] = dhContext->getDhSize();

    // Next the fixed string "ZRTP-HMAC-KDF"
    data[pos] = (unsigned char*)KDFString;
    length[pos++] = strlen(KDFString);

    // Next is Initiator's id (ZIDi), in this case as Initiator
    // it is zid
    data[pos] = ownZid;
    length[pos++] = ZID_SIZE;

    // Next is Responder's id (ZIDr), in this case our peer's id
    data[pos] = peerZid;
    length[pos++] = ZID_SIZE;

    // Next ist total hash (messageHash) itself
    data[pos] = messageHash;
    length[pos++] = hashLength;

    /*
     * For each matching shared secret hash the length of
     * the shared secret as 32 bit big-endian number followd by the
     * shared secret itself. The length of a shared seceret is
     * currently fixed to RS_LENGTH. If a shared
     * secret is not used _only_ its length is hased as zero
     * length. NOTE: if implementing auxSecret and/or pbxSecret -> check
     * this length stuff again.
     */
    int secretHashLen = RS_LENGTH;
    secretHashLen = zrtpHtonl(secretHashLen);        // prepare 32 bit big-endian number

    for (int32_t i = 0; i < 3; i++) {
        if (setD[i] != NULL) {           // a matching secret, set length, then secret
            sLen[i] = secretHashLen;
            data[pos] = (unsigned char*)&sLen[i];
            length[pos++] = sizeof(uint32_t);
            data[pos] = (unsigned char*)setD[i];
            length[pos++] = RS_LENGTH;
        }
        else {                           // no machting secret, set length 0, skip secret
            sLen[i] = 0;
            data[pos] = (unsigned char*)&sLen[i];
            length[pos++] = sizeof(uint32_t);
        }
    }

    data[pos] = NULL;
    hashListFunction(data, length, s0);
//  hexdump("S0 I", s0, hashLength);

    memset(DHss, 0, dhContext->getDhSize());
    delete[] DHss;
    DHss = NULL;

    computeSRTPKeys();
    memset(s0, 0, MAX_DIGEST_LENGTH);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::setEnrollmentMode(bool enrollmentMode) {
    if (zrtpEngine != NULL)
        zrtpEngine->setEnrollmentMode(enrollmentMode);
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::setRs2Valid() {

    if (zidRec != NULL) {
        zidRec->setRs2Valid();
        getZidCacheInstance()->saveRecord(zidRec);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

const uint8_t* ZRtp::getSignatureData() {
    return signatureData;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::storeMsgTemp(ZrtpPacketBase* pkt) {
    uint32_t length = pkt->getLength() * ZRTP_WORD_SIZE;
    length = (length > sizeof(tempMsgBuffer)) ? sizeof(tempMsgBuffer) : length;
    memset(tempMsgBuffer, 0, sizeof(tempMsgBuffer));
    memcpy(tempMsgBuffer, (uint8_t*)pkt->getHeaderBase(), length);
    lengthOfMsgData = length;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

int32_t ZrtpStateClass::startTimer(zrtpTimer_t *t) {

    t->time = t->start;
    t->counter = 0;
    return parent->activateTimer(t->time);
}

Project: ZRTPCPP
File: ZrtpPacketHello.cpp

ZrtpPacketHello::ZrtpPacketHello() {
    DEBUGOUT((fprintf(stdout, "Creating Hello packet without data\n")));
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::setUserCallback(ZrtpUserCallback* ucb) {
    zrtpUserCallback = ucb;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

IncomingZRTPPkt::IncomingZRTPPkt(const unsigned char* const block, size_t len) :
        IncomingRTPPkt(block,len) {
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::setMultiStrParams(std::string parameters) {

    char tmp[MAX_DIGEST_LENGTH + 1 + 1 + 1]; // max. hash length + cipher + authLength + hash

    // First get negotiated hash from parameters, set algorithms and length
    int i = parameters.at(0) & 0xff;
    hash = &zrtpHashes.getByOrdinal(i);
    setNegotiatedHash(hash);           // sets hashlength

    // use string.copy(buffer, num, start=0) to retrieve chars (bytes) from the string
    parameters.copy(tmp, hashLength + 1 + 1 + 1, 0);

    i = tmp[1] & 0xff;
    authLength = &zrtpAuthLengths.getByOrdinal(i);
    i = tmp[2] & 0xff;
    cipher = &zrtpSymCiphers.getByOrdinal(i);
    memcpy(zrtpSession, tmp+3, hashLength);

    // after setting zrtpSession, cipher, and auth-length set multi-stream to true
    multiStream = true;
    stateEngine->setMultiStream(true);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::isEnrollmentMode() {
    if (zrtpEngine != NULL)
        return zrtpEngine->isEnrollmentMode();
    else
        return false;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

bool ZrtpStateClass::subEvWaitRelayAck() {
    char *msg, first, last;
    uint8_t* pkt;

    /*
     * First check the general event type, then discrimnate the real event.
     */
    if  (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));

        /*
         * SAS relayAck:
         * - stop resending SASRelay,
         * - switch to secure substate Normal
         */
        if (first == 'r' && last =='k') {
            cancelTimer();
            secSubstate = Normal;
            sentPacket = NULL;
        }
        return true;
    }
    // Timer event triggered - this is Timer T2 to resend Error.
    else if (event->type == Timer) {
        if (!parent->sendPacketZRTP(sentPacket)) {
            sendFailed(); // returns to state Initial
            return false;
        }
        if (nextTimer(&T2) <= 0) {
            // returns to state initial
            // timerFailed(ZrtpCodes.SevereCodes.SevereTooMuchRetries);
            return false;
        }
        return true;
    }
    return false;
}

Project: ZRTPCPP
File: ZRtp.cpp

std::string ZRtp::getMultiStrParams() {

    // the string will hold binary data - it's opaque to the application
    std::string str("");
    char tmp[MAX_DIGEST_LENGTH + 1 + 1 + 1]; // hash length + cipher + authLength + hash

    if (inState(SecureState) && !multiStream) {
        // construct array that holds zrtpSession, cipher type, auth-length, and hash type
        tmp[0] = zrtpHashes.getOrdinal(*hash);
        tmp[1] = zrtpAuthLengths.getOrdinal(*authLength);
        tmp[2] = zrtpSymCiphers.getOrdinal(*cipher);
        memcpy(tmp+3, zrtpSession, hashLength);
        str.assign(tmp, hashLength + 1 + 1 + 1); // set chars (bytes) to the string
    }
    return str;
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::isMultiStreamAvailable() {
    return multiStreamAvailable;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::resetSASVerified() {

    zidRec->resetSasVerified();
    getZidCacheInstance()->saveRecord(zidRec);
}

Project: ZRTPCPP
File: ZRtp.cpp

AlgorithmEnum* ZRtp::findBestAuthLen(ZrtpPacketHello *hello) {

    int  i;
    int ii;
    int numAlgosOffered;
    AlgorithmEnum* algosOffered[ZrtpConfigure::maxNoOfAlgos+2];

    int numAlgosConf;
    AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+2];

    int num = hello->getNumAuth();
    if (num == 0) {
        return &zrtpAuthLengths.getByName(mandatoryAuthLen_1);
    }

    // Build list of configured Authentication tag length algorithm names.
    numAlgosConf = configureAlgos.getNumConfiguredAlgos(AuthLength);
    for (i = 0; i < numAlgosConf; i++) {
        algosConf[i] = &configureAlgos.getAlgoAt(AuthLength, i);
    }

    // Build list of offered known algos in Hello.
    for (numAlgosOffered = 0, i = 0; i < num; i++) {
        algosOffered[numAlgosOffered] = &zrtpAuthLengths.getByName((const char*)hello->getAuthLen(i));
        if (!algosOffered[numAlgosOffered]->isValid())
            continue;
        numAlgosOffered++;
    }

    // Lookup offered algos in configured algos. Prefer algorithms that appear first in Hello packet (offered).
    for (i = 0; i < numAlgosOffered; i++) {
        for (ii = 0; ii < numAlgosConf; ii++) {
            if (*(int32_t*)(algosOffered[i]->getName()) == *(int32_t*)(algosConf[ii]->getName())) {
                return algosConf[ii];
            }
        }
    }
    // If we don't have a match - use the mandatory algorithm
    return &zrtpAuthLengths.getByName(mandatoryAuthLen_1);
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::handleGoClear(uint8_t *message)
{
    char *msg, first, last;

    msg = (char *)message + 4;
    first = tolower(*msg);
    last = tolower(*(msg+6));

    if (first == 'g' && last == 'r') {
        Event_t ev;

        ev.type = ZrtpGoClear;
        ev.packet = message;
        if (stateEngine != NULL) {
            stateEngine->processEvent(&ev);
        }
        return true;
    }
    else {
        return false;
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

int32_t ZRtp::sendPacketZRTP(ZrtpPacketBase *packet) {
    return ((packet == NULL) ? 0 :
            callback->sendDataZRTP(packet->getHeaderBase(), (packet->getLength() * 4) + 4));
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

ZrtpStateClass::~ZrtpStateClass(void) {

    // If not in Initial state: close the protocol engine
    // before destroying it. This will free pending packets
    // if necessary.
    if (!inState(Initial)) {
        Event_t ev;

        cancelTimer();
        ev.type = ZrtpClose;
        event = &ev;
        engine->processEvent(*this);
    }
    delete engine;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evWaitCommit(void) {

    DEBUGOUT((cout << "Checking for match in WaitCommit.\n"));

    char *msg, first, last;
    uint8_t *pkt;
    uint32_t errorCode = 0;

    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));
        /*
         * Hello:
         * - resend HelloAck
         * - stay in WaitCommit
         */
        if (first == 'h' && last == ' ') {
            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();       // returns to state Initial
            }
            return;
        }
        /*
         * Commit:
         * - prepare DH1Part packet or Confirm1 if multi stream mode
         * - send it to peer
         * - switch state to WaitDHPart2 or WaitConfirm2 if multi stream mode
         * - don't start timer, we are responder
         */
        if (first == 'c' && last == ' ') {
            ZrtpPacketCommit cpkt(pkt);

            if (!multiStream) {
                ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(&cpkt, &errorCode);

                // Something went wrong during processing of the Commit packet
                if (dhPart1 == NULL) {
                    if (errorCode != IgnorePacket) {
                        sendErrorPacket(errorCode);
                    }
                    return;
                }
                sentPacket = static_cast<ZrtpPacketBase *>(dhPart1);
                nextState(WaitDHPart2);
            }
            else {
                ZrtpPacketConfirm* confirm = parent->prepareConfirm1MultiStream(&cpkt, &errorCode);

                // Something went wrong during processing of the Commit packet
                if (confirm == NULL) {
                    if (errorCode != IgnorePacket) {
                        sendErrorPacket(errorCode);
                    }
                    return;
                }
                sentPacket = static_cast<ZrtpPacketBase *>(confirm);
                nextState(WaitConfirm2);
            }
            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();       // returns to state Initial
            }
        }
    }
    else {  // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        sentPacket = NULL;
        nextState(Initial);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketConfirm* ZRtp::prepareConfirm2(ZrtpPacketConfirm* confirm1, uint32_t* errMsg) {

    sendInfo(Info, InfoInitConf1Received);

    uint8_t confMac[MAX_DIGEST_LENGTH];
    uint32_t macLen;

    // Use the Responder's keys here because we are Initiator here and
    // receive packets from Responder
    int16_t hmlen = (confirm1->getLength() - 9) * ZRTP_WORD_SIZE;

    // Use negotiated HMAC (hash)
    hmacFunction(hmacKeyR, hashLength, (unsigned char*)confirm1->getHashH0(), hmlen, confMac, &macLen);

    if (memcmp(confMac, confirm1->getHmac(), HMAC_SIZE) != 0) {
        *errMsg = ConfirmHMACWrong;
        return NULL;
    }
    cipher->getDecrypt()(zrtpKeyR, cipher->getKeylen(), (uint8_t*)confirm1->getIv(), confirm1->getHashH0(), hmlen);

    // Check HMAC of DHPart1 packet stored in temporary buffer. The
    // HMAC key of the DHPart1 packet is peer's H0 that is contained in
    // Confirm1. Refer to chapter 9.
    if (!checkMsgHmac(confirm1->getHashH0())) {
        sendInfo(Severe, SevereDH1HMACFailed);
        *errMsg = CriticalSWError;
        return NULL;
    }
    signatureLength = confirm1->getSignatureLength();
    if (signSasSeen && signatureLength > 0) {
        signatureData = confirm1->getSignatureData();
        callback->checkSASSignature(sasHash);
        // TODO: error handling if checkSASSignature returns false.
    }
    /*
     * The Confirm1 is ok, handle the Retained secret stuff and inform
     * GUI about state.
     */
    bool sasFlag = confirm1->isSASFlag();

    // Our peer did not confirm the SAS in last session, thus reset
    // our SAS flag too. Reset the flag also if paranoidMode is true.
    if (!sasFlag || paranoidMode) {
        zidRec->resetSasVerified();
    }
    // get verified flag from current RS1 before set a new RS1. This
    // may not be set even if peer's flag is set in confirm1 message.
    sasFlag = zidRec->isSasVerified();

    // now we are ready to save the new RS1 which inherits the verified
    // flag from old RS1
    zidRec->setNewRs1((const uint8_t*)newRs1);

    // now generate my Confirm2 message
    zrtpConfirm2.setMessageType((uint8_t*)Confirm2Msg);
    zrtpConfirm2.setHashH0(H0);

    if (sasFlag) {
        zrtpConfirm2.setSASFlag();
    }
    zrtpConfirm2.setExpTime(0xFFFFFFFF);
    zrtpConfirm2.setIv(randomIV);

    // Compute PBX secret if we are in enrollemnt mode (PBX user agent)
    // or enrollment was enabled at normal user agent and flag in confirm packet
    if (enrollmentMode || (enableMitmEnrollment && confirm1->isPBXEnrollment())) {
        computePBXSecret();

        // if this runs at PBX user agent enrollment service then set flag in confirm
        // packet and store the MitM key. The PBX user agent service always stores
        // its MitM key.
        if (enrollmentMode) {
            // As clarification to RFC6189: store new PBX secret only if we don't have
            // a matching PBX secret for the peer's ZID.
            if (!peerIsEnrolled) {
                computePBXSecret();
                zidRec->setMiTMData(pbxSecretTmp);
            }
            // Set flag to enable user's client to ask for confirmation or re-confirmation.
            zrtpConfirm2.setPBXEnrollment();
        }
    }
    getZidCacheInstance()->saveRecord(zidRec);

    // Encrypt and HMAC with Initiator's key - we are Initiator here
    hmlen = (zrtpConfirm2.getLength() - 9) * ZRTP_WORD_SIZE;
    cipher->getEncrypt()(zrtpKeyI, cipher->getKeylen(), randomIV, zrtpConfirm2.getHashH0(), hmlen);

    // Use negotiated HMAC (hash)
    hmacFunction(hmacKeyI, hashLength, (unsigned char*)zrtpConfirm2.getHashH0(), hmlen, confMac, &macLen);

    zrtpConfirm2.setHmac(confMac);

    // Ask for enrollment only if enabled via configuration and the
    // confirm1 packet contains the enrollment flag. The enrolling user
    // agent stores the MitM key only if the user accepts the enrollment
    // request.
    if (enableMitmEnrollment && confirm1->isPBXEnrollment()) {
        // As clarification to RFC6189: if already enrolled (having a matching PBX secret)
        // ask for reconfirmation.
        if (!peerIsEnrolled) {
            callback->zrtpAskEnrollment(EnrollmentRequest);
        }
        else {
            callback->zrtpAskEnrollment(EnrollmentReconfirm);
        }
    }
    return &zrtpConfirm2;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::isMitmMode() {
    return mitmMode;
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketRelayAck* ZRtp::prepareRelayAck(ZrtpPacketSASrelay* srly, uint32_t* errMsg) {
    // handle and render SAS relay data only if the peer announced that it is a trusted
    // PBX. Don't handle SAS relay in paranoidMode.
    if (!mitmSeen || paranoidMode)
        return &zrtpRelayAck;

    uint8_t* hkey, *ekey;
    // If we are responder then the PBX used it's Initiator keys
    if (myRole == Responder) {
        hkey = hmacKeyI;
        ekey = zrtpKeyI;
    }
    else {
        hkey = hmacKeyR;
        ekey = zrtpKeyR;
    }

    uint8_t confMac[MAX_DIGEST_LENGTH];
    uint32_t macLen;

    int16_t hmlen = (srly->getLength() - 9) * ZRTP_WORD_SIZE;

    // Use negotiated HMAC (hash)
    hmacFunction(hkey, hashLength, (unsigned char*)srly->getFiller(), hmlen, confMac, &macLen);

    if (memcmp(confMac, srly->getHmac(), HMAC_SIZE) != 0) {
        *errMsg = ConfirmHMACWrong;
        return NULL;                // TODO - check error handling
    }
    // Cast away the const for the IV - the standalone AES CFB modifies IV on return
    cipher->getDecrypt()(ekey, cipher->getKeylen(), (uint8_t*)srly->getIv(), (uint8_t*)srly->getFiller(), hmlen);

    const uint8_t* newSasHash = srly->getTrustedSas();
    bool sasHashNull = true;
    for (int i = 0; i < HASH_IMAGE_SIZE; i++) {
        if (newSasHash[i] != 0) {
            sasHashNull = false;
            break;
        }
    }
    std::string cs(cipher->getReadable());
    cs.append("/").append(pubKey->getName());

    // Check if new SAS is null or a trusted MitM relationship doesn't exist.
    // If this is the case then don't render and don't show the new SAS - use
    // our computed SAS hash but we may use a different SAS rendering algorithm to
    // render the computed SAS.
    if (sasHashNull || !peerIsEnrolled) {
        cs.append("/MitM");
        newSasHash = sasHash;
    }
    else {
        cs.append("/SASviaMitM");
    }
    // If other SAS schemes required - check here and use others
    const uint8_t* render = srly->getSasAlgo();
    AlgorithmEnum* renderAlgo = &zrtpSasTypes.getByName((const char*)render);
    uint8_t sasBytes[4];
    if (renderAlgo->isValid()) {
        sasBytes[0] = newSasHash[0];
        sasBytes[1] = newSasHash[1];
        sasBytes[2] = newSasHash[2] & 0xf0;
        sasBytes[3] = 0;
        if (*(int32_t*)b32 == *(int32_t*)(renderAlgo->getName())) {
            SAS = Base32(sasBytes, 20).getEncoded();
        }
        else {
            SAS.assign(sas256WordsEven[sasBytes[0]]).append(":").append(sas256WordsOdd[sasBytes[1]]);
        }
    }
    bool verify = zidRec->isSasVerified() && srly->isSASFlag();
    callback->srtpSecretsOn(cs, SAS, verify);
    return &zrtpRelayAck;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::generateKeysResponder(ZrtpPacketDHPart *dhPart, ZIDRecord *zidRec) {
    const uint8_t* setD[3];
    int32_t rsFound = 0;

    setD[0] = setD[1] = setD[2] = NULL;

    detailInfo.secretsMatchedDH = 0;
    if (memcmp(rs1IDi, dhPart->getRs1Id(), HMAC_SIZE) == 0 || memcmp(rs1IDi, dhPart->getRs2Id(), HMAC_SIZE) == 0)
        detailInfo.secretsMatchedDH |= Rs1;
    if (memcmp(rs2IDi, dhPart->getRs1Id(), HMAC_SIZE) == 0 || memcmp(rs2IDi, dhPart->getRs2Id(), HMAC_SIZE) == 0)
        detailInfo.secretsMatchedDH |= Rs2;

    /*
     * Select the real secrets into setD
     */
    // Check which RS we shall use for first place (s1)
    detailInfo.secretsMatched = 0;
    if (memcmp(rs1IDi, dhPart->getRs1Id(), HMAC_SIZE) == 0) {
        setD[0] = zidRec->getRs1();
        rsFound = 0x1;
        detailInfo.secretsMatched = Rs1;
    }
    else if (memcmp(rs1IDi, dhPart->getRs2Id(), HMAC_SIZE) == 0) {
        setD[0] = zidRec->getRs1();
        rsFound = 0x2;
        detailInfo.secretsMatched = Rs1;
    }
    else if (memcmp(rs2IDi, dhPart->getRs1Id(), HMAC_SIZE) == 0) {
        setD[0] = zidRec->getRs2();
        rsFound |= 0x4;
        detailInfo.secretsMatched = Rs2;
    }
    else if (memcmp(rs2IDi, dhPart->getRs2Id(), HMAC_SIZE) == 0) {
        setD[0] = zidRec->getRs2();
        rsFound |= 0x8;
        detailInfo.secretsMatched = Rs2;
    }
    /* ***** not yet supported
    if (memcmp(auxSecretIDi, dhPart->getauxSecretId(), 8) == 0) {
    DEBUGOUT((fprintf(stdout, "%c: Match for aux secret found\n", ownZidzid[0])));
        setD[1] = ;
    }
    */

    if (memcmp(pbxSecretIDi, dhPart->getPbxSecretId(), 8) == 0) {
        DEBUGOUT((fprintf(stdout, "%c: Match for PBX secret found\n", ownZid[0])));
        setD[2] = zidRec->getMiTMData();
        detailInfo.secretsMatched |= Pbx;
        detailInfo.secretsMatchedDH |= Pbx;
        peerIsEnrolled = true;
    }
    // Check if some retained secrets found
    if (rsFound == 0) {                        // no RS matches found
        if (rs1Valid || rs2Valid) {            // but valid RS records in cache
            sendInfo(Warning, WarningNoExpectedRSMatch);
            zidRec->resetSasVerified();
        }
        else {                                 // No valid RS record in cache
            sendInfo(Warning, WarningNoRSMatch);
        }
    }
    else {                                     // at least one RS matches
        sendInfo(Info, InfoRSMatchFound);
    }

    /*
     * ready to generate s0 here.
     * The formular to compute S0 (Refer to ZRTP specification 5.4.4):
     *
      s0 = hash( counter | DHResult | "ZRTP-HMAC-KDF" | ZIDi | ZIDr | \
      total_hash | len(s1) | s1 | len(s2) | s2 | len(s3) | s3)
     *
     * Note: in this function we are Responder, thus ZIDi is the peer's zid
     * (peerZid), ZIDr is our zid.
     */

    /*
     * These arrays hold the pointers and lengths of the data that must be
     * hashed to create S0.  According to the formula the max number of
     * elements to hash is 12, add one for the terminating "NULL"
     */
    unsigned char* data[13];
    unsigned int   length[13];
    uint32_t pos = 0;                  // index into the array


    // we need a number of length data items, so define them here
    uint32_t counter, sLen[3];

    //Very first element is a fixed counter, big endian
    counter = 1;
    counter = zrtpHtonl(counter);
    data[pos] = (unsigned char*)&counter;
    length[pos++] = sizeof(uint32_t);

    // Next is the DH result itself
    data[pos] = DHss;
    length[pos++] = dhContext->getDhSize();

    // Next the fixed string "ZRTP-HMAC-KDF"
    data[pos] = (unsigned char*)KDFString;
    length[pos++] = strlen(KDFString);

    // Next is Initiator's id (ZIDi), in this case as Responder
    // it is peerZid
    data[pos] = peerZid;
    length[pos++] = ZID_SIZE;

    // Next is Responder's id (ZIDr), in this case our own zid
    data[pos] = ownZid;
    length[pos++] = ZID_SIZE;

    // Next ist total hash (messageHash) itself
    data[pos] = messageHash;
    length[pos++] = hashLength;

    /*
     * For each matching shared secret hash the length of
     * the shared secret as 32 bit big-endian number followd by the
     * shared secret itself. The length of a shared seceret is
     * currently fixed to SHA256_DIGEST_LENGTH. If a shared
     * secret is not used _only_ its length is hased as zero
     * length. NOTE: if implementing auxSecret and/or pbxSecret -> check
     * this length stuff again.
     */
    int secretHashLen = RS_LENGTH;
    secretHashLen = zrtpHtonl(secretHashLen);        // prepare 32 bit big-endian number

    for (int32_t i = 0; i < 3; i++) {
        if (setD[i] != NULL) {           // a matching secret, set length, then secret
            sLen[i] = secretHashLen;
            data[pos] = (unsigned char*)&sLen[i];
            length[pos++] = sizeof(uint32_t);
            data[pos] = (unsigned char*)setD[i];
            length[pos++] = RS_LENGTH;
        }
        else {                           // no machting secret, set length 0, skip secret
            sLen[i] = 0;
            data[pos] = (unsigned char*)&sLen[i];
            length[pos++] = sizeof(uint32_t);
        }
    }

    data[pos] = NULL;
    hashListFunction(data, length, s0);
//  hexdump("S0 R", s0, hashLength);

    memset(DHss, 0, dhContext->getDhSize());
    delete[] DHss;
    DHss = NULL;

    computeSRTPKeys();
    memset(s0, 0, MAX_DIGEST_LENGTH);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::zrtpInformEnrollment(GnuZrtpCodes::InfoEnrollment  info) {
    if (zrtpUserCallback != NULL) {
        zrtpUserCallback->zrtpInformEnrollment(info);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::conf2AckSecure() {
    Event_t ev;

    ev.type = ZrtpPacket;
    ev.packet = (uint8_t*)zrtpConf2Ack.getHeaderBase();
    ev.length = sizeof (Conf2AckPacket_t) + 12;  // 12 is fixed ZRTP (RTP) header size

    if (stateEngine != NULL) {
        stateEngine->processEvent(&ev);
    }
}

Project: ZRTPCPP
File: ZrtpPacketHello.cpp

int32_t ZrtpPacketHello::getVersionInt() {
    uint8_t* vp = getVersion();
    int32_t version = 0;

    if (isdigit(*vp) && isdigit(*vp+2)) {
        version = (*vp - '0') * 10;
        version += *(vp+2) - '0';
    }
    return version;
}

Project: ZRTPCPP
File: ZRtp.cpp

int32_t ZRtp::getPeerZid(uint8_t* data) {
    memcpy(data, peerZid, IDENTIFIER_LEN);
    return IDENTIFIER_LEN;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evDetect(void) {

    DEBUGOUT((cout << "Checking for match in Detect.\n"));

    char *msg, first, last;
    uint8_t *pkt;
    uint32_t errorCode = 0;

    /*
     * First check the general event type, then discrimnate
     * the real event.
     */
    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));
        /*
         * HelloAck:
         * - our peer acknowledged our Hello packet, we have not seen the peer's Hello yet
         * - cancel timer T1 to stop resending Hello
         * - switch to state AckDetected, wait for peer's Hello (F3)
         * 
         * When we receive an HelloAck this also means that out partner accepted our protocol version.
         */
        if (first == 'h' && last =='k') {
            cancelTimer();
            sentPacket = NULL;
            nextState(AckDetected);
            return;
        }
        /*
         * Hello:
         * - send HelloAck packet to acknowledge the received Hello packet if versions match.
         *   Otherweise negotiate ZRTP versions.
         * - use received Hello packet to prepare own Commit packet. We need to
         *   do it at this point because we need the hash value computed from
         *   peer's Hello packet. Follwing states my use the prepared Commit.
         * - switch to new state AckSent which sends own Hello packet until 
         *   peer acknowledges this
         * - Don't clear sentPacket, points to Hello
         */
        if (first == 'h' && last ==' ') {
            ZrtpPacketHello hpkt(pkt);

            cancelTimer();

            /*
             * Check and negotiate the ZRTP protocol version first.
             *
             * This selection mechanism relies on the fact that we sent the highest supported protocol version in
             * the initial Hello packet with as stated in RFC6189, section 4.1.1
             */
            int32_t recvVersion = hpkt.getVersionInt();
            if (recvVersion > sentVersion) {   // We don't support this version, stay in state with timer active
                if (startTimer(&T1) <= 0) {
                    timerFailed(SevereNoTimer);      // returns to state Initial
                }
                return;
            }

            /*
             * The versions don't match. Start negotiating versions. This negotiation stays in the Detect state.
             * Only if the received version matches our own sent version we start to send a HelloAck.
             */
            if (recvVersion != sentVersion) {
                ZRtp::HelloPacketVersion* hpv = parent->helloPackets;

                int32_t index;
                for (index = 0; hpv->packet && hpv->packet != parent->currentHelloPacket; hpv++, index++)   // Find current sent Hello
                    ;

                for(; index >= 0 && hpv->version > recvVersion; hpv--, index--)   // find a supported version less-equal to received version
                    ;

                if (index < 0) {
                    sendErrorPacket(UnsuppZRTPVersion);
                    return;
                }
                parent->currentHelloPacket = hpv->packet;
                sentVersion = parent->currentHelloPacket->getVersionInt();

                // remember packet for easy resend in case timer triggers
                sentPacket = static_cast<ZrtpPacketBase *>(parent->currentHelloPacket);

                if (!parent->sendPacketZRTP(sentPacket)) {
                    sendFailed();                 // returns to state Initial
                    return;
                }
                if (startTimer(&T1) <= 0) {
                    timerFailed(SevereNoTimer);      // returns to state Initial
                    return;
                }
                return;
            }
            ZrtpPacketHelloAck* helloAck = parent->prepareHelloAck();

            if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(helloAck))) {
                parent->zrtpNegotiationFailed(Severe, SevereCannotSend);
                return;
            }
            // Use peer's Hello packet to create my commit packet, store it 
            // for possible later usage in state AckSent
            commitPkt = parent->prepareCommit(&hpkt, &errorCode);

            nextState(AckSent);
            if (commitPkt == NULL) {
                sendErrorPacket(errorCode);    // switches to Error state
                return;
            }
            if (startTimer(&T1) <= 0) {        // restart own Hello timer/counter
                timerFailed(SevereNoTimer);    // returns to state Initial
            }
            T1.maxResend = 60;                 // more retries to extend time, see chap. 6
        }
        return;      // unknown packet for this state - Just ignore it
    }
    // Timer event triggered - this is Timer T1 to resend Hello
    else if (event->type == Timer) {
        if (!parent->sendPacketZRTP(sentPacket)) {
            sendFailed();       // returns to state Initial
            return;
        }
        if (nextTimer(&T1) <= 0) {
            commitPkt = NULL;
            parent->zrtpNotSuppOther();
            nextState(Detect);
        }
    }
    // If application calls zrtpStart() to restart discovery
    else if (event->type == ZrtpInitial) {
        cancelTimer();
        if (!parent->sendPacketZRTP(sentPacket)) {
            sendFailed();                 // returns to state Initial
            return;
        }
        if (startTimer(&T1) <= 0) {
            timerFailed(SevereNoTimer);   // returns to state Initial
        }
    }
    else { // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        sentPacket = NULL;
        nextState(Initial);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::checkSASSignature(uint8_t* sasHash) {
    if (zrtpUserCallback != NULL) {
        return zrtpUserCallback->checkSASSignature(sasHash);
    }
    return false;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::KDF(uint8_t* key, uint32_t keyLength, uint8_t* label, int32_t labelLength,
               uint8_t* context, int32_t contextLength, int32_t L, uint8_t* output) {

    unsigned char* data[6];
    uint32_t length[6];
    uint32_t pos = 0;                  // index into the array
    uint32_t maclen = 0;

    // Very first element is a fixed counter, big endian
    uint32_t counter = 1;
    counter = zrtpHtonl(counter);
    data[pos] = (unsigned char*)&counter;
    length[pos++] = sizeof(uint32_t);

    // Next element is the label, null terminated, labelLength includes null byte.
    data[pos] = label;
    length[pos++] = labelLength;

    // Next is the KDF context
    data[pos] = context;
    length[pos++] = contextLength;

    // last element is HMAC length in bits, big endian
    uint32_t len = zrtpHtonl(L);
    data[pos] = (unsigned char*)&len;
    length[pos++] = sizeof(uint32_t);

    data[pos] = NULL;

    // Use negotiated hash.
    hmacListFunction(key, keyLength, data, length, output, &maclen);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::SASVerified() {
    if (zrtpEngine != NULL)
        zrtpEngine->SASVerified();
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

uint8_t* ZrtpQueue::getSasHash() {
    if (zrtpEngine != NULL)
        return zrtpEngine->getSasHash();
    else
        return NULL;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evSecureState(void) {

    DEBUGOUT((cout << "Checking for match in SecureState.\n"));

    char *msg, first, last;
    uint8_t *pkt;

    /*
     * Handle a possible substate. If substate handling was ok just return.
     */
    if (secSubstate == WaitSasRelayAck) {
        if (subEvWaitRelayAck())
            return; 
    }

    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));

        /*
         * Confirm2:
         * - resend Conf2Ack packet
         * - stay in state
         */
        if (first == 'c' && last == '2') {
            if (sentPacket != NULL && !parent->sendPacketZRTP(sentPacket)) {
                sentPacket = NULL;
                nextState(Initial);
                parent->srtpSecretsOff(ForSender);
                parent->srtpSecretsOff(ForReceiver);
                parent->zrtpNegotiationFailed(Severe, SevereCannotSend);
            }
            return;
        }
        /*
         * GoClear received, handle it. TODO fix go clear handling
         *
        if (first == 'g' && last == 'r') {
            ZrtpPacketGoClear gpkt(pkt);
            ZrtpPacketClearAck* clearAck = parent->prepareClearAck(&gpkt);

            if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(clearAck))) {
                return;
            }
        // TODO Timeout to resend clear ack until user user confirmation
        }
        */
    }
    else if (event->type == Timer) {
        // Ignore stray timeout in this state
        ;
    }
    // unknown Event type for this state (covers Error and ZrtpClose)
    else  {
        // If in secure state ingnore error events to avoid Error packet injection
        // attack - found by Dmitry Monakhov (dmonakhov@openvz.org)
        if (event->type == ErrorPkt)
            return;
        sentPacket = NULL;
        parent->srtpSecretsOff(ForSender);
        parent->srtpSecretsOff(ForReceiver);
        nextState(Initial);
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        parent->sendInfo(Info, InfoSecureStateOff);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::checkMultiStream(ZrtpPacketHello *hello) {

    int  i;
    int num = hello->getNumPubKeys();

    // Multi Stream mode is mandatory, thus if nothing is offered then it is supported :-)
    if (num == 0) {
        return true;
    }
    for (i = 0; i < num; i++) {
        if (*(int32_t*)(hello->getPubKeyType(i)) == *(int32_t*)mult) {
            return true;
        }
    }
    return false;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

const uint8* ZrtpQueue::getSignatureData() {
    if (zrtpEngine != NULL)
        return zrtpEngine->getSignatureData();
    return 0;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

int32 ZrtpQueue::getSignatureLength() {
    if (zrtpEngine != NULL)
        return zrtpEngine->getSignatureLength();
    return 0;
}

Project: ZRTPCPP
File: ZRtp.cpp

int32_t ZRtp::getSignatureLength() {
    return signatureLength * ZRTP_WORD_SIZE;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::generateKeysMultiStream() {

    // allocate the maximum size, compute real size to use
    uint8_t KDFcontext[sizeof(peerZid)+sizeof(ownZid)+sizeof(messageHash)];
    int32_t kdfSize = sizeof(peerZid)+sizeof(ownZid)+hashLength;

    if (myRole == Responder) {
        memcpy(KDFcontext, peerZid, sizeof(peerZid));
        memcpy(KDFcontext+sizeof(peerZid), ownZid, sizeof(ownZid));
    }
    else {
        memcpy(KDFcontext, ownZid, sizeof(ownZid));
        memcpy(KDFcontext+sizeof(ownZid), peerZid, sizeof(peerZid));
    }
    memcpy(KDFcontext+sizeof(ownZid)+sizeof(peerZid), messageHash, hashLength);

    KDF(zrtpSession, hashLength, (unsigned char*)zrtpMsk, strlen(zrtpMsk)+1, KDFcontext, kdfSize, hashLength*8, s0);

    memset(KDFcontext, 0, sizeof(KDFcontext));

    computeSRTPKeys();
}

Project: ZRTPCPP
File: ZRtp.cpp

std::string ZRtp::getSasType() {
    std::string sasT(sasType->getName());
    return sasT;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp:: computeSharedSecretSet(ZIDRecord *zidRec) {

    /*
     * Compute the Initiator's and Reponder's retained shared secret Ids.
     * Use negotiated HMAC.
     */
    uint8_t randBuf[RS_LENGTH];
    uint32_t macLen;

    detailInfo.secretsCached = 0;
    if (!zidRec->isRs1Valid()) {
        randomZRTP(randBuf, RS_LENGTH);
        hmacFunction(randBuf, RS_LENGTH, (unsigned char*)initiator, strlen(initiator), rs1IDi, &macLen);
        hmacFunction(randBuf, RS_LENGTH, (unsigned char*)responder, strlen(responder), rs1IDr, &macLen);
    }
    else {
        rs1Valid = true;
        hmacFunction((unsigned char*)zidRec->getRs1(), RS_LENGTH, (unsigned char*)initiator, strlen(initiator), rs1IDi, &macLen);
        hmacFunction((unsigned char*)zidRec->getRs1(), RS_LENGTH, (unsigned char*)responder, strlen(responder), rs1IDr, &macLen);
        detailInfo.secretsCached = Rs1;
    }

    if (!zidRec->isRs2Valid()) {
        randomZRTP(randBuf, RS_LENGTH);
        hmacFunction(randBuf, RS_LENGTH, (unsigned char*)initiator, strlen(initiator), rs2IDi, &macLen);
        hmacFunction(randBuf, RS_LENGTH, (unsigned char*)responder, strlen(responder), rs2IDr, &macLen);
    }
    else {
        rs2Valid = true;
        hmacFunction((unsigned char*)zidRec->getRs2(), RS_LENGTH, (unsigned char*)initiator, strlen(initiator), rs2IDi, &macLen);
        hmacFunction((unsigned char*)zidRec->getRs2(), RS_LENGTH, (unsigned char*)responder, strlen(responder), rs2IDr, &macLen);
        detailInfo.secretsCached |= Rs2;
    }

    /*
    * For the time being we don't support this type of shared secrect. Could be
    * easily done: somebody sets some data into our ZRtp object, check it here
    * and use it. Otherwise use the random data.
    */
    randomZRTP(randBuf, RS_LENGTH);
    hmacFunction(randBuf, RS_LENGTH, (unsigned char*)initiator, strlen(initiator), auxSecretIDi, &macLen);
    hmacFunction(randBuf, RS_LENGTH, (unsigned char*)responder, strlen(responder), auxSecretIDr, &macLen);

    if (!zidRec->isMITMKeyAvailable()) {
        randomZRTP(randBuf, RS_LENGTH);
        hmacFunction(randBuf, RS_LENGTH, (unsigned char*)initiator, strlen(initiator), pbxSecretIDi, &macLen);
        hmacFunction(randBuf, RS_LENGTH, (unsigned char*)responder, strlen(responder), pbxSecretIDr, &macLen);

    }
    else {
        hmacFunction((unsigned char*)zidRec->getMiTMData(), RS_LENGTH, (unsigned char*)initiator, strlen(initiator), pbxSecretIDi, &macLen);
        hmacFunction((unsigned char*)zidRec->getMiTMData(), RS_LENGTH, (unsigned char*)responder, strlen(responder), pbxSecretIDr, &macLen);
        detailInfo.secretsCached |= Pbx;
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

int32_t ZrtpQueue::sendDataZRTP(const unsigned char *data, int32_t length) {

    OutgoingZRTPPkt* packet = new OutgoingZRTPPkt(data, length);

    packet->setSSRC(getLocalSSRC());

    packet->setSeqNum(senderZrtpSeqNo++);

    /*
     * Compute the ZRTP CRC over the full ZRTP packet. Thus include
     * the fixed packet header into the calculation.
     */
    uint16_t temp = packet->getRawPacketSize() - CRC_SIZE;
    uint8_t* pt = (uint8_t*)packet->getRawPacket();
    uint32_t crc = zrtpGenerateCksum(pt, temp);
    // convert and store CRC in crc field of ZRTP packet.
    crc = zrtpEndCksum(crc);

    // advance pointer to CRC storage
    pt += temp;
    *(uint32_t*)pt = htonl(crc);

    dispatchImmediate(packet);
    delete packet;

    return 1;
}

Project: ZRTPCPP
File: ZRtp.cpp

ZRtp::ZRtp(uint8_t *myZid, ZrtpCallback *cb, std::string id, ZrtpConfigure* config, bool mitmm, bool sasSignSupport):
        callback(cb), dhContext(NULL), DHss(NULL), auxSecret(NULL), auxSecretLength(0), rs1Valid(false),
        rs2Valid(false), msgShaContext(NULL), hash(NULL), cipher(NULL), pubKey(NULL), sasType(NULL), authLength(NULL),
        multiStream(false), multiStreamAvailable(false), peerIsEnrolled(false), mitmSeen(false), pbxSecretTmp(NULL),
        enrollmentMode(false), configureAlgos(*config), zidRec(NULL) {

    enableMitmEnrollment = config->isTrustedMitM();
    paranoidMode = config->isParanoidMode();

    // setup the implicit hash function pointers and length
    hashLengthImpl = SHA256_DIGEST_LENGTH;
    hashFunctionImpl = sha256;
    hashListFunctionImpl = sha256;

    hmacFunctionImpl = hmac_sha256;
    hmacListFunctionImpl = hmac_sha256;

    memcpy(ownZid, myZid, ZID_SIZE);        // save the ZID

    /*
     * Generate H0 as a random number (256 bits, 32 bytes) and then
     * the hash chain, refer to chapter 9. Use the implicit hash function.
     */
    randomZRTP(H0, HASH_IMAGE_SIZE);
    sha256(H0, HASH_IMAGE_SIZE, H1);        // hash H0 and generate H1
    sha256(H1, HASH_IMAGE_SIZE, H2);        // H2
    sha256(H2, HASH_IMAGE_SIZE, H3);        // H3

    // configure all supported Hello packet versions
    zrtpHello_11.configureHello(&configureAlgos);
    zrtpHello_11.setH3(H3);                    // set H3 in Hello, included in helloHash
    zrtpHello_11.setZid(ownZid);
    zrtpHello_11.setVersion((uint8_t*)zrtpVersion_11);


    zrtpHello_12.configureHello(&configureAlgos);
    zrtpHello_12.setH3(H3);                 // set H3 in Hello, included in helloHash
    zrtpHello_12.setZid(ownZid);
    zrtpHello_12.setVersion((uint8_t*)zrtpVersion_12);

    if (mitmm) {                            // this session acts for a trusted MitM (PBX)
        zrtpHello_11.setMitmMode();
        zrtpHello_12.setMitmMode();
    }
    if (sasSignSupport) {                   // the application supports SAS signing
        zrtpHello_11.setSasSign();
        zrtpHello_12.setSasSign();
    }

    // Keep array in ascending order (greater index -> greater version)
    helloPackets[0].packet = &zrtpHello_11;
    helloPackets[0].version = zrtpHello_11.getVersionInt();
    setClientId(id, &helloPackets[0]);      // set id, compute HMAC and final helloHash

    helloPackets[1].packet = &zrtpHello_12;
    helloPackets[1].version = zrtpHello_12.getVersionInt();
    setClientId(id, &helloPackets[1]);      // set id, compute HMAC and final helloHash
 
    currentHelloPacket = helloPackets[SUPPORTED_ZRTP_VERSIONS-1].packet;  // start with highest supported version
    helloPackets[SUPPORTED_ZRTP_VERSIONS].packet = NULL;
    peerHelloVersion[0] = 0;

    stateEngine = new ZrtpStateClass(this);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::setClientId(std::string id) {
    clientIdString = id;
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketGoClear* ZRtp::prepareGoClear(uint32_t errMsg) {
    ZrtpPacketGoClear* gclr = &zrtpGoClear;
    gclr->clrClearHmac();
    return gclr;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::sendInfo(MessageSeverity severity, int32_t subCode) {
    if (zrtpUserCallback != NULL) {
        zrtpUserCallback->showMessage(severity, subCode);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::stopZrtp() {
    if (zrtpEngine != NULL) {
        if (zrtpUnprotect < 50 && !zrtpEngine->isMultiStream())
            zrtpEngine->setRs2Valid();
        delete zrtpEngine;
        zrtpEngine = NULL;
        started = false;
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::stopZrtp() {
    Event_t ev;

    if (stateEngine != NULL) {
        ev.type = ZrtpClose;
        stateEngine->processEvent(&ev);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketCommit* ZRtp::prepareCommit(ZrtpPacketHello *hello, uint32_t* errMsg) {

    // Save data before detailed checks - may aid in analysing problems
    peerClientId.assign((char*)hello->getClientId(), ZRTP_WORD_SIZE * 4);
    memcpy(peerHelloVersion, hello->getVersion(), ZRTP_WORD_SIZE);
    peerHelloVersion[ZRTP_WORD_SIZE] = 0;

    // Save our peer's (presumably the Responder) ZRTP id
    memcpy(peerZid, hello->getZid(), ZID_SIZE);
    if (memcmp(peerZid, ownZid, ZID_SIZE) == 0) {       // peers have same ZID????
        *errMsg = EqualZIDHello;
        return NULL;
    }
    memcpy(peerH3, hello->getH3(), HASH_IMAGE_SIZE);

    int32_t helloLen = hello->getLength() * ZRTP_WORD_SIZE;

    // calculate hash over the received Hello packet - is peer's hello hash.
    // Use implicit hash algorithm
    hashFunctionImpl((unsigned char*)hello->getHeaderBase(), helloLen, peerHelloHash);

    sendInfo(Info, InfoHelloReceived);

    /*
     * The Following section extracts the algorithm from the peer's Hello
     * packet. Always the preferend offered algorithms are
     * used. If the received Hello does not contain algo specifiers
     * or offers only unsupported optional algos then replace
     * these with mandatory algos and put them into the Commit packet.
     * Refer to the findBest*() functions.
     * If this is a MultiStream ZRTP object then do not get the cipher,
     * authentication from hello packet but use the pre-initialized values
     * as proposed by the standard. If we switch to responder mode the
     * commit packet may contain other algos - see function
     * prepareConfirm2MultiStream(...).
     */
    sasType = findBestSASType(hello);

    if (!multiStream) {
        pubKey = findBestPubkey(hello);                 // Check for public key algorithm first, sets 'hash' as well
        if (hash == NULL) {
            *errMsg = UnsuppHashType;
            return NULL;
        }
        if (cipher == NULL)                             // public key selection may have set the cipher already
            cipher = findBestCipher(hello, pubKey);
        authLength = findBestAuthLen(hello);
        multiStreamAvailable = checkMultiStream(hello);
    }
    else {
        if (checkMultiStream(hello)) {
            return prepareCommitMultiStream(hello);
        }
        else {
            // we are in multi-stream but peer does not offer multi-stream
            // return error code to other party - unsupported PK, must be Mult
            *errMsg = UnsuppPKExchange;
            return NULL;
        }
    }
    setNegotiatedHash(hash);

    // Modify here when introducing new DH key agreement, for example
    // elliptic curves.
    dhContext = new ZrtpDH(pubKey->getName());
    dhContext->generatePublicKey();

    dhContext->getPubKeyBytes(pubKeyBytes);
    sendInfo(Info, InfoCommitDHGenerated);

    // Prepare IV data that we will use during confirm packet encryption.
    randomZRTP(randomIV, sizeof(randomIV));

    /*
     * Prepare our DHPart2 packet here. Required to compute HVI. If we stay
     * in Initiator role then we reuse this packet later in prepareDHPart2().
     * To create this DH packet we have to compute the retained secret ids,
     * thus get our peer's retained secret data first.
     */
    zidRec = getZidCacheInstance()->getRecord(peerZid);

    //Compute the Initator's and Responder's retained secret ids.
    computeSharedSecretSet(zidRec);

    // Check if a PBX application set the MitM flag.
    mitmSeen = hello->isMitmMode();

    signSasSeen = hello->isSasSign();
    // Construct a DHPart2 message (Initiator's DH message). This packet
    // is required to compute the HVI (Hash Value Initiator), refer to
    // chapter 5.4.1.1.

    // Fill the values in the DHPart2 packet
    zrtpDH2.setPubKeyType(pubKey->getName());
    zrtpDH2.setMessageType((uint8_t*)DHPart2Msg);
    zrtpDH2.setRs1Id(rs1IDi);
    zrtpDH2.setRs2Id(rs2IDi);
    zrtpDH2.setAuxSecretId(auxSecretIDi);
    zrtpDH2.setPbxSecretId(pbxSecretIDi);
    zrtpDH2.setPv(pubKeyBytes);
    zrtpDH2.setH1(H1);

    int32_t len = zrtpDH2.getLength() * ZRTP_WORD_SIZE;

    // Compute HMAC over DH2, excluding the HMAC field (HMAC_SIZE)
    // and store in DH2. Key to HMAC is H0, use HASH_IMAGE_SIZE bytes only.
    // Must use implicit HMAC functions.
    uint8_t hmac[IMPL_MAX_DIGEST_LENGTH];
    uint32_t macLen;
    hmacFunctionImpl(H0, HASH_IMAGE_SIZE, (uint8_t*)zrtpDH2.getHeaderBase(), len-(HMAC_SIZE), hmac, &macLen);
    zrtpDH2.setHMAC(hmac);

    // Compute the HVI, refer to chapter 5.4.1.1 of the specification
    computeHvi(&zrtpDH2, hello);

    zrtpCommit.setZid(ownZid);
    zrtpCommit.setHashType((uint8_t*)hash->getName());
    zrtpCommit.setCipherType((uint8_t*)cipher->getName());
    zrtpCommit.setAuthLen((uint8_t*)authLength->getName());
    zrtpCommit.setPubKeyType((uint8_t*)pubKey->getName());
    zrtpCommit.setSasType((uint8_t*)sasType->getName());
    zrtpCommit.setHvi(hvi);
    zrtpCommit.setH2(H2);

    len = zrtpCommit.getLength() * ZRTP_WORD_SIZE;

    // Compute HMAC over Commit, excluding the HMAC field (HMAC_SIZE)
    // and store in Hello. Key to HMAC is H1, use HASH_IMAGE_SIZE bytes only.
    // Must use implicit HMAC functions.
    hmacFunctionImpl(H1, HASH_IMAGE_SIZE, (uint8_t*)zrtpCommit.getHeaderBase(), len-(HMAC_SIZE), hmac, &macLen);
    zrtpCommit.setHMAC(hmac);

    // hash first messages to produce overall message hash
    // First the Responder's Hello message, second the Commit (always Initator's).
    // Must use negotiated hash.
    msgShaContext = createHashCtx();
    hashCtxFunction(msgShaContext, (unsigned char*)hello->getHeaderBase(), helloLen);
    hashCtxFunction(msgShaContext, (unsigned char*)zrtpCommit.getHeaderBase(), len);

    // store Hello data temporarily until we can check HMAC after receiving Commit as
    // Responder or DHPart1 as Initiator
    storeMsgTemp(hello);

    return &zrtpCommit;
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketConfirm* ZRtp::prepareConfirm1(ZrtpPacketDHPart* dhPart2, uint32_t* errMsg) {

    uint8_t* pvi;

    sendInfo(Info, InfoRespDH2Received);

    // Because we are responder we received a Commit and stored its H2.
    // Now re-compute H2 from received H1 and compare with stored peer's H2.
    // Use implicit hash function
    uint8_t tmpHash[IMPL_MAX_DIGEST_LENGTH];
    hashFunctionImpl(dhPart2->getH1(), HASH_IMAGE_SIZE, tmpHash);
    if (memcmp(tmpHash, peerH2, HASH_IMAGE_SIZE) != 0) {
        *errMsg = IgnorePacket;
        return NULL;
    }

    // Check HMAC of Commit packet stored in temporary buffer. The
    // HMAC key of the Commit packet is peer's H1 that is contained in
    // DHPart2. Refer to chapter 9.1 and chapter 10.
    if (!checkMsgHmac(dhPart2->getH1())) {
        sendInfo(Severe, SevereCommitHMACFailed);
        *errMsg = CriticalSWError;
        return NULL;
    }
    // Now we have the peer's pvi. Because we are responder re-compute my hvi
    // using my Hello packet and the Initiator's DHPart2 and compare with
    // hvi sent in commit packet. If it doesn't macht then a MitM attack
    // may have occured.
    computeHvi(dhPart2, currentHelloPacket);
    if (memcmp(hvi, peerHvi, HVI_SIZE) != 0) {
        *errMsg = DHErrorWrongHVI;
        return NULL;
    }
    DHss = new uint8_t[dhContext->getDhSize()];
    if (DHss == NULL) {
        *errMsg = CriticalSWError;
        return NULL;
    }
    // Get and check the Initiator's public value, see chap. 5.4.2 of the spec
    pvi = dhPart2->getPv();
    if (!dhContext->checkPubKey(pvi)) {
        *errMsg = DHErrorWrongPV;
        return NULL;
    }
    dhContext->computeSecretKey(pvi, DHss);
    // Hash the Initiator's DH2 into the message Hash (other messages already
    // prepared, see method prepareDHPart1().
    // Use neotiated hash function
    hashCtxFunction(msgShaContext, (unsigned char*)dhPart2->getHeaderBase(), dhPart2->getLength() * ZRTP_WORD_SIZE);

    closeHashCtx(msgShaContext, messageHash);
    msgShaContext = NULL;
    /*
     * The expected shared secret Ids were already computed when we built the
     * DHPart1 packet. Generate s0, all depended keys, and the new RS1 value
     * for the ZID record. The functions also performs sign SAS callback if it's
     * active. May reset the verify flag in ZID record.
     */
    generateKeysResponder(dhPart2, zidRec);

    delete dhContext;
    dhContext = NULL;

    // Fill in Confirm1 packet.
    zrtpConfirm1.setMessageType((uint8_t*)Confirm1Msg);

    // Check if user verfied the SAS in a previous call and thus verfied
    // the retained secret. Don't set the verified flag if paranoidMode is true.
    if (zidRec->isSasVerified() && !paranoidMode) {
        zrtpConfirm1.setSASFlag();
    }
    zrtpConfirm1.setExpTime(0xFFFFFFFF);
    zrtpConfirm1.setIv(randomIV);
    zrtpConfirm1.setHashH0(H0);

    // if this runs at PBX user agent enrollment service then set flag in confirm
    // packet and store the MitM key
    if (enrollmentMode) {
        // As clarification to RFC6189: store new PBX secret only if we don't have
        // a matching PBX secret for the peer's ZID.
        if (!peerIsEnrolled) {
            computePBXSecret();
            zidRec->setMiTMData(pbxSecretTmp);
        }
        // Set flag to enable user's client to ask for confirmation or re-confirmation.
        zrtpConfirm1.setPBXEnrollment();
    }
    uint8_t confMac[MAX_DIGEST_LENGTH];
    uint32_t macLen;

    // Encrypt and HMAC with Responder's key - we are Respondere here
    int hmlen = (zrtpConfirm1.getLength() - 9) * ZRTP_WORD_SIZE;
    cipher->getEncrypt()(zrtpKeyR, cipher->getKeylen(), randomIV, zrtpConfirm1.getHashH0(), hmlen);
    hmacFunction(hmacKeyR, hashLength, (unsigned char*)zrtpConfirm1.getHashH0(), hmlen, confMac, &macLen);

    zrtpConfirm1.setHmac(confMac);

    // store DHPart2 data temporarily until we can check HMAC after receiving Confirm2
    storeMsgTemp(dhPart2);
    return &zrtpConfirm1;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::zrtpAskEnrollment(GnuZrtpCodes::InfoEnrollment  info) {
    if (zrtpUserCallback != NULL) {
        zrtpUserCallback->zrtpAskEnrollment(info);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

int32_t ZrtpQueue::getCurrentProtocolVersion() {
    if (zrtpEngine != NULL)
        return zrtpEngine->getCurrentProtocolVersion();

    return 0;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::processZrtpMessage(uint8_t *message, uint32_t pSSRC, size_t length) {
    Event_t ev;

    peerSSRC = pSSRC;
    ev.type = ZrtpPacket;
    ev.length = length;
    ev.packet = message;

    if (stateEngine != NULL) {
        stateEngine->processEvent(&ev);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketError* ZRtp::prepareError(uint32_t errMsg) {
    zrtpError.setErrorCode(errMsg);
    return &zrtpError;
}

Project: ZRTPCPP
File: ZRtp.cpp

AlgorithmEnum* ZRtp::findBestCipher(ZrtpPacketHello *hello, AlgorithmEnum* pk) {

    int i;
    int ii;
    int numAlgosOffered;
    AlgorithmEnum* algosOffered[ZrtpConfigure::maxNoOfAlgos+1];

    int numAlgosConf;
    AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+1];

    int num = hello->getNumCiphers();
    if (num == 0 || (*(int32_t*)(pk->getName()) == *(int32_t*)dh2k)) {
        return &zrtpSymCiphers.getByName(aes1);
    }

    // Build list of configured cipher algorithm names.
    numAlgosConf = configureAlgos.getNumConfiguredAlgos(CipherAlgorithm);
    for (i = 0; i < numAlgosConf; i++) {
        algosConf[i] = &configureAlgos.getAlgoAt(CipherAlgorithm, i);
    }
    // Build list of offered known algos names in Hello.
    for (numAlgosOffered = 0, i = 0; i < num; i++) {
        algosOffered[numAlgosOffered] = &zrtpSymCiphers.getByName((const char*)hello->getCipherType(i));
        if (!algosOffered[numAlgosOffered]->isValid())
            continue;
        numAlgosOffered++;
    }
    // Lookup offered algos in configured algos.  Prefer algorithms that appear first in Hello packet (offered).
    for (i = 0; i < numAlgosOffered; i++) {
        for (ii = 0; ii < numAlgosConf; ii++) {
            if (*(int32_t*)(algosOffered[i]->getName()) == *(int32_t*)(algosConf[ii]->getName())) {
                return algosConf[ii];
            }
        }
    }
    // If we don't have a match - use the mandatory algorithm
    return &zrtpSymCiphers.getByName(mandatoryCipher);
}

Project: ZRTPCPP
File: ZRtp.cpp

std::string ZRtp::getPeerHelloHash() {
    std::ostringstream stm;

    if (peerHelloVersion[0] == 0)
        return std::string();

    uint8_t* hp = peerHelloHash;

    stm << peerHelloVersion;
    stm << " ";
    stm.fill('0');
    stm << hex;
    for (int i = 0; i < hashLengthImpl; i++) {
        stm.width(2);
        stm << static_cast<uint32_t>(*hp++);
    }
    return stm.str();
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::handleTimeout(const std::string &c) {
    if (zrtpEngine != NULL) {
        zrtpEngine->processTimeout();
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::isMultiStream()  {
    if (zrtpEngine != NULL)
        return zrtpEngine->isMultiStream();
    return false;
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketCommit* ZRtp::prepareCommitMultiStream(ZrtpPacketHello *hello) {

    randomZRTP(hvi, ZRTP_WORD_SIZE*4);  // This is the Multi-Stream NONCE size

    zrtpCommit.setZid(ownZid);
    zrtpCommit.setHashType((uint8_t*)hash->getName());
    zrtpCommit.setCipherType((uint8_t*)cipher->getName());
    zrtpCommit.setAuthLen((uint8_t*)authLength->getName());
    zrtpCommit.setPubKeyType((uint8_t*)mult);  // this is fixed because of Multi Stream mode
    zrtpCommit.setSasType((uint8_t*)sasType->getName());
    zrtpCommit.setNonce(hvi);
    zrtpCommit.setH2(H2);

    int32_t len = zrtpCommit.getLength() * ZRTP_WORD_SIZE;

    // Compute HMAC over Commit, excluding the HMAC field (HMAC_SIZE)
    // and store in Hello. Key to HMAC is H1, use HASH_IMAGE_SIZE bytes only.
    // Must use the implicit HMAC function.
    uint8_t hmac[IMPL_MAX_DIGEST_LENGTH];
    uint32_t macLen;
    hmacFunctionImpl(H1, HASH_IMAGE_SIZE, (uint8_t*)zrtpCommit.getHeaderBase(), len-(HMAC_SIZE), hmac, &macLen);
    zrtpCommit.setHMACMulti(hmac);


    // hash first messages to produce overall message hash
    // First the Responder's Hello message, second the Commit
    // (always Initator's).
    // Must use the negotiated hash.
    msgShaContext = createHashCtx();

    int32_t helloLen = hello->getLength() * ZRTP_WORD_SIZE;
    hashCtxFunction(msgShaContext, (unsigned char*)hello->getHeaderBase(), helloLen);
    hashCtxFunction(msgShaContext, (unsigned char*)zrtpCommit.getHeaderBase(), len);

    // store Hello data temporarily until we can check HMAC after receiving Commit as
    // Responder or DHPart1 as Initiator
    storeMsgTemp(hello);

    return &zrtpCommit;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

int32_t ZrtpStateClass::nextTimer(zrtpTimer_t *t) {

    t->time += t->time;
    t->time = (t->time > t->capping)? t->capping : t->time;
    t->counter++;
    if (t->counter > t->maxResend) {
        return -1;
    }
    return parent->activateTimer(t->time);
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

ZrtpStateClass::ZrtpStateClass(ZRtp *p) : parent(p), commitPkt(NULL), multiStream(false), secSubstate(Normal), sentVersion(0) {
    engine = new ZrtpStates(states, numberOfStates, Initial);

    // Set up timers according to ZRTP spec
    T1.start = 50;
    T1.maxResend = 20;
    T1.capping = 200;

    T2.start = 150;
    T2.maxResend = 10;
    T2.capping = 600;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::srtpSecretsReady(SrtpSecret_t* secrets, EnableSecurity part)
{
    CryptoContext* recvCryptoContext;
    CryptoContext* senderCryptoContext;
    CryptoContextCtrl* recvCryptoContextCtrl;
    CryptoContextCtrl* senderCryptoContextCtrl;

    int cipher;
    int authn;
    int authKeyLen;

    if (secrets->authAlgorithm == Sha1) {
        authn = SrtpAuthenticationSha1Hmac;
        authKeyLen = 20;
    }

    if (secrets->authAlgorithm == Skein) {
        authn = SrtpAuthenticationSkeinHmac;
        authKeyLen = 32;
    }

    if (secrets->symEncAlgorithm == Aes)
        cipher = SrtpEncryptionAESCM;

    if (secrets->symEncAlgorithm == TwoFish)
        cipher = SrtpEncryptionTWOCM;

    if (part == ForSender) {
        // To encrypt packets: intiator uses initiator keys,
        // responder uses responder keys
        // Create a "half baked" crypto context first and store it. This is
        // the main crypto context for the sending part of the connection.
        if (secrets->role == Initiator) {
            senderCryptoContext = new CryptoContext(
                    0,
                    0,
                    0L,                                      // keyderivation << 48,
                    cipher,                                  // encryption algo
                    authn,                                   // authtentication algo
                    (unsigned char*)secrets->keyInitiator,   // Master Key
                    secrets->initKeyLen / 8,                 // Master Key length
                    (unsigned char*)secrets->saltInitiator,  // Master Salt
                    secrets->initSaltLen / 8,                // Master Salt length
                    secrets->initKeyLen / 8,                 // encryption keyl
                    authKeyLen,                              // authentication key len
                    secrets->initSaltLen / 8,                // session salt len
                    secrets->srtpAuthTagLen / 8);            // authentication tag lenA
            senderCryptoContextCtrl = new CryptoContextCtrl(0,
                  cipher,                                    // encryption algo
                  authn,                                     // authtication algo
                  (unsigned char*)secrets->keyInitiator,     // Master Key
                  secrets->initKeyLen / 8,                   // Master Key length
                  (unsigned char*)secrets->saltInitiator,    // Master Salt
                  secrets->initSaltLen / 8,                  // Master Salt length
                  secrets->initKeyLen / 8,                   // encryption keyl
                  authKeyLen,                                // authentication key len
                  secrets->initSaltLen / 8,                  // session salt len
                  secrets->srtpAuthTagLen / 8);              // authentication tag len
        }
        else {
            senderCryptoContext = new CryptoContext(
                    0,
                    0,
                    0L,                                      // keyderivation << 48,
                    cipher,                                  // encryption algo
                    authn,                                   // authtentication algo
                    (unsigned char*)secrets->keyResponder,   // Master Key
                    secrets->respKeyLen / 8,                 // Master Key length
                    (unsigned char*)secrets->saltResponder,  // Master Salt
                    secrets->respSaltLen / 8,                // Master Salt length
                    secrets->respKeyLen / 8,                 // encryption keyl
                    authKeyLen,                              // authentication key len
                    secrets->respSaltLen / 8,                // session salt len
                    secrets->srtpAuthTagLen / 8);            // authentication tag len
            senderCryptoContextCtrl = new CryptoContextCtrl(0,
                  cipher,                                    // encryption algo
                  authn,                                     // authtication algo
                  (unsigned char*)secrets->keyResponder,     // Master Key
                  secrets->respKeyLen / 8,                   // Master Key length
                  (unsigned char*)secrets->saltResponder,    // Master Salt
                  secrets->respSaltLen / 8,                  // Master Salt length
                  secrets->respKeyLen / 8,                   // encryption keyl
                  authKeyLen,                                // authentication key len
                  secrets->respSaltLen / 8,                  // session salt len
                  secrets->srtpAuthTagLen / 8);              // authentication tag len
        }
        if (senderCryptoContext == NULL) {
            return false;
        }
        // Insert the Crypto templates (SSRC == 0) into the queue. When we send
        // the first RTP or RTCP packet the real crypto context will be created.
        // Refer to putData(), sendImmediate() in ccrtp's outqueue.cpp and
        // takeinControlPacket() in ccrtp's control.cpp.
        //
         setOutQueueCryptoContext(senderCryptoContext);
         setOutQueueCryptoContextCtrl(senderCryptoContextCtrl);
    }
    if (part == ForReceiver) {
        // To decrypt packets: intiator uses responder keys,
        // responder initiator keys
        // See comment above.
        if (secrets->role == Initiator) {
            recvCryptoContext = new CryptoContext(
                    0,
                    0,
                    0L,                                      // keyderivation << 48,
                    cipher,                                  // encryption algo
                    authn,                                   // authtentication algo
                    (unsigned char*)secrets->keyResponder,   // Master Key
                    secrets->respKeyLen / 8,                 // Master Key length
                    (unsigned char*)secrets->saltResponder,  // Master Salt
                    secrets->respSaltLen / 8,                // Master Salt length
                    secrets->respKeyLen / 8,                 // encryption keyl
                    authKeyLen,                              // authentication key len
                    secrets->respSaltLen / 8,                // session salt len
                    secrets->srtpAuthTagLen / 8);            // authentication tag len
            recvCryptoContextCtrl = new CryptoContextCtrl(0,
                  cipher,                                    // encryption algo
                  authn,                                     // authtication algo
                  (unsigned char*)secrets->keyResponder,     // Master Key
                  secrets->respKeyLen / 8,                   // Master Key length
                  (unsigned char*)secrets->saltResponder,    // Master Salt
                  secrets->respSaltLen / 8,                  // Master Salt length
                  secrets->respKeyLen / 8,                   // encryption keyl
                  authKeyLen,                                // authentication key len
                  secrets->respSaltLen / 8,                  // session salt len
                  secrets->srtpAuthTagLen / 8);              // authentication tag len

        }
        else {
            recvCryptoContext = new CryptoContext(
                    0,
                    0,
                    0L,                                      // keyderivation << 48,
                    cipher,                                  // encryption algo
                    authn,                                   // authtentication algo
                    (unsigned char*)secrets->keyInitiator,   // Master Key
                    secrets->initKeyLen / 8,                 // Master Key length
                    (unsigned char*)secrets->saltInitiator,  // Master Salt
                    secrets->initSaltLen / 8,                // Master Salt length
                    secrets->initKeyLen / 8,                 // encryption keyl
                    authKeyLen,                              // authentication key len
                    secrets->initSaltLen / 8,                // session salt len
                    secrets->srtpAuthTagLen / 8);            // authentication tag len
            recvCryptoContextCtrl = new CryptoContextCtrl(0,
                  cipher,                                    // encryption algo
                  authn,                                     // authtication algo
                  (unsigned char*)secrets->keyInitiator,     // Master Key
                  secrets->initKeyLen / 8,                   // Master Key length
                  (unsigned char*)secrets->saltInitiator,    // Master Salt
                  secrets->initSaltLen / 8,                  // Master Salt length
                  secrets->initKeyLen / 8,                   // encryption keyl
                  authKeyLen,                                // authentication key len
                  secrets->initSaltLen / 8,                  // session salt len
                  secrets->srtpAuthTagLen / 8);              // authentication tag len
        }
        if (recvCryptoContext == NULL) {
            return false;
        }
        // Insert the Crypto templates (SSRC == 0) into the queue. When we receive
        // the first RTP or RTCP packet the real crypto context will be created.
        // Refer to rtpDataPacket() above and takeinControlPacket in ccrtp's control.cpp.
        //
        setInQueueCryptoContext(recvCryptoContext);
        setInQueueCryptoContextCtrl(recvCryptoContextCtrl);
    }
    return true;
}

Project: ZRTPCPP
File: ZRtp.cpp

const ZRtp::zrtpInfo* ZRtp::getDetailInfo() {
    return &detailInfo;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::processTimeout() {
    Event_t ev;

    ev.type = Timer;
    if (stateEngine != NULL) {
        stateEngine->processEvent(&ev);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::computePBXSecret() {
    // Construct the KDF context as per ZRTP specification chap 7.3.1:
    // ZIDi || ZIDr
    uint8_t KDFcontext[sizeof(peerZid)+sizeof(ownZid)];
    int32_t kdfSize = sizeof(peerZid)+sizeof(ownZid);

    if (myRole == Responder) {
        memcpy(KDFcontext, peerZid, sizeof(peerZid));
        memcpy(KDFcontext+sizeof(peerZid), ownZid, sizeof(ownZid));
    }
    else {
        memcpy(KDFcontext, ownZid, sizeof(ownZid));
        memcpy(KDFcontext+sizeof(ownZid), peerZid, sizeof(peerZid));
    }

    KDF(zrtpSession, hashLength, (unsigned char*)zrtpTrustedMitm, strlen(zrtpTrustedMitm)+1, KDFcontext,
        kdfSize, SHA256_DIGEST_LENGTH * 8, pbxSecretTmpBuffer);

    pbxSecretTmp = pbxSecretTmpBuffer;  // set pointer to buffer, signal PBX secret was computed
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::checkMsgHmac(uint8_t* key) {
    uint8_t hmac[IMPL_MAX_DIGEST_LENGTH];
    uint32_t macLen;
    int32_t len = lengthOfMsgData-(HMAC_SIZE);  // compute HMAC, but exlude the stored HMAC :-)

    // Use the implicit hash function
    hmacFunctionImpl(key, HASH_IMAGE_SIZE, tempMsgBuffer, len, hmac, &macLen);
    return (memcmp(hmac, tempMsgBuffer+len, (HMAC_SIZE)) == 0 ? true : false);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

std::string ZrtpQueue::getMultiStrParams()  {
    if (zrtpEngine != NULL)
        return zrtpEngine->getMultiStrParams();
    else
        return std::string();
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::signSAS(uint8_t* sasHash) {
    if (zrtpUserCallback != NULL) {
        zrtpUserCallback->signSAS(sasHash);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

int32_t ZrtpQueue::cancelTimer() {
    std::string s("ZRTP");
    if (staticTimeoutProvider != NULL) {
        staticTimeoutProvider->cancelRequest(this, s);
    }
    return 1;
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::sendSASRelayPacket(uint8_t* sh, std::string render) {

    uint8_t confMac[MAX_DIGEST_LENGTH];
    uint32_t macLen;
    uint8_t* hkey, *ekey;

    // If we are responder then the PBX used it's Initiator keys
    if (myRole == Responder) {
        hkey = hmacKeyR;
        ekey = zrtpKeyR;
        // TODO: check signature length in zrtpConfirm1 and if not zero copy Signature data
    }
    else {
        hkey = hmacKeyI;
        ekey = zrtpKeyI;
        // TODO: check signature length in zrtpConfirm2 and if not zero copy Signature data
    }
    // Prepare IV data that we will use during confirm packet encryption.
    randomZRTP(randomIV, sizeof(randomIV));
    zrtpSasRelay.setIv(randomIV);
    zrtpSasRelay.setTrustedSas(sh);
    zrtpSasRelay.setSasAlgo((uint8_t*)render.c_str());

    int16_t hmlen = (zrtpSasRelay.getLength() - 9) * ZRTP_WORD_SIZE;
    cipher->getEncrypt()(ekey, cipher->getKeylen(), randomIV, (uint8_t*)zrtpSasRelay.getFiller(), hmlen);

    // Use negotiated HMAC (hash)
    hmacFunction(hkey, hashLength, (unsigned char*)zrtpSasRelay.getFiller(), hmlen, confMac, &macLen);

    zrtpSasRelay.setHmac(confMac);

    stateEngine->sendSASRelay(&zrtpSasRelay);
    return true;
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::srtpSecretsReady(EnableSecurity part) {

    SrtpSecret_t sec;

    sec.symEncAlgorithm = cipher->getAlgoId();

    sec.keyInitiator = srtpKeyI;
    sec.initKeyLen = cipher->getKeylen() * 8;
    sec.saltInitiator = srtpSaltI;
    sec.initSaltLen = 112;

    sec.keyResponder = srtpKeyR;
    sec.respKeyLen = cipher->getKeylen() * 8;
    sec.saltResponder = srtpSaltR;
    sec.respSaltLen = 112;

    sec.authAlgorithm = authLength->getAlgoId();
    sec.srtpAuthTagLen = authLength->getKeylen();

    sec.sas = SAS;
    sec.role = myRole;

    bool rc = callback->srtpSecretsReady(&sec, part);

    // The call state engine calls ForSender always after ForReceiver.
    if (part == ForSender) {
        std::string cs(cipher->getReadable());
        if (!multiStream) {
            cs.append("/").append(pubKey->getName());
            if (mitmSeen)
                cs.append("/EndAtMitM");
            callback->srtpSecretsOn(cs, SAS, zidRec->isSasVerified());
        }
        else {
            std::string cs1("");
            if (mitmSeen)
                cs.append("/EndAtMitM");
            callback->srtpSecretsOn(cs, cs1, true);
        }
    }
    return rc;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evInitial(void) {
    DEBUGOUT((cout << "Checking for match in Initial.\n"));

    if (event->type == ZrtpInitial) {
        ZrtpPacketHello* hello = parent->prepareHello();
        sentVersion = hello->getVersionInt();

        // remember packet for easy resend in case timer triggers
        sentPacket = static_cast<ZrtpPacketBase *>(hello);

        if (!parent->sendPacketZRTP(sentPacket)) {
            sendFailed();                 // returns to state Initial
            return;
        }
        if (startTimer(&T1) <= 0) {
            timerFailed(SevereNoTimer);      // returns to state Initial
            return;
        }
        nextState(Detect);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::setAuxSecret(uint8_t* data, int32_t length) {
    if (length > 0) {
        auxSecret = new uint8_t[length];
        auxSecretLength = length;
        memcpy(auxSecret, data, length);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::setNegotiatedHash(AlgorithmEnum* hash) {
    switch (zrtpHashes.getOrdinal(*hash)) {
    case 0:
        hashLength = SHA256_DIGEST_LENGTH;
        hashFunction = sha256;
        hashListFunction = sha256;

        hmacFunction = hmac_sha256;
        hmacListFunction = hmac_sha256;

        createHashCtx = createSha256Context;
        closeHashCtx = closeSha256Context;
        hashCtxFunction = sha256Ctx;
        hashCtxListFunction = sha256Ctx;
        break;

    case 1:
        hashLength = SHA384_DIGEST_LENGTH;
        hashFunction = sha384;
        hashListFunction = sha384;

        hmacFunction = hmac_sha384;
        hmacListFunction = hmac_sha384;

        createHashCtx = createSha384Context;
        closeHashCtx = closeSha384Context;
        hashCtxFunction = sha384Ctx;
        hashCtxListFunction = sha384Ctx;
        break;
    }
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evAckSent(void) {

    DEBUGOUT((cout << "Checking for match in AckSent.\n"));

    char *msg, first, last;
    uint8_t *pkt;
    uint32_t errorCode = 0;

    /*
     * First check the general event type, then discrimnate
     * the real event.
     */
    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));

        /*
         * HelloAck:
         * The peer answers with HelloAck to own HelloAck/Hello. Send Commit
         * and try Initiator mode. The requirement defined in chapter 4.1 to
         * have a complete Hello/HelloAck is fulfilled.
         * - stop Hello timer T1
         * - send own Commit message
         * - switch state to CommitSent, start Commit timer, assume Initiator
         */
        if (first == 'h' && last =='k') {
            cancelTimer();

            // remember packet for easy resend in case timer triggers
            // Timer trigger received in new state CommitSend
            sentPacket = static_cast<ZrtpPacketBase *>(commitPkt);
            commitPkt = NULL;                    // now stored in sentPacket
            nextState(CommitSent);
            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();             // returns to state Initial
                return;
            }
            if (startTimer(&T2) <= 0) {
                timerFailed(SevereNoTimer);  // returns to state Initial
            }
            return;
        }
        /*
         * Hello:
         * - peer didn't receive our HelloAck
         * - repeat HelloAck/Hello response:
         *  -- get HelloAck packet, send it
         *  -- The timeout trigger of T1 sends our Hello packet
         *  -- stay in state AckSent
         *
         * Similar to Detect state: just acknowledge the Hello, the next
         * timeout sends the following Hello.
         */

        if (first == 'h' && last ==' ') {
            ZrtpPacketHelloAck* helloAck = parent->prepareHelloAck();

            if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(helloAck))) {
                nextState(Detect);
                parent->zrtpNegotiationFailed(Severe, SevereCannotSend);
            }
            return;
        }
        /*
         * Commit:
         * The peer answers with Commit to HelloAck/Hello, thus switch to
         * responder mode.
         * - stop timer T1
         * - prepare and send our DHPart1
         * - switch to state WaitDHPart2 and wait for peer's DHPart2
         * - don't start timer, we are responder
         */
        if (first == 'c' && last == ' ') {
            cancelTimer();
            ZrtpPacketCommit cpkt(pkt);

            if (!multiStream) {
                ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(&cpkt, &errorCode);

                // Something went wrong during processing of the Commit packet
                if (dhPart1 == NULL) {
                    if (errorCode != IgnorePacket) {
                        sendErrorPacket(errorCode);
                    }
                    return;
                }
                commitPkt = NULL;
                sentPacket = static_cast<ZrtpPacketBase *>(dhPart1);
                nextState(WaitDHPart2);
            }
            else {
                ZrtpPacketConfirm* confirm = parent->prepareConfirm1MultiStream(&cpkt, &errorCode);

                // Something went wrong during processing of the Commit packet
                if (confirm == NULL) {
                    if (errorCode != IgnorePacket) {
                        sendErrorPacket(errorCode);
                    }
                    return;
                }
                sentPacket = static_cast<ZrtpPacketBase *>(confirm);
                nextState(WaitConfirm2);
            }
            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();      // returns to state Initial
            }
        }
    }
    /*
     * Timer:
     * - resend Hello packet, stay in state, restart timer until repeat
     *   counter triggers
     * - if repeat counter triggers switch to state Detect, con't clear
     *   sentPacket, Detect requires it to point to own Hello message
     */
    else if (event->type == Timer) {
        if (!parent->sendPacketZRTP(sentPacket)) {
            return sendFailed();      // returns to state Initial
        }
        if (nextTimer(&T1) <= 0) {
            parent->zrtpNotSuppOther();
            commitPkt = NULL;
            // Stay in state Detect to be prepared get an hello from
            // other peer any time later
            nextState(Detect);
        }
    }
    else {   // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        commitPkt = NULL;
        sentPacket = NULL;
        nextState(Initial);
    }
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evWaitDHPart2(void) {

    DEBUGOUT((cout << "Checking for match in DHPart2.\n"));

    char *msg, first, secondLast, last;
    uint8_t *pkt;
    uint32_t errorCode = 0;

    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));
        secondLast = tolower(*(msg+6));
        /*
         * Commit:
         * - resend DHPart1
         * - stay in state
         */
        if (first == 'c' && last == ' ') {
            if (!parent->sendPacketZRTP(sentPacket)) {
                return sendFailed();       // returns to state Initial
            }
            return;
        }
        /*
         * DHPart2:
         * - prepare Confirm1 packet
         * - switch to WaitConfirm2
         * - No timer, we are responder
         */
        if (first == 'd' && secondLast == '2') {
            ZrtpPacketDHPart dpkt(pkt);
            ZrtpPacketConfirm* confirm = parent->prepareConfirm1(&dpkt, &errorCode);

            if (confirm == NULL) {
                if (errorCode != IgnorePacket) {
                    sendErrorPacket(errorCode);
                }
                return;
            }
            nextState(WaitConfirm2);
            sentPacket = static_cast<ZrtpPacketBase *>(confirm);
            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();       // returns to state Initial
            }
        }
    }
    else {  // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        sentPacket = NULL;
        nextState(Initial);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketDHPart* ZRtp::prepareDHPart1(ZrtpPacketCommit *commit, uint32_t* errMsg) {

    sendInfo(Info, InfoRespCommitReceived);

    // The following code check the hash chain according chapter 10 to detect
    // false ZRTP packets.
    // Must use the implicit hash function.
    uint8_t tmpH3[IMPL_MAX_DIGEST_LENGTH];
    memcpy(peerH2, commit->getH2(), HASH_IMAGE_SIZE);
    hashFunctionImpl(peerH2, HASH_IMAGE_SIZE, tmpH3);

    if (memcmp(tmpH3, peerH3, HASH_IMAGE_SIZE) != 0) {
        *errMsg = IgnorePacket;
        return NULL;
    }

    // Check HMAC of previous Hello packet stored in temporary buffer. The
    // HMAC key of peer's Hello packet is peer's H2 that is contained in the
    // Commit packet. Refer to chapter 9.1.
    if (!checkMsgHmac(peerH2)) {
        sendInfo(Severe, SevereHelloHMACFailed);
        *errMsg = CriticalSWError;
        return NULL;
    }

    // check if we support the commited Cipher type
    AlgorithmEnum* cp = &zrtpSymCiphers.getByName((const char*)commit->getCipherType());
    if (!cp->isValid()) { // no match - something went wrong
        *errMsg = UnsuppCiphertype;
        return NULL;
    }
    cipher = cp;

    // check if we support the commited Authentication length
    cp = &zrtpAuthLengths.getByName((const char*)commit->getAuthLen());
    if (!cp->isValid()) { // no match - something went wrong
        *errMsg = UnsuppSRTPAuthTag;
        return NULL;
    }
    authLength = cp;

    // check if we support the commited hash type
    cp = &zrtpHashes.getByName((const char*)commit->getHashType());
    if (!cp->isValid()) { // no match - something went wrong
        *errMsg = UnsuppHashType;
        return NULL;
    }
    // check if the peer's commited hash is the same that we used when
    // preparing our commit packet. If not do the necessary resets and
    // recompute some data.
    if (*(int32_t*)(hash->getName()) != *(int32_t*)(cp->getName())) {
        hash = cp;
        setNegotiatedHash(hash);
        // Compute the Initator's and Responder's retained secret ids
        // with the committed hash.
        computeSharedSecretSet(zidRec);
    }
    // check if we support the commited pub key type
    cp = &zrtpPubKeys.getByName((const char*)commit->getPubKeysType());
    if (!cp->isValid()) { // no match - something went wrong
        *errMsg = UnsuppPKExchange;
        return NULL;
    }
    if (*(int32_t*)(cp->getName()) == *(int32_t*)ec38) {
        if (*(int32_t*)(hash->getName()) != *(int32_t*)s384) {
            *errMsg = UnsuppHashType;
            return NULL;
        }
    }
    pubKey = cp;

    // check if we support the commited SAS type
    cp = &zrtpSasTypes.getByName((const char*)commit->getSasType());
    if (!cp->isValid()) { // no match - something went wrong
        *errMsg = UnsuppSASScheme;
        return NULL;
    }
    sasType = cp;

    // dhContext cannot be NULL - always setup during prepareCommit()
    // check if we can use the dhContext prepared by prepareCOmmit(),
    // if not delete old DH context and generate new one
    // The algorithm names are 4 chars only, thus we can cast to int32_t
    if (*(int32_t*)(dhContext->getDHtype()) != *(int32_t*)(pubKey->getName())) {
        delete dhContext;
        dhContext = new ZrtpDH(pubKey->getName());
        dhContext->generatePublicKey();
    }
    sendInfo(Info, InfoDH1DHGenerated);

    dhContext->getPubKeyBytes(pubKeyBytes);

    // Setup a DHPart1 packet.
    zrtpDH1.setPubKeyType(pubKey->getName());
    zrtpDH1.setMessageType((uint8_t*)DHPart1Msg);
    zrtpDH1.setRs1Id(rs1IDr);
    zrtpDH1.setRs2Id(rs2IDr);
    zrtpDH1.setAuxSecretId(auxSecretIDr);
    zrtpDH1.setPbxSecretId(pbxSecretIDr);
    zrtpDH1.setPv(pubKeyBytes);
    zrtpDH1.setH1(H1);

    int32_t len = zrtpDH1.getLength() * ZRTP_WORD_SIZE;

    // Compute HMAC over DHPart1, excluding the HMAC field (HMAC_SIZE)
    // and store in DHPart1.
    // Use implicit Hash function
    uint8_t hmac[IMPL_MAX_DIGEST_LENGTH];
    uint32_t macLen;
    hmacFunctionImpl(H0, HASH_IMAGE_SIZE, (uint8_t*)zrtpDH1.getHeaderBase(), len-(HMAC_SIZE), hmac, &macLen);
    zrtpDH1.setHMAC(hmac);

    // We are definitly responder. Save the peer's hvi for later compare.
    myRole = Responder;
    memcpy(peerHvi, commit->getHvi(), HVI_SIZE);

    // We are responder. Release a possibly pre-computed SHA context
    // because this was prepared for Initiator. Then create a new one.
    if (msgShaContext != NULL) {
        closeHashCtx(msgShaContext, NULL);
    }
    msgShaContext = createHashCtx();

    // Hash messages to produce overall message hash:
    // First the Responder's (my) Hello message, second the Commit
    // (always Initator's), then the DH1 message (which is always a
    // Responder's message).
    // Must use negotiated hash
    hashCtxFunction(msgShaContext, (unsigned char*)currentHelloPacket->getHeaderBase(), currentHelloPacket->getLength() * ZRTP_WORD_SIZE);
    hashCtxFunction(msgShaContext, (unsigned char*)commit->getHeaderBase(), commit->getLength() * ZRTP_WORD_SIZE);
    hashCtxFunction(msgShaContext, (unsigned char*)zrtpDH1.getHeaderBase(), zrtpDH1.getLength() * ZRTP_WORD_SIZE);

    // store Commit data temporarily until we can check HMAC after we got DHPart2
    storeMsgTemp(commit);

    return &zrtpDH1;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::srtpSecretsOff(EnableSecurity part) {
    if (part == ForSender) {
        removeOutQueueCryptoContext(NULL);
        removeOutQueueCryptoContextCtrl(NULL);
    }
    if (part == ForReceiver) {
        removeInQueueCryptoContext(NULL);
        removeInQueueCryptoContextCtrl(NULL);
    }
    if (zrtpUserCallback != NULL) {
        zrtpUserCallback->secureOff();
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::isPeerEnrolled() {
    if (zrtpEngine != NULL)
        return zrtpEngine->isPeerEnrolled();
    else
        return false;
}

Project: ZRTPCPP
File: ZRtp.cpp

int32_t ZRtp::activateTimer(int32_t tm) {
    return (callback->activateTimer(tm));
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketPingAck* ZRtp::preparePingAck(ZrtpPacketPing* ppkt) {
    if (ppkt->getLength() != 6)                    // A PING packet must have a length of 6 words
        return NULL;
    // Because we do not support ZRTP proxy mode use the truncated ZID.
    // If this code shall be used in ZRTP proxy implementation the computation
    // of the endpoint hash must be enhanced (see chaps 5.15ff and 5.16)
    zrtpPingAck.setLocalEpHash(ownZid);
    zrtpPingAck.setRemoteEpHash(ppkt->getEpHash());
    zrtpPingAck.setSSRC(peerSSRC);
    return &zrtpPingAck;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

int32 ZrtpQueue::getPeerZid(uint8* data) {
    if (data == NULL)
        return 0;

    if (zrtpEngine != NULL)
        return zrtpEngine->getPeerZid(data);

    return 0;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::init()
{
    zrtpUserCallback = NULL;
    enableZrtp = false;
    started = false;
    mitmMode = false;
    enableParanoidMode = false;
    zrtpEngine = NULL;
    senderZrtpSeqNo = 1;

    clientIdString = clientId;
    peerSSRC = 0;
}

Project: ZRTPCPP
File: ZRtp.cpp

uint8_t* ZRtp::getSasHash() {
    return sasHash;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evWaitConfirm1(void) {

    DEBUGOUT((cout << "Checking for match in WaitConfirm1.\n"));

    char *msg, first, last;
    uint8_t *pkt;
    uint32_t errorCode = 0;

    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));

        /*
         * Confirm1:
         * - Switch off resending DHPart2
         * - prepare a Confirm2 packet
         * - switch to state WaitConfAck
         * - set timer to monitor Confirm2 packet, we are initiator
         */
        if (first == 'c' && last == '1') {
            cancelTimer();
            ZrtpPacketConfirm cpkt(pkt);

            ZrtpPacketConfirm* confirm = parent->prepareConfirm2(&cpkt, &errorCode);

            // Something went wrong during processing of the Confirm1 packet
            if (confirm == NULL) {
                sendErrorPacket(errorCode);
                return;
            }
            // according to chap 5.8: after sending Confirm2 the Initiator must
            // be ready to receive SRTP data. SRTP sender will be enabled in WaitConfAck
            // state.
            if (!parent->srtpSecretsReady(ForReceiver)) {
                parent->sendInfo(Severe, CriticalSWError);
                sendErrorPacket(CriticalSWError);
                return;
            }
            nextState(WaitConfAck);
            sentPacket = static_cast<ZrtpPacketBase *>(confirm);

            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();         // returns to state Initial
                return;
            }
            if (startTimer(&T2) <= 0) {
                timerFailed(SevereNoTimer);  // returns to state Initial
            }
        }
    }
    else if (event->type == Timer) {
        if (!parent->sendPacketZRTP(sentPacket)) {
            sendFailed();             // returns to state Initial
            return;
        }
        if (nextTimer(&T2) <= 0) {
            timerFailed(SevereTooMuchRetries);     // returns to state Initial
        }
    }
    else {  // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        sentPacket = NULL;
        nextState(Initial);
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::acceptEnrollment(bool accepted) {
    if (!accepted) {
        zidRec->resetMITMKeyAvailable();
        callback->zrtpInformEnrollment(EnrollmentCanceled);
        getZidCacheInstance()->saveRecord(zidRec);
        return;
    }
    if (pbxSecretTmp != NULL) {
        zidRec->setMiTMData(pbxSecretTmp);
        getZidCacheInstance()->saveRecord(zidRec);
        callback->zrtpInformEnrollment(EnrollmentOk);
    }
    else {
        callback->zrtpInformEnrollment(EnrollmentFailed);
    }
    return;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

ZrtpQueue::onSRTPPacketError(IncomingRTPPkt& pkt, int32 errorCode)
{
    if (errorCode == -1) {
        sendInfo(Warning, WarningSRTPauthError);
    }
    else {
        sendInfo(Warning, WarningSRTPreplayError);
    }
    return false;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::setParanoidMode(bool yesNo) {
        enableParanoidMode = yesNo;
}

Project: ZRTPCPP
File: ZRtp.cpp

std::string ZRtp::getPeerProtcolVersion() {
    if (peerHelloVersion[0] == 0)
        return std::string();
    return std::string((char*)peerHelloVersion);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::setSignatureData(uint8* data, int32 length) {
    if (zrtpEngine != NULL)
        return zrtpEngine->setSignatureData(data, length);
    return 0;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::synchLeave() {
    callback->synchLeave();
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketHello* ZRtp::prepareHello() {
    return currentHelloPacket;
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketHelloAck* ZRtp::prepareHelloAck() {
    return &zrtpHelloAck;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

ZrtpQueue::sendImmediate(uint32 stamp, const unsigned char* data, size_t len)
{
    OutgoingDataQueue::sendImmediate(stamp, data, len);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::requestGoClear()  { }

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::zrtpNotSuppOther() {
    if (zrtpUserCallback != NULL) {
        zrtpUserCallback->zrtpNotSuppOther();
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::setSignatureData(uint8_t* data, int32_t length) {
    if ((length % 4) != 0)
        return false;

    ZrtpPacketConfirm* cfrm = (myRole == Responder) ? &zrtpConfirm1 : &zrtpConfirm2;
    cfrm->setSignatureLength(length / 4);
    return cfrm->setSignatureData(data, length);
}

Project: ZRTPCPP
File: ZRtp.cpp

std::string ZRtp::getPeerClientId() {
    if (peerClientId.empty())
        return std::string();
    return peerClientId;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

std::string ZrtpQueue::getPeerHelloHash()  {
    if (zrtpEngine != NULL)
        return zrtpEngine->getPeerHelloHash();
    else
        return std::string();
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::SASVerified() {
    if (paranoidMode)
        return;

    zidRec->setSasVerified();
    getZidCacheInstance()->saveRecord(zidRec);
}

Project: ZRTPCPP
File: ZrtpPacketHello.cpp

void ZrtpPacketHello::configureHello(ZrtpConfigure* config) {
    // The NumSupported* data is in ZrtpTextData.h 
    nHash = config->getNumConfiguredAlgos(HashAlgorithm);
    nCipher = config->getNumConfiguredAlgos(CipherAlgorithm);
    nPubkey = config->getNumConfiguredAlgos(PubKeyAlgorithm);
    nSas = config->getNumConfiguredAlgos(SasType);
    nAuth = config->getNumConfiguredAlgos(AuthLength);

    // length is fixed Header plus HMAC size (2*ZRTP_WORD_SIZE)
    int32_t length = sizeof(HelloPacket_t) + (2 * ZRTP_WORD_SIZE);
    length += nHash * ZRTP_WORD_SIZE;
    length += nCipher * ZRTP_WORD_SIZE;
    length += nPubkey * ZRTP_WORD_SIZE;
    length += nSas * ZRTP_WORD_SIZE;
    length += nAuth * ZRTP_WORD_SIZE;

    // Don't change order of this sequence
    oHash = sizeof(Hello_t);
    oCipher = oHash + (nHash * ZRTP_WORD_SIZE);
    oAuth = oCipher + (nCipher * ZRTP_WORD_SIZE);
    oPubkey = oAuth + (nAuth * ZRTP_WORD_SIZE);
    oSas = oPubkey + (nPubkey * ZRTP_WORD_SIZE);
    oHmac = oSas + (nSas * ZRTP_WORD_SIZE);         // offset to HMAC

    void* allocated = &data;
    memset(allocated, 0, sizeof(data));

    zrtpHeader = (zrtpPacketHeader_t *)&((HelloPacket_t *)allocated)->hdr;	// the standard header
    helloHeader = (Hello_t *)&((HelloPacket_t *)allocated)->hello;

    setZrtpId();

    // minus 1 for CRC size 
    setLength(length / ZRTP_WORD_SIZE);
    setMessageType((uint8_t*)HelloMsg);

    uint32_t lenField = nHash << 16;
    for (int32_t i = 0; i < nHash; i++) {
        AlgorithmEnum& hash = config->getAlgoAt(HashAlgorithm, i);
        setHashType(i, (int8_t*)hash.getName());
    }

    lenField |= nCipher << 12;
    for (int32_t i = 0; i < nCipher; i++) {
        AlgorithmEnum& cipher = config->getAlgoAt(CipherAlgorithm, i);
        setCipherType(i, (int8_t*)cipher.getName());
    }

    lenField |= nAuth << 8;
    for (int32_t i = 0; i < nAuth; i++) {
        AlgorithmEnum& length = config->getAlgoAt(AuthLength, i);
        setAuthLen(i, (int8_t*)length.getName());
    }

    lenField |= nPubkey << 4;
    for (int32_t i = 0; i < nPubkey; i++) {
        AlgorithmEnum& pubKey = config->getAlgoAt(PubKeyAlgorithm, i);
        setPubKeyType(i, (int8_t*)pubKey.getName());
    }

    lenField |= nSas;
    for (int32_t i = 0; i < nSas; i++) {
        AlgorithmEnum& sas = config->getAlgoAt(SasType, i);
        setSasType(i, (int8_t*)sas.getName());
    }
    *((uint32_t*)&helloHeader->flags) = zrtpHtonl(lenField);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::startZrtp() {
    if (zrtpEngine != NULL) {
        zrtpEngine->startZrtpEngine();
        zrtpUnprotect = 0;
        started = true;
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

AlgorithmEnum* ZRtp::findBestSASType(ZrtpPacketHello *hello) {

    int  i;
    int ii;
    int numAlgosOffered;
    AlgorithmEnum* algosOffered[ZrtpConfigure::maxNoOfAlgos+1];

    int numAlgosConf;
    AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+1];

    int num = hello->getNumSas();
    if (num == 0) {
        return &zrtpSasTypes.getByName(mandatorySasType);
    }
    // Build list of configured SAS algorithm names
    numAlgosConf = configureAlgos.getNumConfiguredAlgos(SasType);
    for (i = 0; i < numAlgosConf; i++) {
        algosConf[i] = &configureAlgos.getAlgoAt(SasType, i);
    }
    // Build list of offered known algos in Hello,
    for (numAlgosOffered = 0, i = 0; i < num; i++) {
        algosOffered[numAlgosOffered] = &zrtpSasTypes.getByName((const char*)hello->getSasType(i));
        if (!algosOffered[numAlgosOffered]->isValid())
            continue;
        numAlgosOffered++;
    }
    // Lookup offered algos in configured algos. Prefer algorithms that appear first in Hello packet (offered).
    for (i = 0; i < numAlgosOffered; i++) {
        for (ii = 0; ii < numAlgosConf; ii++) {
            if (*(int32_t*)(algosOffered[i]->getName()) == *(int32_t*)(algosConf[ii]->getName())) {
                return algosConf[ii];
            }
        }
    }
    // If we don't have a match - use the mandatory algorithm
    return &zrtpSasTypes.getByName(mandatorySasType);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

std::string ZrtpQueue::getHelloHash(int32_t index)  {
    if (zrtpEngine != NULL)
        return zrtpEngine->getHelloHash(index);
    else
        return std::string();
}

Project: ZRTPCPP
File: ZRtp.cpp

int32_t ZRtp::cancelTimer() {
    return (callback->cancelTimer());
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::setSignSas(bool sasSignMode) {
    signSas = sasSignMode;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::sendSASRelay(ZrtpPacketSASrelay* relay) {
    cancelTimer();
    sentPacket = static_cast<ZrtpPacketBase *>(relay);
    secSubstate = WaitSasRelayAck;
    if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(relay)) || (startTimer(&T2) <= 0)) {
        sendFailed();
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::setClientId(std::string id, HelloPacketVersion* hpv) {

    unsigned char tmp[CLIENT_ID_SIZE +1] = {' '};
    memcpy(tmp, id.c_str(), id.size());
    tmp[CLIENT_ID_SIZE] = 0;

    hpv->packet->setClientId(tmp);

    int32_t len = hpv->packet->getLength() * ZRTP_WORD_SIZE;

    // Hello packets are ready now, compute its HMAC
    // (excluding the HMAC field (2*ZTP_WORD_SIZE)) and store in Hello
    // use the implicit hash function
    uint8_t hmac[IMPL_MAX_DIGEST_LENGTH];
    uint32_t macLen;
    hmacFunctionImpl(H2, HASH_IMAGE_SIZE, (uint8_t*)hpv->packet->getHeaderBase(), len-(2*ZRTP_WORD_SIZE), hmac, &macLen);
    hpv->packet->setHMAC(hmac);

    // calculate hash over the final Hello packet, refer to chap 9.1 how to
    // use this hash in SIP/SDP.
    hashFunctionImpl((uint8_t*)hpv->packet->getHeaderBase(), len, hpv->helloHash);
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketErrorAck* ZRtp::prepareErrorAck(ZrtpPacketError* epkt) {
    sendInfo(ZrtpError, epkt->getErrorCode() * -1);
    return &zrtpErrorAck;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::acceptEnrollment(bool accepted) {
    if (zrtpEngine != NULL)
        zrtpEngine->acceptEnrollment(accepted);
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::timerFailed(int32_t subCode) {
    sentPacket = NULL;
    nextState(Initial);
    parent->zrtpNegotiationFailed(Severe, subCode);
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::zrtpNotSuppOther() {
    callback->zrtpNotSuppOther();
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::handleGoClear()
{
    fprintf(stderr, "Need to process a GoClear message!");
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evWaitConfirm2(void) {

    DEBUGOUT((cout << "Checking for match in WaitConfirm2.\n"));

    char *msg, first, secondLast, last;
    uint8_t *pkt;
    uint32_t errorCode = 0;

    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        secondLast = tolower(*(msg+6));
        last = tolower(*(msg+7));

        /*
         * DHPart2 or Commit in multi stream mode:
         * - resend Confirm1 packet
         * - stay in state
         */
        if ((first == 'd' && secondLast == '2') || (multiStream && (first == 'c' && last == ' '))) {
            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();             // returns to state Initial
            }
            return;
        }
        /*
         * Confirm2:
         * - prepare ConfAck
         * - switch on security (SRTP)
         * - switch to SecureState
         */
        if (first == 'c' && last == '2') {
            ZrtpPacketConfirm cpkt(pkt);
            ZrtpPacketConf2Ack* confack = parent->prepareConf2Ack(&cpkt, &errorCode);

            // Something went wrong during processing of the confirm2 packet
            if (confack == NULL) {
                sendErrorPacket(errorCode);
                return;
            }
            sentPacket = static_cast<ZrtpPacketBase *>(confack);

            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();             // returns to state Initial
                return;
            }
            if (!parent->srtpSecretsReady(ForReceiver) || !parent->srtpSecretsReady(ForSender))  {
                parent->sendInfo(Severe, CriticalSWError);
                sendErrorPacket(CriticalSWError);
                return;
            }
            nextState(SecureState);
            parent->sendInfo(Info, InfoSecureStateOn);
        }
    }
    else {  // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        sentPacket = NULL;
        nextState(Initial);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

ZrtpQueue::takeInDataPacket(void)
{
    InetHostAddress network_address;
    tpport_t transport_port;

    uint32 nextSize = (uint32)getNextDataPacketSize();
    unsigned char* buffer = new unsigned char[nextSize];
    int32 rtn = (int32)recvData(buffer, nextSize, network_address, transport_port);
    if ( (rtn < 0) || ((uint32)rtn > getMaxRecvPacketSize()) ){
        delete buffer;
        return 0;
    }

    IncomingZRTPPkt* packet = NULL;
    // check if this could be a real RTP/SRTP packet.
    if ((*buffer & 0xf0) != 0x10) {
        return (rtpDataPacket(buffer, rtn, network_address, transport_port));
    }

    // We assume all other packets are ZRTP packets here. Process
    // if ZRTP processing is enabled. Because valid RTP packets are
    // already handled we delete any packets here after processing.
    if (enableZrtp && zrtpEngine != NULL) {
        // Fixed header length + smallest ZRTP packet (includes CRC)
        if (rtn < (12 + sizeof(HelloAckPacket_t))) // data too small, dismiss
            return 0;

        // Get CRC value into crc (see above how to compute the offset)
        uint16_t temp = rtn - CRC_SIZE;
        uint32_t crc = *(uint32_t*)(buffer + temp);
        crc = ntohl(crc);

        if (!zrtpCheckCksum(buffer, temp, crc)) {
            delete buffer;
            if (zrtpUserCallback != NULL)
                zrtpUserCallback->showMessage(Warning, WarningCRCmismatch);
            return 0;
        }

        packet = new IncomingZRTPPkt(buffer,rtn);

        uint32 magic = packet->getZrtpMagic();

        // Check if it is really a ZRTP packet, if not delete it and return 0
        if (magic != ZRTP_MAGIC || zrtpEngine == NULL) {
            delete packet;
            return 0;
        }
        // cover the case if the other party sends _only_ ZRTP packets at the
        // beginning of a session. Start ZRTP in this case as well.
        if (!started) {
            startZrtp();
         }
        // this now points beyond the undefined and length field.
        // We need them, thus adjust
        unsigned char* extHeader =
                const_cast<unsigned char*>(packet->getHdrExtContent());
        extHeader -= 4;

        // store peer's SSRC, used when creating the CryptoContext
        peerSSRC = packet->getSSRC();
        zrtpEngine->processZrtpMessage(extHeader, peerSSRC, rtn);
    }
    delete packet;
    return 0;
}

Project: ZRTPCPP
File: ZRtp.cpp

std::string ZRtp::getHelloHash(int32_t index) {
    std::ostringstream stm;

    if (index < 0 || index >= MAX_ZRTP_VERSIONS)
        return std::string();

    uint8_t* hp = helloPackets[index].helloHash;

    char version[5] = {'\0'};
    strncpy(version, (const char*)helloPackets[index].packet->getVersion(), ZRTP_WORD_SIZE);

    stm << version;
    stm << " ";
    stm.fill('0');
    stm << hex;
    for (int i = 0; i < hashLengthImpl; i++) {
        stm.width(2);
        stm << static_cast<uint32_t>(*hp++);
    }
    return stm.str();
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

ZrtpQueue::ZrtpQueue(uint32 size, RTPApplication& app) :
        AVPQueue(size,app)
{
    init();
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::startZrtpEngine() {
    Event_t ev;

    if (stateEngine != NULL && stateEngine->inState(Initial)) {
        ev.type = ZrtpInitial;
        stateEngine->processEvent(&ev);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

ZrtpQueue::putData(uint32 stamp, const unsigned char* data, size_t len)
{
    OutgoingDataQueue::putData(stamp, data, len);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::synchEnter() {
    synchLock.enter();
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::isMultiStreamAvailable()  {
    if (zrtpEngine != NULL)
        return zrtpEngine->isMultiStreamAvailable();
    return false;
}

Project: ZRTPCPP
File: ZRtp.cpp

AlgorithmEnum* ZRtp::findBestPubkey(ZrtpPacketHello *hello) {

    AlgorithmEnum* peerIntersect[ZrtpConfigure::maxNoOfAlgos+1];
    AlgorithmEnum* ownIntersect[ZrtpConfigure::maxNoOfAlgos+1];

    // Build list of own pubkey algorithm names, must follow the order
    // defined in RFC 6189, chapter 4.1.2.
    const char *orderedAlgos[] = {dh2k, ec25, dh3k, ec38};
    int numOrderedAlgos = sizeof(orderedAlgos) / sizeof(const char*);

    int numAlgosPeer = hello->getNumPubKeys();
    if (numAlgosPeer == 0) {
        hash = &zrtpHashes.getByName(mandatoryHash);             // set mandatory hash
        return &zrtpPubKeys.getByName(mandatoryPubKey);
    }
    // Build own list of intersecting algos, keep own order or algorithms
    // The list must include real public key algorithms only, so skip mult-stream mode, preshared and alike.
    int numAlgosOwn = configureAlgos.getNumConfiguredAlgos(PubKeyAlgorithm);
    int numOwnIntersect = 0;
    for (int i = 0; i < numAlgosOwn; i++) {
        ownIntersect[numOwnIntersect] = &configureAlgos.getAlgoAt(PubKeyAlgorithm, i);
        if (*(int32_t*)(ownIntersect[numOwnIntersect]->getName()) == *(int32_t*)mult) {
            continue;                               // skip multi-stream mode
        }
        for (int ii = 0; ii < numAlgosPeer; ii++) {
            if (*(int32_t*)(ownIntersect[numOwnIntersect]->getName()) == *(int32_t*)(zrtpPubKeys.getByName((const char*)hello->getPubKeyType(ii)).getName())) {
                numOwnIntersect++;
                break;
            }
        }
    }
    // Build list of peer's intersecting algos: take own list as input, order according to sequence in hello packet (peer's order)
    int numPeerIntersect = 0;
    for (int i = 0; i < numAlgosPeer; i++) {
        peerIntersect[numPeerIntersect] = &zrtpPubKeys.getByName((const char*)hello->getPubKeyType(i));
        for (int ii = 0; ii < numOwnIntersect; ii++) {
            if (*(int32_t*)(ownIntersect[ii]->getName()) == *(int32_t*)(peerIntersect[numPeerIntersect]->getName())) {
                numPeerIntersect++;
                break;
            }
        }
    }
    if (numPeerIntersect == 0) {
        // If we don't find a common algorithm - use the mandatory algorithms
        hash = &zrtpHashes.getByName(mandatoryHash);
        return &zrtpPubKeys.getByName(mandatoryPubKey);
    }
    AlgorithmEnum* useAlgo;
    if (numPeerIntersect > 1 && *(int32_t*)(ownIntersect[0]->getName()) != *(int32_t*)(peerIntersect[0]->getName())) {
        int own, peer;

        const int32_t *name = (int32_t*)ownIntersect[0]->getName();
        for (own = 0; own < numOrderedAlgos; own++) {
            if (*name == *(int32_t*)orderedAlgos[own])
                break;
        }
        name = (int32_t*)peerIntersect[0]->getName();
        for (peer = 0; peer < numOrderedAlgos; peer++) {
            if (*name == *(int32_t*)orderedAlgos[peer])
                break;
        }
        if (own < peer) {
            useAlgo = ownIntersect[0];
        }
        else {
            useAlgo = peerIntersect[0];
        }
        // find fastest of conf vs intersecting
    }
    else {
        useAlgo = peerIntersect[0];
    }
    // select a corresponding strong hash if necessary.
    if (*(int32_t*)(useAlgo->getName()) == *(int32_t*)ec38) {
        hash = getStrongHashOffered(hello);
        cipher = getStrongCipherOffered(hello);
    }
    else {
        hash = findBestHash(hello);
    }
    return useAlgo;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::synchEnter() {
    callback->synchEnter();
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::setMultiStrParams(std::string parameters)  {
    if (zrtpEngine != NULL)
        zrtpEngine->setMultiStrParams(parameters);
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketClearAck* ZRtp::prepareClearAck(ZrtpPacketGoClear* gpkt) {
    sendInfo(Warning, WarningGoClearReceived);
    return &zrtpClearAck;
}

Project: ZRTPCPP
File: ZrtpPacketHello.cpp

ZrtpPacketHello::ZrtpPacketHello(uint8_t *data) {
    DEBUGOUT((fprintf(stdout, "Creating Hello packet from data\n")));

    zrtpHeader = (zrtpPacketHeader_t *)&((HelloPacket_t *)data)->hdr;	// the standard header
    helloHeader = (Hello_t *)&((HelloPacket_t *)data)->hello;

    uint32_t t = *((uint32_t*)&helloHeader->flags);
    uint32_t temp = zrtpNtohl(t);

    nHash = (temp & (0xf << 16)) >> 16;
    nHash &= 0x7;                              // restrict to max 7 algorithms
    nCipher = (temp & (0xf << 12)) >> 12;
    nCipher &= 0x7;
    nAuth = (temp & (0xf << 8)) >> 8;
    nAuth &= 0x7;
    nPubkey = (temp & (0xf << 4)) >> 4;
    nPubkey &= 0x7;
    nSas = temp & 0xf;
    nSas &= 0x7;

    // +2 : the MAC at the end of the packet
    computedLength = nHash + nCipher + nAuth + nPubkey + nSas + sizeof(HelloPacket_t)/ZRTP_WORD_SIZE + 2;

    oHash = sizeof(Hello_t);
    oCipher = oHash + (nHash * ZRTP_WORD_SIZE);
    oAuth = oCipher + (nCipher * ZRTP_WORD_SIZE);
    oPubkey = oAuth + (nAuth * ZRTP_WORD_SIZE);
    oSas = oPubkey + (nPubkey * ZRTP_WORD_SIZE);
    oHmac = oSas + (nSas * ZRTP_WORD_SIZE);         // offset to HMAC
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketDHPart* ZRtp::prepareDHPart2(ZrtpPacketDHPart *dhPart1, uint32_t* errMsg) {

    uint8_t* pvr;

    sendInfo(Info, InfoInitDH1Received);

    // Because we are initiator the protocol engine didn't receive Commit
    // thus could not store a peer's H2. A two step SHA256 is required to
    // re-compute H3. Then compare with peer's H3 from peer's Hello packet.
    // Must use implicit hash function.
    uint8_t tmpHash[IMPL_MAX_DIGEST_LENGTH];
    hashFunctionImpl(dhPart1->getH1(), HASH_IMAGE_SIZE, tmpHash); // Compute peer's H2
    memcpy(peerH2, tmpHash, HASH_IMAGE_SIZE);
    hashFunctionImpl(peerH2, HASH_IMAGE_SIZE, tmpHash);          // Compute peer's H3 (tmpHash)

    if (memcmp(tmpHash, peerH3, HASH_IMAGE_SIZE) != 0) {
        *errMsg = IgnorePacket;
        return NULL;
    }

    // Check HMAC of previous Hello packet stored in temporary buffer. The
    // HMAC key of the Hello packet is peer's H2 that was computed above.
    // Refer to chapter 9.1 and chapter 10.
    if (!checkMsgHmac(peerH2)) {
        sendInfo(Severe, SevereHelloHMACFailed);
        *errMsg = CriticalSWError;
        return NULL;
    }

    // get memory to store DH result TODO: make it fixed memory
    DHss = new uint8_t[dhContext->getDhSize()];
    if (DHss == NULL) {
        *errMsg = CriticalSWError;
        return NULL;
    }

    // get and check Responder's public value, see chap. 5.4.3 in the spec
    pvr = dhPart1->getPv();
    if (!dhContext->checkPubKey(pvr)) {
        *errMsg = DHErrorWrongPV;
        return NULL;
    }
    dhContext->computeSecretKey(pvr, DHss);

    myRole = Initiator;

    // We are Initiator: the Responder's Hello and the Initiator's (our) Commit
    // are already hashed in the context. Now hash the Responder's DH1 and then
    // the Initiator's (our) DH2 in that order.
    // Use the negotiated hash function.
    hashCtxFunction(msgShaContext, (unsigned char*)dhPart1->getHeaderBase(), dhPart1->getLength() * ZRTP_WORD_SIZE);
    hashCtxFunction(msgShaContext, (unsigned char*)zrtpDH2.getHeaderBase(), zrtpDH2.getLength() * ZRTP_WORD_SIZE);

    // Compute the message Hash
    closeHashCtx(msgShaContext, messageHash);
    msgShaContext = NULL;
    // Now compute the S0, all dependend keys and the new RS1. The function
    // also performs sign SAS callback if it's active.
    generateKeysInitiator(dhPart1, zidRec);

    delete dhContext;
    dhContext = NULL;

    // TODO: at initiator we can call signSAS at this point, don't dealy until confirm1 reveived
    // store DHPart1 data temporarily until we can check HMAC after receiving Confirm1
    storeMsgTemp(dhPart1);
    return &zrtpDH2;
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::isEnrollmentMode() {
    return enrollmentMode;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

ZrtpQueue::initialize(const char *zidFilename, bool autoEnable, ZrtpConfigure* config)
{
    int32_t ret = 1;

    synchEnter();

    ZrtpConfigure* configOwn = NULL;
    if (config == NULL) {
        config = configOwn = new ZrtpConfigure();
        config->setStandardConfig();
    }
    enableZrtp = autoEnable;

    config->setParanoidMode(enableParanoidMode);

    if (staticTimeoutProvider == NULL) {
        staticTimeoutProvider = new TimeoutProvider<std::string, ZrtpQueue*>();
        staticTimeoutProvider->start();
    }
    ZIDCache* zf = getZidCacheInstance();
    if (!zf->isOpen()) {
        std::string fname;
        if (zidFilename == NULL) {
            char *home = getenv("HOME");
            std::string baseDir = (home != NULL) ? (std::string(home) + std::string("/."))
                                                    : std::string(".");
            fname = baseDir + std::string("GNUZRTP.zid");
            zidFilename = fname.c_str();
        }
        if (zf->open((char *)zidFilename) < 0) {
            enableZrtp = false;
            ret = -1;
        }
    }
    if (ret > 0) {
        const uint8_t* ownZid = zf->getZid();
        zrtpEngine = new ZRtp((uint8_t*)ownZid, (ZrtpCallback*)this, clientIdString, config, mitmMode, signSas);
    }
    if (configOwn != NULL) {
        delete configOwn;
    }
    synchLeave();
    return ret;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evWaitErrorAck(void) {
    DEBUGOUT((cout << "Checking for match in ErrorAck.\n"));

    char *msg, first, last;
    uint8_t *pkt;

    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));

        /*
         * Errorck:
         * - stop resending Error,
         * - switch to state Initial
         */
        if (first == 'e' && last =='k') {
            cancelTimer();
            sentPacket = NULL;
            nextState(Initial);
        }
    }
    // Timer event triggered - this is Timer T2 to resend Error.
    else if (event->type == Timer) {
        if (!parent->sendPacketZRTP(sentPacket)) {
            sendFailed();                 // returns to state Initial
            return;
        }
        if (nextTimer(&T2) <= 0) {
            timerFailed(SevereTooMuchRetries);     // returns to state Initial
        }
    }
    else {  // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        sentPacket = NULL;
        nextState(Initial);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

ZrtpQueue::ZrtpQueue(uint32 ssrc, uint32 size, RTPApplication& app) :
        AVPQueue(ssrc,size,app)
{
    init();
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::isMultiStream() {
    return multiStream;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

ZrtpQueue::rtpDataPacket(unsigned char* buffer, int32 rtn, InetHostAddress network_address, tpport_t transport_port)
{
     // Special handling of padding to take care of encrypted content.
    // In case of SRTP the padding length field is also encrypted, thus
    // it gives a wrong length. Check and clear padding bit before
    // creating the RTPPacket. Will be set and re-computed after a possible
    // SRTP decryption.
    uint8 padSet = (*buffer & 0x20);
    if (padSet) {
        *buffer = *buffer & ~0x20;          // clear padding bit
    }
    //  build a packet. It will link itself to its source
    IncomingRTPPkt* packet =
        new IncomingRTPPkt(buffer,rtn);

    // Generic header validity check.
    if ( !packet->isHeaderValid() ) {
        delete packet;
        return 0;
    }

    // Look for a CryptoContext for this packet's SSRC
    CryptoContext* pcc = getInQueueCryptoContext(packet->getSSRC());

    // If no crypto context is available for this SSRC but we are already in
    // Secure state then create a CryptoContext for this SSRC.
    // Assumption: every SSRC stream sent via this connection is secured
    // _and_ uses the same crypto parameters.
    if (pcc == NULL) {
        pcc = getInQueueCryptoContext(0);
        if (pcc != NULL) {
            pcc = pcc->newCryptoContextForSSRC(packet->getSSRC(), 0, 0L);
            if (pcc != NULL) {
                pcc->deriveSrtpKeys(0);
                setInQueueCryptoContext(pcc);
            }
        }
    }
    // If no crypto context: then either ZRTP is off or in early state
    // If crypto context is available then unprotect data here. If an error
    // occurs report the error and discard the packet.
    if (pcc != NULL) {
        int32 ret;
        if ((ret = packet->unprotect(pcc)) < 0) {
            if (!onSRTPPacketError(*packet, ret)) {
                delete packet;
                return 0;
            }
        }
        if (started && zrtpEngine->inState(WaitConfAck)) {
            zrtpEngine->conf2AckSecure();
        }
    }

    // virtual for profile-specific validation and processing.
    if (!onRTPPacketRecv(*packet) ) {
        delete packet;
        return 0;
    }
    if (padSet) {
        packet->reComputePayLength(true);
    }
    // get time of arrival
    struct timeval recvtime;
    gettimeofday(&recvtime,NULL);

    bool source_created;
    SyncSourceLink* sourceLink =
            getSourceBySSRC(packet->getSSRC(),source_created);
    SyncSource* s = sourceLink->getSource();
    if ( source_created ) {
        // Set data transport address.
        setDataTransportPort(*s,transport_port);
        // Network address is assumed to be the same as the control one
        setNetworkAddress(*s,network_address);
        sourceLink->initStats();
        // First packet arrival time.
        sourceLink->setInitialDataTime(recvtime);
        sourceLink->setProbation(getMinValidPacketSequence());
        if ( sourceLink->getHello() )
            onNewSyncSource(*s);
    }
    else if ( 0 == s->getDataTransportPort() ) {
        // Test if RTCP packets had been received but this is the
        // first data packet from this source.
        setDataTransportPort(*s,transport_port);
    }

    // Before inserting in the queue,
    // 1) check for collisions and loops. If the packet cannot be
    //    assigned to a source, it will be rejected.
    // 2) check the source is a sufficiently well known source
    // TODO: also check CSRC identifiers.
    if (checkSSRCInIncomingRTPPkt(*sourceLink, source_created,
        network_address, transport_port) &&
        recordReception(*sourceLink,*packet,recvtime) ) {
        // now the packet link is linked in the queues
        IncomingRTPPktLink* packetLink = new IncomingRTPPktLink(packet, sourceLink, recvtime,
                                       packet->getTimestamp() - sourceLink->getInitialDataTimestamp(),
                                       NULL,NULL,NULL,NULL);
        insertRecvPacket(packetLink);
    } else {
        // must be discarded due to collision or loop or
        // invalid source
        delete packet;
        return 0;
    }
    // Start the ZRTP engine after we got a at least one RTP packet and
    // sent some as well or we are in multi-stream mode.
    if (!started && enableZrtp) {
        startZrtp();
    }
    return rtn;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

ZrtpQueue::~ZrtpQueue() {

    endQueue();
    stopZrtp();

    if (zrtpUserCallback != NULL) {
        delete zrtpUserCallback;
        zrtpUserCallback = NULL;
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::synchLeave() {
    synchLock.leave();
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::verifyH2(ZrtpPacketCommit *commit) {
    uint8_t tmpH3[IMPL_MAX_DIGEST_LENGTH];

    sha256(commit->getH2(), HASH_IMAGE_SIZE, tmpH3);
    if (memcmp(tmpH3, peerH3, HASH_IMAGE_SIZE) != 0) {
        return false;
    }
    return true;
}

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketConfirm* ZRtp::prepareConfirm1MultiStream(ZrtpPacketCommit* commit, uint32_t* errMsg) {

    sendInfo(Info, InfoRespCommitReceived);

    // The following code checks the hash chain according chapter 10 to detect
    // false ZRTP packets.
    // Use implicit hash function
    uint8_t tmpH3[IMPL_MAX_DIGEST_LENGTH];
    memcpy(peerH2, commit->getH2(), HASH_IMAGE_SIZE);
    hashFunctionImpl(peerH2, HASH_IMAGE_SIZE, tmpH3);

    if (memcmp(tmpH3, peerH3, HASH_IMAGE_SIZE) != 0) {
        *errMsg = IgnorePacket;
        return NULL;
    }

    // Check HMAC of previous Hello packet stored in temporary buffer. The
    // HMAC key of peer's Hello packet is peer's H2 that is contained in the
    // Commit packet. Refer to chapter 9.1.
    if (!checkMsgHmac(peerH2)) {
        sendInfo(Severe, SevereHelloHMACFailed);
        *errMsg = CriticalSWError;
        return NULL;
    }

    // check if Commit contains "Mult" as pub key type
    AlgorithmEnum* cp = &zrtpPubKeys.getByName((const char*)commit->getPubKeysType());
    if (!cp->isValid() || *(int32_t*)(cp->getName()) != *(int32_t*)mult) {
        *errMsg = UnsuppPKExchange;
        return NULL;
    }

    // check if we support the commited cipher
    cp = &zrtpSymCiphers.getByName((const char*)commit->getCipherType());
    if (!cp->isValid()) { // no match - something went wrong
        *errMsg = UnsuppCiphertype;
        return NULL;
    }
    cipher = cp;

    // check if we support the commited Authentication length
    cp = &zrtpAuthLengths.getByName((const char*)commit->getAuthLen());
    if (!cp->isValid()) { // no match - something went wrong
        *errMsg = UnsuppSRTPAuthTag;
        return NULL;
    }
    authLength = cp;

    // check if we support the commited hash type
    cp = &zrtpHashes.getByName((const char*)commit->getHashType());
    if (!cp->isValid()) { // no match - something went wrong
        *errMsg = UnsuppHashType;
        return NULL;
    }
    // check if the peer's commited hash is the same that we used when
    // preparing our commit packet. If not do the necessary resets and
    // recompute some data.
    if (*(int32_t*)(hash->getName()) != *(int32_t*)(cp->getName())) {
        hash = cp;
        setNegotiatedHash(hash);
    }
    myRole = Responder;

    // We are responder. Release a possibly pre-computed SHA256 context
    // because this was prepared for Initiator. Then create a new one.
    if (msgShaContext != NULL) {
        closeHashCtx(msgShaContext, NULL);
    }
    msgShaContext = createHashCtx();

    // Hash messages to produce overall message hash:
    // First the Responder's (my) Hello message, second the Commit
    // (always Initator's)
    // use negotiated hash
    hashCtxFunction(msgShaContext, (unsigned char*)currentHelloPacket->getHeaderBase(), currentHelloPacket->getLength() * ZRTP_WORD_SIZE);
    hashCtxFunction(msgShaContext, (unsigned char*)commit->getHeaderBase(), commit->getLength() * ZRTP_WORD_SIZE);

    closeHashCtx(msgShaContext, messageHash);
    msgShaContext = NULL;

    generateKeysMultiStream();

    // Fill in Confirm1 packet.
    zrtpConfirm1.setMessageType((uint8_t*)Confirm1Msg);
    zrtpConfirm1.setExpTime(0xFFFFFFFF);
    zrtpConfirm1.setIv(randomIV);
    zrtpConfirm1.setHashH0(H0);

    uint8_t confMac[MAX_DIGEST_LENGTH];
    uint32_t macLen;

    // Encrypt and HMAC with Responder's key - we are Respondere here
    int32_t hmlen = (zrtpConfirm1.getLength() - 9) * ZRTP_WORD_SIZE;
    cipher->getEncrypt()(zrtpKeyR, cipher->getKeylen(), randomIV, zrtpConfirm1.getHashH0(), hmlen);

    // Use negotiated HMAC (hash)
    hmacFunction(hmacKeyR, hashLength, (unsigned char*)zrtpConfirm1.getHashH0(), hmlen, confMac, &macLen);

    zrtpConfirm1.setHmac(confMac);

    // Store Commit data temporarily until we can check HMAC after receiving Confirm2
    storeMsgTemp(commit);
    return &zrtpConfirm1;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evCommitSent(void) {

    DEBUGOUT((cout << "Checking for match in CommitSend.\n"));

    char *msg, first, middle, last, secondLast;
    uint8_t *pkt;
    uint32_t errorCode = 0;

    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        middle = tolower(*(msg+4));
        last = tolower(*(msg+7));
        secondLast = tolower(*(msg+6));

        /*
         * HelloAck or Hello:
         * - delayed "HelloAck" or "Hello", maybe due to network latency, just 
         *   ignore it
         * - no switch in state, leave timer as it is
         */
        if (first == 'h' && middle == 'o' && (last =='k' || last == ' ')) {
            return;
        }

        /*
         * Commit:
         * We have a "Commit" clash. Resolve it.
         *
         * - switch off resending Commit
         * - compare my hvi with peer's hvi
         * - if my hvi is greater
         *   - we are Initiator, stay in state, wait for peer's DHPart1 packet
         * - else
         *   - we are Responder, stop timer
         *   - prepare and send DH1Packt,
         *   - switch to state WaitDHPart2, implies Responder path
         */
        if (first == 'c' && last == ' ') {
            ZrtpPacketCommit zpCo(pkt);

            if (!parent->verifyH2(&zpCo)) {
                return;
            }
            cancelTimer();         // this cancels the Commit timer T2

            // if our hvi is less than peer's hvi: switch to Responder mode and
            // send DHPart1 or Confirm1 packet. Peer (as Initiator) will retrigger if
            // necessary
            //
            if (parent->compareCommit(&zpCo) < 0) {
                if (!multiStream) {
                    ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(&zpCo, &errorCode);

                    // Something went wrong during processing of the Commit packet
                    if (dhPart1 == NULL) {
                        if (errorCode != IgnorePacket) {
                            sendErrorPacket(errorCode);
                        }
                        return;
                    }
                    nextState(WaitDHPart2);
                    sentPacket = static_cast<ZrtpPacketBase *>(dhPart1);
                }
                else {
                    ZrtpPacketConfirm* confirm = parent->prepareConfirm1MultiStream(&zpCo, &errorCode);

                    // Something went wrong during processing of the Commit packet
                    if (confirm == NULL) {
                        if (errorCode != IgnorePacket) {
                            sendErrorPacket(errorCode);
                        }
                        return;
                    }
                    nextState(WaitConfirm2);
                    sentPacket = static_cast<ZrtpPacketBase *>(confirm);
                }
                if (!parent->sendPacketZRTP(sentPacket)) {
                    sendFailed();       // returns to state Initial
                }
            }
            // Stay in state, we are Initiator, wait for DHPart1 of Confirm1 packet from peer.
            // Resend Commit after timeout until we get a DHPart1 or Confirm1
            else {
                if (startTimer(&T2) <= 0) { // restart the Commit timer, gives peer more time to react
                    timerFailed(SevereNoTimer);    // returns to state Initial
                }
            }
            return;
        }

        /*
         * DHPart1:
         * - switch off resending Commit
         * - Prepare and send DHPart2
         * - switch to WaitConfirm1
         * - start timer to resend DHPart2 if necessary, we are Initiator
         */
        if (first == 'd' && secondLast == '1') {
            cancelTimer();
            sentPacket = NULL;
            ZrtpPacketDHPart dpkt(pkt);
            ZrtpPacketDHPart* dhPart2 = parent->prepareDHPart2(&dpkt, &errorCode);

            // Something went wrong during processing of the DHPart1 packet
            if (dhPart2 == NULL) {
                if (errorCode != IgnorePacket) {
                    sendErrorPacket(errorCode);
                }
                else {
                    if (startTimer(&T2) <= 0) {
                        timerFailed(SevereNoTimer);       // switches to state Initial
                    }
                }

                return;
            }
            sentPacket = static_cast<ZrtpPacketBase *>(dhPart2);
            nextState(WaitConfirm1);

            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();       // returns to state Initial
                return;
            }
            if (startTimer(&T2) <= 0) {
                timerFailed(SevereNoTimer);       // switches to state Initial
            }
            return;
        }

        /*
         * Confirm1 and multi-stream mode
         * - switch off resending commit
         * - prepare Confirm2
         */
        if (multiStream && (first == 'c' && last == '1')) {
            cancelTimer();
            ZrtpPacketConfirm cpkt(pkt);

            ZrtpPacketConfirm* confirm = parent->prepareConfirm2MultiStream(&cpkt, &errorCode);

            // Something went wrong during processing of the Confirm1 packet
            if (confirm == NULL) {
                sendErrorPacket(errorCode);
                return;
            }
            nextState(WaitConfAck);
            sentPacket = static_cast<ZrtpPacketBase *>(confirm);

            if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();         // returns to state Initial
                return;
            }
            if (startTimer(&T2) <= 0) {
                timerFailed(SevereNoTimer);  // returns to state Initial
                return;
            }
            // according to chap 5.6: after sending Confirm2 the Initiator must
            // be ready to receive SRTP data. SRTP sender will be enabled in WaitConfAck
            // state.
            if (!parent->srtpSecretsReady(ForReceiver)) {
                parent->sendInfo(Severe, CriticalSWError);
                sendErrorPacket(CriticalSWError);
                return;
            }
        }
    }
    // Timer event triggered, resend the Commit packet
    else if (event->type == Timer) {
        if (!parent->sendPacketZRTP(sentPacket)) {
                sendFailed();       // returns to state Initial
                return;
        }
        if (nextTimer(&T2) <= 0) {
            timerFailed(SevereTooMuchRetries);       // returns to state Initial
        }
    }
    else {  // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        sentPacket = NULL;
        nextState(Initial);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::srtpSecretsOn(std::string c, std::string s, bool verified)
{

  if (zrtpUserCallback != NULL) {
    zrtpUserCallback->secureOn(c);
    if (!s.empty()) {
        zrtpUserCallback->showSAS(s, verified);
    }
  }
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::sendErrorPacket(uint32_t errorCode) {
    cancelTimer();

    ZrtpPacketError* err = parent->prepareError(errorCode);
    parent->zrtpNegotiationFailed(ZrtpError, errorCode);

    sentPacket =  static_cast<ZrtpPacketBase *>(err);
    nextState(WaitErrorAck);
    if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(err)) || (startTimer(&T2) <= 0)) {
        sendFailed();
    }
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::setEnrollmentMode(bool enrollmentMode) {
    this->enrollmentMode = enrollmentMode;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

bool ZrtpStateClass::isMultiStream() {
    return multiStream;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::isParanoidMode() {
        return enableParanoidMode;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::computeHvi(ZrtpPacketDHPart* dh, ZrtpPacketHello *hello) {

    unsigned char* data[3];
    unsigned int length[3];
    /*
     * populate the vector to compute the HVI hash according to the
     * ZRTP specification.
     */
    data[0] = (uint8_t*)dh->getHeaderBase();
    length[0] = dh->getLength() * ZRTP_WORD_SIZE;

    data[1] = (uint8_t*)hello->getHeaderBase();
    length[1] = hello->getLength() * ZRTP_WORD_SIZE;

    data[2] = NULL;            // terminate data chunks
    hashListFunction(data, length, hvi);
    return;
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::srtpSecretsOff(EnableSecurity part) {
    callback->srtpSecretsOff(part);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::setEnableZrtp(bool onOff)   {
    enableZrtp = onOff;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::processEvent(Event_t *ev) {

    char *msg, first, middle, last;
    uint8_t *pkt;

    parent->synchEnter();

    event = ev;
    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;
        first = tolower(*msg);
        middle = tolower(*(msg+4));
        last = tolower(*(msg+7));

        // Sanity check of packet size for all states except WaitErrorAck.
        if (!inState(WaitErrorAck)) {
            uint16_t totalLength = *(uint16_t*)(pkt+2);
            totalLength = zrtpNtohs(totalLength) * ZRTP_WORD_SIZE;
            totalLength += 12 + sizeof(uint32_t);           // 12 bytes is fixed header, uint32_t is CRC

            if (totalLength != ev->length) {
                fprintf(stderr, "Total length does not match received length: %d - %ld\n", totalLength, ev->length);
                sendErrorPacket(MalformedPacket);
                parent->synchLeave();
                return;
            }
        }

        // Check if this is an Error packet.
        if (first == 'e' && middle =='r' && last == ' ') {
            /*
             * Process a received Error packet.
             *
             * In any case stop timer to prevent resending packets.
             * Use callback method to prepare and get an ErrorAck packet.
             * Modify event type to "ErrorPkt" and hand it over to current
             * state for further processing.
             */
            cancelTimer();
            ZrtpPacketError epkt(pkt);
            ZrtpPacketErrorAck* eapkt = parent->prepareErrorAck(&epkt);
            parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(eapkt));
            event->type = ErrorPkt;
        }
        else if (first == 'p' && middle == ' ' && last == ' ') {
            ZrtpPacketPing ppkt(pkt);
            ZrtpPacketPingAck* ppktAck = parent->preparePingAck(&ppkt);
            if (ppktAck != NULL) {          // ACK only to valid PING packet, otherwise ignore it
                parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(ppktAck));
            }
            parent->synchLeave();
            return;
        }
        else if (first == 's' && last == 'y') {
            uint32_t errorCode = 0;
            ZrtpPacketSASrelay* srly = new ZrtpPacketSASrelay(pkt);
            ZrtpPacketRelayAck* rapkt = parent->prepareRelayAck(srly, &errorCode);
            parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(rapkt));
            parent->synchLeave();
            return;
        }
    }
    /*
     * Shut down protocol state engine: cancel outstanding timer, further
     * processing in current state.
     */
    else if (event->type == ZrtpClose) {
        cancelTimer();
    }
    engine->processEvent(*this);
    parent->synchLeave();
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::setAuxSecret(uint8* data, int32_t length)  {
    if (zrtpEngine != NULL)
        zrtpEngine->setAuxSecret(data, length);
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::setMultiStream(bool multi) {
    multiStream = multi;
}

Project: ZRTPCPP
File: ZrtpPacketHello.cpp

ZrtpPacketHello::~ZrtpPacketHello() {
    DEBUGOUT((fprintf(stdout, "Deleting Hello packet: alloc: %x\n", allocated)));
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

uint32 IncomingZRTPPkt::getZrtpMagic() const {
     return ntohl(getHeader()->timestamp);
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::resetSASVerified() {
    if (zrtpEngine != NULL)
        zrtpEngine->resetSASVerified();
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::sendFailed() {
    sentPacket = NULL;
    nextState(Initial);
    parent->zrtpNegotiationFailed(Severe, SevereCannotSend);
}

Project: ZRTPCPP
File: ZRtp.cpp

bool ZRtp::isPeerEnrolled() {
    return peerIsEnrolled;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::isEnableZrtp() {
    return enableZrtp;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::goClearOk()    {  }

Project: ZRTPCPP
File: ZRtp.cpp

    int ZrtpAvailable()
    {
        return 1;
    }

Project: ZRTPCPP
File: ZRtp.cpp

ZrtpPacketConfirm* ZRtp::prepareConfirm2MultiStream(ZrtpPacketConfirm* confirm1, uint32_t* errMsg) {

    // check Confirm1 packet using the keys
    // prepare Confirm2 packet
    // don't update SAS, RS
    sendInfo(Info, InfoInitConf1Received);

    uint8_t confMac[MAX_DIGEST_LENGTH];
    uint32_t macLen;

    closeHashCtx(msgShaContext, messageHash);
    msgShaContext = NULL;
    myRole = Initiator;

    generateKeysMultiStream();

    // Use the Responder's keys here because we are Initiator here and
    // receive packets from Responder
    int32_t hmlen = (confirm1->getLength() - 9) * ZRTP_WORD_SIZE;

    // Use negotiated HMAC (hash)
    hmacFunction(hmacKeyR, hashLength, (unsigned char*)confirm1->getHashH0(), hmlen, confMac, &macLen);

    if (memcmp(confMac, confirm1->getHmac(), HMAC_SIZE) != 0) {
        *errMsg = ConfirmHMACWrong;
        return NULL;
    }
    // Cast away the const for the IV - the standalone AES CFB modifies IV on return
    cipher->getDecrypt()(zrtpKeyR, cipher->getKeylen(), (uint8_t*)confirm1->getIv(), confirm1->getHashH0(), hmlen);

    // Because we are initiator the protocol engine didn't receive Commit and
    // because we are using multi-stream mode here we also did not receive a DHPart1 and
    // thus could not store a responder's H2 or H1. A two step hash is required to
    // re-compute H1, H2.
    // USe implicit hash function.
    uint8_t tmpHash[IMPL_MAX_DIGEST_LENGTH];
    hashFunctionImpl(confirm1->getHashH0(), HASH_IMAGE_SIZE, tmpHash); // Compute peer's H1 in tmpHash
    hashFunctionImpl(tmpHash, HASH_IMAGE_SIZE, tmpHash);               // Compute peer's H2 in tmpHash
    memcpy(peerH2, tmpHash, HASH_IMAGE_SIZE);                          // copy and truncate to peerH2

    // Check HMAC of previous Hello packet stored in temporary buffer. The
    // HMAC key of the Hello packet is peer's H2 that was computed above.
    // Refer to chapter 9.1 and chapter 10.
    if (!checkMsgHmac(peerH2)) {
        sendInfo(Severe, SevereHelloHMACFailed);
        *errMsg = CriticalSWError;
        return NULL;
    }
    // now generate my Confirm2 message
    zrtpConfirm2.setMessageType((uint8_t*)Confirm2Msg);
    zrtpConfirm2.setHashH0(H0);
    zrtpConfirm2.setExpTime(0xFFFFFFFF);
    zrtpConfirm2.setIv(randomIV);

    // Encrypt and HMAC with Initiator's key - we are Initiator here
    hmlen = (zrtpConfirm2.getLength() - 9) * ZRTP_WORD_SIZE;
    cipher->getEncrypt()(zrtpKeyI, cipher->getKeylen(), randomIV, zrtpConfirm2.getHashH0(), hmlen);

    // Use negotiated HMAC (hash)
    hmacFunction(hmacKeyI, hashLength, (unsigned char*)zrtpConfirm2.getHashH0(), hmlen, confMac, &macLen);

    zrtpConfirm2.setHmac(confMac);
    return &zrtpConfirm2;
}

Project: ZRTPCPP
File: ZRtp.cpp

AlgorithmEnum* ZRtp::getStrongCipherOffered(ZrtpPacketHello *hello) {

    int num = hello->getNumCiphers();
    for (int i = 0; i < num; i++) {
        if (*(int32_t*)(hello->getCipherType(i)) == *(int32_t*)aes3 ||
            *(int32_t*)(hello->getCipherType(i)) == *(int32_t*)two3) {
            return &zrtpSymCiphers.getByName((const char*)hello->getCipherType(i));
        }
    }
    return NULL;
}

Project: ZRTPCPP
File: ZRtp.cpp

AlgorithmEnum* ZRtp::findBestHash(ZrtpPacketHello *hello) {

    int i;
    int ii;
    int numAlgosOffered;
    AlgorithmEnum* algosOffered[ZrtpConfigure::maxNoOfAlgos+1];

    int numAlgosConf;
    AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+1];

    // If Hello does not contain any hash names return Sha256, its mandatory
    int num = hello->getNumHashes();
    if (num == 0) {
        return &zrtpHashes.getByName(mandatoryHash);
    }
    // Build list of configured hash algorithm names, append mandatory algos
    // if necessary.
    numAlgosConf = configureAlgos.getNumConfiguredAlgos(HashAlgorithm);
    for (i = 0; i < numAlgosConf; i++) {
        algosConf[i] = &configureAlgos.getAlgoAt(HashAlgorithm, i);
    }

    // Build list of offered known algos in Hello, append mandatory algos if necessary
    for (numAlgosOffered = 0, i = 0; i < num; i++) {
        algosOffered[numAlgosOffered] = &zrtpHashes.getByName((const char*)hello->getHashType(i));
        if (!algosOffered[numAlgosOffered]->isValid())
            continue;
        numAlgosOffered++;
    }

    // Lookup offered algos in configured algos. Because of appended
    // mandatory algorithms at least one match will happen
    for (i = 0; i < numAlgosOffered; i++) {
        for (ii = 0; ii < numAlgosConf; ii++) {
            if (*(int32_t*)(algosOffered[i]->getName()) == *(int32_t*)(algosConf[ii]->getName())) {
                return algosConf[ii];
            }
        }
    }
    return &zrtpHashes.getByName(mandatoryHash);
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::sendInfo(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) {

    // We've reached secure state: overwrite the SRTP master key and master salt.
    if (severity == Info && subCode == InfoSecureStateOn) {
        memset(srtpKeyI, 0, cipher->getKeylen());
        memset(srtpSaltI, 0, 112/8);
        memset(srtpKeyR, 0, cipher->getKeylen());
        memset(srtpSaltR, 0, 112/8);
    }
    callback->sendInfo(severity, subCode);
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evWaitClearAck(void) {
    DEBUGOUT((cout << "Checking for match in ClearAck.\n"));

//     char *msg, first, last, middle;
//     uint8_t *pkt;
// 
//     if (event->type == ZrtpPacket) {
// 	pkt = event->packet;
// 	msg = (char *)pkt + 4;
// 
// 	first = tolower(*msg);
//     middle = tolower(*(msg+4));
// 	last = tolower(*(msg+7));
// 
// 	/*
// 	 * ClearAck:
// 	 * - stop resending GoClear,
// 	 * - switch to state AckDetected, wait for peer's Hello
// 	 */
// 	if (first == 'c' && middle == 'r' && last =='k') {
// 	    cancelTimer();
// 	    sentPacket = NULL;
// 	    nextState(Initial);
// 	}
//     }
//     // Timer event triggered - this is Timer T2 to resend GoClear w/o HMAC
//     else if (event->type == Timer) {
//         if (!parent->sendPacketZRTP(sentPacket)) {
//             sendFailed();                 // returns to state Initial
//             return;
//         }
//         if (nextTimer(&T2) <= 0) {
//             timerFailed(SevereTooMuchRetries);     // returns to state Initial
//         }
//     }
//     else {  // unknown Event type for this state (covers Error and ZrtpClose)
//         if (event->type != ZrtpClose) {
//             parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
//         }
// 	sentPacket = NULL;
// 	nextState(Initial);
//     }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

bool ZrtpQueue::sendSASRelayPacket(uint8_t* sh, std::string render) {

    if (zrtpEngine != NULL)
        return zrtpEngine->sendSASRelayPacket(sh, render);
    else
        return false;
}

Project: ZRTPCPP
File: ZrtpStateClass.cpp

void ZrtpStateClass::evWaitConfAck(void) {

    DEBUGOUT((cout << "Checking for match in WaitConfAck.\n"));

    char *msg, first, last;
    uint8_t *pkt;

    if (event->type == ZrtpPacket) {
        pkt = event->packet;
        msg = (char *)pkt + 4;

        first = tolower(*msg);
        last = tolower(*(msg+7));
         /*
         * ConfAck:
         * - Switch off resending Confirm2
         * - switch to SecureState
         */
        if (first == 'c' && last == 'k') {
            cancelTimer();
            sentPacket = NULL;
            // Receiver was already enabled after sending Confirm2 packet
            // see previous states.
            if (!parent->srtpSecretsReady(ForSender)) {
                parent->sendInfo(Severe, CriticalSWError);
                sendErrorPacket(CriticalSWError);
                return;
            }
            nextState(SecureState);
            // TODO: call parent to clear signature data at initiator
            parent->sendInfo(Info, InfoSecureStateOn);
        }
    }
    else if (event->type == Timer) {
        if (!parent->sendPacketZRTP(sentPacket)) {
            sendFailed();             // returns to state Initial
            parent->srtpSecretsOff(ForReceiver);
            return;
        }
        if (nextTimer(&T2) <= 0) {
            timerFailed(SevereTooMuchRetries); // returns to state Initial
            parent->srtpSecretsOff(ForReceiver);
        }
    }
    else {  // unknown Event type for this state (covers Error and ZrtpClose)
        if (event->type != ZrtpClose) {
            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
        }
        sentPacket = NULL;
        nextState(Initial);
        parent->srtpSecretsOff(ForReceiver);
    }
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

void ZrtpQueue::setMitmMode(bool mitmMode) {
    this->mitmMode = mitmMode;
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

OutgoingZRTPPkt::OutgoingZRTPPkt(
    const unsigned char* const hdrext, uint32 hdrextlen) :
        OutgoingRTPPkt(NULL, 0, hdrext, hdrextlen, NULL ,0, 0, NULL)
{
    getHeader()->version = 0;
    getHeader()->timestamp = htonl(ZRTP_MAGIC);
}

Project: ZRTPCPP
File: ZRtp.cpp

int32_t ZRtp::compareCommit(ZrtpPacketCommit *commit) {
    // TODO: enhance to compare according to rules defined in chapter 4.2,
    // but we don't support Preshared.
    int32_t len = 0;
    len = !multiStream ? HVI_SIZE : (4 * ZRTP_WORD_SIZE);
    return (memcmp(hvi, commit->getHvi(), len));
}

Project: ZRTPCPP
File: ZrtpQueue.cpp

uint32 IncomingZRTPPkt::getSSRC() const {
     return ntohl(getHeader()->sources[0]);
}

Project: ZRTPCPP
File: ZRtp.cpp

void ZRtp::zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) {
    callback->zrtpNegotiationFailed(severity, subCode);
}