/*
Copyright (C) 2006-2007 Werner Dittmann
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/*
* Authors: Werner Dittmann
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
static void hexdump(const char* title, const unsigned char *s, int l) {
int n=0;
if (s == NULL) return;
fprintf(stderr, "%s",title);
for( ; n < l ; ++n)
{
if((n%16) == 0)
fprintf(stderr, "\n%04x",n);
fprintf(stderr, " %02x",s[n]);
}
fprintf(stderr, "\n");
}
/*
* This method simplifies detection of libzrtpcpp inside Automake, configure
* and friends
*/
#ifdef __cplusplus
extern "C" {
#endif
int ZrtpAvailable()
{
return 1;
}
#ifdef __cplusplus
}
#endif
ZRtp::ZRtp(uint8_t *myZid, ZrtpCallback *cb):
callback(cb), dhContext(NULL) {
DHss = NULL;
zpDH2 = NULL;
memcpy(zid, myZid, 12);
zrtpHello.setZid(zid);
msgShaContext = createSha256Context(); // prepare for Initiator case
stateEngine = new ZrtpStateClass(this);
}
ZRtp::~ZRtp() {
stopZrtp();
if (DHss != NULL) {
free(DHss);
DHss = NULL;
}
if (zpDH2 != NULL) {
delete zpDH2;
zpDH2 = NULL;
}
if (stateEngine != NULL) {
delete stateEngine;
stateEngine = NULL;
}
if (dhContext != NULL) {
delete dhContext;
dhContext = NULL;
}
if (msgShaContext != NULL) {
closeSha256Context(msgShaContext, NULL);
msgShaContext = NULL;
}
memset(hmacKeyI, 0, SHA256_DIGEST_LENGTH);
memset(hmacKeyR, 0, SHA256_DIGEST_LENGTH);
memset(zrtpKeyI, 0, SHA256_DIGEST_LENGTH);
memset(zrtpKeyR, 0, SHA256_DIGEST_LENGTH);
/*
* Clear the Initiator's srtp key and salt
*/
memset(srtpKeyI, 0, SHA256_DIGEST_LENGTH);
memset(srtpSaltI, 0, SHA256_DIGEST_LENGTH);
/*
* Clear he Responder's srtp key and salt
*/
memset(srtpKeyR, 0, SHA256_DIGEST_LENGTH);
memset(srtpSaltR, 0, SHA256_DIGEST_LENGTH);
memset(s0, 0, SHA256_DIGEST_LENGTH);
}
int32_t ZRtp::processZrtpMessage(uint8_t *message) {
Event_t ev;
ev.type = ZrtpPacket;
ev.data.packet = message;
int32_t ret;
if (stateEngine != NULL) {
ret = stateEngine->processEvent(&ev);
}
return ret;
}
int32_t ZRtp::processTimeout() {
Event_t ev;
ev.type = Timer;
ev.data.packet = NULL;
int32_t ret;
if (stateEngine != NULL) {
ret = stateEngine->processEvent(&ev);
}
return ret;
}
#ifdef oldgoclear
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.data.packet = message;
if (stateEngine != NULL) {
stateEngine->processEvent(&ev);
}
return true;
}
else {
return false;
}
}
#endif
void ZRtp::startZrtpEngine() {
Event_t ev;
ev.type = ZrtpInitial;
stateEngine->processEvent(&ev);
}
void ZRtp::stopZrtp() {
Event_t ev;
/*
* If we need to stop the state engine before we reached SecureState
* reset to initial state only. This state ignores any event except
* ZrtpInitial and effectively stops the engine.
*/
if (stateEngine != NULL) {
if (!stateEngine->inState(SecureState)) {
stateEngine->nextState(Initial);
return;
}
ev.type = ZrtpClose;
stateEngine->processEvent(&ev);
}
}
int32_t ZRtp::checkState(int32_t state)
{
if (stateEngine != NULL) {
return stateEngine->inState(state);
}
else {
return -1;
}
}
/*
* At this point we will assume the role of Initiator. This role may change
* in case we have a commit-clash. Refer to chapter 5.2 in the spec how
* to break this tie.
*/
ZrtpPacketCommit* ZRtp::prepareCommit(ZrtpPacketHello *hello, uint32_t* errMsg) {
sendInfo(Info, "Hello received, preparing a Commit");
if (memcmp(hello->getVersion(), zrtpVersion, 4) != 0) {
*errMsg = UnsuppZRTPVersion;
sendInfo(Error, "Received Hello packet with unsupported version number.");
return NULL;
}
// Save our peer's (presumably the Responder) ZRTP id
uint8_t* cid = hello->getClientId();
memcpy(peerZid, hello->getZid(), 12);
if (memcmp(peerZid, zid, 12) == 0) { // peers have same ZID????
*errMsg = EqualZIDHello;
sendInfo(Error, "Received Hello packet with same ZID.");
return NULL;
}
/*
* The Following section extracts the algorithm from the Hello
* packet. Always the best possible (offered) algorithms are
* used.
*/
cipher = findBestCipher(hello);
if (cipher >= NumSupportedSymCiphers) {
*errMsg = UnsuppCiphertype;
sendInfo(Error, "Hello message does not contain a supported Cipher");
return NULL;
}
hash = findBestHash(hello);
if (hash >= NumSupportedHashes) {
*errMsg = UnsuppHashType;
sendInfo(Error, "Hello message does not contain a supported Hash");
return NULL;
}
pubKey = findBestPubkey(hello);
if (pubKey >= NumSupportedPubKeys) {
*errMsg = UnsuppPKExchange;
sendInfo(Error, "Hello message does not contain a supported public key algorithm");
return NULL;
}
sasType = findBestSASType(hello);
if (sasType >= NumSupportedSASTypes) {
*errMsg = UnsuppSASScheme;
sendInfo(Error, "Hello message does not contain a supported SAS algorithm");
return NULL;
}
authLength = findBestAuthLen(hello);
if (authLength >= NumSupportedAuthLenghts) {
*errMsg = UnsuppSRTPAuthTag;
sendInfo(Error, "Hello message does not contain a supported authentication length");
return NULL;
}
if (cipher == Aes256 && pubKey != Dh4096) {
sendInfo(Warning, "Hello offers an AES256 cipher but does not offer a Diffie-Helman 4096");
}
// Generate the DH data and keys regarding the selected DH algorithm
int32_t maxPubKeySize;
if (pubKey == Dh3072) {
dhContext = new ZrtpDH(3072);
maxPubKeySize = 384;
}
else if (pubKey == Dh4096) {
dhContext = new ZrtpDH(4096);
maxPubKeySize = 512;
}
else {
*errMsg = CriticalSWError;
return NULL;
// Error - shouldn't happen
}
dhContext->generateKey();
pubKeyLen = dhContext->getPubKeySize();
dhContext->getPubKeyBytes(pubKeyBytes);
char buffer[128];
snprintf((char *)buffer, 128, "Commit: Generated a public DH key of size: %d", dhContext->getPubKeySize());
sendInfo(Info, buffer);
// Prepare IV data that we will use during confirm packet encryption.
// This is done in advance to that we can destroy the DH data at the
// earliest posible time.
dhContext->random(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
* first. Thus get our peer's retained secret data first.
*/
ZIDRecord zidRec(peerZid);
ZIDFile *zidFile = ZIDFile::getInstance();
zidFile->getRecord(&zidRec);
//Compute the Initator's and Responder's retained secret ids.
computeSharedSecretSet(zidRec);
// Construct a DHPart2 message (Initiator's DH message). This packet
// is required to compute the HVI (Hash Value Initiator).
zpDH2 = new ZrtpPacketDHPart(pubKey);
// Fill the values in the DHPart2 packet
zpDH2->setMessageType((uint8_t*)DHPart2Msg);
zpDH2->setRs1Id(rs1IDi);
zpDH2->setRs2Id(rs2IDi);
zpDH2->setSigsId(sigsIDi);
zpDH2->setSrtpsId(srtpsIDi);
zpDH2->setOtherSecretId(otherSecretIDi);
zpDH2->setPv(pubKeyBytes);
// Compute the HVI, refer to chapter 5.4.1 of the specification
computeHvi(zpDH2, hello);
ZrtpPacketCommit *commit = new ZrtpPacketCommit();
commit->setZid(zid);
commit->setHashType((uint8_t*)supportedHashes[hash]);
commit->setCipherType((uint8_t*)supportedCipher[cipher]);
commit->setAuthLen((uint8_t*)supportedAuthLen[authLength]);
commit->setPubKeyType((uint8_t*)supportedPubKey[pubKey]);
commit->setSasType((uint8_t*)supportedSASType[sasType]);
commit->setHvi(hvi);
// hash first messages to produce overall message hash
// First the Responder's Hello message, second the Commit
// (always Initator's)
sha256Ctx(msgShaContext, (unsigned char*)hello->getHeaderBase(), hello->getLength() * ZRTP_WORD_SIZE);
sha256Ctx(msgShaContext, (unsigned char*)commit->getHeaderBase(), commit->getLength() * ZRTP_WORD_SIZE);
return commit;
}
/*
* At this point we will take the role of the Responder. We may have been in
* the role of the Initiator before and already sent a commit packet that
* clashed with a commit packet from our peer. If our HVI was lower than out
* peer's HVI the we switched to Responder and handle our peer's commit packet
* here. This method takes care to delete and refresh data left over from a
* possible Initiator preparation. This belongs to a prepared DHPart2 packet,
* DH data, message hash SHA context
*/
ZrtpPacketDHPart* ZRtp::prepareDHPart1(ZrtpPacketCommit *commit, uint32_t* errMsg) {
int i;
sendInfo(Info, "Responder: Commit received, preparing DHPart1");
// check if we support the commited Cipher type
uint8_t *cp = commit->getCipherType();
for (i = 0; i < NumSupportedSymCiphers; i++) {
if (!memcmp(cp, supportedCipher[i], ZRTP_WORD_SIZE)) {
break;
}
}
if (i >= NumSupportedSymCiphers) { // no match - something went wrong
*errMsg = UnsuppCiphertype;
sendInfo(Alert, "Cannot find a supported Cipher in Commit message");
return NULL;
}
cipher = (SupportedSymCiphers)i;
// check if we support the commited Authentication length
cp = commit->getAuthLen();
for (i = 0; i < NumSupportedAuthLenghts; i++) {
if (!memcmp(cp, supportedAuthLen[i], ZRTP_WORD_SIZE)) {
break;
}
}
if (i >= NumSupportedAuthLenghts) { // no match - something went wrong
*errMsg = UnsuppSRTPAuthTag;
sendInfo(Alert, "Cannot find a supported authentication length in Commit message");
return NULL;
}
authLength = (SupportedAuthLengths)i;
// check if we support the commited hash type
cp = commit->getHashType();
for (i = 0; i < NumSupportedHashes; i++) {
if (!memcmp(cp, supportedHashes[i], ZRTP_WORD_SIZE)) {
break;
}
}
if (i >= NumSupportedHashes) { // no match - something went wrong
*errMsg = UnsuppHashType;
sendInfo(Alert, "Cannot find a supported Hash in Commit message");
return NULL;
}
hash = (SupportedHashes)i;
// check if we support the commited pub key type
cp = commit->getPubKeysType();
for (i = 0; i < NumSupportedPubKeys; i++) {
if (!memcmp(cp, supportedPubKey[i], ZRTP_WORD_SIZE)) {
break;
}
}
if (i >= NumSupportedPubKeys) { // no match - something went wrong
*errMsg = UnsuppPKExchange;
sendInfo(Alert, "Cannot find a supported public key algorithm in Commit message");
return NULL;
}
pubKey = (SupportedPubKeys)i;
// check if we support the commited SAS type
cp = commit->getSasType();
for (i = 0; i < NumSupportedSASTypes; i++) {
if (!memcmp(cp, supportedSASType[i], ZRTP_WORD_SIZE)) {
break;
}
}
if (i >= NumSupportedSASTypes) { // no match - something went wrong
*errMsg = UnsuppSASScheme;
sendInfo(Alert, "Cannot find a supported SAS algorithm in Commit message");
return NULL;
}
sasType = (SupportedSASTypes)i;
int32_t maxPubKeySize;
if (cipher == Aes256 && pubKey != Dh4096) {
sendInfo(Warning, "Commit contains an AES256 cipher but does not offer a Diffie-Helman 4096");
// generate a warning
}
// check if a cleanup is required
if (dhContext != NULL) {
delete dhContext;
dhContext = NULL;
}
// setup the DH context and generate a fresh DH key pair
if (pubKey == Dh3072) {
dhContext = new ZrtpDH(3072);
maxPubKeySize = 384;
}
else if (pubKey == Dh4096) {
dhContext = new ZrtpDH(4096);
maxPubKeySize = 512;
}
else {
*errMsg = CriticalSWError;
return NULL;
// Error - shouldn't happen
}
dhContext->generateKey();
pubKeyLen = dhContext->getPubKeySize();
char buffer[128];
snprintf(buffer, 128, "DH1Part: Generated a public DH key of size: %d", pubKeyLen);
sendInfo(Info, buffer);
if (pubKeyLen > maxPubKeySize) {
*errMsg = CriticalSWError;
snprintf(buffer, 128, "Generated DH public key too big: %d, max: %d", pubKeyLen, maxPubKeySize);
sendInfo(Error, buffer);
return NULL;
}
dhContext->getPubKeyBytes(pubKeyBytes);
/*
* If a DH2 packet was computed then also the retained secret ids were
* computed. This maybe a leftover acting as Initiator. Delete the DH2
* packet only and keep the computed retained secretd ids.
* If no DH2 packet exists just compute the reteined secrets.
*/
if (zpDH2 != NULL) { // DH2 and retained secrets already computed but
delete zpDH2; // we are responder, DH2 packet not needed anymore
zpDH2 = NULL;
}
else { // need to compute retained secrets
// We may have not received a Hello at all at this point .
// Set our peer's ZID
memcpy(peerZid, commit->getZid(), 12);
// prepare IV data that we will use during confirm packet handling.
// if a DH2 packet was created then we switched roles and an IV was
// already generated (see prepareCommit() )
dhContext->random(randomIV, sizeof(randomIV));
// Initialize a ZID record to get retained secrets for this peer
ZIDRecord zidRec(peerZid);
ZIDFile *zid = ZIDFile::getInstance();
zid->getRecord(&zidRec);
/*
* Compute the shared Secret Ids. Because here we are responder the real
* keys, salt, and HAMACS are computed after we got the DHPart2.
*/
computeSharedSecretSet(zidRec);
}
// Construct and setup a DHPart1 packet.
ZrtpPacketDHPart *zpDH = new ZrtpPacketDHPart(pubKey);
zpDH->setMessageType((uint8_t*)DHPart1Msg);
zpDH->setRs1Id(rs1IDr);
zpDH->setRs2Id(rs2IDr);
zpDH->setSigsId(sigsIDr);
zpDH->setSrtpsId(srtpsIDr);
zpDH->setOtherSecretId(otherSecretIDr);
zpDH->setPv(pubKeyBytes);
// We are definitly responder. Save the peer's hvi for later compare.
myRole = Responder;
memcpy(peerHvi, commit->getHvi(), SHA256_DIGEST_LENGTH);
// Because we are responder close a possibly pre-computed SHA256 context
// because this was prepared for Initiator. Then create a new one.
if (msgShaContext != NULL) {
closeSha256Context(msgShaContext, NULL);
}
msgShaContext = createSha256Context();
// 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)
sha256Ctx(msgShaContext, (unsigned char*)zrtpHello.getHeaderBase(),
zrtpHello.getLength() * ZRTP_WORD_SIZE);
sha256Ctx(msgShaContext, (unsigned char*)commit->getHeaderBase(),
commit->getLength() * ZRTP_WORD_SIZE);
sha256Ctx(msgShaContext, (unsigned char*)zpDH->getHeaderBase(),
zpDH->getLength() * ZRTP_WORD_SIZE);
return zpDH;
}
/*
* At this point we will take the role of the Initiator.
*/
ZrtpPacketDHPart* ZRtp::prepareDHPart2(ZrtpPacketDHPart *dhPart1, uint32_t* errMsg) {
uint8_t* pvr;
uint8_t sas[SHA256_DIGEST_LENGTH+1];
sendInfo(Info, "Initiator: DHPart1 received, preparing DHPart2");
// get memory to store DH result TODO: make it fixed memory
DHss = (uint8_t*)malloc(dhContext->getSecretSize());
if (DHss == NULL) {
sendInfo(Error, "Out of memory"); // serious error
return NULL;
}
// get and check Responder's public value, see chap. 5.4.3 in the spec
pvr = dhPart1->getPv();
if (pubKey == Dh3072) {
if (!dhContext->checkPubKey(pvr, 384)) {
*errMsg = DHErrorWrongPV;
sendInfo(Alert, "Wrong/weak public key value (pvr) received from other party");
return NULL;
}
dhContext->computeKey(pvr, 384, DHss);
}
else {
if (!dhContext->checkPubKey(pvr, 512)) {
*errMsg = DHErrorWrongPV;
sendInfo(Alert, "Wrong/weak public key value (pvr) received from other party");
return NULL;
}
dhContext->computeKey(pvr, 512, DHss);
}
// Get precomputed DHPart2 packet and set internal pointer to NULL. The
// DHPart2 packet is handed over to ZrtpStateClass. The method
// evWaitConfirm1() deletes this packet after it was sent to our peer.
ZrtpPacketDHPart *zpDH = zpDH2;
zpDH2 = NULL;
myRole = Initiator;
// We are Inititaor: 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.
sha256Ctx(msgShaContext, (unsigned char*)dhPart1->getHeaderBase(), dhPart1->getLength() * ZRTP_WORD_SIZE);
sha256Ctx(msgShaContext, (unsigned char*)zpDH->getHeaderBase(), zpDH->getLength() * ZRTP_WORD_SIZE);
// Compute the message Hash
closeSha256Context(msgShaContext, messageHash);
msgShaContext = NULL;
// To compute the S0 for the Initiator we need the retained secrets of our
// peer. Get them from the storage.
ZIDRecord zidRec(peerZid);
ZIDFile *zid = ZIDFile::getInstance();
zid->getRecord(&zidRec);
// Now compute the S0, all dependend keys and the new RS1
generateS0Initiator(dhPart1, zidRec);
delete dhContext;
dhContext = NULL;
return zpDH;
}
/*
* At this point we are Responder.
*/
ZrtpPacketConfirm* ZRtp::prepareConfirm1(ZrtpPacketDHPart* dhPart2, uint32_t* errMsg) {
uint8_t* pvi;
uint8_t sas[SHA256_DIGEST_LENGTH+1];
sendInfo(Info, "Responder: DHPart2 received, preparing Confirm1");
// TODO: fixed memory
DHss = (uint8_t*)malloc(dhContext->getSecretSize());
if (DHss == NULL) {
// serious error
return NULL;
}
// Get and check the Initiator's public value, see chap. 5.4.2 of the spec
pvi = dhPart2->getPv();
if (pubKey == Dh3072) {
if (!dhContext->checkPubKey(pvi, 384)) {
*errMsg = DHErrorWrongPV;
sendInfo(Alert, "Wrong/weak public key value (pvi) received from other party");
return NULL;
}
dhContext->computeKey(pvi, 384, DHss);
}
else {
if (!dhContext->checkPubKey(pvi, 512)) {
*errMsg = DHErrorWrongPV;
sendInfo(Alert, "Wrong/weak public key value (pvi) received from other party");
return NULL;
}
dhContext->computeKey(pvi, 512, DHss);
}
// 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, &zrtpHello);
if (memcmp(hvi, peerHvi, SHA256_DIGEST_LENGTH) != 0) {
*errMsg = DHErrorWrongHVI;
sendInfo(Alert, "Mismatch of HVI values. Possible MitM problem?");
return NULL;
}
// Hash the Initiator's DH2 into the message Hash (other messages already
// prepared, see method prepareDHPart1().
sha256Ctx(msgShaContext, (unsigned char*)dhPart2->getHeaderBase(),
dhPart2->getLength() * ZRTP_WORD_SIZE);
closeSha256Context(msgShaContext, messageHash);
msgShaContext = NULL;
// To compute the S0 for the Initiator we need the retained secrets of our
// peer. Get them from the storage.
ZIDRecord zidRec(peerZid);
ZIDFile *zid = ZIDFile::getInstance();
zid->getRecord(&zidRec);
/*
* 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.
*/
generateS0Responder(dhPart2, zidRec);
delete dhContext;
dhContext = NULL;
// Create a Confirm1 packet and fill it.
ZrtpPacketConfirm* zpConf = new ZrtpPacketConfirm(static_cast(0));
zpConf->setMessageType((uint8_t*)Confirm1Msg);
// Check if user verfied the SAS in a previous call and thus verfied
// the retained secret.
if (zidRec.isSasVerified()) {
zpConf->setSASFlag();
}
zpConf->setExpTime(0xFFFFFFFF);
zpConf->setIv(randomIV);
uint8_t confMac[SHA256_DIGEST_LENGTH];
uint32_t macLen;
// Encrypt and HMAC with Responder's key - we are Respondere here
int16_t hmlen = (zpConf->getLength() - 9) * ZRTP_WORD_SIZE;
aesCfbEncrypt(zrtpKeyR, (cipher == Aes128) ? 16 : 32, randomIV,
(unsigned char*)zpConf->getFiller(), hmlen);
hmac_sha256(hmacKeyR, SHA256_DIGEST_LENGTH, (unsigned char*)zpConf->getFiller(),
hmlen, confMac, &macLen);
zpConf->setHmac(confMac);
return zpConf;
}
ZrtpPacketConfirm* ZRtp::prepareConfirm2(ZrtpPacketConfirm *confirm1, uint32_t* errMsg) {
sendInfo(Info, "Initiator: Confirm1 received, preparing Confirm2");
uint8_t confMac[SHA256_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;
hmac_sha256(hmacKeyR, SHA256_DIGEST_LENGTH, (unsigned char*)confirm1->getFiller(),
hmlen, confMac, &macLen);
if (memcmp(confMac, confirm1->getHmac(), 2*ZRTP_WORD_SIZE) != 0) {
*errMsg = ConfirmHMACWrong;
sendInfo(Error, "HMAC verification of Confirm1 message failed");
return NULL;
}
aesCfbDecrypt(zrtpKeyR, (cipher == Aes128) ? 16 : 32,
(unsigned char*)confirm1->getIv(),
(unsigned char*)confirm1->getFiller(), hmlen);
/*
* The Confirm1 is ok, handle the Retained secret stuff and inform
* GUI about state.
*/
bool sasFlag = confirm1->isSASFlag();
// Initialize a ZID record to get peer's retained secrets
ZIDRecord zidRec(peerZid);
ZIDFile *zid = ZIDFile::getInstance();
zid->getRecord(&zidRec);
// Our peer did not confirm the SAS in last session, thus reset
// our SAS flag too.
if (!sasFlag) {
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() ? true : false;
// Inform GUI about security state and SAS state
const char* c = (cipher == Aes128) ? "AES-CM-128" : "AES-CM-256";
const char* s = (zidRec.isSasVerified()) ? NULL : SAS.c_str();
callback->srtpSecretsOn(c, s);
// now we are ready to save the new RS1 which inherits the verified
// flag from old RS1
zidRec.setNewRs1((const uint8_t*)newRs1);
zid->saveRecord(&zidRec);
// now generate my Confirm2 message
ZrtpPacketConfirm* zpConf = new ZrtpPacketConfirm(static_cast(0));
zpConf->setMessageType((uint8_t*)Confirm2Msg);
if (sasFlag) {
zpConf->setSASFlag();
}
zpConf->setExpTime(0xFFFFFFFF);
zpConf->setIv(randomIV);
// Encrypt and HMAC with Initiator's key - we are Initiator here
hmlen = (zpConf->getLength() - 9) * ZRTP_WORD_SIZE;
aesCfbEncrypt(zrtpKeyI, (cipher == Aes128) ? 16 : 32, randomIV,
(unsigned char*)zpConf->getFiller(), hmlen);
hmac_sha256(hmacKeyI, SHA256_DIGEST_LENGTH, (unsigned char*)zpConf->getFiller(),
hmlen, confMac, &macLen);
zpConf->setHmac(confMac);
return zpConf;
}
ZrtpPacketConf2Ack* ZRtp::prepareConf2Ack(ZrtpPacketConfirm *confirm2, uint32_t* errMsg) {
sendInfo(Info, "Responder: Confirm2 received, preparing Conf2Ack");
uint8_t confMac[SHA256_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;
hmac_sha256(hmacKeyI, SHA256_DIGEST_LENGTH, (unsigned char*)confirm2->getFiller(),
hmlen, confMac, &macLen);
if (memcmp(confMac, confirm2->getHmac(), 2*ZRTP_WORD_SIZE) != 0) {
*errMsg = ConfirmHMACWrong;
sendInfo(Error, "HMAC verification of Confirm2 message failed");
return NULL;
}
aesCfbDecrypt(zrtpKeyI, (cipher == Aes128) ? 16 : 32,
(unsigned char*)confirm2->getIv(),
(unsigned char*)confirm2->getFiller(), hmlen);
/*
* The Confirm2 is ok, handle the Retained secret stuff and inform
* GUI about state.
*/
bool sasFlag = confirm2->isSASFlag();
// Initialize a ZID record to get peer's retained secrets
ZIDRecord zidRec(peerZid);
ZIDFile *zid = ZIDFile::getInstance();
zid->getRecord(&zidRec);
// Our peer did not confirm the SAS in last session, thus reset
// our SAS flag too.
if (!sasFlag) {
zidRec.resetSasVerified();
}
// Inform GUI about security state and SAS state
const char* c = (cipher == Aes128) ? "AES-CM-128" : "AES-CM-256";
const char* s = (zidRec.isSasVerified()) ? NULL : SAS.c_str();
callback->srtpSecretsOn(c, s);
// save new RS1, this inherits the verified flag from old RS1
zidRec.setNewRs1((const uint8_t*)newRs1);
zid->saveRecord(&zidRec);
return &zrtpConf2Ack;
}
ZrtpPacketErrorAck* ZRtp::prepareErrorAck(ZrtpPacketError* epkt)
{
char buffer[128];
snprintf((char *)buffer, 128, "Error: Received an Error message, code: %x", epkt->getErrorCode());
sendInfo(Error, buffer);
return &zrtpErrorAck;
}
ZrtpPacketError* ZRtp::prepareError(uint32_t errMsg)
{
ZrtpPacketError* err = &zrtpError;
err->setErrorCode(errMsg);
return err;
}
// TODO Implement GoClear handling
ZrtpPacketClearAck* ZRtp::prepareClearAck(ZrtpPacketGoClear* gpkt)
{
sendInfo(Warning, "Received a GoClear message");
return &zrtpClearAck;
}
ZrtpPacketGoClear* ZRtp::prepareGoClear(uint32_t errMsg)
{
uint8_t msg[16];
ZrtpPacketGoClear* gclr = &zrtpGoClear;
gclr->clrClearHmac();
return gclr;
}
/*
* The next functions look up and return a prefered algorithm. These
* functions work as follows:
* - If the Hello packet does not contain an algorithm (number of algorithms is
* zero) then return our prefered algorithm. This prefered algorithm must be
* one of the mandatory algorithms specified in chapter 6.1.x.
* - If the functions find a match return the found algorithm.
* - If the functions do not find a match return a prefered, mandatory
* algorithm.
* This guarantees that we always return a supported alogrithm.
*
* The mandatory algorithms are: (internal enums are our prefered algoritms)
* Hash: S256 (SHA 256) (internal enum Sha256)
* Symmetric Cipher: AES1 (AES 128) (internal enum Aes128)
* SRTP Authentication: HS32 and HS80 (32/80 bits) (internal enum AuthLen32)
* Key Agreement: DH3k (3072 Diffie-Helman) (internal enum Dh3072)
*
*/
SupportedHashes ZRtp::findBestHash(ZrtpPacketHello *hello) {
int i;
int ii;
int num = hello->getNumHashes();
if (num == 0) {
return Sha256;
}
for (i = 0; i < NumSupportedHashes; i++) {
for (ii = 0; ii < num; ii++) {
if (*(uint32_t*)hello->getHashType(ii) == *(uint32_t*)supportedHashes[i]) {
return (SupportedHashes)i;
}
}
}
return Sha256;
}
SupportedSymCiphers ZRtp::findBestCipher(ZrtpPacketHello *hello) {
int i;
int ii;
int num = hello->getNumCiphers();
if (num == 0) {
return Aes128;
}
for (i = 0; i < NumSupportedSymCiphers; i++) {
for (ii = 0; ii < num; ii++) {
if (*(uint32_t*)hello->getCipherType(ii) == *(uint32_t*)supportedCipher[i]) {
return (SupportedSymCiphers)i;
}
}
}
return Aes128;
}
SupportedPubKeys ZRtp::findBestPubkey(ZrtpPacketHello *hello) {
int i;
int ii;
int num = hello->getNumPubKeys();
if (num == 0) {
return Dh3072;
}
for (i = 0; i < NumSupportedPubKeys; i++) {
for (ii = 0; ii < num; ii++) {
if (*(uint32_t*)hello->getPubKeyType(ii) == *(uint32_t*)supportedPubKey[i]) {
return (SupportedPubKeys)i;
}
}
}
return Dh3072;
}
SupportedSASTypes ZRtp::findBestSASType(ZrtpPacketHello *hello) {
int i;
int ii;
int num = hello->getNumSas();
if (num == 0) {
return Libase32;
}
for (i = 0; i < NumSupportedSASTypes ; i++) {
for (ii = 0; ii < num; ii++) {
if (*(uint32_t*)hello->getSasType(ii) == *(uint32_t*)supportedSASType[i]) {
return (SupportedSASTypes)i;
}
}
}
return Libase32;
}
SupportedAuthLengths ZRtp::findBestAuthLen(ZrtpPacketHello *hello) {
int i;
int ii;
int num = hello->getNumAuth();
if (num == 0) {
return AuthLen32;
}
for (i = 0; i < NumSupportedAuthLenghts ; i++) {
for (ii = 0; ii < num; ii++) {
if (*(uint32_t*)hello->getAuthLen(ii) == *(uint32_t*)supportedAuthLen[i]) {
return (SupportedAuthLengths)i;
}
}
}
return AuthLen32;
}
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
sha256(data, length, hvi);
return;
}
void ZRtp:: computeSharedSecretSet(ZIDRecord &zidRec) {
/*
* Compute the Initiator's and Reponder's retained shared secret Ids.
*/
uint8_t randBuf[RS_LENGTH];
uint32_t macLen;
if (!zidRec.isRs1Valid()) {
dhContext->random(randBuf, RS_LENGTH);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)initiator,
strlen(initiator), rs1IDi, &macLen);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)responder,
strlen(responder), rs1IDr, &macLen);
}
else {
hmac_sha256((unsigned char*)zidRec.getRs1(), RS_LENGTH,
(unsigned char*)initiator, strlen(initiator),
rs1IDi, &macLen);
hmac_sha256((unsigned char*)zidRec.getRs1(), RS_LENGTH,
(unsigned char*)responder, strlen(responder),
rs1IDr, &macLen);
}
if (!zidRec.isRs2Valid()) {
dhContext->random(randBuf, RS_LENGTH);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)initiator,
strlen(initiator), rs2IDi, &macLen);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)responder,
strlen(responder), rs2IDr, &macLen);
}
else {
hmac_sha256((unsigned char*)zidRec.getRs2(), RS_LENGTH,
(unsigned char*)initiator, strlen(initiator),
rs2IDi, &macLen);
hmac_sha256((unsigned char*)zidRec.getRs2(), RS_LENGTH,
(unsigned char*)responder, strlen(responder),
rs2IDr, &macLen);
}
/*
* For the time being we don't support these types 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.
*/
dhContext->random(randBuf, RS_LENGTH);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)initiator,
strlen(initiator), sigsIDi, &macLen);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)responder,
strlen(responder), sigsIDr, &macLen);
dhContext->random(randBuf, RS_LENGTH);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)initiator,
strlen(initiator), srtpsIDi, &macLen);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)responder,
strlen(responder), srtpsIDr, &macLen);
dhContext->random(randBuf, RS_LENGTH);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)initiator,
strlen(initiator), otherSecretIDi, &macLen);
hmac_sha256(randBuf, RS_LENGTH, (unsigned char*)responder,
strlen(responder), otherSecretIDr, &macLen);
}
/*
* The DH packet for this function is DHPart1 and contains the Responder's
* retained secret ids. Compare them with the expected secret ids (refer
* to chapter 5.3.2 in the specification).
*/
void ZRtp::generateS0Initiator(ZrtpPacketDHPart *dhPart, ZIDRecord& zidRec) {
const uint8_t* setD[5];
int32_t rsFound = 0;
setD[0] = setD[1] = setD[2] = setD[3] = setD[4] = NULL;
/*
* Select the real secrets into setD
*/
int matchingSecrets = 0;
if (memcmp(rs1IDr, dhPart->getRs1Id(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for Rs1 found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs1();
rsFound = 0x1;
}
if (memcmp(rs2IDr, dhPart->getRs2Id(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for Rs2 found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs2();
rsFound |= 0x2;
}
if (memcmp(sigsIDr, dhPart->getSigsId(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for SigS found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs2();
}
if (memcmp(srtpsIDr, dhPart->getSrtpsId(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for Srtps found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs2();
}
if (memcmp(otherSecretIDr, dhPart->getOtherSecretId(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for Other_secret found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs2();
}
// Check if some retained secrets found
if (rsFound == 0) {
sendInfo(Warning, "No retained secret matches - verify SAS");
}
if ((rsFound & 0x1) && (rsFound & 0x2)) {
sendInfo(Info, "Both retained secrets match - security OK");
}
if ((rsFound & 0x1) && !(rsFound & 0x2)) {
sendInfo(Warning, "Only the first retained secret matches - verify SAS");
}
if (!(rsFound & 0x1) && (rsFound & 0x2)) {
sendInfo(Warning, "Only the second retained secret matches - verify SAS");
}
/*
* 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 | len(s4) | \
s4 | len(s5) | s5 )
*
* 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 16, add one for the terminating "NULL"
*/
unsigned char* data[17];
unsigned int length[17];
uint32_t pos = 0; // index into the array
// we need a number of length data items, so define them here
uint32_t counter, sLen[5];
//Very first element is a fixed counter, big endian
counter = 1;
counter = htonl(counter);
data[pos] = (unsigned char*)&counter;
length[pos++] = sizeof(uint32_t);
// Next is the DH result itself
data[pos] = DHss;
length[pos++] = dhContext->getSecretSize();
// 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] = zid;
length[pos++] = 3*ZRTP_WORD_SIZE;
// Next is Responder's id (ZIDr), in this case our peer's id
data[pos] = peerZid;
length[pos++] = 3*ZRTP_WORD_SIZE;
// Next ist total hash (messageHash) itself
data[pos] = messageHash;
length[pos++] = SHA256_DIGEST_LENGTH;
/*
* 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.
*/
int secretHashLen = SHA256_DIGEST_LENGTH;
secretHashLen = htonl(secretHashLen); // prepare 32 bit big-endian number
for (int32_t i = 0; i < 5; 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++] = SHA256_DIGEST_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;
sha256(data, length, s0);
memset(DHss, 0, dhContext->getSecretSize());
free(DHss);
DHss = NULL;
computeSRTPKeys();
}
/*
* The DH packet for this function is DHPart2 and contains the Initiator's
* retained secret ids. Compare them with the expected secret ids (refer
* to chapter 5.3.1 in the specification).
*/
void ZRtp::generateS0Responder(ZrtpPacketDHPart *dhPart, ZIDRecord& zidRec) {
const uint8_t* setD[5];
int32_t rsFound = 0;
setD[0] = setD[1] = setD[2] = setD[3] = setD[4] = NULL;
/*
* Select the real secrets into setD
*/
int matchingSecrets = 0;
if (memcmp(rs1IDi, dhPart->getRs1Id(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for Rs1 found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs1();
rsFound = 0x1;
}
if (memcmp(rs2IDi, dhPart->getRs2Id(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for Rs2 found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs2();
rsFound |= 0x2;
}
if (memcmp(sigsIDi, dhPart->getSigsId(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for SigS found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs2();
}
if (memcmp(srtpsIDi, dhPart->getSrtpsId(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for Srtps found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs2();
}
if (memcmp(otherSecretIDi, dhPart->getOtherSecretId(), 8) == 0) {
DEBUGOUT((fprintf(stdout, "%c: Match for Other_secret found\n", zid[0])));
setD[matchingSecrets++] = zidRec.getRs2();
}
// Check if some retained secrets found
if (rsFound == 0) {
sendInfo(Warning, "No retained secret matches - verify SAS");
}
if ((rsFound & 0x1) && (rsFound & 0x2)) {
sendInfo(Info, "Both retained secrets match - security OK");
}
if ((rsFound & 0x1) && !(rsFound & 0x2)) {
sendInfo(Warning, "Only the first retained secret matches - verify SAS");
}
if (!(rsFound & 0x1) && (rsFound & 0x2)) {
sendInfo(Warning, "Only the second retained secret matches - verify SAS");
}
/*
* 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 | len(s4) | \
s4 | len(s5) | s5 )
*
* 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 16, add one for the terminating "NULL"
*/
unsigned char* data[17];
unsigned int length[17];
uint32_t pos = 0; // index into the array
// we need a number of length data items, so define them here
uint32_t counter, sLen[5];
//Very first element is a fixed counter, big endian
counter = 1;
counter = htonl(counter);
data[pos] = (unsigned char*)&counter;
length[pos++] = sizeof(uint32_t);
// Next is the DH result itself
data[pos] = DHss;
length[pos++] = dhContext->getSecretSize();
// 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++] = 3*ZRTP_WORD_SIZE;
// Next is Responder's id (ZIDr), in this case our own zid
data[pos] = zid;
length[pos++] = 3*ZRTP_WORD_SIZE;
// Next ist total hash (messageHash) itself
data[pos] = messageHash;
length[pos++] = SHA256_DIGEST_LENGTH;
/*
* 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.
*/
int secretHashLen = SHA256_DIGEST_LENGTH;
secretHashLen = htonl(secretHashLen); // prepare 32 bit big-endian number
for (int32_t i = 0; i < 5; 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++] = SHA256_DIGEST_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;
sha256(data, length, s0);
// hexdump("S0 (R)", s0, 32);
memset(DHss, 0, dhContext->getSecretSize());
free(DHss);
DHss = NULL;
computeSRTPKeys();
}
void ZRtp::computeSRTPKeys() {
uint32_t macLen;
// Inititiator key and salt
hmac_sha256(s0, SHA256_DIGEST_LENGTH, (unsigned char*)iniMasterKey, strlen(iniMasterKey),
srtpKeyI, &macLen);
hmac_sha256(s0, SHA256_DIGEST_LENGTH, (unsigned char*)iniMasterSalt, strlen(iniMasterSalt),
srtpSaltI, &macLen);
// Responder key and salt
hmac_sha256(s0, SHA256_DIGEST_LENGTH, (unsigned char*)respMasterKey, strlen(respMasterKey),
srtpKeyR, &macLen);
hmac_sha256(s0, SHA256_DIGEST_LENGTH, (unsigned char*)respMasterSalt, strlen(respMasterSalt),
srtpSaltR, &macLen);
// The HMAC keys for GoClear
hmac_sha256(s0, SHA256_DIGEST_LENGTH, (unsigned char*)iniHmacKey, strlen(iniHmacKey),
hmacKeyI, &macLen);
hmac_sha256(s0, SHA256_DIGEST_LENGTH, (unsigned char*)respHmacKey, strlen(respHmacKey),
hmacKeyR, &macLen);
// The keys for Confirm messages
hmac_sha256(s0, SHA256_DIGEST_LENGTH, (unsigned char*)iniZrtpKey, strlen(iniZrtpKey),
zrtpKeyI, &macLen);
hmac_sha256(s0, SHA256_DIGEST_LENGTH, (unsigned char*)respZrtpKey, strlen(respZrtpKey),
zrtpKeyR, &macLen);
// Compute the new Retained Secret
hmac_sha256(s0, SHA256_DIGEST_LENGTH, (unsigned char*)retainedSec, strlen(retainedSec),
newRs1, &macLen);
// perform SAS generation
uint32_t sasTemp;
uint8_t sasBytes[4];
uint8_t hmacTmp[SHA256_DIGEST_LENGTH];
hmac_sha256(hmacKeyI, SHA256_DIGEST_LENGTH, (unsigned char*)sasString, strlen(sasString),
hmacTmp, &macLen);
memcpy(sasValue, hmacTmp, sizeof(sasValue));
sasBytes[0] = sasValue[0];
sasBytes[1] = sasValue[1];
sasBytes[2] = sasValue[2] & 0xf0;
sasBytes[3] = 0;
SAS = Base32(sasBytes, 20).getEncoded();
}
bool ZRtp::srtpSecretsReady(EnableSecurity part) {
SrtpSecret_t sec;
sec.keyInitiator = srtpKeyI;
sec.initKeyLen = (cipher == Aes128) ? 128 :256;
sec.saltInitiator = srtpSaltI;
sec.initSaltLen = 112;
sec.keyResponder = srtpKeyR;
sec.respKeyLen = (cipher == Aes128) ? 128 :256;
sec.saltResponder = srtpSaltR;
sec.respSaltLen = 112;
sec.srtpAuthTagLen = (authLength == AuthLen32) ? 32 : 80;
sec.sas = SAS;
sec.role = myRole;
return callback->srtpSecretsReady(&sec, part);
}
void ZRtp::srtpSecretsOff(EnableSecurity part) {
callback->srtpSecretsOff(part);
}
void ZRtp::SASVerified()
{
// Initialize a ZID record to get peer's retained secrets
ZIDRecord zidRec(peerZid);
ZIDFile *zid = ZIDFile::getInstance();
zid->getRecord(&zidRec);
zidRec.setSasVerified();
zid->saveRecord(&zidRec);
}
void ZRtp::resetSASVerified()
{
// Initialize a ZID record to get peer's retained secrets
ZIDRecord zidRec(peerZid);
ZIDFile *zid = ZIDFile::getInstance();
zid->getRecord(&zidRec);
zidRec.resetSasVerified();
zid->saveRecord(&zidRec);
}
int32_t ZRtp::sendPacketZRTP(ZrtpPacketBase *packet) {
return ((packet == NULL) ? 0 :
callback->sendDataZRTP(packet->getHeaderBase(), (packet->getLength() * 4) + 4));
}
void ZRtp::setSigsSecret(uint8_t* data)
{
}
void ZRtp::setSrtpsSecret(uint8_t* data)
{
}
void ZRtp::setOtherSecret(uint8_t* data, int32_t length)
{
}
void ZRtp::setClientId(std::string id) {
const char* tmp = " ";
if (id.size() < 3*ZRTP_WORD_SIZE) {
zrtpHello.setClientId((unsigned char*)tmp);
}
zrtpHello.setClientId((unsigned char*)id.c_str());
}
/** EMACS **
* Local variables:
* mode: c++
* c-default-style: ellemtel
* c-basic-offset: 4
* End:
*/