* #40116: Add zrtp related files, update libzrtpcpp
diff --git a/jni/libzrtp/sources/zrtp/ZRtp.cpp b/jni/libzrtp/sources/zrtp/ZRtp.cpp
index 9fb8e0a..c7d2a46 100755
--- a/jni/libzrtp/sources/zrtp/ZRtp.cpp
+++ b/jni/libzrtp/sources/zrtp/ZRtp.cpp
@@ -1,8 +1,8 @@
 /*
-  Copyright (C) 2006-2009 Werner Dittmann
+  Copyright (C) 2006-2013 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
+  it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
 
@@ -25,6 +25,12 @@
 #include <crypto/sha256.h>
 #include <crypto/hmac384.h>
 #include <crypto/sha384.h>
+
+#include <crypto/skeinMac256.h>
+#include <crypto/skein256.h>
+#include <crypto/skeinMac384.h>
+#include <crypto/skein384.h>
+
 #include <crypto/aesCFB.h>
 #include <crypto/twoCFB.h>
 
@@ -52,7 +58,7 @@
     }
     fprintf(stderr, "\n");
 }
- */
+ * */
 
 /*
  * This method simplifies detection of libzrtpcpp inside Automake, configure
@@ -73,9 +79,10 @@
         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) {
+        enrollmentMode(false), configureAlgos(*config), zidRec(NULL), saveZidRecord(true) {
 
     enableMitmEnrollment = config->isTrustedMitM();
+    signatureData = NULL;
     paranoidMode = config->isParanoidMode();
 
     // setup the implicit hash function pointers and length
@@ -86,6 +93,8 @@
     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.
@@ -95,21 +104,40 @@
     sha256(H1, HASH_IMAGE_SIZE, H2);        // H2
     sha256(H2, HASH_IMAGE_SIZE, H3);        // H3
 
-    zrtpHello.configureHello(&configureAlgos);
-    zrtpHello.setH3(H3);                    // set H3 in Hello, included in helloHash
+    // 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;
 
-    memcpy(ownZid, myZid, ZID_SIZE);
-    zrtpHello.setZid(ownZid);
-
-    if (mitmm)                              // this session acts for a trusted MitM (PBX)
-        zrtpHello.setMitmMode();
-
-    if (sasSignSupport)                     // the application supports SAS signing
-        zrtpHello.setSasSign();
-
-    setClientId(id);                        // set id, compute HMAC and final helloHash
-
     stateEngine = new ZrtpStateClass(this);
 }
 
@@ -235,7 +263,7 @@
 }
 
 ZrtpPacketHello* ZRtp::prepareHello() {
-    return &zrtpHello;
+    return currentHelloPacket;
 }
 
 ZrtpPacketHelloAck* ZRtp::prepareHelloAck() {
@@ -249,16 +277,17 @@
  */
 ZrtpPacketCommit* ZRtp::prepareCommit(ZrtpPacketHello *hello, uint32_t* errMsg) {
 
+    myRole = Initiator;
+
+    if (!hello->isLengthOk()) {
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
     // 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;
 
-    if (memcmp(hello->getVersion(), zrtpVersion, ZRTP_WORD_SIZE-1) != 0) {
-        *errMsg = UnsuppZRTPVersion;
-        return NULL;
-    }
-
     // 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????
@@ -291,14 +320,15 @@
     sasType = findBestSASType(hello);
 
     if (!multiStream) {
-        pubKey = findBestPubkey(hello);                 // Check for public key algorithm first, sets 'hash' as well
+        pubKey = findBestPubkey(hello);                 // Check for public key algorithm first, must set '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);
+        if (authLength == NULL)                         // public key selection may have set the SRTP authLen already
+            authLength = findBestAuthLen(hello);
         multiStreamAvailable = checkMultiStream(hello);
     }
     else {
@@ -440,7 +470,7 @@
 }
 
 /*
- * At this point we will take the role of the Responder. We may have been in
+ * At this point we will take the role of the Responder. We 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 our
  * peer's HVI then we switched to Responder and handle our peer's commit packet
@@ -452,8 +482,21 @@
 
     sendInfo(Info, InfoRespCommitReceived);
 
-    // The following code check the hash chain according chapter 10 to detect
-    // false ZRTP packets.
+    if (!commit->isLengthOk(ZrtpPacketCommit::DhExchange)) {
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
+
+    // Check if ZID in Commit is the same as we got in Hello
+    uint8_t tmpZid[ZID_SIZE];
+    memcpy(tmpZid, commit->getZid(), ZID_SIZE);
+    if (memcmp(peerZid, tmpZid, ZID_SIZE) != 0) {       // ZIDs do not match????
+        sendInfo(Severe, SevereProtocolError);
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
+
+    // The following code checks 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);
@@ -511,8 +554,8 @@
         *errMsg = UnsuppPKExchange;
         return NULL;
     }
-    if (*(int32_t*)(cp->getName()) == *(int32_t*)ec38) {
-        if (*(int32_t*)(hash->getName()) != *(int32_t*)s384) {
+    if (*(int32_t*)(cp->getName()) == *(int32_t*)ec38 || *(int32_t*)(cp->getName()) == *(int32_t*)e414) {
+        if (!(*(int32_t*)(hash->getName()) == *(int32_t*)s384 || *(int32_t*)(hash->getName()) == *(int32_t*)skn3)) {
             *errMsg = UnsuppHashType;
             return NULL;
         }
@@ -528,7 +571,7 @@
     sasType = cp;
 
     // dhContext cannot be NULL - always setup during prepareCommit()
-    // check if we can use the dhContext prepared by 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())) {
@@ -540,7 +583,11 @@
 
     dhContext->getPubKeyBytes(pubKeyBytes);
 
+    // Re-compute auxSecretIDr because we changed roles *IDr with my H3, *IDi with peer's H3
     // Setup a DHPart1 packet.
+    myRole = Responder;
+    computeAuxSecretIds();                 // recompute AUX secret ids because we are now Responder, use different H3
+
     zrtpDH1.setPubKeyType(pubKey->getName());
     zrtpDH1.setMessageType((uint8_t*)DHPart1Msg);
     zrtpDH1.setRs1Id(rs1IDr);
@@ -561,22 +608,20 @@
     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.
+    // We are responder. Release the pre-computed SHA context because it was prepared for Initiator.
+    // Setup and compute for Responder.
     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*)zrtpHello.getHeaderBase(), zrtpHello.getLength() * ZRTP_WORD_SIZE);
+    // 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);
 
@@ -595,6 +640,10 @@
 
     sendInfo(Info, InfoInitDH1Received);
 
+    if (!dhPart1->isLengthOk()) {
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
     // 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.
@@ -633,8 +682,6 @@
     }
     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.
@@ -667,6 +714,10 @@
 
     sendInfo(Info, InfoRespDH2Received);
 
+    if (!dhPart2->isLengthOk()) {
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
     // 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
@@ -689,7 +740,7 @@
     // 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);
+    computeHvi(dhPart2, currentHelloPacket);
     if (memcmp(hvi, peerHvi, HVI_SIZE) != 0) {
         *errMsg = DHErrorWrongHVI;
         return NULL;
@@ -706,8 +757,8 @@
         return NULL;
     }
     dhContext->computeSecretKey(pvi, DHss);
-    // Hash the Initiator's DH2 into the message Hash (other messages already
-    // prepared, see method prepareDHPart1().
+
+    // 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);
 
@@ -770,6 +821,10 @@
 
     sendInfo(Info, InfoRespCommitReceived);
 
+    if (!commit->isLengthOk(ZrtpPacketCommit::MultiStream)) {
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
     // The following code checks the hash chain according chapter 10 to detect
     // false ZRTP packets.
     // Use implicit hash function
@@ -840,7 +895,7 @@
     // First the Responder's (my) Hello message, second the Commit
     // (always Initator's)
     // use negotiated hash
-    hashCtxFunction(msgShaContext, (unsigned char*)zrtpHello.getHeaderBase(), zrtpHello.getLength() * ZRTP_WORD_SIZE);
+    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);
@@ -878,6 +933,10 @@
 
     sendInfo(Info, InfoInitConf1Received);
 
+    if (!confirm1->isLengthOk()) {
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
     uint8_t confMac[MAX_DIGEST_LENGTH];
     uint32_t macLen;
 
@@ -903,7 +962,7 @@
         return NULL;
     }
     signatureLength = confirm1->getSignatureLength();
-    if (signSasSeen && signatureLength > 0) {
+    if (signSasSeen && signatureLength > 0 && confirm1->isSignatureLengthOk()) {
         signatureData = confirm1->getSignatureData();
         callback->checkSASSignature(sasHash);
         // TODO: error handling if checkSASSignature returns false.
@@ -956,7 +1015,8 @@
             zrtpConfirm2.setPBXEnrollment();
         }
     }
-    getZidCacheInstance()->saveRecord(zidRec);
+    if (saveZidRecord)
+        getZidCacheInstance()->saveRecord(zidRec);
 
     // Encrypt and HMAC with Initiator's key - we are Initiator here
     hmlen = (zrtpConfirm2.getLength() - 9) * ZRTP_WORD_SIZE;
@@ -994,6 +1054,10 @@
     // don't update SAS, RS
     sendInfo(Info, InfoInitConf1Received);
 
+    if (!confirm1->isLengthOk()) {
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
     uint8_t confMac[MAX_DIGEST_LENGTH];
     uint32_t macLen;
 
@@ -1059,6 +1123,10 @@
 
     sendInfo(Info, InfoRespConf2Received);
 
+    if (!confirm2->isLengthOk()) {
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
     uint8_t confMac[MAX_DIGEST_LENGTH];
     uint32_t macLen;
 
@@ -1088,7 +1156,7 @@
             return NULL;
         }
         signatureLength = confirm2->getSignatureLength();
-        if (signSasSeen && signatureLength > 0) {
+        if (signSasSeen && signatureLength > 0 && confirm2->isSignatureLengthOk() ) {
             signatureData = confirm2->getSignatureData();
             callback->checkSASSignature(sasHash);
             // TODO: error handling if checkSASSignature returns false.
@@ -1106,7 +1174,8 @@
 
         // save new RS1, this inherits the verified flag from old RS1
         zidRec->setNewRs1((const uint8_t*)newRs1);
-        getZidCacheInstance()->saveRecord(zidRec);
+        if (saveZidRecord)
+            getZidCacheInstance()->saveRecord(zidRec);
 
         // Ask for enrollment only if enabled via configuration and the
         // confirm packet contains the enrollment flag. The enrolling user
@@ -1141,7 +1210,10 @@
 }
 
 ZrtpPacketErrorAck* ZRtp::prepareErrorAck(ZrtpPacketError* epkt) {
-    sendInfo(ZrtpError, epkt->getErrorCode() * -1);
+    if (epkt->getLength() < 4)
+        sendInfo(ZrtpError, CriticalSWError * -1);
+    else
+        sendInfo(ZrtpError, epkt->getErrorCode() * -1);
     return &zrtpErrorAck;
 }
 
@@ -1151,7 +1223,8 @@
 }
 
 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)
@@ -1167,6 +1240,10 @@
     if (!mitmSeen || paranoidMode)
         return &zrtpRelayAck;
 
+    if (!srly->isLengthOk()) {
+        *errMsg = CriticalSWError;
+        return NULL;
+    }
     uint8_t* hkey, *ekey;
     // If we are responder then the PBX used it's Initiator keys
     if (myRole == Responder) {
@@ -1287,8 +1364,7 @@
     if (num == 0) {
         return &zrtpHashes.getByName(mandatoryHash);
     }
-    // Build list of configured hash algorithm names, append mandatory algos
-    // if necessary.
+    // Build list of configured hash algorithm names.
     numAlgosConf = configureAlgos.getNumConfiguredAlgos(HashAlgorithm);
     for (i = 0; i < numAlgosConf; i++) {
         algosConf[i] = &configureAlgos.getAlgoAt(HashAlgorithm, i);
@@ -1302,8 +1378,7 @@
         numAlgosOffered++;
     }
 
-    // Lookup offered algos in configured algos. Because of appended
-    // mandatory algorithms at least one match will happen
+    // Lookup offered algos in configured algos.
     for (i = 0; i < numAlgosOffered; i++) {
         for (ii = 0; ii < numAlgosConf; ii++) {
             if (*(int32_t*)(algosOffered[i]->getName()) == *(int32_t*)(algosConf[ii]->getName())) {
@@ -1354,85 +1429,101 @@
     return &zrtpSymCiphers.getByName(mandatoryCipher);
 }
 
+// We can have the non-NIST in the list of orderedAlgos even if they are not available
+// in the code (refer to ZrtpConfigure.cpp). If they are not build in they cannot appear
+// in'configureAlgos' and thus not in the intersection lists. Thus a ZRTP build that
+// does not include the non-NIST curves also works without problems.
+//
 AlgorithmEnum* ZRtp::findBestPubkey(ZrtpPacketHello *hello) {
 
-    int i;
-    int ii;
-    int numAlgosIntersect;
-    AlgorithmEnum* algosIntersect[ZrtpConfigure::maxNoOfAlgos+1];
-
-    int numAlgosConf;
-    AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+1];
+    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};
+    const char *orderedAlgos[] = {dh2k, e255, ec25, dh3k, e414, ec38};
     int numOrderedAlgos = sizeof(orderedAlgos) / sizeof(const char*);
 
-    int num = hello->getNumPubKeys();
-    if (num == 0) {
-        hash = &zrtpHashes.getByName(mandatoryHash);             // set mandatory hash
+    int numAlgosPeer = hello->getNumPubKeys();
+    if (numAlgosPeer == 0) {
+        hash = findBestHash(hello);                    // find a hash algorithm
         return &zrtpPubKeys.getByName(mandatoryPubKey);
     }
-    // The list must include real public key algorithms only, so skip
-    // mult-stream mode, preshared and alike.
-    numAlgosConf = configureAlgos.getNumConfiguredAlgos(PubKeyAlgorithm);
-    for (i = 0, ii = 0; i < numAlgosConf; i++) {
-        algosConf[ii] = &configureAlgos.getAlgoAt(PubKeyAlgorithm, ii);
-        if (*(int32_t*)(algosConf[ii]->getName()) == *(int32_t*)mult) {
+    // 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
         }
-        ii++;
-    }
-    numAlgosConf = ii;
- 
-    // Build list of intersecting algos: own and offered in Hello, intersect list is ordered according to offered algorithms
-    for (numAlgosIntersect = 0, i = 0; i < num; i++) {
-        for (ii = 0; ii < numAlgosConf; ii++) {
-            algosIntersect[numAlgosIntersect] = &zrtpPubKeys.getByName((const char*)hello->getPubKeyType(i));
-            if (*(int32_t*)(algosConf[ii]->getName()) == *(int32_t*)(algosIntersect[numAlgosIntersect]->getName())) {
-                numAlgosIntersect++;
+        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;
             }
         }
     }
-    if (numAlgosIntersect == 0) {
-        // If we don't find a common algorithm - use the mandatory algorithms
-        hash = &zrtpHashes.getByName(mandatoryHash);
+    // Build list of peer's intersecting algos: take own list as input and build a 
+    // list of algorithms that we have in common. The order of the list is according
+    // to peer's Hello packet (peer's preferences). 
+    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 have a common algorithm - use mandatory algorithms
+        hash = findBestHash(hello);
         return &zrtpPubKeys.getByName(mandatoryPubKey);
     }
+
+    // If we have only one algorithm in common or if the first entry matches - take it.
+    // Otherwise determine which algorithm from the intersection lists is first in the 
+    // list of ordered algorithms and select it (RFC6189, section 4.1.2).
     AlgorithmEnum* useAlgo;
-    if (numAlgosIntersect > 1 && *(int32_t*)(algosConf[0]->getName()) != *(int32_t*)(algosIntersect[0]->getName())) {
+    if (numPeerIntersect > 1 && *(int32_t*)(ownIntersect[0]->getName()) != *(int32_t*)(peerIntersect[0]->getName())) {
         int own, peer;
 
-        const int32_t *name = (int32_t*)algosConf[0]->getName();
+        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*)algosIntersect[0]->getName();
+        name = (int32_t*)peerIntersect[0]->getName();
         for (peer = 0; peer < numOrderedAlgos; peer++) {
             if (*name == *(int32_t*)orderedAlgos[peer])
                 break;
         }
         if (own < peer) {
-            useAlgo = algosConf[0];
+            useAlgo = ownIntersect[0];
         }
         else {
-            useAlgo = algosIntersect[0];
+            useAlgo = peerIntersect[0];
         }
         // find fastest of conf vs intersecting
     }
     else {
-        useAlgo = algosIntersect[0];
+        useAlgo = peerIntersect[0];
     }
+    int32_t algoName = *(int32_t*)(useAlgo->getName());
+
     // select a corresponding strong hash if necessary.
-    if (*(int32_t*)(useAlgo->getName()) == *(int32_t*)ec38) {
-        hash = getStrongHashOffered(hello);
-        cipher = getStrongCipherOffered(hello);
+    if (algoName == *(int32_t*)ec38 || algoName == *(int32_t*)e414) {
+        hash = getStrongHashOffered(hello, algoName);
+        cipher = getStrongCipherOffered(hello, algoName);
     }
     else {
-        hash = findBestHash(hello);
+        hash = getHashOffered(hello, algoName);;
+        cipher = getCipherOffered(hello, algoName);
     }
+    authLength = getAuthLenOffered(hello, algoName);
     return useAlgo;
 }
 
@@ -1450,14 +1541,14 @@
     if (num == 0) {
         return &zrtpSasTypes.getByName(mandatorySasType);
     }
-    // Buildlist of configured SAS algorithm names
+    // 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++));
+        algosOffered[numAlgosOffered] = &zrtpSasTypes.getByName((const char*)hello->getSasType(i));
         if (!algosOffered[numAlgosOffered]->isValid())
             continue;
         numAlgosOffered++;
@@ -1515,27 +1606,109 @@
     return &zrtpAuthLengths.getByName(mandatoryAuthLen_1);
 }
 
-AlgorithmEnum* ZRtp::getStrongHashOffered(ZrtpPacketHello *hello) {
+// The following set of functions implement a 'non-NIST first policy' if nonNist computes 
+// to true. They prefer nonNist algorithms if these are available. Otherwise they use the NIST
+// counterpart or simply call the according findBest*(...) function.
+//
+// Only the findBestPubkey(...) function calls them after it selected the public key algorithm.
+// If the public key algorithm is non-NIST and if the policy is set to PreferNonNist then
+// nonNist becomes true.
+//
+// The functions work according to the RFC6189 spec: the initiator can select every algorithm
+// that both parties support. Thus the Initiator can even select an algorithm the wasn't offered
+// in its own Hello packet but that the Initiator found in the peer's Hello and that is available
+// for it.
+//
+AlgorithmEnum* ZRtp::getStrongHashOffered(ZrtpPacketHello *hello, int32_t algoName) {
 
     int numHash = hello->getNumHashes();
+    bool nonNist = (algoName == *(int32_t*)e414 || algoName == *(int32_t*)e255) && configureAlgos.getSelectionPolicy() == ZrtpConfigure::PreferNonNist;
+
+    if (nonNist) {
+        for (int i = 0; i < numHash; i++) {
+            int32_t nm = *(int32_t*)(hello->getHashType(i));
+            if (nm == *(int32_t*)skn3) {
+                return &zrtpHashes.getByName((const char*)hello->getHashType(i));
+            }
+        }
+    }
     for (int i = 0; i < numHash; i++) {
-        if (*(int32_t*)(hello->getHashType(i)) == *(int32_t*)s384) {
+        int32_t nm = *(int32_t*)(hello->getHashType(i));
+        if (nm == *(int32_t*)s384 || nm == *(int32_t*)skn3) {
             return &zrtpHashes.getByName((const char*)hello->getHashType(i));
         }
     }
-    return NULL;
+    return NULL;         // returning NULL -> prepareCommit(...) terminates ZRTP, missing strong hash is an error
 }
 
-AlgorithmEnum* ZRtp::getStrongCipherOffered(ZrtpPacketHello *hello) {
+AlgorithmEnum* ZRtp::getStrongCipherOffered(ZrtpPacketHello *hello, int32_t algoName) {
 
     int num = hello->getNumCiphers();
+    bool nonNist = (algoName == *(int32_t*)e414 || algoName == *(int32_t*)e255) && configureAlgos.getSelectionPolicy() == ZrtpConfigure::PreferNonNist;
+
+    if (nonNist) {
+        for (int i = 0; i < num; i++) {
+            int32_t nm = *(int32_t*)(hello->getCipherType(i));
+            if (nm == *(int32_t*)two3) {
+                return &zrtpSymCiphers.getByName((const char*)hello->getCipherType(i));
+            }
+        }
+    }
     for (int i = 0; i < num; i++) {
-        if (*(int32_t*)(hello->getCipherType(i)) == *(int32_t*)aes3 ||
-            *(int32_t*)(hello->getCipherType(i)) == *(int32_t*)two3) {
+        int32_t nm = *(int32_t*)(hello->getCipherType(i));
+        if (nm == *(int32_t*)aes3 || nm == *(int32_t*)two3) {
             return &zrtpSymCiphers.getByName((const char*)hello->getCipherType(i));
         }
     }
-    return NULL;
+    return NULL;       // returning NULL -> prepareCommit(...) finds the best cipher
+}
+
+AlgorithmEnum* ZRtp::getHashOffered(ZrtpPacketHello *hello, int32_t algoName) {
+
+    int num = hello->getNumHashes();
+    bool nonNist = (algoName == *(int32_t*)e414 || algoName == *(int32_t*)e255) && configureAlgos.getSelectionPolicy() == ZrtpConfigure::PreferNonNist;
+
+    if (nonNist) {
+        for (int i = 0; i < num; i++) {
+            int32_t nm = *(int32_t*)(hello->getHashType(i));
+            if (nm == *(int32_t*)skn2 || nm == *(int32_t*)skn3) {
+                return &zrtpHashes.getByName((const char*)hello->getHashType(i));
+            }
+        }
+    }
+    return findBestHash(hello);
+}
+
+AlgorithmEnum* ZRtp::getCipherOffered(ZrtpPacketHello *hello, int32_t algoName) {
+
+    int num = hello->getNumCiphers();
+    bool nonNist = (algoName == *(int32_t*)e414 || algoName == *(int32_t*)e255) && configureAlgos.getSelectionPolicy() == ZrtpConfigure::PreferNonNist;
+
+    if (nonNist) {
+        for (int i = 0; i < num; i++) {
+            int32_t nm = *(int32_t*)(hello->getCipherType(i));
+            if (nm == *(int32_t*)two2 || nm == *(int32_t*)two3) {
+                return &zrtpSymCiphers.getByName((const char*)hello->getCipherType(i));
+            }
+        }
+    }
+    return NULL;       // returning NULL -> prepareCommit(...) finds the best cipher
+}
+
+AlgorithmEnum* ZRtp::getAuthLenOffered(ZrtpPacketHello *hello, int32_t algoName) {
+
+    int num = hello->getNumAuth();
+    bool nonNist = (algoName == *(int32_t*)e414 || algoName == *(int32_t*)e255) && configureAlgos.getSelectionPolicy() == ZrtpConfigure::PreferNonNist;
+
+    if (nonNist) {
+        for (int i = 0; i < num; i++) {
+            int32_t nm = *(int32_t*)(hello->getAuthLen(i));
+            if (nm == *(int32_t*)sk32 || nm == *(int32_t*)sk64) {
+                return &zrtpAuthLengths.getByName((const char*)hello->getAuthLen(i));
+            }
+        }
+    }
+    return findBestAuthLen(hello);
 }
 
 bool ZRtp::checkMultiStream(ZrtpPacketHello *hello) {
@@ -1558,6 +1731,10 @@
 bool ZRtp::verifyH2(ZrtpPacketCommit *commit) {
     uint8_t tmpH3[IMPL_MAX_DIGEST_LENGTH];
 
+    // packet does not have the correct size, treat H2 verfication as failed.
+    if (!commit->isLengthOk(multiStream ? ZrtpPacketCommit::MultiStream : ZrtpPacketCommit::DhExchange))
+        return false;
+
     sha256(commit->getH2(), HASH_IMAGE_SIZE, tmpH3);
     if (memcmp(tmpH3, peerH3, HASH_IMAGE_SIZE) != 0) {
         return false;
@@ -1593,6 +1770,7 @@
     uint8_t randBuf[RS_LENGTH];
     uint32_t macLen;
 
+    fprintf(stderr, "Compute shared secrets\n");
     detailInfo.secretsCached = 0;
     if (!zidRec->isRs1Valid()) {
         randomZRTP(randBuf, RS_LENGTH);
@@ -1618,15 +1796,6 @@
         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);
@@ -1638,6 +1807,28 @@
         hmacFunction((unsigned char*)zidRec->getMiTMData(), RS_LENGTH, (unsigned char*)responder, strlen(responder), pbxSecretIDr, &macLen);
         detailInfo.secretsCached |= Pbx;
     }
+    computeAuxSecretIds();
+}
+
+void ZRtp::computeAuxSecretIds() {
+    uint8_t randBuf[RS_LENGTH];
+    uint32_t macLen;
+
+    if (auxSecret == NULL) {
+        randomZRTP(randBuf, RS_LENGTH);
+        hmacFunction(randBuf, RS_LENGTH, H3, HASH_IMAGE_SIZE, auxSecretIDi, &macLen);
+        hmacFunction(randBuf, RS_LENGTH, H3, HASH_IMAGE_SIZE, auxSecretIDr, &macLen);
+    }
+    else {
+        if (myRole == Initiator) {  // I'm initiator thus use my H3 for initiator's IDi, peerH3 for respnder's IDr
+            hmacFunction(auxSecret, auxSecretLength, H3, HASH_IMAGE_SIZE, auxSecretIDi, &macLen);
+            hmacFunction(auxSecret, auxSecretLength, peerH3, HASH_IMAGE_SIZE, auxSecretIDr, &macLen);
+        }
+        else {
+            hmacFunction(auxSecret, auxSecretLength, peerH3, HASH_IMAGE_SIZE, auxSecretIDi, &macLen);
+            hmacFunction(auxSecret, auxSecretLength, H3, HASH_IMAGE_SIZE, auxSecretIDr, &macLen);
+        }
+    }
 }
 
 /*
@@ -1684,12 +1875,17 @@
         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])));
+        DEBUGOUT((fprintf(stdout, "Initiator: Match for aux secret found\n")));
         setD[1] = auxSecret;
+        detailInfo.secretsMatched |= Aux;
+        detailInfo.secretsMatchedDH |= Aux;
     }
-    */
+    if (auxSecret != NULL && (detailInfo.secretsMatched & Aux) == 0) {
+        sendInfo(Warning, WarningNoExpectedAuxMatch);
+    }
+
     // 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])));
@@ -1704,6 +1900,7 @@
         if (rs1Valid || rs2Valid) {            // but valid RS records in cache
             sendInfo(Warning, WarningNoExpectedRSMatch);
             zidRec->resetSasVerified();
+            saveZidRecord = false;             // Don't save RS until user verfied/confirmed SAS
         }
         else {                                 // No valid RS record in cache
             sendInfo(Warning, WarningNoRSMatch);
@@ -1780,7 +1977,7 @@
             data[pos] = (unsigned char*)&sLen[i];
             length[pos++] = sizeof(uint32_t);
             data[pos] = (unsigned char*)setD[i];
-            length[pos++] = RS_LENGTH;
+            length[pos++] = (i != 1) ? RS_LENGTH : auxSecretLength;
         }
         else {                           // no machting secret, set length 0, skip secret
             sLen[i] = 0;
@@ -1842,12 +2039,17 @@
         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(auxSecretIDi, dhPart->getAuxSecretId(), 8) == 0) {
+        DEBUGOUT((fprintf(stdout, "Responder: Match for aux secret found\n")));
+        setD[1] = auxSecret;
+        detailInfo.secretsMatched |= Aux;
+        detailInfo.secretsMatchedDH |= Aux;
     }
-    */
+    // If we have an auxSecret but no match from peer - report this.
+    if (auxSecret != NULL && (detailInfo.secretsMatched & Aux) == 0) {
+        sendInfo(Warning, WarningNoExpectedAuxMatch);
+    }
 
     if (memcmp(pbxSecretIDi, dhPart->getPbxSecretId(), 8) == 0) {
         DEBUGOUT((fprintf(stdout, "%c: Match for PBX secret found\n", ownZid[0])));
@@ -1861,6 +2063,7 @@
         if (rs1Valid || rs2Valid) {            // but valid RS records in cache
             sendInfo(Warning, WarningNoExpectedRSMatch);
             zidRec->resetSasVerified();
+            saveZidRecord = false;             // Don't save RS until user verfied/confirmed SAS
         }
         else {                                 // No valid RS record in cache
             sendInfo(Warning, WarningNoRSMatch);
@@ -1939,7 +2142,7 @@
             data[pos] = (unsigned char*)&sLen[i];
             length[pos++] = sizeof(uint32_t);
             data[pos] = (unsigned char*)setD[i];
-            length[pos++] = RS_LENGTH;
+            length[pos++] = (i != 1) ? RS_LENGTH : auxSecretLength;
         }
         else {                           // no machting secret, set length 0, skip secret
             sLen[i] = 0;
@@ -2189,6 +2392,34 @@
         hashCtxFunction = sha384Ctx;
         hashCtxListFunction = sha384Ctx;
         break;
+
+    case 2:
+        hashLength = SKEIN256_DIGEST_LENGTH;
+        hashFunction = skein256;
+        hashListFunction = skein256;
+
+        hmacFunction = macSkein256;
+        hmacListFunction = macSkein256;
+
+        createHashCtx = createSkein256Context;
+        closeHashCtx = closeSkein256Context;
+        hashCtxFunction = skein256Ctx;
+        hashCtxListFunction = skein256Ctx;
+        break;
+
+    case 3:
+        hashLength = SKEIN384_DIGEST_LENGTH;
+        hashFunction = skein384;
+        hashListFunction = skein384;
+
+        hmacFunction = macSkein384;
+        hmacListFunction = macSkein384;
+
+        createHashCtx = createSkein384Context;
+        closeHashCtx = closeSkein384Context;
+        hashCtxFunction = skein384Ctx;
+        hashCtxListFunction = skein384Ctx;
+        break;
     }
 }
 
@@ -2202,6 +2433,7 @@
         return;
 
     zidRec->setSasVerified();
+    saveZidRecord = true;
     getZidCacheInstance()->saveRecord(zidRec);
 }
 
@@ -2211,6 +2443,14 @@
     getZidCacheInstance()->saveRecord(zidRec);
 }
 
+void ZRtp::setRs2Valid() {
+
+    if (zidRec != NULL) {
+        zidRec->setRs2Valid();
+        if (saveZidRecord)
+            getZidCacheInstance()->saveRecord(zidRec);
+    }
+}
 
 void ZRtp::sendInfo(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) {
 
@@ -2262,33 +2502,32 @@
     }
 }
 
-void ZRtp::setClientId(std::string id) {
-    if (id.size() < CLIENT_ID_SIZE) {
-        unsigned char tmp[CLIENT_ID_SIZE +1] = {' '};
-        memcpy(tmp, id.c_str(), id.size());
-        tmp[CLIENT_ID_SIZE] = 0;
-        zrtpHello.setClientId(tmp);
-    } else {
-        zrtpHello.setClientId((unsigned char*)id.c_str());
-    }
+void ZRtp::setClientId(std::string id, HelloPacketVersion* hpv) {
 
-    int32_t len = zrtpHello.getLength() * ZRTP_WORD_SIZE;
+    unsigned char tmp[CLIENT_ID_SIZE +1] = {' '};
+    memcpy(tmp, id.c_str(), id.size() > CLIENT_ID_SIZE ? CLIENT_ID_SIZE : id.size());
+    tmp[CLIENT_ID_SIZE] = 0;
 
-    // Hello packet is ready now, compute its HMAC
+    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*)zrtpHello.getHeaderBase(), len-(2*ZRTP_WORD_SIZE), hmac, &macLen);
-    zrtpHello.setHMAC(hmac);
+    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*)zrtpHello.getHeaderBase(), len, helloHash);
+    hashFunctionImpl((uint8_t*)hpv->packet->getHeaderBase(), len, hpv->helloHash);
 }
 
 void ZRtp::storeMsgTemp(ZrtpPacketBase* pkt) {
-    int32_t length = pkt->getLength() * ZRTP_WORD_SIZE;
+    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;
@@ -2304,12 +2543,18 @@
     return (memcmp(hmac, tempMsgBuffer+len, (HMAC_SIZE)) == 0 ? true : false);
 }
 
-std::string ZRtp::getHelloHash() {
+std::string ZRtp::getHelloHash(int32_t index) {
     std::ostringstream stm;
 
-    uint8_t* hp = helloHash;
+    if (index < 0 || index >= MAX_ZRTP_VERSIONS)
+        return std::string();
 
-    stm << zrtpVersion;
+    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;
@@ -2426,7 +2671,8 @@
     Event_t ev;
 
     ev.type = ZrtpPacket;
-    ev.packet = (uint8_t*)&zrtpConf2Ack;
+    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);