libzrtpcpp-2.0.0/0000755000175000017500000000000011570331506012713 5ustar dyfetdyfetlibzrtpcpp-2.0.0/demo/0000755000175000017500000000000011570306373013643 5ustar dyfetdyfetlibzrtpcpp-2.0.0/demo/zrtptest.cpp0000644000175000017500000005307411570305710016251 0ustar dyfetdyfet// Test ZRTP extension for ccRTP // // Copyright (C) 2008 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include #include using namespace ost; using namespace std; using namespace GnuZrtpCodes; class PacketsPattern { public: inline const InetHostAddress& getDestinationAddress() const { return destinationAddress; } inline const tpport_t getDestinationPort() const { return destinationPort; } uint32 getPacketsNumber() const { return packetsNumber; } uint32 getSsrc() const { return 0xdeadbeef; } const unsigned char* getPacketData(uint32 i) { return data[i%2]; } const size_t getPacketSize(uint32 i) { return strlen((char*)data[i%2]) + 1 ; } private: static const InetHostAddress destinationAddress; static const uint16 destinationPort = 5002; static const uint32 packetsNumber = 10; static const uint32 packetsSize = 12; static const unsigned char* data[]; }; const InetHostAddress PacketsPattern::destinationAddress = InetHostAddress("localhost"); const unsigned char* PacketsPattern::data[] = { (unsigned char*)"0123456789\n", (unsigned char*)"987654321\n" }; PacketsPattern pattern; /** * SymmetricZRTPSession in non-security mode (RTPSession compatible). * * The next two classes show how to use SymmetricZRTPSession * in the same way as RTPSession. This is straightforward, * just don't do any configuration or initialization. */ class SendPacketTransmissionTest: public Thread, public TimerPort { public: void run() { doTest(); } int doTest() { // should be valid? //RTPSession tx(); SymmetricZRTPSession tx(pattern.getSsrc(), InetHostAddress("localhost")); tx.setSchedulingTimeout(10000); tx.setExpireTimeout(1000000); tx.startRunning(); tx.setPayloadFormat(StaticPayloadFormat(sptPCMU)); if (!tx.addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()) ) { return 1; } // 2 packets per second (packet duration of 500ms) uint32 period = 500; uint16 inc = tx.getCurrentRTPClockRate()/2; TimerPort::setTimer(period); uint32 i; for (i = 0; i < pattern.getPacketsNumber(); i++ ) { tx.putData(i*inc, pattern.getPacketData(i), pattern.getPacketSize(i)); cout << "Sent some data: " << i << endl; Thread::sleep(TimerPort::getTimer()); TimerPort::incTimer(period); } tx.putData(i*inc, (unsigned char*)"exit", 5); Thread::sleep(TimerPort::getTimer()); return 0; } }; class RecvPacketTransmissionTest: public Thread { public: void run() { doTest(); } int doTest() { SymmetricZRTPSession rx(pattern.getSsrc()+1, pattern.getDestinationAddress(), pattern.getDestinationPort()); rx.setSchedulingTimeout(10000); rx.setExpireTimeout(1000000); rx.startRunning(); rx.setPayloadFormat(StaticPayloadFormat(sptPCMU)); // arbitrary number of loops to provide time to start transmitter if (!rx.addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()+2) ) { return 1; } for ( int i = 0; i < 5000 ; i++ ) { const AppDataUnit* adu; while ( (adu = rx.getData(rx.getFirstTimestamp())) ) { cerr << "got some data: " << adu->getData() << endl; if (*adu->getData() == 'e') { delete adu; return 0; } delete adu; } Thread::sleep(70); } return 0; } }; /** * SymmetricZRTPSession in security mode. * * The next two classes show how to use SymmetricZRTPSession * using the standard ZRTP handshake an switching to encrypted (SRTP) mode. * The application enables this by calling initialize(...). * Some embedded logging informs about the ZRTP processing. */ class ZrtpSendPacketTransmissionTest: public Thread, public TimerPort { public: void run() { doTest(); } int doTest() { // should be valid? //RTPSession tx(); SymmetricZRTPSession tx(pattern.getSsrc(), pattern.getDestinationAddress(), pattern.getDestinationPort()+2); tx.initialize("test_t.zid"); tx.setSchedulingTimeout(10000); tx.setExpireTimeout(1000000); tx.startRunning(); tx.setPayloadFormat(StaticPayloadFormat(sptPCMU)); if (!tx.addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()) ) { return 1; } tx.startZrtp(); // 2 packets per second (packet duration of 500ms) uint32 period = 500; uint16 inc = tx.getCurrentRTPClockRate()/2; TimerPort::setTimer(period); uint32 i; for (i = 0; i < pattern.getPacketsNumber(); i++ ) { tx.putData(i*inc, pattern.getPacketData(i), pattern.getPacketSize(i)); cout << "Sent some data: " << i << endl; Thread::sleep(TimerPort::getTimer()); TimerPort::incTimer(period); } tx.putData(i*inc, (unsigned char*)"exit", 5); Thread::sleep(200); return 0; } }; class ZrtpRecvPacketTransmissionTest: public Thread { public: void run() { doTest(); } int doTest() { SymmetricZRTPSession rx(pattern.getSsrc()+1, pattern.getDestinationAddress(), pattern.getDestinationPort()); rx.initialize("test_r.zid"); rx.setSchedulingTimeout(10000); rx.setExpireTimeout(1000000); rx.startRunning(); rx.setPayloadFormat(StaticPayloadFormat(sptPCMU)); // arbitrary number of loops to provide time to start transmitter if (!rx.addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()+2) ) { return 1; } rx.startZrtp(); for ( int i = 0; i < 5000 ; i++ ) { const AppDataUnit* adu; while ( (adu = rx.getData(rx.getFirstTimestamp())) ) { cerr << "got some data: " << adu->getData() << endl; if (*adu->getData() == 'e') { delete adu; return 0; } delete adu; } Thread::sleep(70); } return 0; } }; /** * Simple User Callback class * * This class overwrite some methods from ZrtpUserCallback to get information * about ZRTP processing and information about ZRTP results. The standard * implementation of this class just perform return, thus effectively * supressing any callback or trigger. */ class MyUserCallback: public ZrtpUserCallback { static map infoMap; static map warningMap; static map severeMap; static map zrtpMap; static bool initialized; SymmetricZRTPSession* session; public: MyUserCallback(SymmetricZRTPSession* s) { session = s; if (initialized) { return; } infoMap.insert(pair(InfoHelloReceived, new string("Hello received, preparing a Commit"))); infoMap.insert(pair(InfoCommitDHGenerated, new string("Commit: Generated a public DH key"))); infoMap.insert(pair(InfoRespCommitReceived, new string("Responder: Commit received, preparing DHPart1"))); infoMap.insert(pair(InfoDH1DHGenerated, new string("DH1Part: Generated a public DH key"))); infoMap.insert(pair(InfoInitDH1Received, new string("Initiator: DHPart1 received, preparing DHPart2"))); infoMap.insert(pair(InfoRespDH2Received, new string("Responder: DHPart2 received, preparing Confirm1"))); infoMap.insert(pair(InfoInitConf1Received, new string("Initiator: Confirm1 received, preparing Confirm2"))); infoMap.insert(pair(InfoRespConf2Received, new string("Responder: Confirm2 received, preparing Conf2Ack"))); infoMap.insert(pair(InfoRSMatchFound, new string("At least one retained secrets matches - security OK"))); infoMap.insert(pair(InfoSecureStateOn, new string("Entered secure state"))); infoMap.insert(pair(InfoSecureStateOff, new string("No more security for this session"))); warningMap.insert(pair(WarningDHAESmismatch, new string("Commit contains an AES256 cipher but does not offer a Diffie-Helman 4096"))); warningMap.insert(pair(WarningGoClearReceived, new string("Received a GoClear message"))); warningMap.insert(pair(WarningDHShort, new string("Hello offers an AES256 cipher but does not offer a Diffie-Helman 4096"))); warningMap.insert(pair(WarningNoRSMatch, new string("No retained secret matches - verify SAS"))); warningMap.insert(pair(WarningCRCmismatch, new string("Internal ZRTP packet checksum mismatch - packet dropped"))); warningMap.insert(pair(WarningSRTPauthError, new string("Dropping packet because SRTP authentication failed!"))); warningMap.insert(pair(WarningSRTPreplayError, new string("Dropping packet because SRTP replay check failed!"))); severeMap.insert(pair(SevereHelloHMACFailed, new string("Hash HMAC check of Hello failed!"))); severeMap.insert(pair(SevereCommitHMACFailed, new string("Hash HMAC check of Commit failed!"))); severeMap.insert(pair(SevereDH1HMACFailed, new string("Hash HMAC check of DHPart1 failed!"))); severeMap.insert(pair(SevereDH2HMACFailed, new string("Hash HMAC check of DHPart2 failed!"))); severeMap.insert(pair(SevereCannotSend, new string("Cannot send data - connection or peer down?"))); severeMap.insert(pair(SevereProtocolError, new string("Internal protocol error occured!"))); severeMap.insert(pair(SevereNoTimer, new string("Cannot start a timer - internal resources exhausted?"))); severeMap.insert(pair(SevereTooMuchRetries, new string("Too much retries during ZRTP negotiation - connection or peer down?"))); zrtpMap.insert(pair(MalformedPacket, new string("Malformed packet (CRC OK, but wrong structure)"))); zrtpMap.insert(pair(CriticalSWError, new string("Critical software error"))); zrtpMap.insert(pair(UnsuppZRTPVersion, new string("Unsupported ZRTP version"))); zrtpMap.insert(pair(HelloCompMismatch, new string("Hello components mismatch"))); zrtpMap.insert(pair(UnsuppHashType, new string("Hash type not supported"))); zrtpMap.insert(pair(UnsuppCiphertype, new string("Cipher type not supported"))); zrtpMap.insert(pair(UnsuppPKExchange, new string("Public key exchange not supported"))); zrtpMap.insert(pair(UnsuppSRTPAuthTag, new string("SRTP auth. tag not supported"))); zrtpMap.insert(pair(UnsuppSASScheme, new string("SAS scheme not supported"))); zrtpMap.insert(pair(NoSharedSecret, new string("No shared secret available, DH mode required"))); zrtpMap.insert(pair(DHErrorWrongPV, new string("DH Error: bad pvi or pvr ( == 1, 0, or p-1)"))); zrtpMap.insert(pair(DHErrorWrongHVI, new string("DH Error: hvi != hashed data"))); zrtpMap.insert(pair(SASuntrustedMiTM, new string("Received relayed SAS from untrusted MiTM"))); zrtpMap.insert(pair(ConfirmHMACWrong, new string("Auth. Error: Bad Confirm pkt HMAC"))); zrtpMap.insert(pair(NonceReused, new string("Nonce reuse"))); zrtpMap.insert(pair(EqualZIDHello, new string("Equal ZIDs in Hello"))); zrtpMap.insert(pair(GoCleatNotAllowed, new string("GoClear packet received, but not allowed"))); initialized = true; } void showMessage(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) { string* msg; if (sev == Info) { msg = infoMap[subCode]; if (msg != NULL) { cout << *msg << endl; } } if (sev == Warning) { msg = warningMap[subCode]; if (msg != NULL) { cout << *msg << endl; } } if (sev == Severe) { msg = severeMap[subCode]; if (msg != NULL) { cout << *msg << endl; } } if (sev == ZrtpError) { if (subCode < 0) { // received an error packet from peer subCode *= -1; cout << "Received error packet: "; } else { cout << "Sent error packet: "; } msg = zrtpMap[subCode]; if (msg != NULL) { cout << *msg << endl; } } } void zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) { string* msg; if (sev == ZrtpError) { if (subCode < 0) { // received an error packet from peer subCode *= -1; cout << "Received error packet: "; } else { cout << "Sent error packet: "; } msg = zrtpMap[subCode]; if (msg != NULL) { cout << *msg << endl; } } else { msg = severeMap[subCode]; cout << *msg << endl; } } void secureOn(std::string cipher) { cout << "Using cipher:" << cipher << endl; } void showSAS(std::string sas, bool verified) { cout << "SAS is: " << sas << endl; } }; mapMyUserCallback::infoMap; mapMyUserCallback::warningMap; mapMyUserCallback::severeMap; mapMyUserCallback::zrtpMap; bool MyUserCallback::initialized = false; /** * SymmetricZRTPSession in security mode and using a callback class. * * The next two classes show how to use SymmetricZRTPSession * using the standard ZRTP handshake an switching to encrypted (SRTP) mode. * The application enables this by calling initialize(...). * In addition the application sets a callback class (see above). ZRTP calls * the methods of the callback class and the application may implement * appropriate methods to deal with these triggers. */ class ZrtpSendPacketTransmissionTestCB : public Thread, public TimerPort { public: void run() { doTest(); } int doTest() { // should be valid? //RTPSession tx(); SymmetricZRTPSession tx(/*pattern.getSsrc(),*/ pattern.getDestinationAddress(), pattern.getDestinationPort()+2); tx.initialize("test_t.zid"); // At this point the Hello hash is available. See ZRTP specification // chapter 9.1 for further information when an how to use the Hello // hash. cout << "TX Hello hash: " << tx.getHelloHash() << endl; cout << "TX Hello hash length: " << tx.getHelloHash().length() << endl; tx.setUserCallback(new MyUserCallback(&tx)); tx.setSchedulingTimeout(10000); tx.setExpireTimeout(1000000); tx.startRunning(); tx.setPayloadFormat(StaticPayloadFormat(sptPCMU)); if (!tx.addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()) ) { return 1; } tx.startZrtp(); // 2 packets per second (packet duration of 500ms) uint32 period = 500; uint16 inc = tx.getCurrentRTPClockRate()/2; TimerPort::setTimer(period); uint32 i; for (i = 0; i < pattern.getPacketsNumber(); i++ ) { tx.putData(i*inc, pattern.getPacketData(i), pattern.getPacketSize(i)); cout << "Sent some data: " << i << endl; Thread::sleep(TimerPort::getTimer()); TimerPort::incTimer(period); } tx.putData(i*inc, (unsigned char*)"exit", 5); Thread::sleep(TimerPort::getTimer()); return 0; } }; class ZrtpRecvPacketTransmissionTestCB: public Thread { public: void run() { doTest(); } int doTest() { SymmetricZRTPSession rx( /*pattern.getSsrc()+1,*/ pattern.getDestinationAddress(), pattern.getDestinationPort()); rx.initialize("test_r.zid"); // At this point the Hello hash is available. See ZRTP specification // chapter 9.1 for further information when an how to use the Hello // hash. cout << "RX Hello hash: " << rx.getHelloHash() << endl; cout << "RX Hello hash length: " << rx.getHelloHash().length() << endl; rx.setUserCallback(new MyUserCallback(&rx)); rx.setSchedulingTimeout(10000); rx.setExpireTimeout(1000000); rx.startRunning(); rx.setPayloadFormat(StaticPayloadFormat(sptPCMU)); // arbitrary number of loops to provide time to start transmitter if (!rx.addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()+2) ) { return 1; } rx.startZrtp(); for ( int i = 0; i < 5000 ; i++ ) { const AppDataUnit* adu; while ( (adu = rx.getData(rx.getFirstTimestamp())) ) { cerr << "got some data: " << adu->getData() << endl; if (*adu->getData() == 'e') { delete adu; return 0; } delete adu; } Thread::sleep(70); } return 0; } }; int main(int argc, char *argv[]) { int result = 0; bool send = false; bool recv = false; char c; /* check args */ while (1) { c = getopt(argc, argv, "rs"); if (c == -1) { break; } switch (c) { case 'r': recv = true; break; case 's': send = true; break; default: cerr << "Wrong Arguments, only -s and -r are accepted" << endl; } } if (send || recv) { if (send) { cout << "Running as sender" << endl; } else { cout << "Running as receiver" << endl; } } else { cerr << "No send or receive argument specificied" << endl; exit(1); } // accept as parameter if must run as --send or --recv #if 0 RecvPacketTransmissionTest *rx; SendPacketTransmissionTest *tx; // run several tests in parallel threads if ( send ) { tx = new SendPacketTransmissionTest(); tx->start(); tx->join(); } else if ( recv ) { rx = new RecvPacketTransmissionTest(); rx->start(); rx->join(); } //#endif //#if 0 ZrtpRecvPacketTransmissionTest *zrx; ZrtpSendPacketTransmissionTest *ztx; if ( send ) { ztx = new ZrtpSendPacketTransmissionTest(); ztx->start(); ztx->join(); } else if ( recv ) { zrx = new ZrtpRecvPacketTransmissionTest(); zrx->start(); zrx->join(); } #endif ZrtpRecvPacketTransmissionTestCB *zrxcb; ZrtpSendPacketTransmissionTestCB *ztxcb; if ( send ) { ztxcb = new ZrtpSendPacketTransmissionTestCB(); ztxcb->start(); ztxcb->join(); } else if ( recv ) { zrxcb = new ZrtpRecvPacketTransmissionTestCB(); zrxcb->start(); zrxcb->join(); } exit(result); } /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/demo/zrtptestMulti.cpp0000644000175000017500000005230011570305710017253 0ustar dyfetdyfet// Test ZRTP extension for ccRTP // // Copyright (C) 2008 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include #include #include using namespace ost; using namespace std; using namespace GnuZrtpCodes; /* maybe should be by special define... 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"); } */ class PacketsPattern { public: inline const InetHostAddress& getDestinationAddress() const { return destinationAddress; } inline const tpport_t getDestinationPort() const { return destinationPort; } uint32 getPacketsNumber() const { return packetsNumber; } uint32 getSsrc() const { return 0xdeadbeef; } const unsigned char* getPacketData(uint32 i) { return data[i%2]; } const size_t getPacketSize(uint32 i) { return strlen((char*)data[i%2]) + 1 ; } private: static const InetHostAddress destinationAddress; static const uint16 destinationPort = 5002; static const uint32 packetsNumber = 10; static const uint32 packetsSize = 12; static const unsigned char* data[]; }; const InetHostAddress PacketsPattern::destinationAddress = InetHostAddress("localhost"); const unsigned char* PacketsPattern::data[] = { (unsigned char*)"0123456789\n", (unsigned char*)"987654321\n" }; PacketsPattern pattern; class ZrtpRecvPacketTransmissionTestCB; class ZrtpSendPacketTransmissionTestCB; class MyUserCallback; class MyUserCallbackMulti; static ZrtpRecvPacketTransmissionTestCB* zrxcb = NULL; static ZrtpSendPacketTransmissionTestCB* ztxcb = NULL; static ZrtpRecvPacketTransmissionTestCB* zrxcbMulti = NULL; static ZrtpSendPacketTransmissionTestCB* ztxcbMulti = NULL; /** * SymmetricZRTPSession in security mode and using a callback class. * * The next two classes show how to use SymmetricZRTPSession * using the standard ZRTP handshake an switching to encrypted (SRTP) mode. * The application enables this by calling initialize(...). * In addition the application sets a callback class (see above). ZRTP calls * the methods of the callback class and the application may implement * appropriate methods to deal with these triggers. */ class ZrtpSendPacketTransmissionTestCB : public Thread, public TimerPort { private: SymmetricZRTPSession* tx; string multiParams; string prefix; public: ZrtpSendPacketTransmissionTestCB(): tx(NULL), multiParams("") {}; void run() { doTest(); } int doTest(); string getMultiStrParams() { return tx->getMultiStrParams(); } void setMultiStrParams(string params) { multiParams = params; return; } }; class ZrtpRecvPacketTransmissionTestCB: public Thread { private: SymmetricZRTPSession* rx; string multiParams; string prefix; public: ZrtpRecvPacketTransmissionTestCB(): rx(NULL), multiParams("") {}; void run() { doTest(); } int doTest(); string getMultiStrParams() { return rx->getMultiStrParams(); } void setMultiStrParams(string params) { multiParams = params; return; } }; /** * Simple User Callback class * * This class overwrite some methods from ZrtpUserCallback to get information * about ZRTP processing and information about ZRTP results. The standard * implementation of this class just perform return, thus effectively * supressing any callback or trigger. */ class MyUserCallback: public ZrtpUserCallback { protected: static map infoMap; static map warningMap; static map severeMap; static map zrtpMap; static bool initialized; SymmetricZRTPSession* session; std::string prefix; public: MyUserCallback(SymmetricZRTPSession* s): session(s), prefix("default: ") { if (initialized) { return; } infoMap.insert(pair(InfoHelloReceived, new string("Hello received, preparing a Commit"))); infoMap.insert(pair(InfoCommitDHGenerated, new string("Commit: Generated a public DH key"))); infoMap.insert(pair(InfoRespCommitReceived, new string("Responder: Commit received, preparing DHPart1"))); infoMap.insert(pair(InfoDH1DHGenerated, new string("DH1Part: Generated a public DH key"))); infoMap.insert(pair(InfoInitDH1Received, new string("Initiator: DHPart1 received, preparing DHPart2"))); infoMap.insert(pair(InfoRespDH2Received, new string("Responder: DHPart2 received, preparing Confirm1"))); infoMap.insert(pair(InfoInitConf1Received, new string("Initiator: Confirm1 received, preparing Confirm2"))); infoMap.insert(pair(InfoRespConf2Received, new string("Responder: Confirm2 received, preparing Conf2Ack"))); infoMap.insert(pair(InfoRSMatchFound, new string("At least one retained secrets matches - security OK"))); infoMap.insert(pair(InfoSecureStateOn, new string("Entered secure state"))); infoMap.insert(pair(InfoSecureStateOff, new string("No more security for this session"))); warningMap.insert(pair(WarningDHAESmismatch, new string("Commit contains an AES256 cipher but does not offer a Diffie-Helman 4096"))); warningMap.insert(pair(WarningGoClearReceived, new string("Received a GoClear message"))); warningMap.insert(pair(WarningDHShort, new string("Hello offers an AES256 cipher but does not offer a Diffie-Helman 4096"))); warningMap.insert(pair(WarningNoRSMatch, new string("No retained secret matches - verify SAS"))); warningMap.insert(pair(WarningCRCmismatch, new string("Internal ZRTP packet checksum mismatch - packet dropped"))); warningMap.insert(pair(WarningSRTPauthError, new string("Dropping packet because SRTP authentication failed!"))); warningMap.insert(pair(WarningSRTPreplayError, new string("Dropping packet because SRTP replay check failed!"))); warningMap.insert(pair(WarningNoExpectedRSMatch, new string("Valid retained shared secrets availabe but no matches found - must verify SAS"))); severeMap.insert(pair(SevereHelloHMACFailed, new string("Hash HMAC check of Hello failed!"))); severeMap.insert(pair(SevereCommitHMACFailed, new string("Hash HMAC check of Commit failed!"))); severeMap.insert(pair(SevereDH1HMACFailed, new string("Hash HMAC check of DHPart1 failed!"))); severeMap.insert(pair(SevereDH2HMACFailed, new string("Hash HMAC check of DHPart2 failed!"))); severeMap.insert(pair(SevereCannotSend, new string("Cannot send data - connection or peer down?"))); severeMap.insert(pair(SevereProtocolError, new string("Internal protocol error occured!"))); severeMap.insert(pair(SevereNoTimer, new string("Cannot start a timer - internal resources exhausted?"))); severeMap.insert(pair(SevereTooMuchRetries, new string("Too much retries during ZRTP negotiation - connection or peer down?"))); zrtpMap.insert(pair(MalformedPacket, new string("Malformed packet (CRC OK, but wrong structure)"))); zrtpMap.insert(pair(CriticalSWError, new string("Critical software error"))); zrtpMap.insert(pair(UnsuppZRTPVersion, new string("Unsupported ZRTP version"))); zrtpMap.insert(pair(HelloCompMismatch, new string("Hello components mismatch"))); zrtpMap.insert(pair(UnsuppHashType, new string("Hash type not supported"))); zrtpMap.insert(pair(UnsuppCiphertype, new string("Cipher type not supported"))); zrtpMap.insert(pair(UnsuppPKExchange, new string("Public key exchange not supported"))); zrtpMap.insert(pair(UnsuppSRTPAuthTag, new string("SRTP auth. tag not supported"))); zrtpMap.insert(pair(UnsuppSASScheme, new string("SAS scheme not supported"))); zrtpMap.insert(pair(NoSharedSecret, new string("No shared secret available, DH mode required"))); zrtpMap.insert(pair(DHErrorWrongPV, new string("DH Error: bad pvi or pvr ( == 1, 0, or p-1)"))); zrtpMap.insert(pair(DHErrorWrongHVI, new string("DH Error: hvi != hashed data"))); zrtpMap.insert(pair(SASuntrustedMiTM, new string("Received relayed SAS from untrusted MiTM"))); zrtpMap.insert(pair(ConfirmHMACWrong, new string("Auth. Error: Bad Confirm pkt HMAC"))); zrtpMap.insert(pair(NonceReused, new string("Nonce reuse"))); zrtpMap.insert(pair(EqualZIDHello, new string("Equal ZIDs in Hello"))); zrtpMap.insert(pair(GoCleatNotAllowed, new string("GoClear packet received, but not allowed"))); initialized = true; } void showMessage(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) { string* msg; if (sev == Info) { msg = infoMap[subCode]; if (msg != NULL) { cout << prefix << *msg << endl; } // this sets up and starts off the multi-stream test if (subCode == InfoSecureStateOn) { if (zrxcbMulti != NULL) { zrxcbMulti->setMultiStrParams(session->getMultiStrParams()); zrxcbMulti->start(); } if (ztxcbMulti != NULL) { ztxcbMulti->setMultiStrParams(session->getMultiStrParams()); ztxcbMulti->start(); } } } if (sev == Warning) { msg = warningMap[subCode]; if (msg != NULL) { cout << prefix << *msg << endl; } } if (sev == Severe) { msg = severeMap[subCode]; if (msg != NULL) { cout << prefix << *msg << endl; } } if (sev == ZrtpError) { if (subCode < 0) { // received an error packet from peer subCode *= -1; cout << prefix << "Received error packet: "; } else { cout << prefix << "Sent error packet: "; } msg = zrtpMap[subCode]; if (msg != NULL) { cout << prefix << *msg << endl; } } } void zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) { string* msg; if (sev == ZrtpError) { if (subCode < 0) { // received an error packet from peer subCode *= -1; cout << prefix << "Received error packet: "; } else { cout << prefix << "Sent error packet: "; } msg = zrtpMap[subCode]; if (msg != NULL) { cout << prefix << *msg << endl; } } else { msg = severeMap[subCode]; cout << prefix << *msg << endl; } } void secureOn(std::string cipher) { cout << prefix << "Using cipher:" << cipher << endl; } void showSAS(std::string sas, bool verified) { cout << prefix << "SAS is: " << sas << endl; } void setPrefix(std::string p) { prefix = p; } }; mapMyUserCallback::infoMap; mapMyUserCallback::warningMap; mapMyUserCallback::severeMap; mapMyUserCallback::zrtpMap; bool MyUserCallback::initialized = false; class MyUserCallbackMulti: public MyUserCallback { public: MyUserCallbackMulti(SymmetricZRTPSession* s): MyUserCallback(s) { } void showMessage(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) { string* msg; if (sev == Info) { msg = infoMap[subCode]; if (msg != NULL) { cout << prefix << *msg << endl; } } if (sev == Warning) { msg = warningMap[subCode]; if (msg != NULL) { cout << prefix << *msg << endl; } } if (sev == Severe) { msg = severeMap[subCode]; if (msg != NULL) { cout << prefix << *msg << endl; } } if (sev == ZrtpError) { if (subCode < 0) { // received an error packet from peer subCode *= -1; cout << prefix << "Received error packet: "; } else { cout << prefix << "Sent error packet: "; } msg = zrtpMap[subCode]; if (msg != NULL) { cout << prefix << *msg << endl; } } } }; int ZrtpSendPacketTransmissionTestCB::doTest() { ZrtpConfigure config; MyUserCallback* mcb; if (!multiParams.empty()) { tx = new SymmetricZRTPSession(pattern.getDestinationAddress(), pattern.getDestinationPort()+2+10); // tx->initialize("test_t.zid", true, &config); tx->initialize("test_t.zid", true); tx->setMultiStrParams(multiParams); prefix = "TX Multi: "; mcb = new MyUserCallback(tx); mcb->setPrefix(prefix); } else { tx = new SymmetricZRTPSession(pattern.getDestinationAddress(), pattern.getDestinationPort()+2); //config.addHashAlgo(Sha384); // tx->initialize("test_t.zid", true, &config); tx->initialize("test_t.zid", true); prefix = "TX: "; mcb = new MyUserCallback(tx); mcb->setPrefix(prefix); } // At this point the Hello hash is available. See ZRTP specification // chapter 9.1 for further information when an how to use the Hello // hash. cout << prefix << "Hello hash: " << tx->getHelloHash() << endl; cout << prefix << "Hello hash length: " << tx->getHelloHash().length() << endl; tx->setUserCallback(mcb); tx->setSchedulingTimeout(10000); tx->setExpireTimeout(1000000); tx->startRunning(); tx->setPayloadFormat(StaticPayloadFormat(sptPCMU)); if (!multiParams.empty()) { if (!tx->addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()+10) ) { return 1; } } else { if (!tx->addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()) ) { return 1; } } tx->startZrtp(); // 2 packets per second (packet duration of 500ms) uint32 period = 500; uint16 inc = tx->getCurrentRTPClockRate()/2; TimerPort::setTimer(period); uint32 i; for (i = 0; i < pattern.getPacketsNumber(); i++ ) { tx->putData(i*inc, pattern.getPacketData(i), pattern.getPacketSize(i)); cout << prefix << "Sent some data: " << i << endl; Thread::sleep(TimerPort::getTimer()); TimerPort::incTimer(period); } tx->putData(i*inc, (unsigned char*)"exit", 5); Thread::sleep(TimerPort::getTimer()); delete tx; return 0; } int ZrtpRecvPacketTransmissionTestCB::doTest() { ZrtpConfigure config; MyUserCallback* mcb; if (!multiParams.empty()) { rx = new SymmetricZRTPSession(pattern.getDestinationAddress(), pattern.getDestinationPort()+10); // rx->initialize("test_r.zid", true, &config); rx->initialize("test_r.zid", true); rx->setMultiStrParams(multiParams); prefix = "RX Multi: "; mcb = new MyUserCallbackMulti(rx); mcb->setPrefix(prefix); } else { rx = new SymmetricZRTPSession(pattern.getDestinationAddress(), pattern.getDestinationPort()); // config.addHashAlgo(Sha384); // rx->initialize("test_r.zid", true, &config); rx->initialize("test_r.zid", true); prefix = "RX: "; mcb = new MyUserCallback(rx); mcb->setPrefix(prefix); } // At this point the Hello hash is available. See ZRTP specification // chapter 9.1 for further information when an how to use the Hello // hash. cout << prefix << "Hello hash: " << rx->getHelloHash() << endl; cout << prefix << "Hello hash length: " << rx->getHelloHash().length() << endl; rx->setUserCallback(mcb); rx->setSchedulingTimeout(10000); rx->setExpireTimeout(1000000); rx->startRunning(); rx->setPayloadFormat(StaticPayloadFormat(sptPCMU)); // arbitrary number of loops to provide time to start transmitter if (!multiParams.empty()) { if (!rx->addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()+2+10) ) { return 1; } } else { if (!rx->addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()+2) ) { return 1; } } // rx->startZrtp(); for ( int i = 0; i < 5000 ; i++ ) { const AppDataUnit* adu; while ( (adu = rx->getData(rx->getFirstTimestamp())) ) { cerr << prefix << "got some data: " << adu->getData() << endl; if (*adu->getData() == 'e') { delete adu; delete rx; return 0; } delete adu; } Thread::sleep(70); } delete rx; return 0; } int main(int argc, char *argv[]) { int result = 0; bool send = false; bool recv = false; char c; /* check args */ while (1) { c = getopt(argc, argv, "rs"); if (c == -1) { break; } switch (c) { case 'r': recv = true; break; case 's': send = true; break; default: cerr << "Wrong Arguments, only -s and -r are accepted" << endl; } } if (send || recv) { if (send) { cout << "Running as sender" << endl; } else { cout << "Running as receiver" << endl; } } else { cerr << "No send or receive argument specificied" << endl; exit(1); } if ( send ) { ztxcb = new ZrtpSendPacketTransmissionTestCB(); ztxcbMulti = new ZrtpSendPacketTransmissionTestCB(); ztxcb->start(); ztxcb->join(); ztxcbMulti->join(); } else if ( recv ) { zrxcb = new ZrtpRecvPacketTransmissionTestCB(); zrxcbMulti = new ZrtpRecvPacketTransmissionTestCB(); zrxcb->start(); zrxcb->join(); zrxcbMulti->join(); } exit(result); } /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/demo/README0000644000175000017500000000217411570305710014521 0ustar dyfetdyfet This directory includes example programs intended for testing and illustrating features of ccRTP and the ZRTP extension. Before using these programs make sure that ccRTP is up and working correctly. * zrtptest: is similar to ccrtptest in ccRTP demo directory. This program shows how to use the class SymmetricZRTPSession instead of RTPSession. The first test shows that SymmetricZRTPSession is compatible to RTPSession if it is used without specific initialization or configuration. The second test initializes the ZRTP engine and starts it just before sending or receiving RTP data. The enable ZRTP the test sets RTP in bi-directional mode. This is the main difference to the first test case. The third test shows how to use an application supplied callback class to control message printout, switching to secure mode, displaying the Short Authentication String (SAS). To start the demo application you may open two shell (command) windows and start "zrtptest -r" in one window first, then start "zrtptest -s" in the second window. The application use the port numbers 10002 thruogh 10004 on localhost to communicate. libzrtpcpp-2.0.0/demo/CMakeLists.txt0000755000175000017500000000077411570305710016410 0ustar dyfetdyfet########### next target ############### add_executable(zrtptest zrtptest.cpp) target_link_libraries(zrtptest zrtpcpp) add_dependencies(zrtptest zrtpcpp) ########### next target ############### add_executable(zrtptestMulti zrtptestMulti.cpp) target_link_libraries(zrtptestMulti zrtpcpp) add_dependencies(zrtptestMulti zrtpcpp) ########### next target ############### #add_executable(wrappertest wrappertest.c) #target_link_libraries(wrappertest zrtpcpp) ########### install files ############### # None libzrtpcpp-2.0.0/demo/wrappertest.c0000644000175000017500000001057611570305710016372 0ustar dyfetdyfet/* This class maps the ZRTP C calls to ZRTP C++ methods. Copyright (C) 2010 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 . */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* Forward declaration of thethe ZRTP specific callback functions that this adapter must implement */ static int32_t zrtp_sendDataZRTP (ZrtpContext* ctx, const uint8_t* data, int32_t length ) ; static int32_t zrtp_activateTimer (ZrtpContext* ctx, int32_t time ) ; static int32_t zrtp_cancelTimer(ZrtpContext* ctx) ; static void zrtp_sendInfo (ZrtpContext* ctx, int32_t severity, int32_t subCode ) ; static int32_t zrtp_srtpSecretsReady (ZrtpContext* ctx, C_SrtpSecret_t* secrets, int32_t part ) ; static void zrtp_srtpSecretsOff (ZrtpContext* ctx, int32_t part ) ; static void zrtp_rtpSecretsOn (ZrtpContext* ctx, char* c, char* s, int32_t verified ) ; static void zrtp_handleGoClear(ZrtpContext* ctx) ; static void zrtp_zrtpNegotiationFailed(ZrtpContext* ctx, int32_t severity, int32_t subCode ) ; static void zrtp_zrtpNotSuppOther(ZrtpContext* ctx) ; static void zrtp_synchEnter(ZrtpContext* ctx) ; static void zrtp_synchLeave(ZrtpContext* ctx) ; static void zrtp_zrtpAskEnrollment (ZrtpContext* ctx, char* info ) ; static void zrtp_zrtpInformEnrollment(ZrtpContext* ctx, char* info ) ; static void zrtp_signSAS(ZrtpContext* ctx, char* sas) ; static int32_t zrtp_checkSASSignature (ZrtpContext* ctx, char* sas ) ; /* The callback function structure for ZRTP */ static zrtp_Callbacks c_callbacks = { &zrtp_sendDataZRTP, &zrtp_activateTimer, &zrtp_cancelTimer, &zrtp_sendInfo, &zrtp_srtpSecretsReady, &zrtp_srtpSecretsOff, &zrtp_rtpSecretsOn, &zrtp_handleGoClear, &zrtp_zrtpNegotiationFailed, &zrtp_zrtpNotSuppOther, &zrtp_synchEnter, &zrtp_synchLeave, &zrtp_zrtpAskEnrollment, &zrtp_zrtpInformEnrollment, &zrtp_signSAS, &zrtp_checkSASSignature }; /* * Here start with callback functions that support the ZRTP core */ static int32_t zrtp_sendDataZRTP (ZrtpContext* ctx, const uint8_t* data, int32_t length ) { return 0; } static int32_t zrtp_activateTimer (ZrtpContext* ctx, int32_t time) { return 0; } static int32_t zrtp_cancelTimer(ZrtpContext* ctx) { return 0; } static void zrtp_sendInfo (ZrtpContext* ctx, int32_t severity, int32_t subCode ) { } static int32_t zrtp_srtpSecretsReady (ZrtpContext* ctx, C_SrtpSecret_t* secrets, int32_t part ) { return 0; } static void zrtp_srtpSecretsOff (ZrtpContext* ctx, int32_t part ) { } static void zrtp_rtpSecretsOn (ZrtpContext* ctx, char* c, char* s, int32_t verified ) { } static void zrtp_handleGoClear(ZrtpContext* ctx) { } static void zrtp_zrtpNegotiationFailed (ZrtpContext* ctx, int32_t severity, int32_t subCode ) { } static void zrtp_zrtpNotSuppOther(ZrtpContext* ctx) { } static void zrtp_synchEnter(ZrtpContext* ctx) { } static void zrtp_synchLeave(ZrtpContext* ctx) { } static void zrtp_zrtpAskEnrollment(ZrtpContext* ctx, char* info ) { } static void zrtp_zrtpInformEnrollment(ZrtpContext* ctx, char* info ) { } static void zrtp_signSAS(ZrtpContext* ctx, char* sas) { } static int32_t zrtp_checkSASSignature(ZrtpContext* ctx, char* sas ) { return 0; } int main(int argc, char *argv[]) { ZrtpContext* zrtpCtx; char* hh; char** names; zrtpCtx = zrtp_CreateWrapper (); zrtp_initializeZrtpEngine(zrtpCtx, &c_callbacks, "test", "test.zid", NULL); hh = zrtp_getHelloHash(zrtpCtx); if (hh != 0) { printf("hh: %s\n", hh); } else printf("no hh"); zrtp_InitializeConfig(zrtpCtx); names = zrtp_getAlgorithmNames(zrtpCtx, zrtp_HashAlgorithm); for (; *names; names++) { printf("name: %s\n", *names); } return 0; } #ifdef __cplusplus } #endif libzrtpcpp-2.0.0/config.h.cmake0000644000175000017500000000336211570305710015412 0ustar dyfetdyfet /* Define to 1 if you have the header file. */ #cmakedefine HAVE_GCRYPT_H 1 /* Define to 1 if you have the `pthread' library (-lpthread). */ #cmakedefine HAVE_LIBPTHREAD 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_AES_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_BN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_SHA_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PTHREAD_H 1 /* Name of package */ #define PACKAGE ${PROJECT_NAME} /* Version number of package */ #define VERSION ${VERSION} /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to the equivalent of the C99 'restrict' keyword, or to nothing if this is not supported. Do not define if restrict is supported directly. */ #undef restrict /* Work around a bug in Sun C++: it does not support _Restrict, even though the corresponding Sun C compiler does, which causes "#define restrict _Restrict" in the previous line. Perhaps some future version of Sun C++ will work with _Restrict; if so, it'll probably define __RESTRICT, just as Sun C does. */ #if defined __SUNPRO_CC && !defined __RESTRICT # define _Restrict #endif /* Define to empty if the keyword `volatile' does not work. Warning: valid code using `volatile' can become incorrect without. Disable with care. */ #undef volatile libzrtpcpp-2.0.0/src/0000755000175000017500000000000011570306373013506 5ustar dyfetdyfetlibzrtpcpp-2.0.0/src/libzrtpcpp/0000755000175000017500000000000011570306373015677 5ustar dyfetdyfetlibzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketPingAck.h0000644000175000017500000000422411570305710021370 0ustar dyfetdyfet/* Copyright (C) 2006-2009 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 . */ #ifndef _ZRTPPACKETPINGACK_H_ #define _ZRTPPACKETPINGACK_H_ #include /** * @file ZrtpPacketPingAck.h * @brief The ZRTP PingAck message * * @ingroup GNU_ZRTP * @{ */ /** * Implement the PingAck packet. * * The ZRTP simple message PingAck. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketPingAck : public ZrtpPacketBase { protected: PingAck_t* pingAckHeader; ///< Points to PingAck message public: /// Creates a PingAck message with default data ZrtpPacketPingAck(); /// Creates a PingAck message from received data ZrtpPacketPingAck(uint8_t* data); virtual ~ZrtpPacketPingAck(); /// Get SSRC from PingAck message uint32_t getSSRC() { return ntohl(pingAckHeader->ssrc); }; /// Set ZRTP protocol version field, fixed ASCII character array void setVersion(uint8_t *text) { memcpy(pingAckHeader->version, text, ZRTP_WORD_SIZE ); } /// Set SSRC in PingAck message void setSSRC(uint32_t data) {pingAckHeader->ssrc = htonl(data); }; /// Set remote endpoint hash, fixed byte array void setRemoteEpHash(uint8_t *hash) { memcpy(pingAckHeader->remoteEpHash, hash, sizeof(pingAckHeader->remoteEpHash)); } /// Set local endpoint hash, fixed byte array void setLocalEpHash(uint8_t *hash) { memcpy(pingAckHeader->localEpHash, hash, sizeof(pingAckHeader->localEpHash)); } private: PingAckPacket_t data; }; /** * @} */ #endif // ZRTPPACKETCLEARACK libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpUserCallback.h0000644000175000017500000001771211570305710021265 0ustar dyfetdyfet/* Copyright (C) 2006-2008 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 . */ #ifndef _ZRTPUSERCALLBACK_H_ #define _ZRTPUSERCALLBACK_H_ /** * @file ZrtpUserCallback.h * @brief The ZRTP UserCallback class * * @ingroup GNU_ZRTP * @{ */ #include #include #include /** * Application callback methods. * * The ccRTP specific part of GNU ZRTP uses these callback methods * to report ZRTP events to the application. This class implements a * default behaviour for each callback method, usually just a return. * * An application may extend this class and overload methods * to implement its own behaviour. The application must register its * callback class using ZrtpQueue#setUserCallback(). * * CAVEAT
* All methods of the user callback class and classes that * extend this class run in the context of the RTP thread. Thus it is * of paramount importance to keep the execution time of the methods * as short as possible. * * @author Werner Dittmann */ class __EXPORT ZrtpUserCallback { public: /// Create the stadard user callback class. ZrtpUserCallback() {} virtual ~ZrtpUserCallback() {}; /** * Inform user interface that security is active now. * * ZRTP calls this method if the sender and the receiver are * in secure mode now. * * @param cipher * Name and mode of cipher used to encrypt the SRTP stream */ virtual void secureOn(std::string cipher) { return; } /** * Inform user interface that security is not active any more. * * ZRTP calls this method if either the sender or the receiver * left secure mode. * */ virtual void secureOff() { return; } /** * Show the Short Authentication String (SAS) on user interface. * * ZRTP calls this method to display the SAS and inform about the SAS * verification status. The user interface shall enable a SAS verfication * button (or similar UI element). The user shall click on this UI * element after he/she confirmed the SAS code with the partner. * * @param sas * The string containing the SAS. * @param verified * If verified is true then SAS was verified by both * parties during a previous call, otherwise it is set to false. */ virtual void showSAS(std::string sas, bool verified) { return; } /** * Inform the user that ZRTP received "go clear" message from its peer. * * On receipt of a go clear message the user is requested to confirm * a switch to unsecure (clear) modus. Until the user confirms ZRTP * (and the underlying RTP) does not send any data. */ virtual void confirmGoClear() { return; } /** * Show some information to user. * * ZRTP calls this method to display some information to the user. * Along with the message ZRTP provides a severity indicator that * defines: Info, Warning, Error, and Alert. Refer to the * MessageSeverity enum in ZrtpCodes.h. The * UI may use this indicator to highlight messages or alike. * * @param sev * Severity of the message. * @param subCode * The subcode identifying the reason. */ virtual void showMessage(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) { return; } /** * ZRTPQueue calls this if the negotiation failed. * * ZRTPQueue calls this method in case ZRTP negotiation failed. The * parameters show the severity as well as some explanatory text. * Refer to the MessageSeverity enum above. * * @param severity * This defines the message's severity * @param subCode * The subcode identifying the reason. */ virtual void zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) { return; } /** * ZRTPQueue calls this method if the other side does not support ZRTP. * * If the other side does not answer the ZRTP Hello packets then * ZRTP calls this method. * */ virtual void zrtpNotSuppOther() { return; } /** * ZRTPQueue calls this method to inform about a PBX enrollment request. * * Please refer to chapter 8.3 ff to get more details about PBX enrollment * and SAS relay. * * @param info * Give some information to the user about the PBX requesting an * enrollment. * */ virtual void zrtpAskEnrollment(std::string info) { return; } /** * ZRTPQueue calls this method to inform about PBX enrollment result. * * Informs the use about the acceptance or denial of an PBX enrollment * request * * @param info * Give some information to the user about the result of an * enrollment. * */ virtual void zrtpInformEnrollment(std::string info) { return; } /** * ZRTPQueue calls this method to request a SAS signature. * * After ZRTP core was able to compute the Short Authentication String * (SAS) it calls this method. The client may now use an approriate * method to sign the SAS. The client may use * setSignatureData() of ZrtpQueue to store the signature * data an enable signature transmission to the other peer. Refer * to chapter 8.2 of ZRTP specification. * * @param sas * The SAS string to sign. * @see ZrtpQueue#setSignatureData * */ virtual void signSAS(std::string sas) { return; } /** * ZRTPQueue calls this method to request a SAS signature check. * * After ZRTP received a SAS signature in one of the Confirm packets it * call this method. The client may use getSignatureLength() * and getSignatureData()of ZrtpQueue to get the signature * data and perform the signature check. Refer to chapter 8.2 of ZRTP * specification. * * If the signature check fails the client may return false to ZRTP. In * this case ZRTP signals an error to the other peer and terminates * the ZRTP handshake. * * @param sas * The SAS string that was signed by the other peer. * @return * true if the signature was ok, false otherwise. * */ virtual bool checkSASSignature(std::string sas) { return true; } }; #endif libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketGoClear.h0000644000175000017500000000346511570305710021376 0ustar dyfetdyfet/* 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 . */ #ifndef _ZRTPPACKETGOCLEAR_H_ #define _ZRTPPACKETGOCLEAR_H_ /** * @file ZrtpPacketGoClear.h * @brief The ZRTP GoClear message * * GNU ZRTP does not implement GoClear feature * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the GoClear packet. * * The ZRTP message GoClear. The implementation sends this * to order the peer to switch to clear mode (non-SRTP mode). * * @author Werner Dittmann */ class __EXPORT ZrtpPacketGoClear : public ZrtpPacketBase { protected: GoClear_t* clearHeader; public: /// Creates a GoCLear packet with default data ZrtpPacketGoClear(); /// Creates a GoClear packet from received data ZrtpPacketGoClear(uint8_t* data); virtual ~ZrtpPacketGoClear(); /// Not used const uint8_t* getClearHmac() { return clearHeader->clearHmac; }; /// Not used void setClearHmac(uint8_t *text) { memcpy(clearHeader->clearHmac, text, 32); }; /// Not used void clrClearHmac() { memset(clearHeader->clearHmac, 0, 32); }; private: GoClearPacket_t data; }; /** * @} */ #endif // ZRTPPACKETGOCLEAR libzrtpcpp-2.0.0/src/libzrtpcpp/ZIDRecord.h0000644000175000017500000002061611570305710017634 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 . */ #ifndef _ZIDRECORD_H_ #define _ZIDRECORD_H_ /** * @file ZIDRecord.h * @brief ZID record management * * A ZID record stores (caches) ZID (ZRTP ID) specific data that helps ZRTP * to achives its key continuity feature. Please refer to the ZRTP * specification to get detailed information about the ZID. * * @ingroup GNU_ZRTP * @{ */ #include #include #include #define IDENTIFIER_LEN 12 #define RS_LENGTH 32 #define TIME_LENGTH 8 // 64 bit, can hold time on 64 bit systems /** * This is the recod structure of version 1 ZID records. * * This is not longer in use - only during migration. */ typedef struct zidrecord1 { char recValid; //!< if 1 record is valid, if 0: invalid char ownZid; //!< if >1 record contains own ZID, usually 1st record char rs1Valid; //!< if 1 RS1 contains valid data char rs2Valid; //!< if 1 RS2 contains valid data unsigned char identifier[IDENTIFIER_LEN]; ///< the peer's ZID or own ZID unsigned char rs1Data[RS_LENGTH], rs2Data[RS_LENGTH]; ///< the peer's RS data } zidrecord1_t; /** * This is the recod structure of version 2 ZID records. */ typedef struct zidrecord2 { char version; ///< version number of file format, this is #2 char flags; ///< bit field holding various flags, see below char filler1; ///< round up to next 32 bit char filler2; ///< round up to next 32 bit unsigned char identifier[IDENTIFIER_LEN]; ///< the peer's ZID or own ZID unsigned char rs1Interval[TIME_LENGTH]; ///< expiration time of RS1; -1 means indefinite unsigned char rs1Data[RS_LENGTH]; ///< the peer's RS2 data unsigned char rs2Interval[TIME_LENGTH]; ///< expiration time of RS2; -1 means indefinite unsigned char rs2Data[RS_LENGTH]; ///< the peer's RS2 data unsigned char mitmKey[RS_LENGTH]; ///< MiTM key if available } zidrecord2_t; /** * This class implements the ZID record. * * The ZID record holds data about a peer. According to ZRTP specification * we use a ZID to identify a peer. ZRTP uses the RS (Retained Secret) data * to construct shared secrets. *

* NOTE: ZIDRecord has ZIDFile as friend. ZIDFile knows about the private * data of ZIDRecord - please keep both classes synchronized. * * @author: Werner Dittmann */ static const int Valid = 0x1; static const int SASVerified = 0x2; static const int RS1Valid = 0x4; static const int RS2Valid = 0x8; static const int MITMKeyAvailable = 0x10; static const int OwnZIDRecord = 0x20; class __EXPORT ZIDRecord { friend class ZIDFile; private: zidrecord2_t record; unsigned long position; /* * The default constructor is private */ ZIDRecord() { record.version = 2; } /** * Functions for I/O availabe for ZID file handling * * These functions are private, thus only friends may use it. */ void setPosition(long pos) {position = pos;} long getPosition() {return position; } zidrecord2_t* getRecordData() {return &record; } int getRecordLength() {return sizeof(zidrecord2_t); } bool isValid() { return ((record.flags & Valid) == Valid); } void setValid() { record.flags |= Valid; } public: /** * Create a ZID Record with given ZID data * * The method creates a new ZID record and initializes its ZID * data field. All other fields are set to null. * * An application can use this pre-initialized record to look * up the associated record in the ZID file. If the record is * available, the ZID record fields are filled with the stored * data. * * @param idData * Pointer to the fixed length ZID data * @see ZIDFile::getRecord */ ZIDRecord(const unsigned char *idData) { memset(&record, 0, sizeof(zidrecord2_t)); memcpy(record.identifier, idData, IDENTIFIER_LEN); record.version = 2; } /** * Set @c valid flag in RS1 */ void setRs1Valid() { record.flags |= RS1Valid; } /** * reset @c valid flag in RS1 */ void resetRs1Valid() { record.flags &= ~RS1Valid; } /** * Check @c valid flag in RS1 */ bool isRs1Valid() { return ((record.flags & RS1Valid) == RS1Valid); } /** * Set @c valid flag in RS2 */ void setRs2Valid() { record.flags |= RS2Valid; } /** * Reset @c valid flag in RS2 */ void resetRs2Valid() { record.flags &= ~RS2Valid; } /** * Check @c valid flag in RS2 */ bool isRs2Valid() { return ((record.flags & RS2Valid) == RS2Valid); } /** * Set MITM key available */ void setMITMKeyAvailable() { record.flags |= MITMKeyAvailable; } /** * Reset MITM key available */ void resetMITMKeyAvailable() { record.flags &= ~MITMKeyAvailable; } /** * Check MITM key available is set */ bool isMITMKeyAvailable() { return ((record.flags & MITMKeyAvailable) == MITMKeyAvailable); } /** * Mark this as own ZID record */ void setOwnZIDRecord() { record.flags = OwnZIDRecord; } /** * Reset own ZID record marker */ void resetOwnZIDRecord(){ record.flags = 0; } /** * Check own ZID record marker */ bool isOwnZIDRecord() { return (record.flags == OwnZIDRecord); } // no other flag allowed if own ZID /** * Set SAS for this ZID as verified */ void setSasVerified() { record.flags |= SASVerified; } /** * Reset SAS for this ZID as verified */ void resetSasVerified() { record.flags &= ~SASVerified; } /** * Check if SAS for this ZID was verified */ bool isSasVerified() { return ((record.flags & SASVerified) == SASVerified); } /** * Return the ZID for this record */ const uint8_t* getIdentifier() {return record.identifier; } /** * Check if RS1 is still valid * * Returns true if RS1 is still valid, false otherwise. * * @return * Returns true is RS1 is not expired (valid), false otherwise. */ const bool isRs1NotExpired(); /** * Returns pointer to RS1 data. */ const unsigned char* getRs1() { return record.rs1Data; } /** * Check if RS2 is still valid * * Returns true if RS2 is still valid, false otherwise. * * @return * Returns true is RS2 is not expired (valid), false otherwise. */ const bool isRs2NotExpired(); /** * Returns pointer to RS1 data. */ const unsigned char* getRs2() { return record.rs2Data; } /** * Sets new RS1 data and associated expiration value. * * If the expiration value is >0 or -1 the method stores the new * RS1. Before it stores the new RS1 it shifts the exiting RS1 * into RS2 (together with its expiration time). Then it computes * the expiration time of the and stores the result together with * the new RS1. * * If the expiration value is -1 then this RS will never expire. * * If the expiration value is 0 then the expiration value of a * stored RS1 is cleared and no new RS1 value is stored. Also RS2 * is left unchanged. * * @param data * Points to the new RS1 data. * @param expire * The expiration interval in seconds. Default is -1. * */ void setNewRs1(const unsigned char* data, int32_t expire =-1); /** * Set MiTM key data. * */ void setMiTMData(const unsigned char* data); /** * Get MiTM key data. * */ const unsigned char* getMiTMData() {return record.mitmKey; } }; #endif // ZIDRECORD /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/zrtpPacket.h0000644000175000017500000002331711570305710020177 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 */ #ifndef ZRTPPACKET_H #define ZRTPPACKET_H /** * * @file zrtpPacket.h * @brief The data structures and definitions for ZRTP messages * * This include file defines the ZRTP message structures. Refer to * chapter 5 of the ZRTP specification which defines the ZRTP messages and * the transport format. * * @ingroup GNU_ZRTP * @{ */ #include /** * The following defines match the ZRTP specification, chapter 5 */ #define ZRTP_MAGIC 0x5a525450 #define ZRTP_WORD_SIZE 4 #define CRC_SIZE 4 #define TYPE_SIZE (2*ZRTP_WORD_SIZE) #define CLIENT_ID_SIZE (4*ZRTP_WORD_SIZE) #define HASH_IMAGE_SIZE (8*ZRTP_WORD_SIZE) #define ZID_SIZE (3*ZRTP_WORD_SIZE) #define HVI_SIZE (8*ZRTP_WORD_SIZE) #define HMAC_SIZE (2*ZRTP_WORD_SIZE) #define ID_SIZE (2*ZRTP_WORD_SIZE) #define IV_SIZE (4*ZRTP_WORD_SIZE) #define PING_HASH_SIZE (2*ZRTP_WORD_SIZE) /** * The ZRTP message header * * A complete ZRTP message always consists of the ZRTP header * and a message specific part. This specific part may have a variable * length. The length field includes the header. */ typedef struct zrtpPacketHeader { uint16_t zrtpId; ///< Id to identify the message, always 0x505a uint16_t length; ///< Length of the ZRTP message in words uint8_t messageType[TYPE_SIZE]; ///< 2 word (8 octest) message type in ASCII } zrtpPacketHeader_t; /** * Hello message, fixed part. * * The complete Hello message consists of ZRTP message header, Hello fixed * part and a variable part. The Hello class initializes the variable part. */ typedef struct Hello { uint8_t version[ZRTP_WORD_SIZE]; ///< Announces the ZRTP protocol version uint8_t clientId[CLIENT_ID_SIZE]; ///< An 4 word ASCII identifier of the ZRTP client uint8_t hashH3[HASH_IMAGE_SIZE]; ///< The last hash of the hash chain (chap. 9) uint8_t zid[ZID_SIZE]; ///< ZID - 3 word identifier for the ZRTP endpoint uint32_t flagLength; ///< flag bits (chap 7.2), number of algorithms present } Hello_t; /** * The complete ZRTP Hello message. */ typedef struct HelloPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header Hello_t hello; ///< Fixed part of Hello message } HelloPacket_t; /** * HelloAck message. * * The complete HelloAck message consists of ZRTP message header and * the CRC which is the only HelloAck specific data. */ typedef struct HelloAckPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message } HelloAckPacket_t; /** * Commit message * * There are three subtypes of Commit messages, each of which * has a fixed size. The data structure defines the maximum * Commit message. During the ZRTP protocol the implementation * uses fileds according to the use case (DH handshake, * Multi-stream handshake) and adjusts the length. */ typedef struct Commit { uint8_t hashH2[HASH_IMAGE_SIZE]; ///< The second hash of the hash chain (chap. 9) uint8_t zid[ZID_SIZE]; ///< ZID - 3 word identifier for the ZRTP endpoint uint8_t hash[ZRTP_WORD_SIZE]; ///< Commited hash algorithm uint8_t cipher[ZRTP_WORD_SIZE]; ///< Commited symmetrical cipher algorithm uint8_t authlengths[ZRTP_WORD_SIZE]; ///< Commited SRTP authentication algorithm uint8_t pubkey[ZRTP_WORD_SIZE]; ///< Commited key agreement algorithm uint8_t sas[ZRTP_WORD_SIZE]; ///< Commited SAS algorithm uint8_t hvi[HVI_SIZE]; ///< Hash value Initiator - chap 4.4.1.1 uint8_t hmac[HMAC_SIZE]; ///< MAC of the Commit message } Commit_t; /** * The complete ZRTP Commit message. */ typedef struct CommitPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header Commit_t commit; ///< Commit message uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message } CommitPacket_t; /** * DHPart1 and DHPart2 messages * * The DHPart messages have a variable length. The following struct * defines the fixed part only. The DHPart class initializes the * variable part. */ typedef struct DHPart { uint8_t hashH1[HASH_IMAGE_SIZE]; ///< The first hash of the hash chain (chap. 9) uint8_t rs1Id[ID_SIZE]; ///< Id of first retained secret uint8_t rs2Id[ID_SIZE]; ///< Id of second retained secret uint8_t auxSecretId[ID_SIZE]; ///< Id of additional (auxilliary) secret uint8_t pbxSecretId[ID_SIZE]; ///< Id of PBX secret (chap 7.3.1) } DHPart_t; /** * The complete ZRTP DHPart message. */ typedef struct DHPartPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header DHPart_t dhPart; ///< DHPart message fixed part } DHPartPacket_t; /** * Confirm1 and Confirm2 messages * * The Confirm message have a variable length. The following struct * defines the fixed part only. The Confirm class initializes the * variable part. * * ZRTP encrypts a part of the Confirm messages, starting at @c hashH0 * and includes the variable part. */ typedef struct Confirm { uint8_t hmac[HMAC_SIZE]; ///< MAC over the encrypted part of Commit message uint8_t iv[IV_SIZE]; ///< IV for CFB mode to encrypt part of Commit uint8_t hashH0[HASH_IMAGE_SIZE]; ///< starting hash of hash chain (chap. 9) uint8_t filler[2]; ///< Filler bytes uint8_t sigLength; ///< Length of an optional signature length (chap 7.2) uint8_t flags; ///< various flags to control behaviour uint32_t expTime; ///< Expiration time of retained secrets (chap 4.9) } Confirm_t; /** * The complete ZRTP Confirm message. */ typedef struct ConfirmPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header Confirm_t confirm; ///< Confirm message fixed part } ConfirmPacket_t; /** * Conf2Ack message. * * The complete Conf2Ack message consists of ZRTP message header and * the CRC which is the only Conf2Ack specific data. */ typedef struct Conf2AckPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message } Conf2AckPacket_t; /** * The GoClear message is currently not used in * GNU ZRTP C++ - not support for GoClear. */ typedef struct GoClear { uint8_t clearHmac[HMAC_SIZE]; ///< no used } GoClear_t; /** * The complete ZRTP GoClear message - no used. */ typedef struct GoClearPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header GoClear_t goClear; ///< not used uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message } GoClearPacket_t; /** * The ClearAck message is currently not used in * GNU ZRTP C++ - not support for GoClear. */ typedef struct ClearAckPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message } ClearAckPacket_t; /** * The Error message */ typedef struct Error { uint32_t errorCode; ///< Error code, see chap 5.9 } Error_t; /** * The complete ZRTP Error message. */ typedef struct ErrorPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header Error_t error; ///< Error message part uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message } ErrorPacket_t; /** * ErrorAck message. * * The complete ErrorAck message consists of ZRTP message header and * the CRC which is the only ErrorAck specific data. */ typedef struct ErrorAckPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message } ErrorAckPacket_t; /** * Ping message. * * The Ping message has a fixed size. */ typedef struct Ping { uint8_t version[ZRTP_WORD_SIZE]; ///< The ZRTP protocol version uint8_t epHash[PING_HASH_SIZE]; ///< End point hash, see chap 5.16 } Ping_t; /** * The complete ZRTP Ping message. */ typedef struct PingPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header Ping_t ping; ///< Ping message part uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message } PingPacket_t; /** * PingAck message. * * The PingAck message has a fixed size. */ typedef struct PingAck { uint8_t version[ZRTP_WORD_SIZE]; ///< The ZRTP protocol version uint8_t localEpHash[PING_HASH_SIZE]; ///< Local end point hash, see chap 5.16 uint8_t remoteEpHash[PING_HASH_SIZE]; ///< Remote end point hash, see chap 5.16 uint32_t ssrc; ///< SSRC copied from the Ping message (RTP packet part) } PingAck_t; /** * The complete ZRTP PingAck message. */ typedef struct PingAckPacket { zrtpPacketHeader_t hdr; ///< ZRTP Header PingAck_t pingAck; ///< PingAck message part uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message } PingAckPacket_t; #endif // ZRTPPACKET_H /** * @} */ /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpCrc32.h0000755000175000017500000000337411570305710017610 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 . */ #ifndef _ZRTPCRC32_H_ #define _ZRTPCRC32_H_ /** * * @file ZrtpCrc32.h * @brief Methods to compute the CRC32 checksum for ZRTP packets * * @ingroup GNU_ZRTP * @{ * * @see ZrtpCallback */ /** * Check if a buffer matches a given CRC32 checksum. * * @param buffer * Pointer to the data buffer. * @param length * Length in bytes of the data buffer. * @param crc32 * The CRC32 checksum. * * @return * @c true if the CRC32 checksum matches the computed checksum of the * buffer, @c false otherwise. */ bool zrtpCheckCksum(uint8_t *buffer, uint16_t length, uint32_t crc32); /** * Generate a CRC32 checksum of a data buffer * * @param buffer * Pointer to the buffer. * @param length * Lenght of the buffer in bytes. * * @return * A preliminary CRC32 checksum */ uint32_t zrtpGenerateCksum(uint8_t *buffer, uint16_t length); /** * Close CRC32 computation. * * @param crc32 * A preliminary CRC32 checksum. * * @return * The ready to use CRC32 checksum in host order. */ uint32_t zrtpEndCksum(uint32_t crc32); /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpTextData.h0000644000175000017500000000476211570305710020451 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 */ #ifndef _ZRTPTEXTDATA_H_ #define _ZRTPTEXTDATA_H_ /** * @file ZrtpTextData.h * @brief The ZRTP ASCII texts - extern references * * @ingroup GNU_ZRTP * @{ */ #include /** * The extern references to the global data. * * @author Werner Dittmann */ extern char clientId[]; extern char zrtpVersion[]; /** * */ extern char HelloMsg[]; extern char HelloAckMsg[]; extern char CommitMsg[]; extern char DHPart1Msg[]; extern char DHPart2Msg[]; extern char Confirm1Msg[]; extern char Confirm2Msg[]; extern char Conf2AckMsg[]; extern char ErrorMsg[]; extern char ErrorAckMsg[]; extern char GoClearMsg[]; extern char ClearAckMsg[]; extern char PingMsg[]; extern char PingAckMsg[]; /** * */ extern char responder[]; extern char initiator[]; extern char iniMasterKey[]; extern char iniMasterSalt[]; extern char respMasterKey[]; extern char respMasterSalt[]; extern char iniHmacKey[]; extern char respHmacKey[]; extern char retainedSec[]; extern char iniZrtpKey[]; extern char respZrtpKey[]; extern char sasString[]; extern char KDFString[]; extern char zrtpSessionKey[]; extern char zrtpMsk[]; extern char s256[]; extern char s384[]; extern const char* mandatoryHash; extern char aes3[]; extern char aes2[]; extern char aes1[]; extern char two3[]; extern char two2[]; extern char two1[]; extern const char* mandatoryCipher; extern char dh2k[]; extern char dh3k[]; extern char ec25[]; extern char ec38[]; extern char mult[]; extern const char* mandatoryPubKey; extern char b32[]; extern const char* mandatorySasType; extern char hs32[]; extern char hs80[]; extern char sk32[]; extern char sk64[]; extern const char* mandatoryAuthLen_1; extern const char* mandatoryAuthLen_2; /** * @} */ #endif // _ZRTPTEXTDATA_H_ libzrtpcpp-2.0.0/src/libzrtpcpp/TimeoutProvider.h0000644000175000017500000002005211570305710021202 0ustar dyfetdyfet/* Copyright (C) 2006, 2005, 2004 Erik Eliasson, Johan Bilien, Werner Dittmann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef TIMEOUTPROVIDER_H #define TIMEOUTPROVIDER_H /** * Provides a way to request timeouts after a number of milli seconds. * * A command is associated to each timeout. * * Modified to use the common c++ library functions and the STL * list by Werner Dittmann. * * @author Erik Eliasson, eliasson@it.kth.se, 2003 * @author Werner Dittmann */ #include #include #include #include /** * Represents a request of a "timeout" (delivery of a command to a * "timeout receiver" after at least a specified time period). * * Slightly modified to use gettimeofday directly. * * NOTE: This class is only used internaly. * @author Erik Eliasson * @author Werner Dittmann */ template class TPRequest { public: TPRequest( TOSubscriber tsi, int timeoutMs, const TOCommand &command): subscriber(tsi) { struct timeval tv; gettimeofday(&tv, NULL ); when_ms = ((uint64)tv.tv_sec) * (uint64)1000 + ((uint64)tv.tv_usec) / (uint64)1000; when_ms += timeoutMs; this->command = command; } /** * @param t ms since Epoch */ bool happensBefore(uint64 t) { if (when_ms < t) { return true; } if (when_ms > t) { return false; } return false; // if equal it does not "happens_before" } bool happensBefore(const TPRequest *req){ return happensBefore(req->when_ms); } /** * Number of milli seconds until timeout from when this method is * called */ int getMsToTimeout () { struct timeval tv; gettimeofday(&tv, NULL ); uint64 now = ((uint64)tv.tv_sec) * (uint64)1000 + ((uint64)tv.tv_usec) / (uint64)1000; if (happensBefore(now)) { return 0; } else { return (int)(when_ms - now); } } TOCommand getCommand() { return command; } TOSubscriber getSubscriber() { return subscriber; } /** * Two timeout requests are considered equeal if they have * the same subscriber AND command AND time when they * occur. If one of the time is zero then this is a * wildcard and matches always. */ bool operator==(const TPRequest &req) { if (req.subscriber == subscriber && req.command == command && req.when_ms == when_ms) { return true; } return false; } private: TOSubscriber subscriber; uint64 when_ms; // Time since Epoch in ms when the timeout // will happen TOCommand command; // Command that will be delivered to the // receiver (subscriber) of the timeout. }; /** * Class to generate objects giving timeout functionality. * * @author Erik Eliasson * @author Werner Dittmann */ template class TimeoutProvider : public ost::Thread, ost::Event { public: /** * Timeout Provide Constructor */ TimeoutProvider(): requests(), synchLock(), stop(false) { } /** * Destructor also terminates the Timeout thread. */ ~TimeoutProvider() { terminate(); } /** * Terminates the Timeout provider thread. */ void stopThread(){ stop = true; signal(); // signal event to waiting thread } /** * Request a timeout trigger. * * @param time_ms Number of milli-seconds until the timeout is * wanted. Note that a small additional period of time is * added that depends on execution speed. * @param subscriber The receiver of the callback when the command has timed * out. This argument must not be NULL. * @param command Specifies the String command to be passed back in the * callback. */ void requestTimeout(int32_t time_ms, TOSubscriber subscriber, const TOCommand &command) { TPRequest* request = new TPRequest(subscriber, time_ms, command); synchLock.enter(); if (requests.size()==0) { requests.push_front(request); signal(); synchLock.leave(); return; } if (request->happensBefore(requests.front())) { requests.push_front(request); signal(); synchLock.leave(); return; } if (requests.back()->happensBefore(request)){ requests.push_back(request); signal(); synchLock.leave(); return; } typename std::list* >::iterator i; for(i = requests.begin(); i != requests.end(); i++ ) { if( request->happensBefore(*i)) { requests.insert(i, request); break; } } signal(); synchLock.leave(); } /** * Removes timeout requests that belong to a subscriber and command. * * @see requestTimeout */ void cancelRequest(TOSubscriber subscriber, const TOCommand &command) { synchLock.enter(); typename std::list* >::iterator i; for(i = requests.begin(); i != requests.end(); ) { if( (*i)->getCommand() == command && (*i)->getSubscriber() == subscriber) { i = requests.erase(i); continue; } i++; } synchLock.leave(); } protected: void run() { do { synchLock.enter(); int32_t time = 3600000; int32_t size = 0; if ((size = requests.size()) > 0) { time = requests.front()->getMsToTimeout(); } if (time == 0 && size > 0) { if (stop){ // This must be checked so that we will // stop even if we have timeouts to deliver. synchLock.leave(); return; } TPRequest* req = requests.front(); TOSubscriber subs = req->getSubscriber(); TOCommand command = req->getCommand(); requests.pop_front(); synchLock.leave(); // call the command with free Mutex subs->handleTimeout(command); continue; } synchLock.leave(); if (stop) { // If we were told to stop while delivering // a timeout we will exit here return; } reset(); // ready to receive triggers again wait(time); if (stop) { // If we are told to exit while waiting we // will exit return; } } while(true); } private: // The timeouts are ordered in the order of which they // will expire. Nearest in future is first in list. std::list *> requests; ost::Mutex synchLock; // Protects the internal data structures bool stop; // Flag to tell the worker thread // to terminate. Set to true and // wake the worker thread to // terminate it. }; #endif /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpConfigure.h0000644000175000017500000003346511570305710020656 0ustar dyfetdyfet/* Copyright (C) 2009 - 2010 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 */ #ifndef _ZRTPCONFIGURE_H_ #define _ZRTPCONFIGURE_H_ /** * @file ZrtpConfigure.h * @brief The ZRTP configure functions * @ingroup GNU_ZRTP * @{ */ #include #include #include #include #include #include #include /** * This enumerations list all configurable algorithm types. */ enum AlgoTypes { Invalid = 0, HashAlgorithm = 1, CipherAlgorithm, PubKeyAlgorithm, SasType, AuthLength }; typedef void(*encrypt_t)(uint8_t*, int32_t, uint8_t*, uint8_t*, int32_t); typedef void(*decrypt_t)(uint8_t*, int32_t, const uint8_t*, uint8_t*, int32_t); /** * The algorithm enumration class. * * This simple class is just a container of an algorithm's name and * its associated algorithm type. We use this class together with the * EnumBase class to implement a Java-like enum class functionality * (not fully, but OK for our use case). * * An application shall use the get / check methods to retrieve information. */ class AlgorithmEnum { public: /** * Create an AlgorithmEnum object. * * @param type * Defines the algorithm type * @param name * Set the names of the algorithm. The name is copied * and the call may reuse the space. * * @see AlgoTypes */ AlgorithmEnum(const AlgoTypes type, const char* name, int32_t klen, const char* ra, encrypt_t en, decrypt_t de, SrtpAlgorithms alId); /** * AlgorithmEnum destructor */ ~AlgorithmEnum(); /** * Get the algorihm's name * * @returns * Algorithm's name as null terminated C-string. The * application must not free this memory. */ const char* getName(); /** * Get the algorihm's readable name * * @returns * Algorithm's readable name as null terminated C-string. The * application must not free this memory. */ const char* getReadable(); /** * Get the algorihm's key length. * * @returns * An integer definig the key length in bytes. */ int getKeylen(); /** * Get the algorihm's integer id. * * @returns * An integer that defines the algorithm. */ SrtpAlgorithms getAlgoId(); /** * Get the algorihm's key length. * * @returns * An integer definig the key length in bytes. */ encrypt_t getEncrypt(); /** * Get the algorihm's key length. * * @returns * An integer definig the key length in bytes. */ decrypt_t getDecrypt(); /** * Get the algorithm type of this AlgorithmEnum object. * * @returns * The algorithm type. * * @see AlgoTypes */ AlgoTypes getAlgoType(); /** * Check if this AlgorithmEnum object is valid * * @returns * @c true if the object is valid, @c false otherwise */ bool isValid(); private: AlgoTypes algoType; std::string algoName; int32_t keyLen; std::string readable; encrypt_t encrypt; decrypt_t decrypt; SrtpAlgorithms algoId; }; /** * EnumBase provides methods to store and access algorithm enumerations of * a specific algorithm type. * * An application shall use the get / check methods to retrieve information * from the preset Algorithm Enumerations. * * @see AlgoTypes * @see zrtpHashes * @see zrtpSymCiphers * @see zrtpPubKeys * @see zrtpSasTypes * @see zrtpAuthLengths */ class EnumBase { public: /** * Get an AlgorithmEnum by its name * * @param name * The name of the AlgorithmEnum to search. * @returns * The AlgorithmEnum if found or an invalid AlgorithmEnum if the name * was not found */ AlgorithmEnum& getByName(const char* name); /** * Return all names of all currently stored AlgorithmEnums * * @return * A C++ std::list of C++ std::strings that contain the names. */ std::list* getAllNames(); /** * Get the number of currently stored AlgorithmEnums * * @return * The number of currently stored AlgorithmEnums */ int getSize(); /** * Get the AlgoTypes to which this EnumBase belongs. * * @return * The AlgoTypes of this EnumBase. * @see AlgoTypes. */ AlgoTypes getAlgoType(); /** * Return the AlgorithmEnum by its ordinal number * * @param ord * The ordinal number of the AlgorithmEnum. * @return * The AlgorithmEnum if found, an invalid Algorithm otherwise. */ AlgorithmEnum& getByOrdinal(int ord); /** * Get the ordinal number of an AlgorithmEnum * * @param algo * Return toe ordinal numer of this AlgorithmEnum. * * @return * Return the ordinal number of this AlgorithmEnum if found, * -1 otherwise. */ int getOrdinal(AlgorithmEnum& algo); protected: EnumBase(AlgoTypes algo); ~EnumBase(); void insert(const char* name); void insert(const char* name, int32_t klen, const char* ra, encrypt_t en, decrypt_t de, SrtpAlgorithms alId); private: AlgoTypes algoType; std::vector algos; }; /** * The enumaration subclasses that contain the supported algorithm enumerations. */ class HashEnum : public EnumBase { public: HashEnum(); ~HashEnum(); }; class SymCipherEnum : public EnumBase { public: SymCipherEnum(); ~SymCipherEnum(); }; class PubKeyEnum : public EnumBase { public: PubKeyEnum(); ~PubKeyEnum(); }; class SasTypeEnum : public EnumBase { public: SasTypeEnum(); ~SasTypeEnum(); }; class AuthLengthEnum : public EnumBase { public: AuthLengthEnum(); ~AuthLengthEnum(); }; extern HashEnum zrtpHashes; extern SymCipherEnum zrtpSymCiphers; extern PubKeyEnum zrtpPubKeys; extern SasTypeEnum zrtpSasTypes; extern AuthLengthEnum zrtpAuthLengths; /** * ZRTP configuration data. * * This class contains data and functions to set ZRTP configuration data. * An application may use this class to set configuration information for * ZRTP. ZRTP uses this configuration information to announce various * algorithms via its Hello message. An application may use this class to * restrict or allow use of algorithms. * * The constructor does not set any algorithms, thus it is an empty * configuration. An application may use this empty configuration and * hand it over to ZRTP. In this case ZRTP does not announce any algorithms * in its Hello message and uses mandatory algorithms only. * * An application can configure implemented algorithms only. */ class __EXPORT ZrtpConfigure { public: ZrtpConfigure(); /* Creates Configuration data */ ~ZrtpConfigure(); /** * Set the maximum number of algorithms per algorithm type that an application can * configure. */ static const int maxNoOfAlgos = 7; /** * Convenience function that sets a pre-defined standard configuration. * * The standard configuration consists of the following algorithms: *

    *
  • Hash: SHA256
  • *
  • Symmetric Cipher: AES 128, AES 256
  • *
  • Public Key Algorithm: DH2048, DH3027, MultiStream
  • *
  • SAS type: libase 32
  • *
  • SRTP Authentication lengths: 32, 80
  • *
*/ void setStandardConfig(); /** * Convenience function that sets the mandatory algorithms only. * * Mandatory algorithms are: *
    *
  • Hash: SHA256
  • *
  • Symmetric Cipher: AES 128
  • *
  • Public Key Algorithm: DH3027, MultiStream
  • *
  • SAS type: libase 32
  • *
  • SRTP Authentication lengths: 32, 80
  • *
*/ void setMandatoryOnly(); /** * Clear all configuration data. * * The functions clears all configuration data. */ void clear(); /** * Add an algorithm to configuration data. * * Adds the specified algorithm to the configuration data. * If no free configuration data slot is available the * function does not add the algorithm and returns -1. The * methods appends the algorithm to the existing algorithms. * * @param algoType * Specifies which algorithm type to select * @param algo * The enumeration of the algorithm to add. * @return * Number of free configuration data slots or -1 on error */ int32_t addAlgo(AlgoTypes algoType, AlgorithmEnum& algo); /** * Add an algorithm to configuration data at given index. * * Adds the specified algorithm to the configuration data vector * at a given index. If the index is larger than the actual size * of the configuration vector the method just appends the algorithm. * * @param algoType * Specifies which algorithm type to select * @param algo * The enumeration of the algorithm to add. * @param index * The index where to add the algorihm * @return * Number of free configuration data slots or -1 on error */ int32_t addAlgoAt(AlgoTypes algoType, AlgorithmEnum& algo, int32_t index); /** * Remove a algorithm from configuration data. * * Removes the specified algorithm from configuration data. If * the algorithm was not configured previously the function does * not modify the configuration data and returns the number of * free configuration data slots. * * If an application removes all algorithms then ZRTP does not * include any algorithm into the hello message and falls back * to a predefined mandatory algorithm. * * @param algoType * Specifies which algorithm type to select * @param algo * The enumeration of the algorithm to remove. * @return * Number of free configuration slots. */ int32_t removeAlgo(AlgoTypes algoType, AlgorithmEnum& algo); /** * Returns the number of configured algorithms. * * @param algoType * Specifies which algorithm type to select * @return * The number of configured algorithms (used configuration * data slots) */ int32_t getNumConfiguredAlgos(AlgoTypes algoType); /** * Returns the identifier of the algorithm at index. * * @param algoType * Specifies which algorithm type to select * @param index * The index in the list of the algorihm type * @return * A pointer the the algorithm enumeration. If the index * does not point to a configured slot then the function * returns NULL. * */ AlgorithmEnum& getAlgoAt(AlgoTypes algoType, int32_t index); /** * Checks if the configuration data of the algorihm type already contains * a specific algorithms. * * @param algoType * Specifies which algorithm type to select * @param algo * The algorithm to check * @return * True if the algorithm was found, false otherwise. * */ bool containsAlgo(AlgoTypes algoType, AlgorithmEnum& algo); /** * Enables or disables trusted MitM processing. * * For further details of trusted MitM processing refer to ZRTP * specification, chapter 7.3 * * @param yesNo * If set to true then trusted MitM processing is enabled. */ void setTrustedMitM(bool yesNo); /** * Check status of trusted MitM processing. * * @return * Returns true if trusted MitM processing is enabled. */ bool isTrustedMitM(); /** * Enables or disables SAS signature processing. * * For further details of trusted MitM processing refer to ZRTP * specification, chapter 7.2 * * @param yesNo * If set to true then certificate processing is enabled. */ void setSasSignature(bool yesNo); /** * Check status of SAS signature processing. * * @return * Returns true if certificate processing is enabled. */ bool isSasSignature(); /// Helper function to print some internal data void printConfiguredAlgos(AlgoTypes algoTyp); private: std::vector hashes; std::vector symCiphers; std::vector publicKeyAlgos; std::vector sasTypes; std::vector authLengths; bool enableTrustedMitM; bool enableSasSignature; AlgorithmEnum& getAlgoAt(std::vector& a, int32_t index); int32_t addAlgo(std::vector& a, AlgorithmEnum& algo); int32_t addAlgoAt(std::vector& a, AlgorithmEnum& algo, int32_t index); int32_t removeAlgo(std::vector& a, AlgorithmEnum& algo); int32_t getNumConfiguredAlgos(std::vector& a); bool containsAlgo(std::vector& a, AlgorithmEnum& algo); std::vector& getEnum(AlgoTypes algoType); void printConfiguredAlgos(std::vector& a); protected: public: }; /** * @} */ #endif /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpStates.h0000644000175000017500000000437711570305710020200 0ustar dyfetdyfet/* 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 */ #ifndef _ZRTPSTATES_H_ #define _ZRTPSTATES_H_ /** * @file ZrtpStates.h * @brief The ZRTP state switching class * * @ingroup GNU_ZRTP * @{ */ #include #include #include #include class __EXPORT ZrtpStateClass; /** * This structure hold the state name as enum (int) number and the pointer to * the functions that handles the various triggers that can occur in a state. */ typedef struct { int32_t stateName; ///< The state number void (ZrtpStateClass::* handler)(void); ///< The state handler } state_t; /** * Implement a simple state switching. * * This class provides functions that manage the states and the event handler * functions. Its a very simple implementation. * * @author Werner Dittmann */ class __EXPORT ZrtpStates { public: /// Create an initialize state switching ZrtpStates(state_t* const zstates, const int32_t numStates, const int32_t initialState): numStates(numStates), states(zstates), state(initialState) {} /// Call a state handler int32_t processEvent(ZrtpStateClass& zsc) { (zsc.*states[state].handler)(); return 0; } /// Check if in specified state bool inState(const int32_t s) { return ((s == state)); } /// Set the next state void nextState(int32_t s) { state = s; } private: const int32_t numStates; const state_t* states; int32_t state; ZrtpStates(); }; /** * @} */ #endif //ZRTPSTATES libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpCallback.h0000644000175000017500000002751511570305710020430 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 . */ #ifndef _ZRTPCALLBACK_H_ #define _ZRTPCALLBACK_H_ /** * @file ZrtpCallback.h * @brief Callback interface between ZRTP and the RTP stack implementation * @ingroup GNU_ZRTP * @{ */ #include #include #include #include /** * This enum defines which role a ZRTP peer has. * * According to the ZRTP specification the role determines which keys to * use to encrypt or decrypt SRTP data. * *
    *
  • The Initiator encrypts SRTP data using the keyInitiator and the * saltInitiator data, the Responder uses these data to decrypt. *
  • *
  • The Responder encrypts SRTP data using the keyResponder and the * saltResponder data, the Initiator uses these data to decrypt. *
  • *
*/ typedef enum { Responder = 1, ///< This client is in ZRTP Responder mode Initiator ///< This client is in ZRTP Initiator mode } Role; /// The algorihms that we support in SRTP and that ZRTP can negotiate. typedef enum { None, Aes = 1, ///< Use AES as symmetrical cipher algorithm TwoFish, ///< Use TwoFish as symmetrical cipher algorithm Sha1, ///< Use Sha1 as authentication algorithm Skein ///< Use Skein as authentication algorithm } SrtpAlgorithms; /** * This structure contains pointers to the SRTP secrets and the role info. * * About the role and what the meaning of the role is refer to the * of the enum Role. The pointers to the secrets are valid as long as * the ZRtp object is active. To use these data after the ZRtp object's * lifetime you may copy the data into a save place. The destructor * of ZRtp clears the data. */ typedef struct srtpSecrets { SrtpAlgorithms symEncAlgorithm; ///< symmetrical cipher algorithm const uint8_t* keyInitiator; ///< Initiator's key int32_t initKeyLen; ///< Initiator's key length const uint8_t* saltInitiator; ///< Initiator's salt int32_t initSaltLen; ///< Initiator's salt length const uint8_t* keyResponder; ///< Responder's key int32_t respKeyLen; ///< Responder's key length const uint8_t* saltResponder; ///< Responder's salt int32_t respSaltLen; ///< Responder's salt length SrtpAlgorithms authAlgorithm; ///< SRTP authentication algorithm int32_t srtpAuthTagLen; ///< SRTP authentication length std::string sas; ///< The SAS string Role role; ///< ZRTP role of this client } SrtpSecret_t; enum EnableSecurity { ForReceiver = 1, ///< Enable security for SRTP receiver ForSender = 2 ///< Enable security for SRTP sender }; /** * This abstract class defines the callback functions required by GNU ZRTP. * * This class is a pure abstract class, aka Interface in Java, that * defines the callback interface that the specific part of a GNU ZRTP * must implement. The generic part of GNU ZRTP uses these mehtods * to communicate with the specific part, for example to send data * via the RTP/SRTP stack, to set timers and cancel timer and so on. * * The generiy part of GNU ZRTP needs only a few callback methods to * be implemented by the specific part. * * @author Werner Dittmann */ class __EXPORT ZrtpCallback { protected: friend class ZRtp; virtual ~ZrtpCallback() {}; /** * Send a ZRTP packet via RTP. * * ZRTP calls this method to send a ZRTP packet via the RTP session. * * @param data * Points to ZRTP packet to send. * @param length * The length in bytes of the data * @return * zero if sending failed, one if packet was send */ virtual int32_t sendDataZRTP(const uint8_t* data, int32_t length) =0; /** * Activate timer. * * @param time * The time in ms for the timer * @return * zero if activation failed, one if timer was activated */ virtual int32_t activateTimer(int32_t time) =0; /** * Cancel the active timer. * * @return * zero if cancel action failed, one if timer was canceled */ virtual int32_t cancelTimer() =0; /** * Send information messages to the hosting environment. * * The ZRTP implementation uses this method to send information * messages to the host. Along with the message ZRTP provides a * severity indicator that defines: Info, Warning, Error, * Alert. Refer to the MessageSeverity enum above. * * @param severity * This defines the message's severity * @param subCode * The subcode identifying the reason. * @see ZrtpCodes#MessageSeverity */ virtual void sendInfo(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) =0; /** * SRTP crypto data ready for the sender or receiver. * * The ZRTP implementation calls this method right after all SRTP * secrets are computed and ready to be used. The parameter points * to a structure that contains pointers to the SRTP secrets and a * enum Role. The called method (the implementation * of this abstract method) must either copy the pointers to the SRTP * data or the SRTP data itself to a save place. The SrtpSecret_t * structure is destroyed after the callback method returns to the * ZRTP implementation. * * The SRTP data themselfs are ontained in the ZRtp object and are * valid as long as the ZRtp object is active. TheZRtp's * destructor clears the secrets. Thus the called method needs to * save the pointers only, ZRtp takes care of the data. * * The implementing class may enable SRTP processing in this * method or delay it to srtpSecertsOn(). * * @param secrets A pointer to a SrtpSecret_t structure that * contains all necessary data. * * @param part for which part (Sender or Receiver) this data is * valid. * * @return Returns false if something went wrong during * initialization of SRTP context, for example memory shortage. */ virtual bool srtpSecretsReady(SrtpSecret_t* secrets, EnableSecurity part) =0; /** * Switch off the security for the defined part. * * @param part Defines for which part (sender or receiver) to * switch on security */ virtual void srtpSecretsOff(EnableSecurity part) =0; /** * Switch on the security. * * ZRTP calls this method after it has computed the SAS and check * if it is verified or not. In addition ZRTP provides information * about the cipher algorithm and key length for the SRTP session. * * This method must enable SRTP processing if it was not enabled * during sertSecretsReady(). * * @param c The name of the used cipher algorithm and mode, or * NULL * * @param s The SAS string * * @param verified if verified is true then SAS was * verified by both parties during a previous call. */ virtual void srtpSecretsOn(std::string c, std::string s, bool verified) =0; /** * This method handles GoClear requests. * * According to the ZRTP specification the user must be informed about * a GoClear request because the ZRTP implementation switches off security * if it could authenticate the GoClear packet. * * Note: GoClear is not yet implemented in GNU ZRTP. * */ virtual void handleGoClear() =0; /** * Handle ZRTP negotiation failed. * * ZRTP calls this method in case ZRTP negotiation failed. The * parameters show the severity as well as the reason. * * @param severity * This defines the message's severity * @param subCode * The subcode identifying the reason. * @see ZrtpCodes#MessageSeverity */ virtual void zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) =0; /** * ZRTP calls this method if the other side does not support ZRTP. * * If the other side does not answer the ZRTP Hello packets then * ZRTP calls this method, * */ virtual void zrtpNotSuppOther() =0; /** * Enter synchronization mutex. * * GNU ZRTP requires one mutes to synchronize its * processing. Because mutex implementations depend on the * underlying infrastructure, for example operating system or * thread implementation, GNU ZRTP delegates mutex handling to the * spcific part of its implementation. */ virtual void synchEnter() =0; /** * Leave synchronization mutex. */ virtual void synchLeave() =0; /** * Inform about a PBX enrollment request. * * Please refer to chapter 8.3 ff to get more details about PBX * enrollment and SAS relay. * * Note: PBX enrollement is not yet fully supported by GNU * ZRTP. * * @param info Give some information to the user about the PBX * requesting an enrollment. */ virtual void zrtpAskEnrollment(std::string info) =0; /** * Inform about PBX enrollment result. * * Informs the use about the acceptance or denial of an PBX enrollment * request * * Note: PBX enrollement is not yet fully supported by GNU * ZRTP. * * @param info Give some information to the user about the result * of an enrollment. */ virtual void zrtpInformEnrollment(std::string info) =0; /** * Request a SAS signature. * * After ZRTP was able to compute the Short Authentication String * (SAS) it calls this method. The client may now use an * approriate method to sign the SAS. The client may use * ZrtpQueue#setSignatureData() to store the signature data an * enable signature transmission to the other peer. Refer to * chapter 8.2 of ZRTP specification. * * Note: SAS signing is not yet fully supported by GNU * ZRTP. * * @param sas * The SAS string to sign. * */ virtual void signSAS(std::string sas) =0; /** * ZRTPQueue calls this method to request a SAS signature check. * * After ZRTP received a SAS signature in one of the Confirm packets it * call this method. The client may use getSignatureLength() * and getSignatureData()of ZrtpQueue to get the signature * data and perform the signature check. Refer to chapter 8.2 of ZRTP * specification. * * If the signature check fails the client may return false to ZRTP. In * this case ZRTP signals an error to the other peer and terminates * the ZRTP handshake. * * Note: SAS signing is not yet fully supported by GNU * ZRTP. * * @param sas * The SAS string that was signed by the other peer. * @return * true if the signature was ok, false otherwise. * */ virtual bool checkSASSignature(std::string sas) =0; }; #endif // ZRTPCALLBACK /** * @} */ /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketError.h0000644000175000017500000000327211570305710021147 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 . */ #ifndef _ZRTPPACKETERROR_H_ #define _ZRTPPACKETERROR_H_ /** * @file ZrtpPacketError.h * @brief The ZRTP Error message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the Error packet. * * The ZRTP simple message Error. The implementation sends this * after detecting an error. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketError : public ZrtpPacketBase { protected: Error_t* errorHeader; ///< Points to Error message public: /// Creates a Error packet with default data ZrtpPacketError(); /// Creates a Error packet from received data ZrtpPacketError(uint8_t* data); virtual ~ZrtpPacketError(); /// Get the error code from Error message uint32_t getErrorCode() { return ntohl(errorHeader->errorCode); }; /// Set error code in Error message void setErrorCode(uint32_t code) {errorHeader->errorCode = htonl(code); }; private: ErrorPacket_t data; }; /** * @} */ #endif // ZRTPPACKETERROR libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpCodes.h0000755000175000017500000001473011570305710017767 0ustar dyfetdyfet/** @file ZrtpCodes.h */ /* Copyright (C) 2006-2010 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 . */ #ifndef _ZRTPCODES_H_ #define _ZRTPCODES_H_ /** * @file ZrtpCodes.h * @brief The ZRTP info, warning, and error codes * @ingroup GNU_ZRTP * @{ */ namespace GnuZrtpCodes { /** * \namespace GnuZrtpCodes * * This enum defines the information message severity. * * The ZRTP implementation issues information messages to inform the user * about ongoing processing, unusual behavior, or alerts in case of severe * problems. Each main severity code a number of sub-codes exist that * specify the exact nature of the problem. * * An application gets message severity codes and the associated sub-codes * via the ZrtpUserCallback#showMessage method. * * The severity levels and their meaning are: * *
*
Info
keeps the user informed about ongoing processing and * security setup. The enumeration InfoCodes defines the subcodes. *
*
Warning
is an information about some security issues, e.g. if * an AES 256 encryption is request but only DH 3072 as public key scheme * is supported. ZRTP will establish a secure session (SRTP). The * enumeration WarningCodes defines the sub-codes. *
*
Severe
is used if an error occured during ZRTP protocol usage. * In case of Severe ZRTP will not establish a secure session. * The enumeration SevereCodes defines the sub-codes. *
*
Zrtp
shows a ZRTP security problem. Refer to the enumeration * ZrtpErrorCodes for sub-codes. GNU ZRTP of course will not * establish a secure session. *
*
* */ enum MessageSeverity { Info = 1, Warning, Severe, ZrtpError }; /** * Sub-codes for Info */ enum InfoCodes { InfoHelloReceived = 1, //!< Hello received, preparing a Commit InfoCommitDHGenerated, //!< Commit: Generated a public DH key InfoRespCommitReceived, //!< Responder: Commit received, preparing DHPart1 InfoDH1DHGenerated, //!< DH1Part: Generated a public DH key InfoInitDH1Received, //!< Initiator: DHPart1 received, preparing DHPart2 InfoRespDH2Received, //!< Responder: DHPart2 received, preparing Confirm1 InfoInitConf1Received, //!< Initiator: Confirm1 received, preparing Confirm2 InfoRespConf2Received, //!< Responder: Confirm2 received, preparing Conf2Ack InfoRSMatchFound, //!< At least one retained secrets matches - security OK InfoSecureStateOn, //!< Entered secure state InfoSecureStateOff //!< No more security for this session }; /** * Sub-codes for Warning */ enum WarningCodes { WarningDHAESmismatch = 1, //!< Commit contains an AES256 cipher but does not offer a Diffie-Helman 4096 WarningGoClearReceived, //!< Received a GoClear message WarningDHShort, //!< Hello offers an AES256 cipher but does not offer a Diffie-Helman 4096 WarningNoRSMatch, //!< No retained shared secrets available - must verify SAS WarningCRCmismatch, //!< Internal ZRTP packet checksum mismatch - packet dropped WarningSRTPauthError, //!< Dropping packet because SRTP authentication failed! WarningSRTPreplayError, //!< Dropping packet because SRTP replay check failed! WarningNoExpectedRSMatch //!< Valid retained shared secrets availabe but no matches found - must verify SAS }; /** * Sub-codes for Severe */ enum SevereCodes { SevereHelloHMACFailed = 1, //!< Hash HMAC check of Hello failed! SevereCommitHMACFailed, //!< Hash HMAC check of Commit failed! SevereDH1HMACFailed, //!< Hash HMAC check of DHPart1 failed! SevereDH2HMACFailed, //!< Hash HMAC check of DHPart2 failed! SevereCannotSend, //!< Cannot send data - connection or peer down? SevereProtocolError, //!< Internal protocol error occured! SevereNoTimer, //!< Cannot start a timer - internal resources exhausted? SevereTooMuchRetries //!< Too much retries during ZRTP negotiation - connection or peer down? }; /** * Error codes according to the ZRTP specification chapter 6.9 * * GNU ZRTP uses these error codes in two ways: to fill the appropriate * field ing the ZRTP Error packet and as sub-code in * ZrtpUserCallback#showMessage(). GNU ZRTP uses thes error codes also * to report received Error packts, in this case the sub-codes are their * negative values. * * The enumeration member comments are copied from the ZRTP specification. */ enum ZrtpErrorCodes { MalformedPacket = 0x10, //!< Malformed packet (CRC OK, but wrong structure) CriticalSWError = 0x20, //!< Critical software error UnsuppZRTPVersion = 0x30, //!< Unsupported ZRTP version HelloCompMismatch = 0x40, //!< Hello components mismatch UnsuppHashType = 0x51, //!< Hash type not supported UnsuppCiphertype = 0x52, //!< Cipher type not supported UnsuppPKExchange = 0x53, //!< Public key exchange not supported UnsuppSRTPAuthTag = 0x54, //!< SRTP auth. tag not supported UnsuppSASScheme = 0x55, //!< SAS scheme not supported NoSharedSecret = 0x56, //!< No shared secret available, DH mode required DHErrorWrongPV = 0x61, //!< DH Error: bad pvi or pvr ( == 1, 0, or p-1) DHErrorWrongHVI = 0x62, //!< DH Error: hvi != hashed data SASuntrustedMiTM = 0x63, //!< Received relayed SAS from untrusted MiTM ConfirmHMACWrong = 0x70, //!< Auth. Error: Bad Confirm pkt HMAC NonceReused = 0x80, //!< Nonce reuse EqualZIDHello = 0x90, //!< Equal ZIDs in Hello GoCleatNotAllowed = 0x100, //!< GoClear packet received, but not allowed IgnorePacket = 0x7fffffff }; } /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/ZRtp.h0000644000175000017500000010626511570305710016753 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 . */ #ifndef _ZRTP_H_ #define _ZRTP_H_ /** * @file ZRtp.h * @brief The ZRTP main engine * @defgroup GNU_ZRTP The GNU ZRTP C++ implementation * @{ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef SHA256_DIGEST_LENGTH #define SHA256_DIGEST_LENGTH 32 #endif // Prepare to support digest algorithms up to 512 bit (64 bytes) #define MAX_DIGEST_LENGTH 64 #define IMPL_MAX_DIGEST_LENGTH 64 class __EXPORT ZrtpStateClass; class ZrtpDH; /** * The main ZRTP class. * * This is the main class of the RTP/SRTP independent part of the GNU * ZRTP. It handles the ZRTP HMAC, DH, and other data management. The * user of this class needs to know only a few methods and needs to * provide only a few external functions to connect to a Timer * mechanism and to send data via RTP and SRTP. Refer to the * ZrtpCallback class to get detailed information regading the * callback methods required by GNU RTP. * * The class ZrtpQueue is the GNU ccRTP specific implementation that * extends standard ccRTP RTP provide ZRTP support. Refer to the * documentation of ZrtpQueue to get more information about the usage * of ZRtp and associated classes. * * The main entry into the ZRTP class is the processExtensionHeader() * method. * * This class does not directly handle the protocol states, timers, * and packet resend. The protocol state engine is responsible for * these actions. * * Example how to use ZRtp: *
 *    zrtpEngine = new ZRtp((uint8_t*)ownZid, (ZrtpCallback*)this, idString);
 *    zrtpEngine->startZrtpEngine();
 *
* @see ZrtpCallback * * @author Werner Dittmann */ class __EXPORT ZRtp { public: /** * Constructor intializes all relevant data but does not start the * engine. */ ZRtp(uint8_t* myZid, ZrtpCallback* cb, std::string id, ZrtpConfigure* config); /** * Destructor cleans up. */ ~ZRtp(); /** * Kick off the ZRTP protocol engine. * * This method calls the ZrtpStateClass#evInitial() state of the state * engine. After this call we are able to process ZRTP packets * from our peer and to process them. */ void startZrtpEngine(); /** * Stop ZRTP security. * */ void stopZrtp(); /** * Process RTP extension header. * * This method expects to get a pointer to the extension header of * a RTP packet. The method checks if this is really a ZRTP * packet. If this check fails the method returns 0 (false) in * case this is not a ZRTP packet. We return a 1 if we processed * the ZRTP extension header and the caller may process RTP data * after the extension header as usual. The method return -1 the * call shall dismiss the packet and shall not forward it to * further RTP processing. * * @param extHeader * A pointer to the first byte of the extension header. Refer to * RFC3550. * @param peerSSRC * The peer's SSRC. * @return * Code indicating further packet handling, see description above. */ void processZrtpMessage(uint8_t *extHeader, uint32_t peerSSRC); /** * Process a timeout event. * * We got a timeout from the timeout provider. Forward it to the * protocol state engine. * */ void processTimeout(); /** * Check for and handle GoClear ZRTP packet header. * * This method checks if this is a GoClear packet. If not, just return * false. Otherwise handle it according to the specification. * * @param extHeader * A pointer to the first byte of the extension header. Refer to * RFC3550. * @return * False if not a GoClear, true otherwise. */ bool handleGoClear(uint8_t *extHeader); /** * Set the auxilliary secret. * * Use this method to set the auxilliary secret data. Refer to ZRTP * specification, chapter 4.3 ff * * @param data * Points to the secret data. * @param length * Length of the auxilliary secrect in bytes */ void setAuxSecret(uint8_t* data, int32_t length); /** * Set the PBX secret. * * Use this method to set the PBX secret data. Refer to ZRTP * specification, chapter 4.3 ff and 7.3 * * @param data * Points to the other PBX data. * @param length * The length in bytes of the data. */ void setPbxSecret(uint8_t* data, int32_t length); /** * Check current state of the ZRTP state engine * * @param state * The state to check. * @return * Returns true id ZRTP engine is in the given state, false otherwise. */ bool inState(int32_t state); /** * Set SAS as verified. * * Call this method if the user confirmed (verfied) the SAS. ZRTP * remembers this together with the retained secrets data. */ void SASVerified(); /** * Reset the SAS verfied flag for the current active user's retained secrets. * */ void resetSASVerified(); /** * Get the ZRTP Hello Hash data. * * Use this method to get the ZRTP Hello Hash data. The method * returns the data as a string containing the ZRTP protocol version and * hex-digits. Refer to ZRTP specification, chapter 8. * * @return * a std:string containing the Hello hash value as hex-digits. The * hello hash is available immediately after class instantiation. */ std::string getHelloHash(); /** * Get Multi-stream parameters. * * Use this method to get the Multi-stream that were computed during * the ZRTP handshake. An application may use these parameters to * enable multi-stream processing for an associated SRTP session. * * Refer to chapter 4.4.2 in the ZRTP specification for further details * and restriction how and when to use multi-stream mode. * * @return * a string that contains the multi-stream parameters. The application * must not modify the contents of this string, it is opaque data. The * application may hand over this string to a new ZrtpQueue instance * to enable multi-stream processing for this ZrtpQueue. * If ZRTP was not started or ZRTP is not yet in secure state the method * returns an empty string. */ std::string getMultiStrParams(); /** * Set Multi-stream parameters. * * Use this method to set the parameters required to enable Multi-stream * processing of ZRTP. The multi-stream parameters must be set before the * application starts the ZRTP protocol engine. * * Refer to chapter 4.4.2 in the ZRTP specification for further details * of multi-stream mode. * * @param parameters * A string that contains the multi-stream parameters that this * new ZrtpQueue instanace shall use. See also * getMultiStrParams() */ void setMultiStrParams(std::string parameters); /** * Check if this ZRTP session is a Multi-stream session. * * Use this method to check if this ZRTP instance uses multi-stream. * Refer to chapters 4.2 and 4.4.2 in the ZRTP. * * @return * True if multi-stream is used, false otherwise. */ bool isMultiStream(); /** * Check if the other ZRTP client supports Multi-stream. * * Use this method to check if the other ZRTP client supports * Multi-stream mode. * * @return * True if multi-stream is available, false otherwise. */ bool isMultiStreamAvailable(); /** * Accept a PBX enrollment request. * * If a PBX service asks to enroll the PBX trusted MitM key and the user * accepts this request, for example by pressing an OK button, the client * application shall call this method and set the parameter * accepted to true. If the user does not accept the request * set the parameter to false. * * @param accepted * True if the enrollment request is accepted, false otherwise. */ void acceptEnrollment(bool accepted); /** * Enable PBX enrollment * * The application calls this method to allow or disallow PBX enrollment. * If the applications allows PBX enrollment then the ZRTP implementation * honors the PBX enrollment flag in Confirm packets. Refer to chapter 7.3 * for further details of PBX enrollment. * * @param yesNo * If set to true then ZRTP honors the PBX enrollment flag in Commit * packets and calls the appropriate user callback methods. If * the parameter is set to false ZRTP ignores the PBX enrollment flags. */ void setPBXEnrollment(bool yesNo); /** * Set signature data * * This functions stores signature data and transmitts it during ZRTP * processing to the other party as part of the Confirm packets. Refer to * chapters 5.7 and 7.2. * * The signature data must be set before ZRTP the application calls * start(). * * @param data * The signature data including the signature type block. The method * copies this data into the Confirm packet at signature type block. * @param length * The length of the signature data in bytes. This length must be * multiple of 4. * @return * True if the method stored the data, false otherwise. */ bool setSignatureData(uint8_t* data, int32_t length); /** * Get signature data * * This functions returns signature data that was receivied during ZRTP * processing. Refer to chapters 5.7 and 7.2. * * The signature data can be retrieved after ZRTP enters secure state. * start(). * * @param data * Pointer to a data buffer. This buffer must be large enough to * hold the signature data. Refer to getSignatureLength() * to get the length of the received signature data. * @return * Number of bytes copied into the data buffer */ int32_t getSignatureData(uint8_t* data); /** * Get length of signature data * * This functions returns the length of signature data that was receivied * during ZRTP processing. Refer to chapters 5.7 and 7.2. * * @return * Length in bytes of the received signature data. The method returns * zero if no signature data avilable. */ int32_t getSignatureLength(); /** * Emulate a Conf2Ack packet. * * This method emulates a Conf2Ack packet. According to ZRTP specification * the first valid SRTP packet that the Initiator receives must switch * on secure mode. Refer to chapter 4 in the specificaton * */ void conf2AckSecure(); /** * Get other party's ZID (ZRTP Identifier) data * * This functions returns the other party's ZID that was receivied * during ZRTP processing. * * The ZID data can be retrieved after ZRTP receive the first Hello * packet from the other party. The application may call this method * for example during SAS processing in showSAS(...) user callback * method. * * @param data * Pointer to a data buffer. This buffer must have a size of * at least 12 bytes (96 bit) (ZRTP Identifier, see chap. 4.9) * @return * Number of bytes copied into the data buffer - must be equivalent * to 96 bit, usually 12 bytes. */ int32_t getZid(uint8_t* data); private: friend class ZrtpStateClass; /** * The state engine takes care of protocol processing. */ ZrtpStateClass* stateEngine; /** * This is my ZID that I send to the peer. */ uint8_t zid[IDENTIFIER_LEN]; /** * The peer's ZID */ uint8_t peerZid[IDENTIFIER_LEN]; /** * The callback class provides me with the interface to send * data and to deal with timer management of the hosting system. */ ZrtpCallback* callback; /** * My active Diffie-Helman context */ ZrtpDH* dhContext; /** * The computed DH shared secret */ uint8_t* DHss; /** * My computed public key */ uint8_t pubKeyBytes[400]; /** * Length off public key */ // int32_t pubKeyLen; /** * My Role in the game */ Role myRole; /** * The human readable SAS value */ std::string SAS; /** * The SAS hash for signaling and alike. Refer to chapters * 4.5 and 7 how sasHash, sasValue and the SAS string are derived. */ uint8_t sasHash[MAX_DIGEST_LENGTH]; /** * The ids for the retained and other shared secrets */ uint8_t rs1IDr[MAX_DIGEST_LENGTH]; uint8_t rs2IDr[MAX_DIGEST_LENGTH]; uint8_t auxSecretIDr[MAX_DIGEST_LENGTH]; uint8_t pbxSecretIDr[MAX_DIGEST_LENGTH]; uint8_t rs1IDi[MAX_DIGEST_LENGTH]; uint8_t rs2IDi[MAX_DIGEST_LENGTH]; uint8_t auxSecretIDi[MAX_DIGEST_LENGTH]; uint8_t pbxSecretIDi[MAX_DIGEST_LENGTH]; /** * pointers to aux secret storage and length of aux secret */ uint8_t* auxSecret; int32_t auxSecretLength; /** * Record if valid rs1 and/or rs1 were found in the * retaind secret cache. */ bool rs1Valid; bool rs2Valid; /** * My hvi */ uint8_t hvi[MAX_DIGEST_LENGTH]; /** * The peer's hvi */ uint8_t peerHvi[8*ZRTP_WORD_SIZE]; /** * Context to compute the SHA256 hash of selected messages. * Used to compute the s0, refer to chapter 4.4.1.4 */ void* msgShaContext; /** * Commited Hash, Cipher, and public key algorithms */ AlgorithmEnum* hash; AlgorithmEnum* cipher; AlgorithmEnum* pubKey; /** * The selected SAS type. */ AlgorithmEnum* sasType; /** * The selected SAS type. */ AlgorithmEnum* authLength; /** * The Hash images as defined in chapter 5.1.1 (H0 is a random value, * not stored here). Need full SHA 256 lenght to store hash value but * only the leftmost 128 bits are used in computations and comparisons. */ uint8_t H0[IMPL_MAX_DIGEST_LENGTH]; uint8_t H1[IMPL_MAX_DIGEST_LENGTH]; uint8_t H2[IMPL_MAX_DIGEST_LENGTH]; uint8_t H3[IMPL_MAX_DIGEST_LENGTH]; uint8_t helloHash[IMPL_MAX_DIGEST_LENGTH]; // We get the peer's H? from the message where length is defined as 8 words uint8_t peerH0[8*ZRTP_WORD_SIZE]; uint8_t peerH1[8*ZRTP_WORD_SIZE]; uint8_t peerH2[8*ZRTP_WORD_SIZE]; uint8_t peerH3[8*ZRTP_WORD_SIZE]; /** * The SHA256 hash over selected messages */ uint8_t messageHash[MAX_DIGEST_LENGTH]; /** * The s0 */ uint8_t s0[MAX_DIGEST_LENGTH]; /** * The new Retained Secret */ uint8_t newRs1[MAX_DIGEST_LENGTH]; /** * The GoClear HMAC keys and confirm HMAC key */ uint8_t hmacKeyI[MAX_DIGEST_LENGTH]; uint8_t hmacKeyR[MAX_DIGEST_LENGTH]; /** * The Initiator's srtp key and salt */ uint8_t srtpKeyI[MAX_DIGEST_LENGTH]; uint8_t srtpSaltI[MAX_DIGEST_LENGTH]; /** * The Responder's srtp key and salt */ uint8_t srtpKeyR[MAX_DIGEST_LENGTH]; uint8_t srtpSaltR[MAX_DIGEST_LENGTH]; /** * The keys used to encrypt/decrypt the confirm message */ uint8_t zrtpKeyI[MAX_DIGEST_LENGTH]; uint8_t zrtpKeyR[MAX_DIGEST_LENGTH]; /** * Pointers to negotiated hash and HMAC functions */ void (*hashFunction)(unsigned char *data, unsigned int data_length, unsigned char *digest); void (*hashListFunction)(unsigned char *data[], unsigned int data_length[], unsigned char *digest); void (*hmacFunction)(uint8_t* key, uint32_t key_length, uint8_t* data, int32_t data_length, uint8_t* mac, uint32_t* mac_length); void (*hmacListFunction)( uint8_t* key, uint32_t key_length, uint8_t* data[], uint32_t data_length[], uint8_t* mac, uint32_t* mac_length ); void* (*createHashCtx)(); void (*closeHashCtx)(void* ctx, unsigned char* digest); void (*hashCtxFunction)(void* ctx, unsigned char* data, unsigned int dataLength); void (*hashCtxListFunction)(void* ctx, unsigned char* dataChunks[], unsigned int dataChunkLength[]); int32_t hashLength; // Funtion pointers to implicit hash and hmac functions void (*hashFunctionImpl)(unsigned char *data, unsigned int data_length, unsigned char *digest); void (*hashListFunctionImpl)(unsigned char *data[], unsigned int data_length[], unsigned char *digest); void (*hmacFunctionImpl)(uint8_t* key, uint32_t key_length, uint8_t* data, int32_t data_length, uint8_t* mac, uint32_t* mac_length); void (*hmacListFunctionImpl)( uint8_t* key, uint32_t key_length, uint8_t* data[], uint32_t data_length[], uint8_t* mac, uint32_t* mac_length ); int32_t hashLengthImpl; /** * The ZRTP Session Key * Refer to chapter 5.4.1.4 */ uint8_t zrtpSession[MAX_DIGEST_LENGTH]; /** * True if this ZRTP instance uses multi-stream mode. */ bool multiStream; /** * True if the other ZRTP client supports multi-stream mode. */ bool multiStreamAvailable; /** * True if PBX enrollment is enabled. */ bool PBXEnrollment; /** * Configuration data which algorithms to use. */ ZrtpConfigure configureAlgos; /** * Pre-initialized packets. */ ZrtpPacketHello zrtpHello; ZrtpPacketHelloAck zrtpHelloAck; ZrtpPacketConf2Ack zrtpConf2Ack; ZrtpPacketClearAck zrtpClearAck; ZrtpPacketGoClear zrtpGoClear; ZrtpPacketError zrtpError; ZrtpPacketErrorAck zrtpErrorAck; ZrtpPacketDHPart zrtpDH1; ZrtpPacketDHPart zrtpDH2; ZrtpPacketCommit zrtpCommit; ZrtpPacketConfirm zrtpConfirm1; ZrtpPacketConfirm zrtpConfirm2; ZrtpPacketPingAck zrtpPingAck; /** * Random IV data to encrypt the confirm data, 128 bit for AES */ uint8_t randomIV[16]; uint8_t tempMsgBuffer[1024]; int32_t lengthOfMsgData; /** * Variables to store signature data. Includes the signature type block */ uint8_t* signatureData; // will be allocated when needed int32_t signatureLength; // overall length in bytes uint32_t peerSSRC; // peer's SSRC, required to setup PingAck packet /** * Find the best Hash algorithm that is offered in Hello. * * Find the best, that is the strongest, Hash algorithm that our peer * offers in its Hello packet. * * @param hello * The Hello packet. * @return * The Enum that identifies the best offered Hash algortihm. Return * NumSupportedHashes to signal that no matching Hash algorithm * was found at all. */ AlgorithmEnum* findBestHash(ZrtpPacketHello *hello); /** * Find the best symmetric cipher algorithm that is offered in Hello. * * Find the best, that is the strongest, cipher algorithm that our peer * offers in its Hello packet. * * @param hello * The Hello packet. * @param pk * The id of the selected public key algorithm * @return * The Enum that identifies the best offered Cipher algortihm. Return * NumSupportedSymCiphers to signal that no matching Cipher algorithm * was found at all. */ AlgorithmEnum* findBestCipher(ZrtpPacketHello *hello, AlgorithmEnum* pk); /** * Find the best Public Key algorithm that is offered in Hello. * * Find the best, that is the strongest, public key algorithm that our peer * offers in its Hello packet. * * @param hello * The Hello packet. * @return * The Enum that identifies the best offered Public Key algortihm. Return * NumSupportedPubKeys to signal that no matching Public Key algorithm * was found at all. */ AlgorithmEnum* findBestPubkey(ZrtpPacketHello *hello); /** * Find the best SAS algorithm that is offered in Hello. * * Find the best, that is the strongest, SAS algorithm that our peer * offers in its Hello packet. * * @param hello * The Hello packet. * @return * The Enum that identifies the best offered SAS algortihm. Return * NumSupportedSASTypes to signal that no matching SAS algorithm * was found at all. */ AlgorithmEnum* findBestSASType(ZrtpPacketHello* hello); /** * Find the best authentication length that is offered in Hello. * * Find the best, that is the strongest, authentication length that our peer * offers in its Hello packet. * * @param hello * The Hello packet. * @return * The Enum that identifies the best offered authentication length. Return * NumSupportedAuthLenghts to signal that no matching length * was found at all. */ AlgorithmEnum* findBestAuthLen(ZrtpPacketHello* hello); /** * Check if MultiStream mode is offered in Hello. * * Find the best, that is the strongest, authentication length that our peer * offers in its Hello packet. * * @param hello * The Hello packet. * @return * True if multi stream mode is available, false otherwise. */ bool checkMultiStream(ZrtpPacketHello* hello); /** * Compute my hvi value according to ZRTP specification. */ void computeHvi(ZrtpPacketDHPart* dh, ZrtpPacketHello *hello); void computeSharedSecretSet(ZIDRecord& zidRec); void computeSRTPKeys(); void 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); void generateKeysInitiator(ZrtpPacketDHPart *dhPart, ZIDRecord& zidRec); void generateKeysResponder(ZrtpPacketDHPart *dhPart, ZIDRecord& zidRec); void generateKeysMultiStream(); void setNegotiatedHash(AlgorithmEnum* hash); /* * The following methods are helper functions for ZrtpStateClass. * ZrtpStateClass calls them to prepare packets, send data, report * problems, etc. */ /** * Send a ZRTP packet. * * The state engines calls this method to send a packet via the RTP * stack. * * @param packet * Points to the ZRTP packet. * @return * zero if sending failed, one if packet was send */ int32_t sendPacketZRTP(ZrtpPacketBase *packet); /** * Activate a Timer using the host callback. * * @param tm * The time in milliseconds. * @return * zero if activation failed, one if timer was activated */ int32_t activateTimer(int32_t tm); /** * Cancel the active Timer using the host callback. * * @return * zero if activation failed, one if timer was activated */ int32_t cancelTimer(); /** * Prepare a Hello packet. * * Just take the preinitialized Hello packet and return it. No * further processing required. * * @return * A pointer to the initialized Hello packet. */ ZrtpPacketHello* prepareHello(); /** * Prepare a HelloAck packet. * * Just take the preinitialized HelloAck packet and return it. No * further processing required. * * @return * A pointer to the initialized HelloAck packet. */ ZrtpPacketHelloAck* prepareHelloAck(); /** * Prepare a Commit packet. * * We have received a Hello packet from our peer. Check the offers * it makes to us and select the most appropriate. Using the * selected values prepare a Commit packet and return it to protocol * state engine. * * @param hello * Points to the received Hello packet * @param errMsg * Points to an integer that can hold a ZRTP error code. * @return * A pointer to the prepared Commit packet */ ZrtpPacketCommit* prepareCommit(ZrtpPacketHello *hello, uint32_t* errMsg); /** * Prepare a Commit packet for Multi Stream mode. * * Using the selected values prepare a Commit packet and return it to protocol * state engine. * * @param hello * Points to the received Hello packet * @return * A pointer to the prepared Commit packet for multi stream mode */ ZrtpPacketCommit* prepareCommitMultiStream(ZrtpPacketHello *hello); /** * Prepare the DHPart1 packet. * * This method prepares a DHPart1 packet. The input to the method is always * a Commit packet received from the peer. Also we a in the role of the * Responder. * * When we receive a Commit packet we get the selected ciphers, hashes, etc * and cross-check if this is ok. Then we need to initialize a set of DH * keys according to the selected cipher. Using this data we prepare our DHPart1 * packet. */ ZrtpPacketDHPart* prepareDHPart1(ZrtpPacketCommit *commit, uint32_t* errMsg); /** * Prepare the DHPart2 packet. * * This method prepares a DHPart2 packet. The input to the method is always * a DHPart1 packet received from the peer. Our peer sends the DH1Part as * response to our Commit packet. Thus we are in the role of the * Initiator. * */ ZrtpPacketDHPart* prepareDHPart2(ZrtpPacketDHPart* dhPart1, uint32_t* errMsg); /** * Prepare the Confirm1 packet. * * This method prepare the Confirm1 packet. The input to this method is the * DHPart2 packect received from our peer. The peer sends the DHPart2 packet * as response of our DHPart1. Here we are in the role of the Responder * */ ZrtpPacketConfirm* prepareConfirm1(ZrtpPacketDHPart* dhPart2, uint32_t* errMsg); /** * Prepare the Confirm1 packet in multi stream mode. * * This method prepares the Confirm1 packet. The state engine call this method * if multi stream mode is selected and a Commit packet was received. The input to * this method is the Commit. * Here we are in the role of the Responder * */ ZrtpPacketConfirm* prepareConfirm1MultiStream(ZrtpPacketCommit* commit, uint32_t* errMsg); /** * Prepare the Confirm2 packet. * * This method prepare the Confirm2 packet. The input to this method is the * Confirm1 packet received from our peer. The peer sends the Confirm1 packet * as response of our DHPart2. Here we are in the role of the Initiator */ ZrtpPacketConfirm* prepareConfirm2(ZrtpPacketConfirm* confirm1, uint32_t* errMsg); /** * Prepare the Confirm2 packet in multi stream mode. * * This method prepares the Confirm2 packet. The state engine call this method if * multi stream mode is active and in state CommitSent. The input to this method is * the Confirm1 packet received from our peer. The peer sends the Confirm1 packet * as response of our Commit packet in multi stream mode. * Here we are in the role of the Initiator */ ZrtpPacketConfirm* prepareConfirm2MultiStream(ZrtpPacketConfirm* confirm1, uint32_t* errMsg); /** * Prepare the Conf2Ack packet. * * This method prepare the Conf2Ack packet. The input to this method is the * Confirm2 packet received from our peer. The peer sends the Confirm2 packet * as response of our Confirm1. Here we are in the role of the Initiator */ ZrtpPacketConf2Ack* prepareConf2Ack(ZrtpPacketConfirm* confirm2, uint32_t* errMsg); /** * Prepare the ErrorAck packet. * * This method prepares the ErrorAck packet. The input to this method is the * Error packet received from the peer. */ ZrtpPacketErrorAck* prepareErrorAck(ZrtpPacketError* epkt); /** * Prepare the Error packet. * * This method prepares the Error packet. The input to this method is the * error code to be included into the message. */ ZrtpPacketError* prepareError(uint32_t errMsg); /** * Prepare a ClearAck packet. * * This method checks if the GoClear message is valid. If yes then switch * off SRTP processing, stop sending of RTP packets (pause transmit) and * inform the user about the fact. Only if user confirms the GoClear message * normal RTP processing is resumed. * * @return * NULL if GoClear could not be authenticated, a ClearAck packet * otherwise. */ ZrtpPacketClearAck* prepareClearAck(ZrtpPacketGoClear* gpkt); /** * Prepare the ErrorAck packet. * * This method prepares the ErrorAck packet. The input to this method is the * Error packet received from the peer. */ ZrtpPacketPingAck* preparePingAck(ZrtpPacketPing* ppkt); /** * Prepare a GoClearAck packet w/o HMAC * * Prepare a GoCLear packet without a HMAC but with a short error message. * This type of GoClear is used if something went wrong during the ZRTP * negotiation phase. * * @return * A goClear packet without HMAC */ ZrtpPacketGoClear* prepareGoClear(uint32_t errMsg = 0); /** * Compare the hvi values. * * Compare a received Commit packet with our Commit packet and returns * which Commit packt is "more important". See chapter 5.2 to get further * information how to compare Commit packets. * * @param commit * Pointer to the peer's commit packet we just received. * @return * <0 if our Commit packet is "less important" * >0 if our Commit is "more important" * 0 shouldn't happen because we compare crypto hashes */ int32_t compareCommit(ZrtpPacketCommit *commit); /** * Verify the H2 hash image. * * Verifies the H2 hash contained in a received commit message. * This functions just verifies H2 but does not store it. * * @param commit * Pointer to the peer's commit packet we just received. * @return * true if H2 is ok and verified * false if H2 could not be verified */ bool verifyH2(ZrtpPacketCommit *commit); /** * Send information messages to the hosting environment. * * The ZRTP implementation uses this method to send information messages * to the host. Along with the message ZRTP provides a severity indicator * that defines: Info, Warning, Error, Alert. Refer to the MessageSeverity * enum in the ZrtpCallback class. * * @param severity * This defines the message's severity * @param subCode * The subcode identifying the reason. * @see ZrtpCodes#MessageSeverity */ void sendInfo(GnuZrtpCodes::MessageSeverity severity, int32_t subCode); /** * ZRTP state engine calls this if the negotiation failed. * * ZRTP calls this method in case ZRTP negotiation failed. The parameters * show the severity as well as some explanatory text. * * @param severity * This defines the message's severity * @param subCode * The subcode identifying the reason. * @see ZrtpCodes#MessageSeverity */ void zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity severity, int32_t subCode); /** * ZRTP state engine calls this method if the other side does not support ZRTP. * * If the other side does not answer the ZRTP Hello packets then * ZRTP calls this method, * */ void zrtpNotSuppOther(); /** * Signal SRTP secrets are ready. * * This method calls a callback method to inform the host that the SRTP * secrets are ready. * * @param part * Defines for which part (sender or receiver) to switch on security * @return * Returns false if something went wrong during initialization of SRTP * context. Propagate error back to state engine. */ bool srtpSecretsReady(EnableSecurity part); /** * Switch off SRTP secrets. * * This method calls a callback method to inform the host that the SRTP * secrets shall be cleared. * * @param part * Defines for which part (sender or receiver) to clear */ void srtpSecretsOff(EnableSecurity part); /** * ZRTP state engine calls these methods to enter or leave its * synchronization mutex. */ void synchEnter(); void synchLeave(); /** * Helper function to store ZRTP message data in a temporary buffer * * This functions first clears the temporary buffer, then stores * the packet's data to it. We use this to check the packet's HMAC * after we received the HMAC key in to following packet. * * @param data * Pointer to the packet's ZRTP message */ void storeMsgTemp(ZrtpPacketBase* pkt); /** * Helper function to check a ZRTP message HMAC * * This function gets a HMAC key and uses it to compute a HMAC * with this key and the stored data of a previous received ZRTP * message. It compares the computed HMAC and the HMAC stored in * the received message and returns the result. * * @param key * Pointer to the HMAC key. * @return * Returns true if the computed HMAC and the stored HMAC match, * false otherwise. */ bool checkMsgHmac(uint8_t* key); /** * Set the client ID for ZRTP Hello message. * * The user of ZRTP must set its id to identify itself in the * ZRTP HELLO message. The maximum length is 16 characters. Shorter * id string are allowed, they will be filled with blanks. A longer id * is truncated to 16 characters. * * The identifier is set in the Hello packet of ZRTP. Thus only after * setting the identifier ZRTP can compute the HMAC and the final * helloHash. * * @param id * The client's id */ void setClientId(std::string id); }; /** * @} */ #endif // ZRTP libzrtpcpp-2.0.0/src/libzrtpcpp/Base32.h0000644000175000017500000002012011570305710017054 0ustar dyfetdyfet#ifndef BASE32_H #define BASE32_H /* * * Copyright (c) 2002 Bryce "Zooko" Wilcox-O'Hearn Permission is hereby * granted, free of charge, to any person obtaining a copy of this software to * deal in this software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of this software, and to permit persons to whom this software * is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of this software. * * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER * DEALINGS IN THIS SOFTWARE. * * Converted to C++ by: * @author Werner Dittmann */ /** * @file Base32.h * @brief C++ implmentation of the Base32 encoding and decoding * * ZRTP uses the base 32 encoding and decoding to generate the Short * Authentication String (SAS). * * @ingroup GNU_ZRTP * @{ */ #include #include #include #include #include using namespace std; extern int divceil(int a, int b); class Base32 { public: /** * A Constructor that decodes from base32 into binary. * * The constructor decodes the base32 encoded data back into binary * data. Use getDecoded(...) to get the binary data. * * @param encoded * The string that contains the base32 encoded data. */ Base32(const string encoded); /** * A Constructor that decodes from base32 into binary. * * This constructor decodes the base32 encoded data back into * binary data. Only the specified number of bits are decoded * (should be a multiple of 5). Use * getDecoded(...) to get the binary data. * * @param encoded * The string that contains the base32 encoded data. * @param noOfBits * How many bits to decode into binary data. */ Base32(const string encoded, int noOfBits); /** * A Constructor that encodes binary data. * * The constructor converts the first specified number of bits of * the binary data into a base32 presentation. Use * getEncoded to get the encoded data. * * @param data * A pointer to the first bits (byte) of binary data * @param noOfBits * How many bits to use for encoding. Should be a * multiple of 5. */ Base32(const unsigned char* data, int noOfBits); ~Base32(); /** * Get the decoded binary data and its length. * * The method returns the decoded binary data if the appropriate * Constructor was used. Otherwise we return NULL * pointer and length zero. * * Note: This method returns a pointer to the decoded * binary data. The Base32 object manages this pointer, thus you * may need to copy the data to a save place before deleting this * object. If the object is deleted this pointer is no longer * valid. * * @param length * A reference to an integer. * @return * A pointer to the decoded binary data. */ const unsigned char* getDecoded(int &length); /** * Get the encoded base32 string. * * The method returns a string that contains the base32 encoded * data if the appropriate constructor was used. Otherwise we * return an empty string. * * @return * The string containing the base32 encoded data. */ const string getEncoded() { return encoded; }; /** * Compute the number of base32 encoded characters given the * number of bits. * * @param lengthInBits * The length of the data in bits * @return * The length of the base-32 encoding of the data in characters */ static size_t const b2alen(const size_t lengthInBits) { return divceil(lengthInBits, 5); }; private: /** * Decodes a string with base32 presentation into binary data. * * a2b_l() will return a result big enough to hold lengthinbits bits. So * for example if cs is 4 characters long (encoding at least 15 and up to * 20 bits) and lengthinbits is 16, then a2b_l() will return a string of * length 2 (since 2 bytes is sufficient to store 16 bits). If cs is 4 * characters long and lengthinbits is 20, then a2b_l() will return a * string of length 3 (since 3 bytes is sufficient to store 20 bits). Note * that `b2a_l()' does not mask off unused least-significant bits, so for * example if cs is 4 characters long and lengthinbits is 17, then you * must ensure that all three of the unused least-significant bits of cs * are zero bits or you will get the wrong result. This precondition is * tested by assertions if assertions are enabled. (Generally you just * require the encoder to ensure this consistency property between the * least significant zero bits and value of `lengthinbits', and reject * strings that have a length-in-bits which isn't a multiple of 8 and yet * don't have trailing zero bits, as improperly encoded.) * * @param cs * The data to be decoded * @param size * The length of the input data buffer. Usually divceil(length in bits, 5). * @param lengthinbits * The number of bits of data in cs to be decoded */ void a2b_l(const string cs, size_t size, const size_t lengthinbits); /** * Encodes binary to to base32 presentation. * * b2a_l() will generate a base-32 encoded string big enough to encode * lengthinbits bits. So for example if os is 2 bytes long and * lengthinbits is 15, then b2a_l() will generate a 3-character- long * base-32 encoded string (since 3 quintets is sufficient to encode 15 * bits). If os is 2 bytes long and lengthinbits is 16 (or None), then * b2a_l() will generate a 4-character string. Note that `b2a_l()' does * not mask off unused least-significant bits, so for example if os is 2 * bytes long and lengthinbits is 15, then you must ensure that the unused * least-significant bit of os is a zero bit or you will get the wrong * result. This precondition is tested by assertions if assertions are * enabled. * * Warning: if you generate a base-32 encoded string with `b2a_l()', and * then someone else tries to decode it by calling `a2b()' instead of * `a2b_l()', then they will (probably) get a different string than the * one you encoded! So only use `b2a_l()' when you are sure that the * encoding and decoding sides know exactly which `lengthinbits' to use. * If you do not have a way for the encoder and the decoder to agree upon * the lengthinbits, then it is best to use `b2a()' and `a2b()'. The only * drawback to using `b2a()' over `b2a_l()' is that when you have a number * of bits to encode that is not a multiple of 8, `b2a()' can sometimes * generate a base-32 encoded string that is one or two characters longer * than necessary. * * @param cs * Pointer to binary data. * @param len * Length of the binary data buffer. Usually (noOfBits+7)/8. * @param noOfBits * The number of bits of data in encoded into `cs' */ void b2a_l(const unsigned char* cs, int len, const size_t noOfBits); /** * Holds the pointer to decoded binary data */ unsigned char *binaryResult; /** * Length of decoding result */ int resultLength; /** * The string containing the base32 encoded data. */ string encoded; unsigned char smallBuffer[128]; }; /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpCWrapper.h0000644000175000017500000013563611570305710020463 0ustar dyfetdyfet/* This file defines the GNU ZRTP C-to-C++ wrapper. Copyright (C) 2010 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 . */ #ifndef ZRTPCWRAPPER_H #define ZRTPCWRAPPER_H /** * * @file ZrtpCWrapper.h * @brief The GNU ZRTP C-to-C++ wrapper. * * To avoid any include of C++ header files some structure, defines, and * enumerations are repeated in this file. Refer to the inline comments if * you modify the file. * * @ingroup GNU_ZRTP * @{ * * @see ZRtp */ #include /** * Defines to specify the role a ZRTP peer has. * * According to the ZRTP specification the role determines which keys to * use to encrypt or decrypt SRTP data. * *
    *
  • The Initiator encrypts SRTP data using the keyInitiator and the * saltInitiator data, the Responder uses these data to decrypt. *
  • *
  • The Responder encrypts SRTP data using the keyResponder and the * saltResponder data, the Initiator uses these data to decrypt. *
  • *
*/ /* * Keep the following defines in sync with Role enumeration in ZrtpCallback.h */ #define Responder 1 /*!< This client is in ZRTP Responder mode */ #define Initiator 2 /*!< This client is in ZRTP Initiator mode */ #define CRC_SIZE 4 /*!< Size of CRC code of a ZRTP packet */ #define ZRTP_MAGIC 0x5a525450 /*!< The magic code that identifies a ZRTP packet */ #define MAX_ZRTP_SIZE 3072 /*!< The biggest ZRTP packet ever possible */ /* * IMPORTANT: keep the following enums in synch with ZrtpCodes. We copy them here * to avoid any C++ header includes and defines. The protocol states are located * ZrtpStateClass.h . */ /** * This enum defines the information message severity. * * The ZRTP implementation issues information messages to inform the user * about ongoing processing, unusual behavior, or alerts in case of severe * problems. Each main severity code a number of sub-codes exist that * specify the exact nature of the problem. * * An application gets message severity codes and the associated sub-codes * via the ZrtpUserCallback#showMessage method. * * The severity levels and their meaning are: * *
*
Info
keeps the user informed about ongoing processing and * security setup. The enumeration InfoCodes defines the subcodes. *
*
Warning
is an information about some security issues, e.g. if * an AES 256 encryption is request but only DH 3072 as public key scheme * is supported. ZRTP will establish a secure session (SRTP). The * enumeration WarningCodes defines the sub-codes. *
*
Severe
is used if an error occured during ZRTP protocol usage. * In case of Severe ZRTP will not establish a secure session. * The enumeration SevereCodes defines the sub-codes. *
*
Zrtp
shows a ZRTP security problem. Refer to the enumeration * ZrtpErrorCodes for sub-codes. GNU ZRTP of course will not * establish a secure session. *
*
* */ enum zrtp_MessageSeverity { zrtp_Info = 1, /*!< Just an info message */ zrtp_Warning, /*!< A Warning message - security can be established */ zrtp_Severe, /*!< Severe error, security will not be established */ zrtp_ZrtpError /*!< ZRTP error, security will not be established */ }; /** * Sub-codes for Info */ enum zrtp_InfoCodes { zrtp_InfoHelloReceived = 1, /*!< Hello received, preparing a Commit */ zrtp_InfoCommitDHGenerated, /*!< Commit: Generated a public DH key */ zrtp_InfoRespCommitReceived, /*!< Responder: Commit received, preparing DHPart1 */ zrtp_InfoDH1DHGenerated, /*!< DH1Part: Generated a public DH key */ zrtp_InfoInitDH1Received, /*!< Initiator: DHPart1 received, preparing DHPart2 */ zrtp_InfoRespDH2Received, /*!< Responder: DHPart2 received, preparing Confirm1 */ zrtp_InfoInitConf1Received, /*!< Initiator: Confirm1 received, preparing Confirm2 */ zrtp_InfoRespConf2Received, /*!< Responder: Confirm2 received, preparing Conf2Ack */ zrtp_InfoRSMatchFound, /*!< At least one retained secrets matches - security OK */ zrtp_InfoSecureStateOn, /*!< Entered secure state */ zrtp_InfoSecureStateOff /*!< No more security for this session */ }; /** * Sub-codes for Warning */ enum zrtp_WarningCodes { zrtp_WarningDHAESmismatch = 1, /*!< Commit contains an AES256 cipher but does not offer a Diffie-Helman 4096 */ zrtp_WarningGoClearReceived, /*!< Received a GoClear message */ zrtp_WarningDHShort, /*!< Hello offers an AES256 cipher but does not offer a Diffie-Helman 4096 */ zrtp_WarningNoRSMatch, /*!< No retained shared secrets available - must verify SAS */ zrtp_WarningCRCmismatch, /*!< Internal ZRTP packet checksum mismatch - packet dropped */ zrtp_WarningSRTPauthError, /*!< Dropping packet because SRTP authentication failed! */ zrtp_WarningSRTPreplayError, /*!< Dropping packet because SRTP replay check failed! */ zrtp_WarningNoExpectedRSMatch /*!< Valid retained shared secrets availabe but no matches found - must verify SAS */ }; /** * Sub-codes for Severe */ enum zrtp_SevereCodes { zrtp_SevereHelloHMACFailed = 1, /*!< Hash HMAC check of Hello failed! */ zrtp_SevereCommitHMACFailed, /*!< Hash HMAC check of Commit failed! */ zrtp_SevereDH1HMACFailed, /*!< Hash HMAC check of DHPart1 failed! */ zrtp_SevereDH2HMACFailed, /*!< Hash HMAC check of DHPart2 failed! */ zrtp_SevereCannotSend, /*!< Cannot send data - connection or peer down? */ zrtp_SevereProtocolError, /*!< Internal protocol error occured! */ zrtp_SevereNoTimer, /*!< Cannot start a timer - internal resources exhausted? */ zrtp_SevereTooMuchRetries /*!< Too much retries during ZRTP negotiation - connection or peer down? */ }; /** * Error codes according to the ZRTP specification chapter 6.9 * * GNU ZRTP uses these error codes in two ways: to fill the appropriate * field ing the ZRTP Error packet and as sub-code in * ZrtpUserCallback#showMessage(). GNU ZRTP uses thes error codes also * to report received Error packts, in this case the sub-codes are their * negative values. * * The enumeration member comments are copied from the ZRTP specification. */ enum zrtp_ZrtpErrorCodes { zrtp_MalformedPacket = 0x10, /*!< Malformed packet (CRC OK, but wrong structure) */ zrtp_CriticalSWError = 0x20, /*!< Critical software error */ zrtp_UnsuppZRTPVersion = 0x30, /*!< Unsupported ZRTP version */ zrtp_HelloCompMismatch = 0x40, /*!< Hello components mismatch */ zrtp_UnsuppHashType = 0x51, /*!< Hash type not supported */ zrtp_UnsuppCiphertype = 0x52, /*!< Cipher type not supported */ zrtp_UnsuppPKExchange = 0x53, /*!< Public key exchange not supported */ zrtp_UnsuppSRTPAuthTag = 0x54, /*!< SRTP auth. tag not supported */ zrtp_UnsuppSASScheme = 0x55, /*!< SAS scheme not supported */ zrtp_NoSharedSecret = 0x56, /*!< No shared secret available, DH mode required */ zrtp_DHErrorWrongPV = 0x61, /*!< DH Error: bad pvi or pvr ( == 1, 0, or p-1) */ zrtp_DHErrorWrongHVI = 0x62, /*!< DH Error: hvi != hashed data */ zrtp_SASuntrustedMiTM = 0x63, /*!< Received relayed SAS from untrusted MiTM */ zrtp_ConfirmHMACWrong = 0x70, /*!< Auth. Error: Bad Confirm pkt HMAC */ zrtp_NonceReused = 0x80, /*!< Nonce reuse */ zrtp_EqualZIDHello = 0x90, /*!< Equal ZIDs in Hello */ zrtp_GoCleatNotAllowed = 0x100, /*!< GoClear packet received, but not allowed */ zrtp_IgnorePacket = 0x7fffffff /*!< Internal state, not reported */ }; /* The ZRTP protocol states */ enum zrtpStates { Initial, /*!< Initial state after starting the state engine */ Detect, /*!< State sending Hello, try to detect answer message */ AckDetected, /*!< HelloAck received */ AckSent, /*!< HelloAck sent after Hello received */ WaitCommit, /*!< Wait for a Commit message */ CommitSent, /*!< Commit message sent */ WaitDHPart2, /*!< Wait for a DHPart2 message */ WaitConfirm1, /*!< Wait for a Confirm1 message */ WaitConfirm2, /*!< Wait for a confirm2 message */ WaitConfAck, /*!< Wait for Conf2Ack */ WaitClearAck, /*!< Wait for clearAck - not used */ SecureState, /*!< This is the secure state - SRTP active */ WaitErrorAck, /*!< Wait for ErrorAck message */ numberOfStates /*!< Gives total number of protocol states */ }; /*! The algorihms that we support in SRTP and that ZRTP can negotiate. */ typedef enum { zrtp_Aes = 1, /*!< Use AES as symmetrical cipher algorithm */ zrtp_TwoFish, /*!< Use TwoFish as symmetrical cipher algorithm */ zrtp_Sha1, /*!< Use Sha1 as authentication algorithm */ zrtp_Skein /*!< Use Skein as authentication algorithm */ } zrtp_SrtpAlgorithms; /** * This structure contains pointers to the SRTP secrets and the role info. * * About the role and what the meaning of the role is refer to the * of the enum Role. The pointers to the secrets are valid as long as * the ZRtp object is active. To use these data after the ZRtp object's * lifetime you may copy the data into a save place. */ typedef struct c_srtpSecrets { zrtp_SrtpAlgorithms symEncAlgorithm;/*!< symmetrical cipher algorithm */ const uint8_t* keyInitiator; /*!< Initiator's key */ int32_t initKeyLen; /*!< Initiator's key length */ const uint8_t* saltInitiator; /*!< Initiator's salt */ int32_t initSaltLen; /*!< Initiator's salt length */ const uint8_t* keyResponder; /*!< Responder's key */ int32_t respKeyLen; /*!< Responder's key length */ const uint8_t* saltResponder; /*!< Responder's salt */ int32_t respSaltLen; /*!< Responder's salt length */ zrtp_SrtpAlgorithms authAlgorithm; /*!< SRTP authentication algorithm */ int32_t srtpAuthTagLen; /*!< SRTP authentication length */ char* sas; /*!< The SAS string */ int32_t role; /*!< ZRTP role of this client */ } C_SrtpSecret_t; /* * Keep the following defines in sync with enum EnableSecurity in ZrtpCallback.h */ #define ForReceiver 1 /*!< Enable security for SRTP receiver */ #define ForSender 2 /*!< Enable security for SRTP sender */ #ifdef __cplusplus extern "C" { #endif typedef struct ZRtp ZRtp; typedef struct ZrtpCallbackWrapper ZrtpCallbackWrapper; typedef struct ZrtpConfigure ZrtpConfigure; typedef struct zrtpContext { ZRtp* zrtpEngine; /*!< Holds the real ZRTP engine */ ZrtpCallbackWrapper* zrtpCallback; /*!< Help class Callback wrapper */ ZrtpConfigure* configure; /*!< Optional configuration data */ void* userData; /*!< User data, set by application */ } ZrtpContext; /** * This structure defines the callback functions required by GNU ZRTP. * * The RTP stack specific part must implement the callback methods. * The generic part of GNU ZRTP uses these mehtods * to communicate with the specific part, for example to send data * via the RTP/SRTP stack, to set timers and cancel timer and so on. * * The generiy part of GNU ZRTP needs only a few callback methods to * be implemented by the specific part. * * @author Werner Dittmann */ /** * The following methods define the GNU ZRTP callback interface. * For detailed documentation refer to file ZrtpCallback.h, each C * method has "zrtp_" prepended to the C++ name. * * @see ZrtpCallback */ typedef struct zrtp_Callbacks { /** * Send a ZRTP packet via RTP. * * ZRTP calls this method to send a ZRTP packet via the RTP session. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param data * Points to ZRTP packet to send. * @param length * The length in bytes of the data * @return * zero if sending failed, one if packet was send */ int32_t (*zrtp_sendDataZRTP) (ZrtpContext* ctx, const uint8_t* data, int32_t length ) ; /** * Activate timer. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param time * The time in ms for the timer * @return * zero if activation failed, one if timer was activated */ int32_t (*zrtp_activateTimer) (ZrtpContext* ctx, int32_t time ) ; /** * Cancel the active timer. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @return * zero if cancel action failed, one if timer was canceled */ int32_t (*zrtp_cancelTimer)(ZrtpContext* ctx) ; /** * Send information messages to the hosting environment. * * The ZRTP implementation uses this method to send information * messages to the host. Along with the message ZRTP provides a * severity indicator that defines: Info, Warning, Error, * Alert. Refer to the MessageSeverity enum above. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param severity * This defines the message's severity * @param subCode * The subcode identifying the reason. * @see ZrtpCodes#MessageSeverity */ void (*zrtp_sendInfo) (ZrtpContext* ctx, int32_t severity, int32_t subCode ) ; /** * SRTP crypto data ready for the sender or receiver. * * The ZRTP implementation calls this method right after all SRTP * secrets are computed and ready to be used. The parameter points * to a structure that contains pointers to the SRTP secrets and a * enum Role. The called method (the implementation * of this abstract method) must either copy the pointers to the SRTP * data or the SRTP data itself to a save place. The SrtpSecret_t * structure is destroyed after the callback method returns to the * ZRTP implementation. * * The SRTP data themselfs are ontained in the ZRtp object and are * valid as long as the ZRtp object is active. TheZRtp's * destructor clears the secrets. Thus the called method needs to * save the pointers only, ZRtp takes care of the data. * * The implementing class may enable SRTP processing in this * method or delay it to srtpSecertsOn(). * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param secrets A pointer to a SrtpSecret_t structure that * contains all necessary data. * * @param part for which part (Sender or Receiver) this data is * valid. * * @return Returns false if something went wrong during * initialization of SRTP context, for example memory shortage. */ int32_t (*zrtp_srtpSecretsReady) (ZrtpContext* ctx, C_SrtpSecret_t* secrets, int32_t part ) ; /** * Switch off the security for the defined part. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param part Defines for which part (sender or receiver) to * switch on security */ void (*zrtp_srtpSecretsOff) (ZrtpContext* ctx, int32_t part ) ; /** * Switch on the security. * * ZRTP calls this method after it has computed the SAS and check * if it is verified or not. In addition ZRTP provides information * about the cipher algorithm and key length for the SRTP session. * * This method must enable SRTP processing if it was not enabled * during sertSecretsReady(). * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param c The name of the used cipher algorithm and mode, or * NULL * * @param s The SAS string * * @param verified if verified is true then SAS was * verified by both parties during a previous call. */ void (*zrtp_rtpSecretsOn) (ZrtpContext* ctx, char* c, char* s, int32_t verified ) ; /** * This method handles GoClear requests. * * According to the ZRTP specification the user must be informed about * a GoClear request because the ZRTP implementation switches off security * if it could authenticate the GoClear packet. * * Note: GoClear is not yet implemented in GNU ZRTP. * * @param ctx * Pointer to the opaque ZrtpContext structure. */ void (*zrtp_handleGoClear)(ZrtpContext* ctx) ; /** * Handle ZRTP negotiation failed. * * ZRTP calls this method in case ZRTP negotiation failed. The * parameters show the severity as well as the reason. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param severity * This defines the message's severity * @param subCode * The subcode identifying the reason. * @see ZrtpCodes#MessageSeverity */ void (*zrtp_zrtpNegotiationFailed) (ZrtpContext* ctx, int32_t severity, int32_t subCode ) ; /** * ZRTP calls this method if the other side does not support ZRTP. * * @param ctx * Pointer to the opaque ZrtpContext structure. * If the other side does not answer the ZRTP Hello packets then * ZRTP calls this method, * */ void (*zrtp_zrtpNotSuppOther)(ZrtpContext* ctx) ; /** * Enter synchronization mutex. * * GNU ZRTP requires one mutes to synchronize its * processing. Because mutex implementations depend on the * underlying infrastructure, for example operating system or * thread implementation, GNU ZRTP delegates mutex handling to the * spcific part of its implementation. * * @param ctx * Pointer to the opaque ZrtpContext structure. */ void (*zrtp_synchEnter)(ZrtpContext* ctx) ; /** * Leave synchronization mutex. * * @param ctx * Pointer to the opaque ZrtpContext structure. */ void (*zrtp_synchLeave)(ZrtpContext* ctx) ; /** * Inform about a PBX enrollment request. * * Please refer to chapter 8.3 ff to get more details about PBX * enrollment and SAS relay. * * Note: PBX enrollement is not yet fully supported by GNU * ZRTP. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param info Give some information to the user about the PBX * requesting an enrollment. */ void (*zrtp_zrtpAskEnrollment) (ZrtpContext* ctx, char* info ) ; /** * Inform about PBX enrollment result. * * Informs the use about the acceptance or denial of an PBX enrollment * request * * Note: PBX enrollement is not yet fully supported by GNU * ZRTP. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param info Give some information to the user about the result * of an enrollment. */ void (*zrtp_zrtpInformEnrollment) (ZrtpContext* ctx, char* info ) ; /** * Request a SAS signature. * * After ZRTP was able to compute the Short Authentication String * (SAS) it calls this method. The client may now use an * approriate method to sign the SAS. The client may use * ZrtpQueue#setSignatureData() to store the signature data an * enable signature transmission to the other peer. Refer to * chapter 8.2 of ZRTP specification. * * Note: SAS signing is not yet fully supported by GNU * ZRTP. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param sas * The SAS string to sign. * */ void (*zrtp_signSAS)(ZrtpContext* ctx, char* sas) ; /** * ZRTPQueue calls this method to request a SAS signature check. * * After ZRTP received a SAS signature in one of the Confirm packets it * call this method. The client may use getSignatureLength() * and getSignatureData()of ZrtpQueue to get the signature * data and perform the signature check. Refer to chapter 8.2 of ZRTP * specification. * * If the signature check fails the client may return false to ZRTP. In * this case ZRTP signals an error to the other peer and terminates * the ZRTP handshake. * * Note: SAS signing is not yet fully supported by GNU * ZRTP. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param sas * The SAS string that was signed by the other peer. * @return * true if the signature was ok, false otherwise. * */ int32_t (*zrtp_checkSASSignature) (ZrtpContext* ctx, char* sas ) ; } zrtp_Callbacks; /** * Create the GNU ZRTP C wrapper. * * This wrapper implements the C interface to the C++ based GNU ZRTP. * @returns * Pointer to the ZrtpContext */ ZrtpContext* zrtp_CreateWrapper(); /** * Initialize the ZRTP protocol engine. * * This method initialized the GNU ZRTP protocol engine. An application * call this method to actually create the ZRTP protocol engine and * initialize its configuration data. This method does not start the * protocol engine. * * If an application requires a specific algorithm configuration then it * must set the algorithm configuration data before it initializes the * ZRTP protocol engine. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param cb * The callback structure that holds the addresses of the callback * methods. * @param id * A C string that holds the ZRTP client id, only the first 16 chars * are used. * @param zidFilename * The name of the ZID file. This file holds some parameters and * other data like additional shared secrets. * @param userData * A pointer to user data. The wrapper just stores this pointer in * the ZrtpContext and the application may use it for its purposes. * @returns * Pointer to the ZrtpContext * * @see zrtp_InitializeConfig */ void zrtp_initializeZrtpEngine(ZrtpContext* zrtpContext, zrtp_Callbacks *cb, char* id, const char* zidFilename, void* userData); /** * Destroy the ZRTP wrapper and its underlying objects. */ void zrtp_DestroyWrapper (ZrtpContext* zrtpContext); /** * Computes the ZRTP checksum over a received ZRTP packet buffer and * compares the result with received checksum. * * @param buffer * Pointer to ZRTP packet buffer * @param length * Length of the packet buffer excluding received CRC data * @param crc * The received CRC data. * @returns * True if CRC matches, false otherwise. */ int32_t zrtp_CheckCksum(uint8_t* buffer, uint16_t length, uint32_t crc); /** * Computes the ZRTP checksum over a newly created ZRTP packet buffer. * * @param buffer * Pointer to the created ZRTP packet buffer * @param length * Length of the packet buffer * @returns * The computed CRC. */ uint32_t zrtp_GenerateCksum(uint8_t* buffer, uint16_t length); /** * Prepares the ZRTP checksum for appending to ZRTP packet. * @param crc * The computed CRC data. * @returns * Prepared CRC data in host order */ uint32_t zrtp_EndCksum(uint32_t crc); /** * Kick off the ZRTP protocol engine. * * This method calls the ZrtpStateClass#evInitial() state of the state * engine. After this call we are able to process ZRTP packets * from our peer and to process them. * * NOTE: application shall never call this method directly but use the * appropriate method provided by the RTP implementation. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. */ void zrtp_startZrtpEngine(ZrtpContext* zrtpContext); /** * Stop ZRTP security. * * NOTE: application shall never call this method directly but use the * appropriate method provided by the RTP implementation. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. */ void zrtp_stopZrtpEngine(ZrtpContext* zrtpContext); /** * Process RTP extension header. * * This method expects to get a pointer to the message part of * a ZRTP packet. * * NOTE: application shall never call this method directly. Only * the module that implements the RTP binding shall use this method * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param extHeader * A pointer to the first byte of the ZRTP message part. * @param peerSSRC * The peer's SSRC. * @return * Code indicating further packet handling, see description above. */ void zrtp_processZrtpMessage(ZrtpContext* zrtpContext, uint8_t *extHeader, uint32_t peerSSRC); /** * Process a timeout event. * * We got a timeout from the timeout provider. Forward it to the * protocol state engine. * * NOTE: application shall never call this method directly. Only * the module that implements the RTP binding shall use this method * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. */ void zrtp_processTimeout(ZrtpContext* zrtpContext); /* * Check for and handle GoClear ZRTP packet header. * * This method checks if this is a GoClear packet. If not, just return * false. Otherwise handle it according to the specification. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param extHeader * A pointer to the first byte of the extension header. Refer to * RFC3550. * @return * False if not a GoClear, true otherwise. * int32_t zrtp_handleGoClear(ZrtpContext* zrtpContext, uint8_t *extHeader); */ /** * Set the auxilliary secret. * * Use this method to set the auxilliary secret data. Refer to ZRTP * specification, chapter 4.3 ff * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param data * Points to the secret data. * @param length * Length of the auxilliary secrect in bytes */ void zrtp_setAuxSecret(ZrtpContext* zrtpContext, uint8_t* data, int32_t length); /** * Set the PBX secret. * * Use this method to set the PBX secret data. Refer to ZRTP * specification, chapter 4.3 ff and 7.3 * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param data * Points to the other PBX data. * @param length * The length in bytes of the data. */ void zrtp_setPbxSecret(ZrtpContext* zrtpContext, uint8_t* data, int32_t length); /** * Check current state of the ZRTP state engine * * NOTE: application usually don't call this method. Only * the module that implements the RTP binding shall use this method * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param state * The state to check. * @return * Returns true id ZRTP engine is in the given state, false otherwise. */ int32_t zrtp_inState(ZrtpContext* zrtpContext, int32_t state); /** * Set SAS as verified. * * Call this method if the user confirmed (verfied) the SAS. ZRTP * remembers this together with the retained secrets data. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. */ void zrtp_SASVerified(ZrtpContext* zrtpContext); /** * Reset the SAS verfied flag for the current active user's retained secrets. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. */ void zrtp_resetSASVerified(ZrtpContext* zrtpContext); /** * Get the ZRTP Hello Hash data. * * Use this method to get the ZRTP Hello Hash data. The method * returns the data as a string containing the ZRTP protocol version and * hex-digits. Refer to ZRTP specification, chapter 8. * * NOTE: An application may call this method if it needs this information. * Usually it is not necessary. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @return * a pointer to a C-string that contains the Hello hash value as * hex-digits. The hello hash is available immediately after * @c zrtp_CreateWrapper . * The caller must @c free() if it does not use the * hello hash C-string anymore. */ char* zrtp_getHelloHash(ZrtpContext* zrtpContext); /** * Get Multi-stream parameters. * * Use this method to get the Multi-stream parameters that were computed * during the ZRTP handshake. An application may use these parameters to * enable multi-stream processing for an associated SRTP session. * * The application must not modify the contents of returned char array, it * is opaque data. The application may hand over this string to a new ZRTP * instance to enable multi-stream processing for this new session. * * Refer to chapter 4.4.2 in the ZRTP specification for further details * and restriction how and when to use multi-stream mode. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param length * Pointer to an integer that receives the length of the char array * @return * a char array that contains the multi-stream parameters. * If ZRTP was not started or ZRTP is not yet in secure state the method * returns NULL and a length of 0. */ char* zrtp_getMultiStrParams(ZrtpContext* zrtpContext, int32_t *length); /** * Set Multi-stream parameters. * * Use this method to set the parameters required to enable Multi-stream * processing of ZRTP. The multi-stream parameters must be set before the * application starts the ZRTP protocol engine. * * Refer to chapter 4.4.2 in the ZRTP specification for further details * of multi-stream mode. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param length * The integer that contains the length of the char array * @param parameters * A char array that contains the multi-stream parameters that this * new ZRTP instanace shall use. See also * getMultiStrParams() */ void zrtp_setMultiStrParams(ZrtpContext* zrtpContext, char* parameters, int32_t length); /** * Check if this ZRTP session is a Multi-stream session. * * Use this method to check if this ZRTP instance uses multi-stream. * Refer to chapters 4.2 and 4.4.2 in the ZRTP. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @return * True if multi-stream is used, false otherwise. */ int32_t zrtp_isMultiStream(ZrtpContext* zrtpContext); /** * Check if the other ZRTP client supports Multi-stream. * * Use this method to check if the other ZRTP client supports * Multi-stream mode. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @return * True if multi-stream is available, false otherwise. */ int32_t zrtp_isMultiStreamAvailable(ZrtpContext* zrtpContext); /** * Accept a PBX enrollment request. * * If a PBX service asks to enroll the PBX trusted MitM key and the user * accepts this request, for example by pressing an OK button, the client * application shall call this method and set the parameter * accepted to true. If the user does not accept the request * set the parameter to false. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param accepted * True if the enrollment request is accepted, false otherwise. */ void zrtp_acceptEnrollment(ZrtpContext* zrtpContext, int32_t accepted); /** * Enable PBX enrollment * * The application calls this method to allow or disallow PBX enrollment. * If the applications allows PBX enrollment then the ZRTP implementation * honors the PBX enrollment flag in Confirm packets. Refer to chapter 7.3 * for further details of PBX enrollment. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param yesNo * If set to true then ZRTP honors the PBX enrollment flag in Commit * packets and calls the appropriate user callback methods. If * the parameter is set to false ZRTP ignores the PBX enrollment flags. */ void zrtp_setPBXEnrollment(ZrtpContext* zrtpContext, int32_t yesNo); /** * Set signature data * * This functions stores signature data and transmitts it during ZRTP * processing to the other party as part of the Confirm packets. Refer to * chapters 5.7 and 7.2. * * The signature data must be set before ZRTP the application calls * start(). * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param data * The signature data including the signature type block. The method * copies this data into the Confirm packet at signature type block. * @param length * The length of the signature data in bytes. This length must be * multiple of 4. * @return * True if the method stored the data, false otherwise. */ int32_t zrtp_setSignatureData(ZrtpContext* zrtpContext, uint8_t* data, int32_t length); /** * Get signature data * * This functions returns signature data that was receivied during ZRTP * processing. Refer to chapters 5.7 and 7.2. * * The signature data can be retrieved after ZRTP enters secure state. * start(). * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param data * Pointer to a data buffer. This buffer must be large enough to * hold the signature data. Refer to getSignatureLength() * to get the length of the received signature data. * @return * Number of bytes copied into the data buffer */ int32_t zrtp_getSignatureData(ZrtpContext* zrtpContext, uint8_t* data); /** * Get length of signature data * * This functions returns the length of signature data that was receivied * during ZRTP processing. Refer to chapters 5.7 and 7.2. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @return * Length in bytes of the received signature data. The method returns * zero if no signature data avilable. */ int32_t zrtp_getSignatureLength(ZrtpContext* zrtpContext); /** * Emulate a Conf2Ack packet. * * This method emulates a Conf2Ack packet. According to ZRTP specification * the first valid SRTP packet that the Initiator receives must switch * on secure mode. Refer to chapter 4 in the specificaton * * NOTE: application shall never call this method directly. Only * the module that implements the RTP binding shall use this method * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. */ void zrtp_conf2AckSecure(ZrtpContext* zrtpContext); /** * Get other party's ZID (ZRTP Identifier) data * * This functions returns the other party's ZID that was receivied * during ZRTP processing. * * The ZID data can be retrieved after ZRTP receive the first Hello * packet from the other party. The application may call this method * for example during SAS processing in showSAS(...) user callback * method. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param data * Pointer to a data buffer. This buffer must have a size of * at least 12 bytes (96 bit) (ZRTP Identifier, see chap. 4.9) * @return * Number of bytes copied into the data buffer - must be equivalent * to 12 bytes. */ int32_t zrtp_getZid(ZrtpContext* zrtpContext, uint8_t* data); /** * This enumerations list all configurable algorithm types. */ /* Keep in synch with enumeration in ZrtpConfigure.h */ typedef enum zrtp_AlgoTypes { zrtp_HashAlgorithm = 1, zrtp_CipherAlgorithm, zrtp_PubKeyAlgorithm, zrtp_SasType, zrtp_AuthLength } Zrtp_AlgoTypes; /** * Initialize the GNU ZRTP Configure data. * * Initializing and setting a ZRTP configuration is optional. GNU ZRTP * uses a sensible default if an application does not define its own * ZRTP configuration. * * If an application initialize th configure data it must set the * configuration data. * * The ZRTP specification, chapters 5.1.2 through 5.1.6 defines the * algorithm names and their meaning. * * The current ZRTP implementation implements all mandatory algorithms * plus a set of the optional algorithms. An application shall use * @c zrtp_getAlgorithmNames to get the names of the available algorithms. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @returns * Pointer to the ZrtpConfCtx * * @see zrtp_getAlgorithmNames */ int32_t zrtp_InitializeConfig (ZrtpContext* zrtpContext); /** * Get names of all available algorithmes of a given algorithm type. * * The algorithm names are as specified in the ZRTP specification, chapters * 5.1.2 through 5.1.6 . * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param type * The algorithm type. * @returns * A NULL terminated array of character pointers. */ char** zrtp_getAlgorithmNames(ZrtpContext* zrtpContext, Zrtp_AlgoTypes type); /** * Free storage used to store the algorithm names. * * If an application does not longer require the algoritm names it should * free the space. * * @param names * The NULL terminated array of character pointers. */ void zrtp_freeAlgorithmNames(char** names); /** * Convenience function that sets a pre-defined standard configuration. * * The standard configuration consists of the following algorithms: *
    *
  • Hash: SHA256
  • *
  • Symmetric Cipher: AES 128, AES 256
  • *
  • Public Key Algorithm: DH2048, DH3027, MultiStream
  • *
  • SAS type: libase 32
  • *
  • SRTP Authentication lengths: 32, 80
  • *
* * @param zrtpContext * Pointer to the opaque ZrtpContext structure. */ void zrtp_setStandardConfig(ZrtpContext* zrtpContext); /** * Convenience function that sets the mandatory algorithms only. * * Mandatory algorithms are: *
    *
  • Hash: SHA256
  • *
  • Symmetric Cipher: AES 128
  • *
  • Public Key Algorithm: DH3027, MultiStream
  • *
  • SAS type: libase 32
  • *
  • SRTP Authentication lengths: 32, 80
  • *
* * @param zrtpContext * Pointer to the opaque ZrtpContext structure. */ void zrtp_setMandatoryOnly(ZrtpContext* zrtpContext); /** * Clear all configuration data. * * The functions clears all configuration data. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. */ void zrtp_confClear(ZrtpContext* zrtpContext); /** * Add an algorithm to configuration data. * * Adds the specified algorithm to the configuration data. * If no free configuration data slot is available the * function does not add the algorithm and returns -1. The * methods appends the algorithm to the existing algorithms. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param algoType * Specifies which algorithm type to select * @param algo * The name of the algorithm to add. * @return * Number of free configuration data slots or -1 on error */ int32_t zrtp_addAlgo(ZrtpContext* zrtpContext, Zrtp_AlgoTypes algoType, const char* algo); /** * Add an algorithm to configuration data at given index * * Adds the specified algorithm to the configuration data vector * at a given index. If the index is larger than the actual size * of the configuration vector the method just appends the algorithm. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param algoType * Specifies which algorithm type to select * @param algo * The name of the algorithm to add. * @param index * The index where to add the algorihm * @return * Number of free configuration data slots or -1 on error */ int32_t zrtp_addAlgoAt(ZrtpContext* zrtpContext, Zrtp_AlgoTypes algoType, const char* algo, int32_t index); /** * Remove a algorithm from configuration data. * * Removes the specified algorithm from configuration data. If * the algorithm was not configured previously the function does * not modify the configuration data and returns the number of * free configuration data slots. * * If an application removes all algorithms then ZRTP does not * include any algorithm into the hello message and falls back * to a predefined mandatory algorithm. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param algoType * Specifies which algorithm type to select * @param algo * The name of the algorithm to remove. * @return * Number of free configuration slots. */ int32_t zrtp_removeAlgo(ZrtpContext* zrtpContext, Zrtp_AlgoTypes algoType, const char* algo); /** * Returns the number of configured algorithms. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param algoType * Specifies which algorithm type to select * @return * The number of configured algorithms (used configuration * data slots) */ int32_t zrtp_getNumConfiguredAlgos(ZrtpContext* zrtpContext, Zrtp_AlgoTypes algoType); /** * Returns the identifier of the algorithm at index. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param algoType * Specifies which algorithm type to select * @param index * The index in the list of the algorihm type * @return * A pointer to the algorithm name. If the index * does not point to a configured slot then the function * returns NULL. * */ const char* zrtp_getAlgoAt(ZrtpContext* zrtpContext, Zrtp_AlgoTypes algoType, int32_t index); /** * Checks if the configuration data of the algorihm type already contains * a specific algorithms. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param algoType * Specifies which algorithm type to select * @param algo * The name of the algorithm to check * @return * True if the algorithm was found, false otherwise. * */ int32_t zrtp_containsAlgo(ZrtpContext* zrtpContext, Zrtp_AlgoTypes algoType, const char* algo); /** * Enables or disables trusted MitM processing. * * For further details of trusted MitM processing refer to ZRTP * specification, chapter 7.3 * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param yesNo * If set to true then trusted MitM processing is enabled. */ void zrtp_setTrustedMitM(ZrtpContext* zrtpContext, int32_t yesNo); /** * Check status of trusted MitM processing. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @return * Returns true if trusted MitM processing is enabled. */ int32_t zrtp_isTrustedMitM(ZrtpContext* zrtpContext); /** * Enables or disables SAS signature processing. * * For further details of trusted MitM processing refer to ZRTP * specification, chapter 7.2 * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @param yesNo * If true then certificate processing is enabled. */ void zrtp_setSasSignature(ZrtpContext* zrtpContext, int32_t yesNo); /** * Check status of SAS signature processing. * * @param zrtpContext * Pointer to the opaque ZrtpContext structure. * @return * Returns true if certificate processing is enabled. */ int32_t zrtp_isSasSignature(ZrtpContext* zrtpContext); #ifdef __cplusplus } #endif /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/ZIDFile.h0000644000175000017500000001011311570305710017264 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 . */ #include #include #ifndef _ZIDFILE_H_ #define _ZIDFILE_H_ /** * @file ZIDFile.h * @brief ZID file management * * A ZID file stores (caches) some data that helps ZRTP to achives its * key continuity feature. See @c ZIDRecord for further info which data * the ZID file contains. * * @ingroup GNU_ZRTP * @{ */ /** * This class implements a ZID (ZRTP Identifiers) file. * * The ZID file holds information about peers. * * @author: Werner Dittmann */ class __EXPORT ZIDFile { private: FILE* zidFile; unsigned char associatedZid[IDENTIFIER_LEN]; /** * The private ZID file constructor. * */ ZIDFile(): zidFile(NULL) {}; ~ZIDFile(); void createZIDFile(char* name); void checkDoMigration(char* name); public: /** * Get the an instance of ZIDFile. * * This method just creates an instance an store a pointer to it * in a static variable. The ZIDFile is a singleton, thus only * one ZID file can be open at one time. * * @return * A pointer to the global ZIDFile singleton instance. */ static ZIDFile* getInstance(); /** * Open the named ZID file and return a ZID file class. * * This static function either opens an existing ZID file or * creates a new ZID file with the given name. The ZIDFile is a * singleton, thus only one ZID file can be open at one * time. * * To open another ZID file you must close the active ZID file * first. * * @param name * The name of the ZID file to open or create * @return * 1 if file could be opened/created, 0 if the ZID instance * already has an open file, -1 if open/creation of file failed. */ int open(char *name); /** * Check if ZIDFile has an active (open) file. * * @return * True if ZIDFile has an active file, false otherwise */ bool isOpen() { return (zidFile != NULL); }; /** * Close the ZID file. * Closes the ZID file, and prepares to open a new ZID file. */ void close(); /** * Get a ZID record from the active ZID file. * * The method get the identifier data from the ZID record parameter, * locates the record in the ZID file and fills in the RS1, RS2, and * other data. * * If no matching record exists in the ZID file the method creates * it and fills it with default values. * * @param zidRecord * The ZID record that contains the identifier data. The method * fills in data . * @return * Currently always 1 to indicate sucess */ unsigned int getRecord(ZIDRecord* zidRecord); /** * Save a ZID record into the active ZID file. * * This method saves the content of a ZID record into the ZID file. Before * you can save the ZID record you must have performed a getRecord() * first. * * @param zidRecord * The ZID record to save. * @return * 1 on success */ unsigned int saveRecord(ZIDRecord *zidRecord); /** * Get the ZID associated with this ZID file. * * @return * Pointer to the ZID */ const unsigned char* getZid() { return associatedZid; }; }; /** * @} */ #endif /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketConfirm.h0000644000175000017500000000743111570305710021454 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 . */ #ifndef _ZRTPPACKETCONFIRM_H_ #define _ZRTPPACKETCONFIRM_H_ /** * @file ZrtpPacketConfirm.h * @brief The ZRTP Confirm message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the Confirm packet. * * The ZRTP message Confirm. The implementation sends this * to confirm the switch to SRTP (encrypted) mode. The contents of * the Confirm message are encrypted, thus the implementation * can check if the secret keys work. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketConfirm : public ZrtpPacketBase { private: Confirm_t* confirmHeader; ///< Point to the Confirm message part public: /// Creates a Confirm packet with default data ZrtpPacketConfirm(); /// Creates a Confirm packet with default data and a given signature length ZrtpPacketConfirm(uint32_t sl); /// Creates a Confirm packet from received data ZrtpPacketConfirm(uint8_t* d); /// Normal destructor virtual ~ZrtpPacketConfirm(); /// Check is SAS verify flag is set const bool isSASFlag() { return confirmHeader->flags & 0x4; } /// Get pointer to filler bytes (contains one bit of signature length) const uint8_t* getFiller() { return confirmHeader->filler; } /// Get pointer to IV data, fixed byte array const uint8_t* getIv() { return confirmHeader->iv; } /// Get pointer to MAC data, fixed byte array const uint8_t* getHmac() { return confirmHeader->hmac; } /// Get Expiration time data const uint32_t getExpTime() { return ntohl(confirmHeader->expTime); } /// Get pointer to initial hash chain (H0) data, fixed byte array uint8_t* getHashH0() { return confirmHeader->hashH0; } /// get the signature length in words uint32_t getSignatureLength(); /// set SAS verified flag void setSASFlag() { confirmHeader->flags |= 0x4; } /// Set MAC data, fixed length byte array void setHmac(uint8_t* text) { memcpy(confirmHeader->hmac, text, sizeof(confirmHeader->hmac)); } /// Set IV data, fixed length byte array void setIv(uint8_t* text) { memcpy(confirmHeader->iv, text, sizeof(confirmHeader->iv)); } /// Set expiration time data void setExpTime(uint32_t t) { confirmHeader->expTime = htonl(t); } /// Set initial hash chain (H0) data, fixed length byte array void setHashH0(uint8_t* t) { memcpy(confirmHeader->hashH0, t, sizeof(confirmHeader->hashH0)); } /// Set signature length in words void setSignatureLength(uint32_t sl); private: void initialize(); // Confirm packet is of variable length. It maximum size is 524 words: // - 11 words fixed size // - up to 513 words variable part, depending if signature is present and its length. // This leads to a maximum of 4*524=2096 bytes. uint8_t data[2100]; // large enough to hold a full blown Confirm packet }; /** * @} */ #endif // ZRTPPACKETCONFIRM libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketBase.h0000644000175000017500000000730111570305710020725 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 */ #ifndef _ZRTPPACKETBASE_H_ #define _ZRTPPACKETBASE_H_ /** * @file ZrtpPacketBase.h * @brief The ZRTP message header class * * This class defines the ZRTP message header and provides access and * check methods. * * @ingroup GNU_ZRTP * @{ */ #include #include #include #include #include #include #include #include #include // #define DEBUGOUT(deb) deb #define DEBUGOUT(deb) /* * This is the unique ZRTP ID in network order (PZ) */ const uint16_t zrtpId = 0x505a; /** * This is the base class for all ZRTP packets * * All other ZRTP packet classes inherit from this class. It does not have * an implementation of its own. * * The standard constructors of the subclasses usually initialize the @c allocate * field with their fixed data array which is large enough to hold all message * data. If an implementation needs to change this to use dynamic memory * allocation only that line in the subclasses must be changed and the destructors * should take care of memory management. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketBase { private: protected: void* allocated; ///< Pointer to ZRTP message data zrtpPacketHeader_t* zrtpHeader; ///< points to the fixed ZRTP header structure public: /** * Destructor is empty */ virtual ~ZrtpPacketBase() {}; /** * Get pointer to ZRTP header * * @return * Pointer to ZRTP header structure. */ const uint8_t* getHeaderBase() { return (const uint8_t*)zrtpHeader; }; /** * Check is this is a ZRTP message * * @return * @c true if check was ok */ bool isZrtpPacket() { return (ntohs(zrtpHeader->zrtpId) == zrtpId); }; /** * Get the length in words of the ZRTP message * * @return * The length in words */ uint16_t getLength() { return ntohs(zrtpHeader->length); }; /** * Return pointer to fixed length message type ASCII data * * @return * Pointer to ASCII character array */ uint8_t* getMessageType() { return zrtpHeader->messageType; }; /** * Set the lenght field in the ZRTP header * * @param len * The length of the ZRTP message in words, host order */ void setLength(uint16_t len) { zrtpHeader->length = htons(len); }; /** * Copy the message type ASCII data to ZRTP message type field * * @param msg * Pointer to message type ASCII character array */ void setMessageType(uint8_t *msg) { memcpy(zrtpHeader->messageType, msg, sizeof(zrtpHeader->messageType)); }; /** * Initializes the ZRTP Id field */ void setZrtpId() { zrtpHeader->zrtpId = htons(zrtpId); } }; /** * @} */ #endif // ZRTPPACKETBASE libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketClearAck.h0000644000175000017500000000272511570305710021525 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 . */ #ifndef _ZRTPPACKETCLEARACK_H_ #define _ZRTPPACKETCLEARACK_H_ /** * @file ZrtpPacketClearAck.h * @brief The ZRTP ClearAck message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the ClearAck packet - Currently not used * * The ZRTP simple message ClearAck. The implementation sends this * after switching to clear mode (non-SRTP mode). * * @author Werner Dittmann */ class __EXPORT ZrtpPacketClearAck : public ZrtpPacketBase { public: ZrtpPacketClearAck(); /// Creates a ClearAck packet with default data ZrtpPacketClearAck(uint8_t* data); /// Creates a ClearAck packet from received data virtual ~ZrtpPacketClearAck(); private: ClearAckPacket_t data; }; /** * @} */ #endif // ZRTPPACKETCLEARACK libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketPing.h0000644000175000017500000000325411570305710020753 0ustar dyfetdyfet/* Copyright (C) 2006-2009 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 . */ #ifndef _ZRTPPACKETPING_H_ #define _ZRTPPACKETPING_H_ /** * @file ZrtpPacketPing.h * @brief The ZRTP Ping message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the PingAck packet. * * The ZRTP simple message PingAck. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketPing : public ZrtpPacketBase { protected: Ping_t* pingHeader; ///< Point the the Ping message public: /// Creates a Ping message with default data ZrtpPacketPing(); /// Creates a Ping message from received data ZrtpPacketPing(uint8_t* data); virtual ~ZrtpPacketPing(); /// Set ZRTP protocol version field, fixed ASCII character array void setVersion(uint8_t *text) { memcpy(pingHeader->version, text,ZRTP_WORD_SIZE ); } /// Get the endpoit hash, fixed byte array uint8_t* getEpHash() { return pingHeader->epHash; } private: PingPacket_t data; }; /** * @} */ #endif // ZRTPPACKETCLEARACK libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketHello.h0000644000175000017500000001633011570305710021120 0ustar dyfetdyfet/* 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 . */ #ifndef _ZRTPPACKETHELLO_H_ #define _ZRTPPACKETHELLO_H_ /** * @file ZrtpPacketHello.h * @brief The ZRTP Hello message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the Hello packet. * * The ZRTP Hello message. The implementation sends this * to start the ZRTP negotiation sequence. The Hello message * offers crypto methods and parameters to the other party. The * other party selects methods and parameters it can support * and uses the Commit message to commit these. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketHello : public ZrtpPacketBase { protected: Hello_t* helloHeader; ///< Point to the Hello message part bool passive; ///< Set if the client shall be passive (not implemented) int32_t nHash, ///< number of hash algorithms offered nCipher, ///< number of cipher algorithms offered nPubkey, ///< number of key agreement algorithms offered nSas, ///< number of SAS algorithms offered nAuth; ///< number of SRTP authentication algorithms offered int32_t oHash, ///< offsets in bytes to hash algorithm names oCipher, ///< offsets in bytes to cipher algorithm names oPubkey, ///< offsets in bytes to key agreement algorithm names oSas, ///< offsets in bytes to SAS algorithm names oAuth, ///< offsets in bytes to SRTP authentication algorithm names oHmac; ///< offsets in bytes to MAC of Hello message public: /// Creates a Hello packet with default data ZrtpPacketHello(); /// Creates a Hello packet from received data ZrtpPacketHello(uint8_t *data); virtual ~ZrtpPacketHello(); /** * Set configure data and populate Hello message data. * * Fill in the offered Algorithm names and compute all offset to * names and MAC. An application must call this method on Hello message * objects created with the standard constructor (with default data) * before the application can use most of the getter and setter methods. * * @param config * Pointer to ZrtpConfigure data. */ void configureHello(ZrtpConfigure* config); /// Get version number from Hello message, fixed ASCII character array uint8_t* getVersion() { return helloHeader->version; }; /// Get client id from Hello message, fixed ASCII character array uint8_t* getClientId() { return helloHeader->clientId; }; /// Get H3 hash from Hello message, fixed byte array uint8_t* getH3() { return helloHeader->hashH3; }; /// Get client ZID from Hello message, fixed bytes array uint8_t* getZid() { return helloHeader->zid; }; /// Set version sting in Hello message, fixed ASCII character array void setVersion(uint8_t *text) { memcpy(helloHeader->version, text,ZRTP_WORD_SIZE ); } /// Set client id in Hello message, fixed ASCII character array void setClientId(const uint8_t *t) { memcpy(helloHeader->clientId, t, sizeof(helloHeader->clientId)); } /// Set H3 hash in Hello message, fixed byte array void setH3(uint8_t *hash) { memcpy(helloHeader->hashH3, hash, sizeof(helloHeader->hashH3)); } /// Set client ZID in Hello message, fixed bytes array void setZid(uint8_t *text) { memcpy(helloHeader->zid, text, sizeof(helloHeader->zid)); } /// Check passive mode (mode not implemented) bool isPassive() { return passive; }; /// Get hash algorithm name at position n, fixed ASCII character array uint8_t* getHashType(int32_t n) { return ((uint8_t*)helloHeader)+oHash+(n*ZRTP_WORD_SIZE); } /// Get ciper algorithm name at position n, fixed ASCII character array uint8_t* getCipherType(int32_t n) { return ((uint8_t*)helloHeader)+oCipher+(n*ZRTP_WORD_SIZE); } /// Get SRTP authentication algorithm name at position n, fixed ASCII character array uint8_t* getAuthLen(int32_t n) { return ((uint8_t*)helloHeader)+oAuth+(n*ZRTP_WORD_SIZE); } /// Get key agreement algorithm name at position n, fixed ASCII character array uint8_t* getPubKeyType(int32_t n) { return ((uint8_t*)helloHeader)+oPubkey+(n*ZRTP_WORD_SIZE); } /// Get SAS algorithm name at position n, fixed ASCII character array uint8_t* getSasType(int32_t n) { return ((uint8_t*)helloHeader)+oSas+(n*ZRTP_WORD_SIZE); } /// Get Hello MAC, fixed byte array uint8_t* getHMAC() { return ((uint8_t*)helloHeader)+oHmac; } /// Set hash algorithm name at position n, fixed ASCII character array void setHashType(int32_t n, int8_t* t) { memcpy(((uint8_t*)helloHeader)+oHash+(n*ZRTP_WORD_SIZE), t, ZRTP_WORD_SIZE); } /// Set ciper algorithm name at position n, fixed ASCII character array void setCipherType(int32_t n, int8_t* t) { memcpy(((uint8_t*)helloHeader)+oCipher+(n*ZRTP_WORD_SIZE), t, ZRTP_WORD_SIZE); } /// Set SRTP authentication algorithm name at position n, fixed ASCII character array void setAuthLen(int32_t n, int8_t* t) { memcpy(((uint8_t*)helloHeader)+oAuth+(n*ZRTP_WORD_SIZE), t, ZRTP_WORD_SIZE); } /// Set key agreement algorithm name at position n, fixed ASCII character array void setPubKeyType(int32_t n, int8_t* t) { memcpy(((uint8_t*)helloHeader)+oPubkey+(n*ZRTP_WORD_SIZE), t, ZRTP_WORD_SIZE); } /// Set SAS algorithm name at position n, fixed ASCII character array void setSasType(int32_t n, int8_t* t) { memcpy(((uint8_t*)helloHeader)+oSas+(n*ZRTP_WORD_SIZE), t, ZRTP_WORD_SIZE); } /// Set Hello MAC, fixed byte array void setHMAC(uint8_t* t) { memcpy(((uint8_t*)helloHeader)+oHmac, t, 2*ZRTP_WORD_SIZE); } /// Get number of offered hash algorithms int32_t getNumHashes() {return nHash; } /// Get number of offered cipher algorithms int32_t getNumCiphers() {return nCipher; } /// Get number of offered key agreement algorithms int32_t getNumPubKeys() {return nPubkey; } /// Get number of offered SAS algorithms int32_t getNumSas() {return nSas; } /// Get number of offered SRTP authentication algorithms int32_t getNumAuth() {return nAuth; } private: // Hello packet is of variable length. It maximum size is 46 words: // - 11 words fixed sizze // - up to 35 words variable part, depending on number of algorithms // leads to a maximum of 4*46=184 bytes. uint8_t data[256]; // large enough to hold a full blown Hello packet }; /** * @} */ #endif // ZRTPPACKETHELLO libzrtpcpp-2.0.0/src/libzrtpcpp/CMakeLists.txt0000755000175000017500000000035311570305710020435 0ustar dyfetdyfet if(enable_ccrtp) set(ccrtp_inst ZrtpQueue.h zrtpccrtp.h ZrtpUserCallback.h TimeoutProvider.h) endif() install(FILES ZrtpCodes.h ZrtpConfigure.h ZrtpCallback.h ZrtpCWrapper.h ${ccrtp_inst} DESTINATION include/libzrtpcpp) libzrtpcpp-2.0.0/src/libzrtpcpp/zrtpccrtp.h0000644000175000017500000000414111570305710020075 0ustar dyfetdyfet/* 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 . */ #ifndef _ZRTPCCRTP_H_ #define _ZRTPCCRTP_H_ #include #include NAMESPACE_COMMONCPP /** * @typedef SymmetricZRTPSession * * Uses one pair of sockets, (1) for RTP data and (2) for RTCP * transmission/reception. * * This session uses the ZrtpQueue instead of the AVPQueue. The ZrtpQueue * inherits from AVPQueue and adds support for ZRTP thus enabling * ad-hoc key negotiation to setup SRTP sessions. * * @short Symmetric UDP/IPv4 RTP session scheduled by one thread of execution. **/ typedef SingleThreadRTPSession SymmetricZRTPSession; #ifdef CCXX_IPV6 /** * @typedef SymmetricZRTPSession * * Uses one pair of sockets, (1) for RTP data and (2) for RTCP * transmission/reception. * * This session uses the ZrtpQueue instead of the AVPQueue. The ZrtpQueue * inherits from AVPQueue and adds support for ZRTP thus enabling * ad-hoc key negotiation to setup SRTP sessions. * * @short Symmetric UDP/IPv6 RTP session scheduled by one thread of execution. **/ typedef SingleThreadRTPSessionIPV6 SymmetricZRTPSessionIPV6; #endif // CCXX_IPV6 END_NAMESPACE #endif // _ZRTPCCRTP_H_ /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketDHPart.h0000644000175000017500000001052211570305710021174 0ustar dyfetdyfet/* 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 . */ #ifndef _ZRTPPACKETDHPART_H_ #define _ZRTPPACKETDHPART_H_ /** * @file ZrtpPacketDHPart.h * @brief The ZRTP DHPart message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the DHPart packet. * * The ZRTP message DHPart. The implementation sends this * to exchange the Diffie-Helman public keys and the shared * secrets between the two parties. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketDHPart : public ZrtpPacketBase { protected: uint8_t *pv; ///< points to public key value inside DH message DHPart_t* DHPartHeader; ///< points to DH message structure int32_t dhLength; ///< length of DH message, DH message has variable length public: /// Creates a DHPart packet no data, must use setPubKeyType(...) ZrtpPacketDHPart(); /// Creates a DHPart packet with default data and a give public key type ZrtpPacketDHPart(const char* pkt); /// Creates a DHPart packet from received data ZrtpPacketDHPart(uint8_t* data); /// Standard destructor virtual ~ZrtpPacketDHPart(); /// Get pointer to public key value, variable length byte array uint8_t* getPv() { return pv; } /// Get pointer to first retained secretd id, fixed length byte array uint8_t* getRs1Id() { return DHPartHeader->rs1Id; }; /// Get pointer to second retained secretd id, fixed length byte array uint8_t* getRs2Id() { return DHPartHeader->rs2Id; }; /// Get pointer to additional retained secretd id, fixed length byte array uint8_t* getAuxSecretId() { return DHPartHeader->auxSecretId; }; /// Get pointer to PBX retained secretd id, fixed length byte array uint8_t* getPbxSecretId() { return DHPartHeader->pbxSecretId; }; /// Get pointer to first hash (H1) for hash chain, fixed length byte array uint8_t* getH1() { return DHPartHeader->hashH1; }; /// Get pointer to HMAC, fixed length byte array uint8_t* getHMAC() { return pv+dhLength; }; /// Setpublic key value, variable length byte array void setPv(uint8_t* text) { memcpy(pv, text, dhLength); }; /// Set first retained secretd id, fixed length byte array void setRs1Id(uint8_t* text) { memcpy(DHPartHeader->rs1Id, text, sizeof(DHPartHeader->rs1Id)); }; /// Set second retained secretd id, fixed length byte array void setRs2Id(uint8_t* text) { memcpy(DHPartHeader->rs2Id, text, sizeof(DHPartHeader->rs2Id)); }; /// Set additional retained secretd id, fixed length byte array void setAuxSecretId(uint8_t* t) { memcpy(DHPartHeader->auxSecretId, t, sizeof(DHPartHeader->auxSecretId)); }; /// Set PBX retained secretd id, fixed length byte array void setPbxSecretId(uint8_t* t) { memcpy(DHPartHeader->pbxSecretId,t, sizeof(DHPartHeader->pbxSecretId)); }; /// Set first hash (H1) of hash chain, fixed length byte array void setH1(uint8_t* t) { memcpy(DHPartHeader->hashH1, t, sizeof(DHPartHeader->hashH1)); }; /// Set key agreement type, fixed size character array void setPubKeyType(const char* pkt); /// Set first MAC, fixed length byte array void setHMAC(uint8_t* t) { memcpy(pv+dhLength, t, 2*ZRTP_WORD_SIZE); }; private: void initialize(); // SupportedPubKeys pktype; // DHPart packet is of variable length. It maximum size is 141 words: // - 13 words fixed sizze // - up to 128 words variable part, depending on DH algorithm // leads to a maximum of 4*141=564 bytes. uint8_t data[768]; // large enough to hold a full blown DHPart packet }; /** * @} */ #endif // ZRTPPACKETDHPART libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketErrorAck.h0000644000175000017500000000271211570305710021564 0ustar dyfetdyfet/* Copyright (C) 2007 - 2010 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 . */ #ifndef _ZRTPPACKETERRORACK_H_ #define _ZRTPPACKETERRORACK_H_ /** * @file ZrtpPacketErrorAck.h * @brief The ZRTP ErrorAck message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the ErrorAck packet. * * The ZRTP simple message ErrorAck. The implementation sends this * after receiving and checking the Error message. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketErrorAck : public ZrtpPacketBase { public: /// Creates a ErrorAck packet with default data ZrtpPacketErrorAck(); /// Creates a ErrorAck packet from received data ZrtpPacketErrorAck(uint8_t* data); virtual ~ZrtpPacketErrorAck(); private: ErrorAckPacket_t data; }; /** * @} */ #endif // _ZRTPPACKETERRORACK_H_ libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketConf2Ack.h0000644000175000017500000000273711570305710021451 0ustar dyfetdyfet/* 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 . */ #ifndef _ZRTPPACKETCON2FACK_H_ #define _ZRTPPACKETCON2FACK_H_ /** * @file ZrtpPacketConf2Ack.h * @brief The ZRTP Conf2Ack message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the Conf2Ack packet. * * The ZRTP simple message Conf2Ack. The implementation sends this * after receiving and checking the Confirm2 message. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketConf2Ack : public ZrtpPacketBase { public: /// Creates a Conf2Ack packet with default data ZrtpPacketConf2Ack(); ///Creates a Conf2Ack packet from received data ZrtpPacketConf2Ack(char* data); /// Normal destructor virtual ~ZrtpPacketConf2Ack(); private: Conf2AckPacket_t data; }; /** * @} */ #endif // ZRTPPACKETCONF2ACK libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpStateClass.h0000644000175000017500000001775111570305710021003 0ustar dyfetdyfet/* Copyright (C) 2006-2010 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 . */ #ifndef _ZRTPSTATECLASS_H_ #define _ZRTPSTATECLASS_H_ /** * @file ZrtpStateClass.h * @brief The ZRTP state handling class * * @ingroup GNU_ZRTP * @{ */ #include #include /** * The ZRTP states * * Depending on the role of this state engine and the actual protocl flow * not all states are processed during a ZRTP handshake. */ enum zrtpStates { Initial, ///< Initial state after starting the state engine Detect, ///< State sending Hello, try to detect answer message AckDetected, ///< HelloAck received AckSent, ///< HelloAck sent after Hello received WaitCommit, ///< Wait for a Commit message CommitSent, ///< Commit message sent WaitDHPart2, ///< Wait for a DHPart2 message WaitConfirm1, ///< Wait for a Confirm1 message WaitConfirm2, ///< Wait for a confirm2 message WaitConfAck, ///< Wait for Conf2Ack WaitClearAck, ///< Wait for clearAck - not used SecureState, ///< This is the secure state - SRTP active WaitErrorAck, ///< Wait for ErrorAck message numberOfStates ///< Gives total number of protocol states }; enum EventReturnCodes { Fail = 0, ///< ZRTP event processing failed. Done = 1 ///< Event processing ok. }; enum EventDataType { ZrtpInitial = 1, ///< Initial event, enter Initial state ZrtpClose, ///< Close event, shut down state engine ZrtpPacket, ///< Normal ZRTP message event, process according to state Timer, ///< Timer event ErrorPkt ///< Error packet event }; /// A ZRTP state event typedef struct Event { EventDataType type; ///< Type of event uint8_t* packet; ///< Event data if availabe, usually a ZRTP message } Event_t; /** * The ZRTP timer structure. * * This structure holds all necessary data to compute the timer for * the protocol timers. The state engine allocate one structure for * each timer. ZRTP uses two timers, T1 and T2, to monitor protocol * timeouts. As a slight misuse but to make overall handling a bit * simpler this structure also contains the resend counter. This is * possible in ZRTP because it uses a simple timeout strategy. */ typedef struct zrtpTimer { int32_t time, ///< Current timeout value start, ///< Start value for timeout increment, ///< increment timeout after each timeout event (not used anymore) capping, ///< Maximum timeout value counter, ///< Current number of timeouts maxResend; ///< Maximum number of timeout resends } zrtpTimer_t; class ZRtp; /** * This class is the ZRTP protocol state engine. * * This class is responsible to handle the ZRTP protocol. It does not * handle the ZRTP HMAC, DH, and other data management. This is done in * class ZRtp, which is the parent of this class. * * The methods of this class implement the ZRTP state actions. * */ class __EXPORT ZrtpStateClass { private: ZRtp* parent; ///< The ZRTP implmentation ZrtpStates* engine; ///< The state switching engine Event_t* event; ///< Current event to process /** * The last packet that was sent. * * If we are Initiator then resend this packet in case of * timeout. */ ZrtpPacketBase* sentPacket; /** * Points to prepared Commit packet after receiving a Hello packet */ ZrtpPacketCommit* commitPkt; zrtpTimer_t T1; ///< The Hello message timeout timer zrtpTimer_t T2; ///< Timeout timer for other messages /* * If this is set to true the protocol engine handle the multi-stream * variant of ZRTP. Refer to chapter 5.4.2 in the ZRTP specification. */ bool multiStream; public: /// Create a ZrtpStateClass ZrtpStateClass(ZRtp *p); ~ZrtpStateClass(); /// Check if in a specified state bool inState(const int32_t state) { return engine->inState(state); }; /// Switch to the specified state void nextState(int32_t state) { engine->nextState(state); }; /// Process an event, the main entry point into the state engine void processEvent(Event_t *ev); /** * The state event handling methods. * * Refer to the protocol state diagram for further documentation. */ /// Initial event state void evInitial(); /// Detect state void evDetect(); /// HelloAck detected state void evAckDetected(); /// HelloAck sent state void evAckSent(); /// Wait for Commit message void evWaitCommit(); /// Commit sent state void evCommitSent(); /// Wait for DHPart2 message void evWaitDHPart2(); /// Wait for Confirm2 message void evWaitConfirm1(); /// Wait for Confirm2 message void evWaitConfirm2(); /// Wait for ConfAck message void evWaitConfAck(); /// Wait for ClearAck message (not used) void evWaitClearAck(); /// Secure reached state void evSecureState(); /// Wait for ErrorAck message void evWaitErrorAck(); /** * Initialize and activate a timer. * * @param t * The ZRTP timer structure to use for the timer. * @return * 1 timer was activated * 0 activation failed */ int32_t startTimer(zrtpTimer_t *t); /** * Compute and set the next timeout value. * * @param t * The ZRTP timer structure to use for the timer. * @return * 1 timer was activated * 0 activation failed * -1 resend counter exceeded */ int32_t nextTimer(zrtpTimer_t *t); /** * Cancel the active timer. * * @return * 1 timer was canceled * 0 cancelation failed */ int32_t cancelTimer() {return parent->cancelTimer(); }; /** * Prepare and send an Error packet. * * Preparse an Error packet and sends it. It stores the Error * packet in the sentPacket variable to enable resending. The * method switches to protocol state Initial. */ void sendErrorPacket(uint32_t errorCode); /** * Set status if an error occured while sending a ZRTP packet. * * This functions clears data and set the state to Initial after the engine * detected a problem while sending a ZRTP packet. * * @return * Fail code */ void sendFailed(); /** * Set status if a timer problems occure. * * This functions clears data and set state to Initial after a timer * error occured. Either no timer available or resend counter exceedeed. * * @return * Fail code */ void timerFailed(int32_t subCode); /** * Set multi-stream mode flag. * * This functions set the multi-stream mode. The protocol * engine will run the multi-stream mode variant of the ZRTP * protocol if this flag is set to true. * * @param multi * Set the multi-stream mode flag to true or false. */ void setMultiStream(bool multi); /** * Status of multi-stream mode flag. * * This functions returns the value of the multi-stream mode flag. * * @return * Value of the multi-stream mode flag. */ bool isMultiStream(); }; /** * @} */ #endif // _ZRTPSTATECLASS_H_ libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/0000755000175000017500000000000011570305710017211 5ustar dyfetdyfetlibzrtpcpp-2.0.0/src/libzrtpcpp/crypto/gcrypt/0000755000175000017500000000000011570305710020521 5ustar dyfetdyfetlibzrtpcpp-2.0.0/src/libzrtpcpp/crypto/gcrypt/gcryptZrtpDH.cpp0000644000175000017500000003231711570305710023637 0ustar dyfetdyfet/* Copyright (C) 2006, 2009 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 . */ /** Copyright (C) 2006, 2009 * * @author Werner Dittmann */ #include #include #include #include struct gcryptCtx { gcry_mpi_t privKey; gcry_mpi_t pubKey; // int32_t pLength; }; extern void initializeGcrypt(); static gcry_mpi_t bnP2048 = NULL; static gcry_mpi_t bnP3072 = NULL; // static gcry_mpi_t bnP4096 = NULL; static gcry_mpi_t two = NULL; static gcry_mpi_t bnP2048MinusOne = NULL; static gcry_mpi_t bnP3072MinusOne = NULL; // static gcry_mpi_t bnP4096MinusOne = NULL; static uint8_t dhinit = 0; void randomZRTP(uint8_t *buf, int32_t length) { initializeGcrypt(); gcry_randomize(buf, length, GCRY_STRONG_RANDOM); } static const uint8_t P2048[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static const uint8_t P3072[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* ************* static const uint8_t P4096[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; *************** */ #define DH3K 1 #define DH2K 0 ZrtpDH::ZrtpDH(const char* type){ // Well - the algo type is only 4 char thus cast to int32 and compare if (*(int32_t*)type == *(int32_t*)dh2k) { pkType = DH2K; } else if (*(int32_t*)type == *(int32_t*)dh3k) { pkType = DH3K; } else { fprintf(stderr, "Unknown pubkey algo: %d\n", pkType); } ctx = static_cast(new gcryptCtx); gcryptCtx* tmpCtx = static_cast(ctx); tmpCtx->privKey = NULL; tmpCtx->pubKey = NULL; initializeGcrypt(); if (!dhinit) { gcry_mpi_scan(&bnP2048, GCRYMPI_FMT_USG, P2048, sizeof(P2048), NULL); gcry_mpi_scan(&bnP3072, GCRYMPI_FMT_USG, P3072, sizeof(P3072), NULL); // gcry_mpi_scan(&bnP4096, GCRYMPI_FMT_USG, P4096, sizeof(P4096), NULL); two = gcry_mpi_set_ui(NULL, 2); bnP2048MinusOne = gcry_mpi_new(sizeof(P2048)*8); gcry_mpi_sub_ui(bnP2048MinusOne, bnP2048, 1); bnP3072MinusOne = gcry_mpi_new(sizeof(P3072)*8); gcry_mpi_sub_ui(bnP3072MinusOne, bnP3072, 1); // bnP4096MinusOne = gcry_mpi_new(sizeof(P4096)*8); // gcry_mpi_sub_ui(bnP4096MinusOne, bnP4096, 1); dhinit = 1; } if (pkType == DH3K) { tmpCtx->privKey = gcry_mpi_new(256); gcry_mpi_randomize(tmpCtx->privKey, 256, GCRY_STRONG_RANDOM); } else if (pkType == DH2K) { tmpCtx->privKey = gcry_mpi_new(512); gcry_mpi_randomize(tmpCtx->privKey, 512, GCRY_STRONG_RANDOM); } // else { // tmpCtx->privKey = gcry_mpi_new(512); // gcry_mpi_randomize(tmpCtx->privKey, 512, GCRY_STRONG_RANDOM); // } } ZrtpDH::~ZrtpDH() { gcryptCtx* tmpCtx = static_cast(ctx); if (tmpCtx != NULL) { gcry_mpi_release(tmpCtx->privKey); tmpCtx->privKey = NULL; gcry_mpi_release(tmpCtx->pubKey); tmpCtx->pubKey = NULL; delete tmpCtx; ctx = NULL; } } int32_t ZrtpDH::computeSecretKey(uint8_t *pubKeyBytes, uint8_t *secret) { int32_t length = getDhSize(); gcryptCtx* tmpCtx = static_cast(ctx); gcry_mpi_t pubKeyOther; gcry_mpi_t sec = gcry_mpi_new(0); gcry_mpi_scan(&pubKeyOther, GCRYMPI_FMT_USG, pubKeyBytes, length, NULL); if (pkType == DH2K) { gcry_mpi_powm(sec, pubKeyOther, tmpCtx->privKey, bnP2048); } else if (pkType == DH3K) { gcry_mpi_powm(sec, pubKeyOther, tmpCtx->privKey, bnP3072); } else { // gcry_mpi_powm(sec, pubKeyOther, tmpCtx->privKey, bnP4096); return 0; } gcry_mpi_release(pubKeyOther); size_t result; gcry_mpi_print(GCRYMPI_FMT_USG, secret, length, &result, sec); gcry_mpi_release(sec); return result; } int32_t ZrtpDH::generatePublicKey() { gcryptCtx* tmpCtx = static_cast(ctx); tmpCtx->pubKey = gcry_mpi_new(0); if (pkType == DH2K) { gcry_mpi_powm(tmpCtx->pubKey, two, tmpCtx->privKey, bnP2048); } else if (pkType == DH3K) { gcry_mpi_powm(tmpCtx->pubKey, two, tmpCtx->privKey, bnP3072); } else { // gcry_mpi_powm(tmpCtx->pubKey, two, tmpCtx->privKey, bnP4096); return 0; } return 1; } int32_t ZrtpDH::getPubKeyBytes(uint8_t *buf) const { gcryptCtx* tmpCtx = static_cast(ctx); int32_t len = getPubKeySize(); // get length of Dh in bytes, prepend buffer with zeros if necessary int32_t prepend = getDhSize() - getPubKeySize(); if (prepend > 0) { memset(buf, 0, prepend); } size_t i = 0; gcry_mpi_print(GCRYMPI_FMT_USG, buf + prepend, len, &i, tmpCtx->pubKey); return i; } int32_t ZrtpDH::getDhSize() const { switch (pkType) { case DH2K: return 2048/8; break; case DH3K: return 3072/8; break; } return 0; } int32_t ZrtpDH::getPubKeySize() const { return ((gcry_mpi_get_nbits(static_cast(ctx)->pubKey) + 7) / 8); } int32_t ZrtpDH::checkPubKey(uint8_t *pubKeyBytes) const { gcry_mpi_t pubKeyOther = NULL; gcry_mpi_scan(&pubKeyOther, GCRYMPI_FMT_USG, pubKeyBytes, getDhSize(), NULL); if (pkType == DH2K) { if (gcry_mpi_cmp(bnP2048MinusOne, pubKeyOther) == 0) return 0; } else if (pkType == DH3K) { if (gcry_mpi_cmp(bnP3072MinusOne, pubKeyOther) == 0) return 0; } else { // if (gcry_mpi_cmp(bnP4096MinusOne, pubKeyOther) == 0) return 0; } if (gcry_mpi_cmp_ui(pubKeyOther, 1) == 0) { return 0; } gcry_mpi_release(pubKeyOther); return 1; } const char* ZrtpDH::getDHtype() { switch (pkType) { case DH2K: return dh2k; break; case DH3K: return dh3k; break; } return NULL; } /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/gcrypt/gcryptsha384.cpp0000644000175000017500000000460111570305710023471 0ustar dyfetdyfet/* 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 . */ /** * @author Erik Eliasson * Johan Bilien * Werner Dittmann */ #include #include void sha384(unsigned char* data, unsigned int dataLength, unsigned char* mac) { gcry_md_hash_buffer(GCRY_MD_SHA384, mac, data, dataLength); } void sha384(unsigned char* dataChunks[], unsigned int dataChunkLength[], unsigned char* mac) { gcry_md_hd_t hd; gcry_error_t err = 0; err = gcry_md_open(&hd, GCRY_MD_SHA384, 0); while (*dataChunks) { gcry_md_write (hd, *dataChunks, (uint32_t)(*dataChunkLength)); dataChunks++; dataChunkLength++; } uint8_t* p = gcry_md_read (hd, GCRY_MD_SHA384); memcpy(mac, p, SHA384_DIGEST_LENGTH); gcry_md_close (hd); } void* createSha384Context() { gcry_error_t err = 0; gcry_md_hd_t hd; err = gcry_md_open(&hd, GCRY_MD_SHA384, 0); return (void*)hd; } void closeSha384Context(void* ctx, unsigned char* digest) { gcry_md_hd_t hd = (gcry_md_hd_t)ctx; if (digest != NULL) { uint8_t* p = gcry_md_read (hd, GCRY_MD_SHA384); memcpy(digest, p, SHA384_DIGEST_LENGTH); } gcry_md_close (hd); } void sha384Ctx(void* ctx, unsigned char* data, unsigned int dataLength) { gcry_md_hd_t hd = (gcry_md_hd_t)ctx; gcry_md_write (hd, data, dataLength); } void sha384Ctx(void* ctx, unsigned char* dataChunks[], unsigned int dataChunkLength[]) { gcry_md_hd_t hd = (gcry_md_hd_t)ctx; while (*dataChunks) { gcry_md_write (hd, *dataChunks, (uint32_t)(*dataChunkLength)); dataChunks++; dataChunkLength++; } } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/gcrypt/gcryptAesCFB.cpp0000644000175000017500000000420411570305710023501 0ustar dyfetdyfet/* 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 . */ /** Copyright (C) 2006, 2007 * * @author Werner Dittmann */ #include #include extern void initializeGcrypt(); void aesCfbEncrypt(uint8_t* key, int32_t keyLength, uint8_t* IV, uint8_t *data, int32_t dataLength); { gcry_error_t err = 0; int algo; initializeGcrypt(); if (keyLength == 16) { algo = GCRY_CIPHER_AES; } else if (keyLength == 32) { algo = GCRY_CIPHER_AES256; } else { return; } gcry_cipher_hd_t tmp; err = gcry_cipher_open(&tmp, algo, GCRY_CIPHER_MODE_CFB, 0); err = gcry_cipher_setkey(tmp, key, keyLength); err = gcry_cipher_setiv (tmp, IV, AES_BLOCK_SIZE); err = gcry_cipher_encrypt (tmp, data, dataLength, data, dataLength); gcry_cipher_close(tmp); } void aesCfbDecrypt(uint8_t* key, int32_t keyLength, const uint8_t* IV, uint8_t *data, int32_t dataLength); { gcry_error_t err = 0; int algo; initializeGcrypt(); if (keyLength == 16) { algo = GCRY_CIPHER_AES; } else if (keyLength == 32) { algo = GCRY_CIPHER_AES256; } else { return; } gcry_cipher_hd_t tmp; err = gcry_cipher_open(&tmp, algo, GCRY_CIPHER_MODE_CFB, 0); err = gcry_cipher_setkey(tmp, key, keyLength); err = gcry_cipher_setiv (tmp, IV, AES_BLOCK_SIZE); err = gcry_cipher_decrypt (tmp, data, dataLength, data, dataLength); gcry_cipher_close(tmp); }libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/gcrypt/gcrypthmac256.cpp0000644000175000017500000000401411570305710023622 0ustar dyfetdyfet/* 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: Erik Eliasson * Johan Bilien */ #include #include void hmac_sha256(uint8_t* key, uint32_t keyLength, uint8_t* data, int32_t dataLength, uint8_t* mac, uint32_t* macLength) { gcry_md_hd_t hd; gcry_error_t err = 0; err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); gcry_md_setkey(hd, key, keyLength); gcry_md_write (hd, data, dataLength); uint8_t* p = gcry_md_read (hd, GCRY_MD_SHA256); memcpy(mac, p, SHA256_DIGEST_LENGTH); if (macLength != NULL) { *macLength = SHA256_DIGEST_LENGTH; } gcry_md_close (hd); } void hmac_sha256( uint8_t* key, uint32_t keyLength, uint8_t* dataChunks[], uint32_t dataChunkLength[], uint8_t* mac, uint32_t* macLength ) { gcry_md_hd_t hd; gcry_error_t err = 0; err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); gcry_md_setkey(hd, key, keyLength); while (*dataChunks) { gcry_md_write (hd, *dataChunks, (uint32_t)(*dataChunkLength)); dataChunks++; dataChunkLength++; } uint8_t* p = gcry_md_read (hd, GCRY_MD_SHA256); memcpy(mac, p, SHA256_DIGEST_LENGTH); if (macLength != NULL) { *macLength = SHA256_DIGEST_LENGTH; } gcry_md_close (hd); } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/gcrypt/InitializeGcrypt.cpp0000644000175000017500000000712511570305710024524 0ustar dyfetdyfet/* 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 . */ #include #include #include #include #include /* * The following macro was copied from gcrypt.h and modified to explicitly * cast the pointer types to keep the compiler happy. */ #define GCRY_THREAD_OPTION_PTHREAD_CPP_IMPL \ static int gcry_pthread_mutex_init (void **priv) \ { \ int err = 0; \ pthread_mutex_t *lock = (pthread_mutex_t *)malloc (sizeof (pthread_mutex_t)); \ \ if (!lock) \ err = ENOMEM; \ if (!err) \ { \ err = pthread_mutex_init (lock, NULL); \ if (err) \ free (lock); \ else \ *priv = lock; \ } \ return err; \ } \ static int gcry_pthread_mutex_destroy (void **lock) \ { int err = pthread_mutex_destroy ((pthread_mutex_t *)*lock); free (*lock); return err; } \ static int gcry_pthread_mutex_lock (void **lock) \ { return pthread_mutex_lock ((pthread_mutex_t *)*lock); } \ static int gcry_pthread_mutex_unlock (void **lock) \ { return pthread_mutex_unlock ((pthread_mutex_t *)*lock); } \ \ static struct gcry_thread_cbs gcry_threads_pthread = \ { GCRY_THREAD_OPTION_PTHREAD, NULL, \ gcry_pthread_mutex_init, gcry_pthread_mutex_destroy, \ gcry_pthread_mutex_lock, gcry_pthread_mutex_unlock } /** Implement the locking callback functions for libgcrypt. * */ static int initialized = 0; #ifdef __cplusplus extern "C" { #endif GCRY_THREAD_OPTION_PTHREAD_CPP_IMPL; #ifdef __cplusplus } #endif int initializeGcrypt () { if (initialized) { return 1; } gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); gcry_check_version(NULL); gcry_control(GCRYCTL_DISABLE_SECMEM); initialized = 1; return 1; } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/gcrypt/gcryptsha256.cpp0000644000175000017500000000460111570305710023467 0ustar dyfetdyfet/* 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 . */ /** * @author Erik Eliasson * Johan Bilien * Werner Dittmann */ #include #include void sha256(unsigned char* data, unsigned int dataLength, unsigned char* mac) { gcry_md_hash_buffer(GCRY_MD_SHA256, mac, data, dataLength); } void sha256(unsigned char* dataChunks[], unsigned int dataChunkLength[], unsigned char* mac) { gcry_md_hd_t hd; gcry_error_t err = 0; err = gcry_md_open(&hd, GCRY_MD_SHA256, 0); while (*dataChunks) { gcry_md_write (hd, *dataChunks, (uint32_t)(*dataChunkLength)); dataChunks++; dataChunkLength++; } uint8_t* p = gcry_md_read (hd, GCRY_MD_SHA256); memcpy(mac, p, SHA256_DIGEST_LENGTH); gcry_md_close (hd); } void* createSha256Context() { gcry_error_t err = 0; gcry_md_hd_t hd; err = gcry_md_open(&hd, GCRY_MD_SHA256, 0); return (void*)hd; } void closeSha256Context(void* ctx, unsigned char* digest) { gcry_md_hd_t hd = (gcry_md_hd_t)ctx; if (digest != NULL) { uint8_t* p = gcry_md_read (hd, GCRY_MD_SHA256); memcpy(digest, p, SHA256_DIGEST_LENGTH); } gcry_md_close (hd); } void sha256Ctx(void* ctx, unsigned char* data, unsigned int dataLength) { gcry_md_hd_t hd = (gcry_md_hd_t)ctx; gcry_md_write (hd, data, dataLength); } void sha256Ctx(void* ctx, unsigned char* dataChunks[], unsigned int dataChunkLength[]) { gcry_md_hd_t hd = (gcry_md_hd_t)ctx; while (*dataChunks) { gcry_md_write (hd, *dataChunks, (uint32_t)(*dataChunkLength)); dataChunks++; dataChunkLength++; } } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/gcrypt/gcrypthmac384.cpp0000644000175000017500000000401411570305710023624 0ustar dyfetdyfet/* Copyright (C) 2006-2009 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: Erik Eliasson * Johan Bilien */ #include #include void hmac_sha384(uint8_t* key, uint32_t keyLength, uint8_t* data, int32_t dataLength, uint8_t* mac, uint32_t* macLength) { gcry_md_hd_t hd; gcry_error_t err = 0; err = gcry_md_open(&hd, GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC); gcry_md_setkey(hd, key, keyLength); gcry_md_write (hd, data, dataLength); uint8_t* p = gcry_md_read (hd, GCRY_MD_SHA384); memcpy(mac, p, SHA384_DIGEST_LENGTH); if (macLength != NULL) { *macLength = SHA384_DIGEST_LENGTH; } gcry_md_close (hd); } void hmac_sha384( uint8_t* key, uint32_t keyLength, uint8_t* dataChunks[], uint32_t dataChunkLength[], uint8_t* mac, uint32_t* macLength ) { gcry_md_hd_t hd; gcry_error_t err = 0; err = gcry_md_open(&hd, GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC); gcry_md_setkey(hd, key, keyLength); while (*dataChunks) { gcry_md_write (hd, *dataChunks, (uint32_t)(*dataChunkLength)); dataChunks++; dataChunkLength++; } uint8_t* p = gcry_md_read (hd, GCRY_MD_SHA384); memcpy(mac, p, SHA384_DIGEST_LENGTH); if (macLength != NULL) { *macLength = SHA384_DIGEST_LENGTH; } gcry_md_close (hd); } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/sha256.h0000644000175000017500000001033311570305710020372 0ustar dyfetdyfet/* 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 . */ /** * Functions to compute SHA256 digest. * * @author: Werner Dittmann */ #ifndef _SHA256_H #define _SHA256_H /** * @file sha256.h * @brief Function that provide SHA256 support * * @ingroup GNU_ZRTP * @{ */ #include #ifndef SHA256_DIGEST_LENGTH #define SHA256_DIGEST_LENGTH 32 #endif /** * Compute SHA256 digest. * * This functions takes one data chunk and computes its SHA256 digest. This * function creates and deletes an own SHA256 context to perform the SHA256 * operations. * * @param data * Points to the data chunk. * @param data_length * Length of the data in bytes * @param digest * Points to a buffer that receives the computed digest. This * buffer must have a size of at least 32 bytes (SHA256_DIGEST_LENGTH). */ void sha256(unsigned char *data, unsigned int data_length, unsigned char *digest); /** * Compute SHA256 digest over several data cunks. * * This functions takes several data chunks and computes the SHA256 digest. * This function creates and deletes an own SHA256 context to perform the * SHA256 operations. * * @param data * Points to an array of pointers that point to the data chunks. A NULL * pointer in an array element terminates the data chunks. * @param data_length * Points to an array of integers that hold the length of each data chunk. * @param digest * Points to a buffer that receives the computed digest. This * buffer must have a size of at least 32 bytes (SHA256_DIGEST_LENGTH). */ void sha256(unsigned char *data[], unsigned int data_length[], unsigned char *digest); /** * Create and initialize a SHA256 context. * * An application uses this context to hash several data into one SHA256 * digest. See also sha256Ctx(...) and closeSha256Context(...). * * @return Returns a pointer to the initialized SHA256 context */ void* createSha256Context(); /** * Compute a digest and close the SHa256 digest. * * An application uses this function to compute the SHA256 digest and to * close the SHA256 context. * * @param ctx * Points to the SHA256 context. * @param digest * If this pointer is not NULL then it must point to a byte array that * is big enough to hold the SHA256 digest (256 bit = 32 Bytes). If this * pointer is NULL then the functions does not compute the digest but * closes the context only. The context cannot be used anymore. */ void closeSha256Context(void* ctx, unsigned char* digest); /** * Update the SHA256 context with data. * * This functions updates the SHA256 context with some data. * See also CloseSha256Context(...) how to get the digest. * * @param ctx * Points to the SHA256 context. * @param data * Points to the data to update the context. * @param dataLength * The length of the data in bytes. */ void sha256Ctx(void* ctx, unsigned char* data, unsigned int dataLength); /** * Update the SHA256 context with several data chunks. * * This functions updates the SHA256 context with some data. * See also CloseSha256Context(...) how to get the digest. * * @param ctx * Points to the SHA256 context. * @param dataChunks * Points to an array of pointers that point to the data chunks. A NULL * pointer in an array element terminates the data chunks. * @param dataChunkLength * Points to an array of integers that hold the length of each data chunk. * */ void sha256Ctx(void* ctx, unsigned char* dataChunks[], unsigned int dataChunkLength[]); /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/ZrtpDH.h0000644000175000017500000001022711570305710020537 0ustar dyfetdyfet/* Copyright (C) 2006-2009 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 */ #ifndef _ZRTPDH_H__ #define _ZRTPDH_H__ #include #include /** * @file ZrtpDH.h * @brief Class that implemets Diffie-Helman key agreement for ZRTP * * @ingroup GNU_ZRTP * @{ */ /** * Generates a number of random bytes. * * @param buf * Pointer to a buffer that receives the random data. Must have a size * of at least length bytes. * * @param length * Number of random bytes to produce. */ void randomZRTP(uint8_t *buf, int32_t length); const int32_t DH2K = 0; const int32_t DH3K = 1; const int32_t EC25 = 2; const int32_t EC38 = 3; /** * Implementation of Diffie-Helman for ZRTP * * This class defines functions to generate and compute the * Diffie-Helman public and secret data and the shared secret. According to * the ZRTP specification we use the MODP groups as defined by RFC 3526 for * length 3072 and 4096. * * @author Werner Dittmann */ class ZrtpDH { private: void* ctx; ///< Context the DH int pkType; ///< Which type of DH to use public: /** * Create a Diffie-Helman key agreement algorithm * * @param type * Name of the DH algorithm to use */ ZrtpDH(const char* type); ~ZrtpDH(); /** * Generates a public key based on the DH parameters and a random * private key. * * @return 1 on success, 0 on failure */ int32_t generatePublicKey(); /** * Returns the size in bytes of the DH parameter p. * * @return Size in bytes. */ int32_t getDhSize() const; /** * Returns the size in bytes of computed public key. * * @return Size in bytes. */ int32_t getPubKeySize() const; /** * Returns the bytes of computed secret key. * * Returns the bytes of the public key in network (big endian) order.# * * @param buf * Pointer to a buffer of at least getPubKeySize() bytes. * * @return Size in bytes. */ int32_t getPubKeyBytes(uint8_t *buf) const; /** * Compute the secret key and returns it to caller. * * This method computes the secret key based on the DH parameters, the * private key and the peer's public key. * * @param pubKeyBytes * Pointer to the peer's public key bytes. Must be in big endian order. * * @param secret * Pointer to a buffer that receives the secret key. This buffer must * have a length of at least getSecretSize() bytes. * * @return the size of the shared secret on success, -1 on error. */ int32_t computeSecretKey(uint8_t *pubKeyBytes, uint8_t *secret); /** * Check and validate the public key received from peer. * * Check if this is a correct Diffie-Helman public key. If the public * key value is either one or (P-1) then this is a wrong public key * value. * * @param pubKeyBytes * Pointer to the peer's public key bytes. Must be in big endian order. * * @return 0 if check faild, 1 if public key value is ok. */ int32_t checkPubKey(uint8_t* pubKeyBytes) const; /** * Get type of DH algorithm. * * @return * Pointer to DH algorithm name */ const char* getDHtype(); }; #endif // ZRTPDH_H /** * @} */ /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/twofish.c0000644000175000017500000020500711570305710021044 0ustar dyfetdyfet/* * Fast, portable, and easy-to-use Twofish implementation, * Version 0.3. * Copyright (c) 2002 by Niels Ferguson. * (See further down for the almost-unrestricted licensing terms.) * * -------------------------------------------------------------------------- * There are two files for this implementation: * - twofish.h, the header file. * - twofish.c, the code file. * * To incorporate this code into your program you should: * - Check the licensing terms further down in this comment. * - Fix the two type definitions in twofish.h to suit your platform. * - Fix a few definitions in twofish.c in the section marked * PLATFORM FIXES. There is one important ones that affects * functionality, and then a few definitions that you can optimise * for efficiency but those have no effect on the functionality. * Don't change anything else. * - Put the code in your project and compile it. * * To use this library you should: * - Call Twofish_initialise() in your program before any other function in * this library. * - Use Twofish_prepare_key(...) to convert a key to internal form. * - Use Twofish_encrypt(...) and Twofish_decrypt(...) to encrypt and decrypt * data. * See the comments in the header file for details on these functions. * -------------------------------------------------------------------------- * * There are many Twofish implementation available for free on the web. * Most of them are hard to integrate into your own program. * As we like people to use our cipher, I thought I would make it easier. * Here is a free and easy-to-integrate Twofish implementation in C. * The latest version is always available from my personal home page at * http://niels.ferguson.net/ * * Integrating library code into a project is difficult because the library * header files interfere with the project's header files and code. * And of course the project's header files interfere with the library code. * I've tried to resolve these problems here. * The header file of this implementation is very light-weight. * It contains two typedefs, a structure, and a few function declarations. * All names it defines start with "Twofish_". * The header file is therefore unlikely to cause problems in your project. * The code file of this implementation doesn't need to include the header * files of the project. There is thus no danger of the project interfering * with all the definitions and macros of the Twofish code. * In most situations, all you need to do is fill in a few platform-specific * definitions in the header file and code file, * and you should be able to run the Twofish code in your project. * I estimate it should take you less than an hour to integrate this code * into your project, most of it spent reading the comments telling you what * to do. * * For people using C++: it is very easy to wrap this library into a * TwofishKey class. One of the big advantages is that you can automate the * wiping of the key material in the destructor. I have not provided a C++ * class because the interface depends too much on the abstract base class * you use for block ciphers in your program, which I don't know about. * * This implementation is designed for use on PC-class machines. It uses the * Twofish 'full' keying option which uses large tables. Total table size is * around 5-6 kB for static tables plus 4.5 kB for each pre-processed key. * If you need an implementation that uses less memory, * take a look at Brian Gladman's code on his web site: * http://fp.gladman.plus.com/cryptography_technology/aes/ * He has code for all AES candidates. * His Twofish code has lots of options trading off table size vs. speed. * You can also take a look at the optimised code by Doug Whiting on the * Twofish web site * http://www.counterpane.com/twofish.html * which has loads of options. * I believe these existing implementations are harder to re-use because they * are not clean libraries and they impose requirements on the environment. * This implementation is very careful to minimise those, * and should be easier to integrate into any larger program. * * The default mode of this implementation is fully portable as it uses no * behaviour not defined in the C standard. (This is harder than you think.) * If you have any problems porting the default mode, please let me know * so that I can fix the problem. (But only if this code is at fault, I * don't fix compilers.) * Most of the platform fixes are related to non-portable but faster ways * of implementing certain functions. * * In general I've tried to make the code as fast as possible, at the expense * of memory and code size. However, C does impose limits, and this * implementation will be slower than an optimised assembler implementation. * But beware of assembler implementations: a good Pentium implementation * uses completely different code than a good Pentium II implementation. * You basically have to re-write the assembly code for every generation of * processor. Unless you are severely pressed for speed, stick with C. * * The initialisation routine of this implementation contains a self-test. * If initialisation succeeds without calling the fatal routine, then * the implementation works. I don't think you can break the implementation * in such a way that it still passes the tests, unless you are malicious. * In other words: if the initialisation routine returns, * you have successfully ported the implementation. * (Or not implemented the fatal routine properly, but that is your problem.) * * I'm indebted to many people who helped me in one way or another to write * this code. During the design of Twofish and the AES process I had very * extensive discussions of all implementation issues with various people. * Doug Whiting in particular provided a wealth of information. The Twofish * team spent untold hours discussion various cipher features, and their * implementation. Brian Gladman implemented all AES candidates in C, * and we had some fruitful discussions on how to implement Twofish in C. * Jan Nieuwenhuizen tested this code on Linux using GCC. * * Now for the license: * The author hereby grants a perpetual license to everybody to * use this code for any purpose as long as the copyright message is included * in the source code of this or any derived work. * * Yes, this means that you, your company, your club, and anyone else * can use this code anywhere you want. You can change it and distribute it * under the GPL, include it in your commercial product without releasing * the source code, put it on the web, etc. * The only thing you cannot do is remove my copyright message, * or distribute any source code based on this implementation that does not * include my copyright message. * * I appreciate a mention in the documentation or credits, * but I understand if that is difficult to do. * I also appreciate it if you tell me where and why you used my code. * * Please send any questions or comments to niels@ferguson.net * * Have Fun! * * Niels */ /* * DISCLAIMER: As I'm giving away my work for free, I'm of course not going * to accept any liability of any form. This code, or the Twofish cipher, * might very well be flawed; you have been warned. * This software is provided as-is, without any kind of warrenty or * guarantee. And that is really all you can expect when you download * code for free from the Internet. * * I think it is really sad that disclaimers like this seem to be necessary. * If people only had a little bit more common sense, and didn't come * whining like little children every time something happens.... */ /* * Version history: * Version 0.0, 2002-08-30 * First written. * Version 0.1, 2002-09-03 * Added disclaimer. Improved self-tests. * Version 0.2, 2002-09-09 * Removed last non-portabilities. Default now works completely within * the C standard. UInt32 can be larger than 32 bits without problems. * Version 0.3, 2002-09-28 * Bugfix: use instead of to adhere to ANSI/ISO. * Rename BIG_ENDIAN macro to CPU_IS_BIG_ENDIAN. The gcc library * header already defines BIG_ENDIAN, even though it is not * supposed to. */ /* * Minimum set of include files. * You should not need any application-specific include files for this code. * In fact, adding you own header files could break one of the many macros or * functions in this file. Be very careful. * Standard include files will probably be ok. */ #include #include #include /* #include * for memset(), memcpy(), and memcmp() */ #include "twofish.h" /* * PLATFORM FIXES * ============== * * Fix the type definitions in twofish.h first! * * The following definitions have to be fixed for each particular platform * you work on. If you have a multi-platform program, you no doubt have * portable definitions that you can substitute here without changing the * rest of the code. */ /* * Function called if something is fatally wrong with the implementation. * This fatal function is called when a coding error is detected in the * Twofish implementation, or when somebody passes an obviously erroneous * parameter to this implementation. There is not much you can do when * the code contains bugs, so we just stop. * * The argument is a string. Ideally the fatal function prints this string * as an error message. Whatever else this function does, it should never * return. A typical implementation would stop the program completely after * printing the error message. * * This default implementation is not very useful, * but does not assume anything about your environment. * It will at least let you know something is wrong.... * I didn't want to include any libraries to print and error or so, * as this makes the code much harder to integrate in a project. * * Note that the Twofish_fatal function may not return to the caller. * Unfortunately this is not something the self-test can test for, * so you have to make sure of this yourself. * * If you want to call an external function, be careful about including * your own header files here. This code uses a lot of macros, and your * header file could easily break it. Maybe the best solution is to use * a separate extern statement for your fatal function. */ /* #define Twofish_fatal(pmsgx) { fprintf(stderr, pmsgx); exit(1); } */ #define Twofish_fatal(pmsgx, code) { return(code); } /* * The rest of the settings are not important for the functionality * of this Twofish implementation. That is, their default settings * work on all platforms. You can change them to improve the * speed of the implementation on your platform. Erroneous settings * will result in erroneous implementations, but the self-test should * catch those. */ /* * Macros to rotate a Twofish_UInt32 value left or right by the * specified number of bits. This should be a 32-bit rotation, * and not rotation of, say, 64-bit values. * * Every encryption or decryption operation uses 32 of these rotations, * so it is a good idea to make these macros efficient. * * This fully portable definition has one piece of tricky stuff. * The UInt32 might be larger than 32 bits, so we have to mask * any higher bits off. The simplest way to do this is to 'and' the * value first with 0xffffffff and then shift it right. An optimising * compiler that has a 32-bit type can optimise this 'and' away. * * Unfortunately there is no portable way of writing the constant * 0xffffffff. You don't know which suffix to use (U, or UL?) * The UINT32_MASK definition uses a bit of trickery. Shift-left * is only defined if the shift amount is strictly less than the size * of the UInt32, so we can't use (1<<32). The answer it to take the value * 2, cast it to a UInt32, shift it left 31 positions, and subtract one. * Another example of how to make something very simple extremely difficult. * I hate C. * * The rotation macros are straightforward. * They are only applied to UInt32 values, which are _unsigned_ * so the >> operator must do a logical shift that brings in zeroes. * On most platforms you will only need to optimise the ROL32 macro; the * ROR32 macro is not inefficient on an optimising compiler as all rotation * amounts in this code are known at compile time. * * On many platforms there is a faster solution. * For example, MS compilers have the __rotl and __rotr functions * that generate x86 rotation instructions. */ #define UINT32_MASK ( (((Twofish_UInt32)2)<<31) - 1 ) #ifndef _MSC_VER #define ROL32(x,n) ( (x)<<(n) | ((x) & UINT32_MASK) >> (32-(n)) ) #define ROR32(x,n) ( (x)>>(n) | ((x) & UINT32_MASK) << (32-(n)) ) #else #define ROL32(x,n) (_lrotl((x), (n))) #define ROR32(x,n) (_lrotr((x), (n))) #endif /* * Select data type for q-table entries. * * Larger entry types cost more memory (1.5 kB), and might be faster * or slower depending on the CPU and compiler details. * * This choice only affects the static data size and the key setup speed. * Functionality, expanded key size, or encryption speed are not affected. * Define to 1 to get large q-table entries. */ #define LARGE_Q_TABLE 0 /* default = 0 */ /* * Method to select a single byte from a UInt32. * WARNING: non-portable code if set; might not work on all platforms. * * Inside the inner loop of Twofish it is necessary to access the 4 * individual bytes of a UInt32. This can be done using either shifts * and masks, or memory accesses. * * Set to 0 to use shift and mask operations for the byte selection. * This is more ALU intensive. It is also fully portable. * * Set to 1 to use memory accesses. The UInt32 is stored in memory and * the individual bytes are read from memory one at a time. * This solution is more memory-intensive, and not fully portable. * It might be faster on your platform, or not. If you use this option, * make sure you set the CPU_IS_BIG_ENDIAN flag appropriately. * * This macro does not affect the conversion of the inputs and outputs * of the cipher. See the CONVERT_USING_CASTS macro for that. */ #define SELECT_BYTE_FROM_UINT32_IN_MEMORY 0 /* default = 0 */ /* * Method used to read the input and write the output. * WARNING: non-portable code if set; might not work on all platforms. * * Twofish operates on 32-bit words. The input to the cipher is * a byte array, as is the output. The portable method of doing the * conversion is a bunch of rotate and mask operations, but on many * platforms it can be done faster using a cast. * This only works if your CPU allows UInt32 accesses to arbitrary Byte * addresses. * * Set to 0 to use the shift and mask operations. This is fully * portable. . * * Set to 1 to use a cast. The Byte * is cast to a UInt32 *, and a * UInt32 is read. If necessary (as indicated by the CPU_IS_BIG_ENDIAN * macro) the byte order in the UInt32 is swapped. The reverse is done * to write the output of the encryption/decryption. Make sure you set * the CPU_IS_BIG_ENDIAN flag appropriately. * This option does not work unless a UInt32 is exactly 32 bits. * * This macro only changes the reading/writing of the plaintext/ciphertext. * See the SELECT_BYTE_FROM_UINT32_IN_MEMORY to affect the way in which * a UInt32 is split into 4 bytes for the S-box selection. */ #define CONVERT_USING_CASTS 0 /* default = 0 */ /* * Endianness switch. * Only relevant if SELECT_BYTE_FROM_UINT32_IN_MEMORY or * CONVERT_USING_CASTS is set. * * Set to 1 on a big-endian machine, and to 0 on a little-endian machine. * Twofish uses the little-endian convention (least significant byte first) * and big-endian machines (using most significant byte first) * have to do a few conversions. * * CAUTION: This code has never been tested on a big-endian machine, * because I don't have access to one. Feedback appreciated. */ #define CPU_IS_BIG_ENDIAN 0 /* * Macro to reverse the order of the bytes in a UInt32. * Used to convert to little-endian on big-endian machines. * This macro is always tested, but only used in the encryption and * decryption if CONVERT_USING_CASTS, and CPU_IS_BIG_ENDIAN * are both set. In other words: this macro is only speed-critical if * both these flags have been set. * * This default definition of SWAP works, but on many platforms there is a * more efficient implementation. */ #define BSWAP(x) ((ROL32((x),8)&0x00ff00ff) | (ROR32((x),8) & 0xff00ff00)) /* * END OF PLATFORM FIXES * ===================== * * You should not have to touch the rest of this file. */ /* * Convert the external type names to some that are easier to use inside * this file. I didn't want to use the names Byte and UInt32 in the * header file, because many programs already define them and using two * conventions at once can be very difficult. * Don't change these definitions! Change the originals * in twofish.h instead. */ /* A Byte must be an unsigned integer, 8 bits long. */ /* typedef Twofish_Byte Byte; */ /* A UInt32 must be an unsigned integer at least 32 bits long. */ /* typedef Twofish_UInt32 UInt32; */ /* * Define a macro ENDIAN_CONVERT. * * We define a macro ENDIAN_CONVERT that performs a BSWAP on big-endian * machines, and is the identity function on little-endian machines. * The code then uses this macro without considering the endianness. */ #if CPU_IS_BIG_ENDIAN #define ENDIAN_CONVERT(x) BSWAP(x) #else #define ENDIAN_CONVERT(x) (x) #endif /* * Compute byte offset within a UInt32 stored in memory. * * This is only used when SELECT_BYTE_FROM_UINT32_IN_MEMORY is set. * * The input is the byte number 0..3, 0 for least significant. * Note the use of sizeof() to support UInt32 types that are larger * than 4 bytes. */ #if CPU_IS_BIG_ENDIAN #define BYTE_OFFSET( n ) (sizeof(Twofish_UInt32) - 1 - (n) ) #else #define BYTE_OFFSET( n ) (n) #endif /* * Macro to get Byte no. b from UInt32 value X. * We use two different definition, depending on the settings. */ #if SELECT_BYTE_FROM_UINT32_IN_MEMORY /* Pick the byte from the memory in which X is stored. */ #define SELECT_BYTE( X, b ) (((Twofish_Byte *)(&(X)))[BYTE_OFFSET(b)]) #else /* Portable solution: Pick the byte directly from the X value. */ #define SELECT_BYTE( X, b ) (((X) >> (8*(b))) & 0xff) #endif /* Some shorthands because we use byte selection in large formulae. */ #define b0(X) SELECT_BYTE((X),0) #define b1(X) SELECT_BYTE((X),1) #define b2(X) SELECT_BYTE((X),2) #define b3(X) SELECT_BYTE((X),3) /* * We need macros to load and store UInt32 from/to byte arrays * using the least-significant-byte-first convention. * * GET32( p ) gets a UInt32 in lsb-first form from four bytes pointed to * by p. * PUT32( v, p ) writes the UInt32 value v at address p in lsb-first form. */ #if CONVERT_USING_CASTS /* Get UInt32 from four bytes pointed to by p. */ #define GET32( p ) ENDIAN_CONVERT( *((Twofish_UInt32 *)(p)) ) /* Put UInt32 into four bytes pointed to by p */ #define PUT32( v, p ) *((Twofish_UInt32 *)(p)) = ENDIAN_CONVERT(v) #else /* Get UInt32 from four bytes pointed to by p. */ #define GET32( p ) \ ( \ (Twofish_UInt32)((p)[0]) \ | (Twofish_UInt32)((p)[1])<< 8 \ | (Twofish_UInt32)((p)[2])<<16 \ | (Twofish_UInt32)((p)[3])<<24 \ ) /* Put UInt32 into four bytes pointed to by p */ #define PUT32( v, p ) \ (p)[0] = (Twofish_Byte)(((v) ) & 0xff); \ (p)[1] = (Twofish_Byte)(((v) >> 8) & 0xff); \ (p)[2] = (Twofish_Byte)(((v) >> 16) & 0xff); \ (p)[3] = (Twofish_Byte)(((v) >> 24) & 0xff) #endif /* * Test the platform-specific macros. * This function tests the macros defined so far to make sure the * definitions are appropriate for this platform. * If you make any mistake in the platform configuration, this should detect * that and inform you what went wrong. * Somewhere, someday, this is going to save somebody a lot of time, * because misbehaving macros are hard to debug. */ static int test_platform() { /* Buffer with test values. */ Twofish_Byte buf[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0}; Twofish_UInt32 C; Twofish_UInt32 x,y; int i; /* * Some sanity checks on the types that can't be done in compile time. * A smart compiler will just optimise these tests away. * The pre-processor doesn't understand different types, so we cannot * do these checks in compile-time. * * I hate C. * * The first check in each case is to make sure the size is correct. * The second check is to ensure that it is an unsigned type. */ if( ((Twofish_UInt32)((Twofish_UInt32)1 << 31) == 0) || ((Twofish_UInt32)-1 < 0 )) { Twofish_fatal( "Twofish code: Twofish_UInt32 type not suitable", ERR_UINT32 ); } if( (sizeof( Twofish_Byte ) != 1) || (((Twofish_Byte)-1) < 0) ) { Twofish_fatal( "Twofish code: Twofish_Byte type not suitable", ERR_BYTE ); } /* * Sanity-check the endianness conversions. * This is just an aid to find problems. If you do the endianness * conversion macros wrong you will fail the full cipher test, * but that does not help you find the error. * Always make it easy to find the bugs! * * Detail: There is no fully portable way of writing UInt32 constants, * as you don't know whether to use the U or UL suffix. Using only U you * might only be allowed 16-bit constants. Using UL you might get 64-bit * constants which cannot be stored in a UInt32 without warnings, and * which generally behave subtly different from a true UInt32. * As long as we're just comparing with the constant, * we can always use the UL suffix and at worst lose some efficiency. * I use a separate '32-bit constant' macro in most of my other code. * * I hate C. * * Start with testing GET32. We test it on all positions modulo 4 * to make sure we can handly any position of inputs. (Some CPUs * do not allow non-aligned accesses which we would do if you used * the CONVERT_USING_CASTS option. */ if( (GET32( buf ) != 0x78563412UL) || (GET32(buf+1) != 0x9a785634UL) || (GET32( buf+2 ) != 0xbc9a7856UL) || (GET32(buf+3) != 0xdebc9a78UL) ) { Twofish_fatal( "Twofish code: GET32 not implemented properly", ERR_GET32 ); } /* * We can now use GET32 to test PUT32. * We don't test the shifted versions. If GET32 can do that then * so should PUT32. */ C = GET32( buf ); PUT32( 3*C, buf ); if( GET32( buf ) != 0x69029c36UL ) { Twofish_fatal( "Twofish code: PUT32 not implemented properly", ERR_PUT32 ); } /* Test ROL and ROR */ for( i=1; i<32; i++ ) { /* Just a simple test. */ x = ROR32( C, i ); y = ROL32( C, i ); x ^= (C>>i) ^ (C<<(32-i)); /*y ^= (C<>(32-i)); */ y ^= (C<>(32-i)); x |= y; /* * Now all we check is that x is zero in the least significant * 32 bits. Using the UL suffix is safe here, as it doesn't matter * if we get a larger type. */ if( (x & 0xffffffffUL) != 0 ) { Twofish_fatal( "Twofish ROL or ROR not properly defined.", ERR_ROLR ); } } /* Test the BSWAP macro */ if( BSWAP(C) != 0x12345678UL ) { /* * The BSWAP macro should always work, even if you are not using it. * A smart optimising compiler will just remove this entire test. */ Twofish_fatal( "BSWAP not properly defined.", ERR_BSWAP ); } /* And we can test the b macros which use SELECT_BYTE. */ if( (b0(C)!=0x12) || (b1(C) != 0x34) || (b2(C) != 0x56) || (b3(C) != 0x78) ) { /* * There are many reasons why this could fail. * Most likely is that CPU_IS_BIG_ENDIAN has the wrong value. */ Twofish_fatal( "Twofish code: SELECT_BYTE not implemented properly", ERR_SELECTB ); } return SUCCESS; } /* * Finally, we can start on the Twofish-related code. * You really need the Twofish specifications to understand this code. The * best source is the Twofish book: * "The Twofish Encryption Algorithm", by Bruce Schneier, John Kelsey, * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson. * you can also use the AES submission document of Twofish, which is * available from my list of publications on my personal web site at * http://niels.ferguson.net/. * * The first thing we do is write the testing routines. This is what the * implementation has to satisfy in the end. We only test the external * behaviour of the implementation of course. */ /* * Perform a single self test on a (plaintext,ciphertext,key) triple. * Arguments: * key array of key bytes * key_len length of key in bytes * p plaintext * c ciphertext */ static int test_vector( Twofish_Byte key[], int key_len, Twofish_Byte p[16], Twofish_Byte c[16] ) { Twofish_Byte tmp[16]; /* scratch pad. */ Twofish_key xkey; /* The expanded key */ int i; /* Prepare the key */ if ((i = Twofish_prepare_key( key, key_len, &xkey)) < 0) return i; /* * We run the test twice to ensure that the xkey structure * is not damaged by the first encryption. * Those are hideous bugs to find if you get them in an application. */ for( i=0; i<2; i++ ) { /* Encrypt and test */ Twofish_encrypt( &xkey, p, tmp ); if( memcmp( c, tmp, 16 ) != 0 ) { Twofish_fatal( "Twofish encryption failure", ERR_TEST_ENC ); } /* Decrypt and test */ Twofish_decrypt( &xkey, c, tmp ); if( memcmp( p, tmp, 16 ) != 0 ) { Twofish_fatal( "Twofish decryption failure", ERR_TEST_DEC ); } } /* The test keys are not secret, so we don't need to wipe xkey. */ return SUCCESS; } /* * Check implementation using three (key,plaintext,ciphertext) * test vectors, one for each major key length. * * This is an absolutely minimal self-test. * This routine does not test odd-sized keys. */ static int test_vectors() { /* * We run three tests, one for each major key length. * These test vectors come from the Twofish specification. * One encryption and one decryption using randomish data and key * will detect almost any error, especially since we generate the * tables ourselves, so we don't have the problem of a single * damaged table entry in the source. */ /* 128-bit test is the I=3 case of section B.2 of the Twofish book. */ static Twofish_Byte k128[] = { 0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A, }; static Twofish_Byte p128[] = { 0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E, 0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19 }; static Twofish_Byte c128[] = { 0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85, 0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3 }; /* 192-bit test is the I=4 case of section B.2 of the Twofish book. */ static Twofish_Byte k192[] = { 0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36, 0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88, 0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44 }; static Twofish_Byte p192[] = { 0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5, 0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2 }; static Twofish_Byte c192[] = { 0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45, 0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65 }; /* 256-bit test is the I=4 case of section B.2 of the Twofish book. */ static Twofish_Byte k256[] = { 0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46, 0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D, 0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B, 0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F }; static Twofish_Byte p256[] = { 0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6 }; static Twofish_Byte c256[] = { 0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97, 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA }; int ret; /* Run the actual tests. */ if ((ret = test_vector( k128, 16, p128, c128 )) < 0) return ret; if ((ret = test_vector( k192, 24, p192, c192 )) < 0) return ret; if ((ret = test_vector( k256, 32, p256, c256 )) < 0) return ret; return SUCCESS; } /* * Perform extensive test for a single key size. * * Test a single key size against the test vectors from section * B.2 in the Twofish book. This is a sequence of 49 encryptions * and decryptions. Each plaintext is equal to the ciphertext of * the previous encryption. The key is made up from the ciphertext * two and three encryptions ago. Both plaintext and key start * at the zero value. * We should have designed a cleaner recurrence relation for * these tests, but it is too late for that now. At least we learned * how to do it better next time. * For details see appendix B of the book. * * Arguments: * key_len Number of bytes of key * final_value Final plaintext value after 49 iterations */ static int test_sequence( int key_len, Twofish_Byte final_value[] ) { Twofish_Byte buf[ (50+3)*16 ]; /* Buffer to hold our computation values. */ Twofish_Byte tmp[16]; /* Temp for testing the decryption. */ Twofish_key xkey; /* The expanded key */ int i, ret; Twofish_Byte * p; /* Wipe the buffer */ memset( buf, 0, sizeof( buf ) ); /* * Because the recurrence relation is done in an inconvenient manner * we end up looping backwards over the buffer. */ /* Pointer in buffer points to current plaintext. */ p = &buf[50*16]; for( i=1; i<50; i++ ) { /* * Prepare a key. * This automatically checks that key_len is valid. */ if ((ret = Twofish_prepare_key( p+16, key_len, &xkey)) < 0) return ret; /* Compute the next 16 bytes in the buffer */ Twofish_encrypt( &xkey, p, p-16 ); /* Check that the decryption is correct. */ Twofish_decrypt( &xkey, p-16, tmp ); if( memcmp( tmp, p, 16 ) != 0 ) { Twofish_fatal( "Twofish decryption failure in sequence", ERR_SEQ_DEC ); } /* Move on to next 16 bytes in the buffer. */ p -= 16; } /* And check the final value. */ if( memcmp( p, final_value, 16 ) != 0 ) { Twofish_fatal( "Twofish encryption failure in sequence", ERR_SEQ_ENC ); } /* None of the data was secret, so there is no need to wipe anything. */ return SUCCESS; } /* * Run all three sequence tests from the Twofish test vectors. * * This checks the most extensive test vectors currently available * for Twofish. The data is from the Twofish book, appendix B.2. */ static int test_sequences() { static Twofish_Byte r128[] = { 0x5D, 0x9D, 0x4E, 0xEF, 0xFA, 0x91, 0x51, 0x57, 0x55, 0x24, 0xF1, 0x15, 0x81, 0x5A, 0x12, 0xE0 }; static Twofish_Byte r192[] = { 0xE7, 0x54, 0x49, 0x21, 0x2B, 0xEE, 0xF9, 0xF4, 0xA3, 0x90, 0xBD, 0x86, 0x0A, 0x64, 0x09, 0x41 }; static Twofish_Byte r256[] = { 0x37, 0xFE, 0x26, 0xFF, 0x1C, 0xF6, 0x61, 0x75, 0xF5, 0xDD, 0xF4, 0xC3, 0x3B, 0x97, 0xA2, 0x05 }; /* Run the three sequence test vectors */ int ret; if ((ret = test_sequence( 16, r128)) < 0) return ret; if ((ret = test_sequence( 24, r192)) < 0) return ret; if ((ret = test_sequence( 32, r256)) < 0) return ret; return SUCCESS; } /* * Test the odd-sized keys. * * Every odd-sized key is equivalent to a one of 128, 192, or 256 bits. * The equivalent key is found by padding at the end with zero bytes * until a regular key size is reached. * * We just test that the key expansion routine behaves properly. * If the expanded keys are identical, then the encryptions and decryptions * will behave the same. */ static int test_odd_sized_keys() { Twofish_Byte buf[32]; Twofish_key xkey; Twofish_key xkey_two; int i, ret; /* * We first create an all-zero key to use as PRNG key. * Normally we would not have to fill the buffer with zeroes, as we could * just pass a zero key length to the Twofish_prepare_key function. * However, this relies on using odd-sized keys, and those are just the * ones we are testing here. We can't use an untested function to test * itself. */ memset( buf, 0, sizeof( buf ) ); if ((ret = Twofish_prepare_key( buf, 16, &xkey)) < 0) return ret; /* Fill buffer with pseudo-random data derived from two encryptions */ Twofish_encrypt( &xkey, buf, buf ); Twofish_encrypt( &xkey, buf, buf+16 ); /* Create all possible shorter keys that are prefixes of the buffer. */ for( i=31; i>=0; i-- ) { /* Set a byte to zero. This is the new padding byte */ buf[i] = 0; /* Expand the key with only i bytes of length */ if ((ret = Twofish_prepare_key( buf, i, &xkey)) < 0) return ret; /* Expand the corresponding padded key of regular length */ if ((ret = Twofish_prepare_key( buf, i<=16 ? 16 : (i<= 24 ? 24 : 32), &xkey_two )) < 0) return ret; /* Compare the two */ if( memcmp( &xkey, &xkey_two, sizeof( xkey ) ) != 0 ) { Twofish_fatal( "Odd sized keys do not expand properly", ERR_ODD_KEY ); } } /* None of the key values are secret, so we don't need to wipe them. */ return SUCCESS; } /* * Test the Twofish implementation. * * This routine runs all the self tests, in order of importance. * It is called by the Twofish_initialise routine. * * In almost all applications the cost of running the self tests during * initialisation is insignificant, especially * compared to the time it takes to load the application from disk. * If you are very pressed for initialisation performance, * you could remove some of the tests. Make sure you did run them * once in the software and hardware configuration you are using. */ static int self_test() { int ret; /* The three test vectors form an absolute minimal test set. */ if ((ret = test_vectors()) < 0) return ret; /* * If at all possible you should run these tests too. They take * more time, but provide a more thorough coverage. */ if ((ret = test_sequences()) < 0) return ret; /* Test the odd-sized keys. */ if ((ret = test_odd_sized_keys()) < 0) return ret; return SUCCESS; } /* * And now, the actual Twofish implementation. * * This implementation generates all the tables during initialisation. * I don't like large tables in the code, especially since they are easily * damaged in the source without anyone noticing it. You need code to * generate them anyway, and this way all the code is close together. * Generating them in the application leads to a smaller executable * (the code is smaller than the tables it generates) and a * larger static memory footprint. * * Twofish can be implemented in many ways. I have chosen to * use large tables with a relatively long key setup time. * If you encrypt more than a few blocks of data it pays to pre-compute * as much as possible. This implementation is relatively inefficient for * applications that need to re-key every block or so. */ /* * We start with the t-tables, directly from the Twofish definition. * These are nibble-tables, but merging them and putting them two nibbles * in one byte is more work than it is worth. */ static Twofish_Byte t_table[2][4][16] = { { {0x8,0x1,0x7,0xD,0x6,0xF,0x3,0x2,0x0,0xB,0x5,0x9,0xE,0xC,0xA,0x4}, {0xE,0xC,0xB,0x8,0x1,0x2,0x3,0x5,0xF,0x4,0xA,0x6,0x7,0x0,0x9,0xD}, {0xB,0xA,0x5,0xE,0x6,0xD,0x9,0x0,0xC,0x8,0xF,0x3,0x2,0x4,0x7,0x1}, {0xD,0x7,0xF,0x4,0x1,0x2,0x6,0xE,0x9,0xB,0x3,0x0,0x8,0x5,0xC,0xA} }, { {0x2,0x8,0xB,0xD,0xF,0x7,0x6,0xE,0x3,0x1,0x9,0x4,0x0,0xA,0xC,0x5}, {0x1,0xE,0x2,0xB,0x4,0xC,0x3,0x7,0x6,0xD,0xA,0x5,0xF,0x9,0x0,0x8}, {0x4,0xC,0x7,0x5,0x1,0x6,0x9,0xA,0x0,0xE,0xD,0x8,0x2,0xB,0x3,0xF}, {0xB,0x9,0x5,0x1,0xC,0x3,0xD,0xE,0x6,0x4,0x7,0xF,0x2,0x0,0x8,0xA} } }; /* A 1-bit rotation of 4-bit values. Input must be in range 0..15 */ #define ROR4BY1( x ) (((x)>>1) | (((x)<<3) & 0x8) ) /* * The q-boxes are only used during the key schedule computations. * These are 8->8 bit lookup tables. Some CPUs prefer to have 8->32 bit * lookup tables as it is faster to load a 32-bit value than to load an * 8-bit value and zero the rest of the register. * The LARGE_Q_TABLE switch allows you to choose 32-bit entries in * the q-tables. Here we just define the Qtype which is used to store * the entries of the q-tables. */ #if LARGE_Q_TABLE typedef Twofish_UInt32 Qtype; #else typedef Twofish_Byte Qtype; #endif /* * The actual q-box tables. * There are two q-boxes, each having 256 entries. */ static Qtype q_table[2][256]; /* * Now the function that converts a single t-table into a q-table. * * Arguments: * t[4][16] : four 4->4bit lookup tables that define the q-box * q[256] : output parameter: the resulting q-box as a lookup table. */ static void make_q_table( Twofish_Byte t[4][16], Qtype q[256] ) { int ae,be,ao,bo; /* Some temporaries. */ int i; /* Loop over all input values and compute the q-box result. */ for( i=0; i<256; i++ ) { /* * This is straight from the Twofish specifications. * * The ae variable is used for the a_i values from the specs * with even i, and ao for the odd i's. Similarly for the b's. */ ae = i>>4; be = i&0xf; ao = ae ^ be; bo = ae ^ ROR4BY1(be) ^ ((ae<<3)&8); ae = t[0][ao]; be = t[1][bo]; ao = ae ^ be; bo = ae ^ ROR4BY1(be) ^ ((ae<<3)&8); ae = t[2][ao]; be = t[3][bo]; /* Store the result in the q-box table, the cast avoids a warning. */ q[i] = (Qtype) ((be<<4) | ae); } } /* * Initialise both q-box tables. */ static void initialise_q_boxes() { /* Initialise each of the q-boxes using the t-tables */ make_q_table( t_table[0], q_table[0] ); make_q_table( t_table[1], q_table[1] ); } /* * Next up is the MDS matrix multiplication. * The MDS matrix multiplication operates in the field * GF(2)[x]/p(x) with p(x)=x^8+x^6+x^5+x^3+1. * If you don't understand this, read a book on finite fields. You cannot * follow the finite-field computations without some background. * * In this field, multiplication by x is easy: shift left one bit * and if bit 8 is set then xor the result with 0x169. * * The MDS coefficients use a multiplication by 1/x, * or rather a division by x. This is easy too: first make the * value 'even' (i.e. bit 0 is zero) by xorring with 0x169 if necessary, * and then shift right one position. * Even easier: shift right and xor with 0xb4 if the lsbit was set. * * The MDS coefficients are 1, EF, and 5B, and we use the fact that * EF = 1 + 1/x + 1/x^2 * 5B = 1 + 1/x^2 * in this field. This makes multiplication by EF and 5B relatively easy. * * This property is no accident, the MDS matrix was designed to allow * this implementation technique to be used. * * We have four MDS tables, each mapping 8 bits to 32 bits. * Each table performs one column of the matrix multiplication. * As the MDS is always preceded by q-boxes, each of these tables * also implements the q-box just previous to that column. */ /* The actual MDS tables. */ static Twofish_UInt32 MDS_table[4][256]; /* A small table to get easy conditional access to the 0xb4 constant. */ static Twofish_UInt32 mds_poly_divx_const[] = {0,0xb4}; /* Function to initialise the MDS tables. */ static void initialise_mds_tables() { int i; Twofish_UInt32 q,qef,q5b; /* Temporary variables. */ /* Loop over all 8-bit input values */ for( i=0; i<256; i++ ) { /* * To save some work during the key expansion we include the last * of the q-box layers from the h() function in these MDS tables. */ /* We first do the inputs that are mapped through the q0 table. */ q = q_table[0][i]; /* * Here we divide by x, note the table to get 0xb4 only if the * lsbit is set. * This sets qef = (1/x)*q in the finite field */ qef = (q >> 1) ^ mds_poly_divx_const[ q & 1 ]; /* * Divide by x again, and add q to get (1+1/x^2)*q. * Note that (1+1/x^2) = 5B in the field, and addition in the field * is exclusive or on the bits. */ q5b = (qef >> 1) ^ mds_poly_divx_const[ qef & 1 ] ^ q; /* * Add q5b to qef to set qef = (1+1/x+1/x^2)*q. * Again, (1+1/x+1/x^2) = EF in the field. */ qef ^= q5b; /* * Now that we have q5b = 5B * q and qef = EF * q * we can fill two of the entries in the MDS matrix table. * See the Twofish specifications for the order of the constants. */ MDS_table[1][i] = (q <<24) | (q5b<<16) | (qef<<8) | qef; MDS_table[3][i] = (q5b<<24) | (qef<<16) | (q <<8) | q5b; /* Now we do it all again for the two columns that have a q1 box. */ q = q_table[1][i]; qef = (q >> 1) ^ mds_poly_divx_const[ q & 1 ]; q5b = (qef >> 1) ^ mds_poly_divx_const[ qef & 1 ] ^ q; qef ^= q5b; /* The other two columns use the coefficient in a different order. */ MDS_table[0][i] = (qef<<24) | (qef<<16) | (q5b<<8) | q ; MDS_table[2][i] = (qef<<24) | (q <<16) | (qef<<8) | q5b; } } /* * The h() function is the heart of the Twofish cipher. * It is a complicated sequence of q-box lookups, key material xors, * and finally the MDS matrix. * We use lots of macros to make this reasonably fast. */ /* First a shorthand for the two q-tables */ #define q0 q_table[0] #define q1 q_table[1] /* * Each macro computes one column of the h for either 2, 3, or 4 stages. * As there are 4 columns, we have 12 macros in all. * * The key bytes are stored in the Byte array L at offset * 0,1,2,3, 8,9,10,11, [16,17,18,19, [24,25,26,27]] as this is the * order we get the bytes from the user. If you look at the Twofish * specs, you'll see that h() is applied to the even key words or the * odd key words. The bytes of the even words appear in this spacing, * and those of the odd key words too. * * These macros are the only place where the q-boxes and the MDS table * are used. */ #define H02( y, L ) MDS_table[0][q0[q0[y]^L[ 8]]^L[0]] #define H12( y, L ) MDS_table[1][q0[q1[y]^L[ 9]]^L[1]] #define H22( y, L ) MDS_table[2][q1[q0[y]^L[10]]^L[2]] #define H32( y, L ) MDS_table[3][q1[q1[y]^L[11]]^L[3]] #define H03( y, L ) H02( q1[y]^L[16], L ) #define H13( y, L ) H12( q1[y]^L[17], L ) #define H23( y, L ) H22( q0[y]^L[18], L ) #define H33( y, L ) H32( q0[y]^L[19], L ) #define H04( y, L ) H03( q1[y]^L[24], L ) #define H14( y, L ) H13( q0[y]^L[25], L ) #define H24( y, L ) H23( q0[y]^L[26], L ) #define H34( y, L ) H33( q1[y]^L[27], L ) /* * Now we can define the h() function given an array of key bytes. * This function is only used in the key schedule, and not to pre-compute * the keyed S-boxes. * * In the key schedule, the input is always of the form k*(1+2^8+2^16+2^24) * so we only provide k as an argument. * * Arguments: * k input to the h() function. * L pointer to array of key bytes at * offsets 0,1,2,3, ... 8,9,10,11, [16,17,18,19, [24,25,26,27]] * kCycles # key cycles, 2, 3, or 4. */ static Twofish_UInt32 h( int k, Twofish_Byte L[], int kCycles ) { switch( kCycles ) { /* We code all 3 cases separately for speed reasons. */ case 2: return H02(k,L) ^ H12(k,L) ^ H22(k,L) ^ H32(k,L); case 3: return H03(k,L) ^ H13(k,L) ^ H23(k,L) ^ H33(k,L); case 4: return H04(k,L) ^ H14(k,L) ^ H24(k,L) ^ H34(k,L); default: /* This is always a coding error, which is fatal. */ Twofish_fatal( "Twofish h(): Illegal argument", ERR_ILL_ARG ); return ERR_ILL_ARG; } } /* * Pre-compute the keyed S-boxes. * Fill the pre-computed S-box array in the expanded key structure. * Each pre-computed S-box maps 8 bits to 32 bits. * * The S argument contains half the number of bytes of the full key, but is * derived from the full key. (See Twofish specifications for details.) * S has the weird byte input order used by the Hxx macros. * * This function takes most of the time of a key expansion. * * Arguments: * S pointer to array of 8*kCycles Bytes containing the S vector. * kCycles number of key words, must be in the set {2,3,4} * xkey pointer to Twofish_key structure that will contain the S-boxes. */ static int fill_keyed_sboxes( Twofish_Byte S[], int kCycles, Twofish_key * xkey ) { int i; switch( kCycles ) { /* We code all 3 cases separately for speed reasons. */ case 2: for( i=0; i<256; i++ ) { xkey->s[0][i]= H02( i, S ); xkey->s[1][i]= H12( i, S ); xkey->s[2][i]= H22( i, S ); xkey->s[3][i]= H32( i, S ); } break; case 3: for( i=0; i<256; i++ ) { xkey->s[0][i]= H03( i, S ); xkey->s[1][i]= H13( i, S ); xkey->s[2][i]= H23( i, S ); xkey->s[3][i]= H33( i, S ); } break; case 4: for( i=0; i<256; i++ ) { xkey->s[0][i]= H04( i, S ); xkey->s[1][i]= H14( i, S ); xkey->s[2][i]= H24( i, S ); xkey->s[3][i]= H34( i, S ); } break; default: /* This is always a coding error, which is fatal. */ Twofish_fatal( "Twofish fill_keyed_sboxes(): Illegal argument", ERR_ILL_ARG ); } return SUCCESS; } /* A flag to keep track of whether we have been initialised or not. */ static int Twofish_initialised = 0; /* * Initialise the Twofish implementation. * This function must be called before any other function in the * Twofish implementation is called. * This routine also does some sanity checks, to make sure that * all the macros behave, and it tests the whole cipher. */ int Twofish_initialise() { int ret; /* First test the various platform-specific definitions. */ if ((ret = test_platform()) < 0) return ret; /* We can now generate our tables, in the right order of course. */ initialise_q_boxes(); initialise_mds_tables(); /* We're finished with the initialisation itself. */ Twofish_initialised = 1; /* * And run some tests on the whole cipher. * Yes, you need to do this every time you start your program. * It is called assurance; you have to be certain that your program * still works properly. */ return self_test(); } /* * The Twofish key schedule uses an Reed-Solomon code matrix multiply. * Just like the MDS matrix, the RS-matrix is designed to be easy * to implement. Details are below in the code. * * These constants make it easy to compute in the finite field used * for the RS code. * * We use Bytes for the RS computation, but these are automatically * widened to unsigned integers in the expressions. Having unsigned * ints in these tables therefore provides the fastest access. */ static unsigned int rs_poly_const[] = {0, 0x14d}; static unsigned int rs_poly_div_const[] = {0, 0xa6 }; /* * Prepare a key for use in encryption and decryption. * Like most block ciphers, Twofish allows the key schedule * to be pre-computed given only the key. * Twofish has a fairly 'heavy' key schedule that takes a lot of time * to compute. The main work is pre-computing the S-boxes used in the * encryption and decryption. We feel that this makes the cipher much * harder to attack. The attacker doesn't even know what the S-boxes * contain without including the entire key schedule in the analysis. * * Unlike most Twofish implementations, this one allows any key size from * 0 to 32 bytes. Odd key sizes are defined for Twofish (see the * specifications); the key is simply padded with zeroes to the next real * key size of 16, 24, or 32 bytes. * Each odd-sized key is thus equivalent to a single normal-sized key. * * Arguments: * key array of key bytes * key_len number of bytes in the key, must be in the range 0,...,32. * xkey Pointer to an Twofish_key structure that will be filled * with the internal form of the cipher key. */ int Twofish_prepare_key( Twofish_Byte key[], int key_len, Twofish_key * xkey ) { /* We use a single array to store all key material in, * to simplify the wiping of the key material at the end. * The first 32 bytes contain the actual (padded) cipher key. * The next 32 bytes contain the S-vector in its weird format, * and we have 4 bytes of overrun necessary for the RS-reduction. */ Twofish_Byte K[32+32+4]; int kCycles; /* # key cycles, 2,3, or 4. */ int i; Twofish_UInt32 A, B; /* Used to compute the round keys. */ Twofish_Byte * kptr; /* Three pointers for the RS computation. */ Twofish_Byte * sptr; Twofish_Byte * t; Twofish_Byte b,bx,bxx; /* Some more temporaries for the RS computation. */ /* Check that the Twofish implementation was initialised. */ if( Twofish_initialised == 0 ) { /* * You didn't call Twofish_initialise before calling this routine. * This is a programming error, and therefore we call the fatal * routine. * * I could of course call the initialisation routine here, * but there are a few reasons why I don't. First of all, the * self-tests have to be done at startup. It is no good to inform * the user that the cipher implementation fails when he wants to * write his data to disk in encrypted form. You have to warn him * before he spends time typing his data. Second, the initialisation * and self test are much slower than a single key expansion. * Calling the initialisation here makes the performance of the * cipher unpredictable. This can lead to really weird problems * if you use the cipher for a real-time task. Suddenly it fails * once in a while the first time you try to use it. Things like * that are almost impossible to debug. */ /* Twofish_fatal( "Twofish implementation was not initialised.", ERR_INIT ); */ /* * There is always a danger that the Twofish_fatal routine returns, * in spite of the specifications that it should not. * (A good programming rule: don't trust the rest of the code.) * This would be disasterous. If the q-tables and MDS-tables have * not been initialised, they are probably still filled with zeroes. * Suppose the MDS-tables are all zero. The key expansion would then * generate all-zero round keys, and all-zero s-boxes. The danger * is that nobody would notice as the encry * mangles the input, and the decryption still 'decrypts' it, * but now in a completely key-independent manner. * To stop such security disasters, we use blunt force. * If your program hangs here: fix the fatal routine! */ for(;;); /* Infinite loop, which beats being insecure. */ } /* Check for valid key length. */ if( key_len < 0 || key_len > 32 ) { /* * This can only happen if a programmer didn't read the limitations * on the key size. */ Twofish_fatal( "Twofish_prepare_key: illegal key length", ERR_KEY_LEN ); /* * A return statement just in case the fatal macro returns. * The rest of the code assumes that key_len is in range, and would * buffer-overflow if it wasn't. * * Why do we still use a programming language that has problems like * buffer overflows, when these problems were solved in 1960 with * the development of Algol? Have we not leared anything? */ return ERR_KEY_LEN; } /* Pad the key with zeroes to the next suitable key length. */ memcpy( K, key, key_len ); memset( K+key_len, 0, sizeof(K)-key_len ); /* * Compute kCycles: the number of key cycles used in the cipher. * 2 for 128-bit keys, 3 for 192-bit keys, and 4 for 256-bit keys. */ kCycles = (key_len + 7) >> 3; /* Handle the special case of very short keys: minimum 2 cycles. */ if( kCycles < 2 ) { kCycles = 2; } /* * From now on we just pretend to have 8*kCycles bytes of * key material in K. This handles all the key size cases. */ /* * We first compute the 40 expanded key words, * formulas straight from the Twofish specifications. */ for( i=0; i<40; i+=2 ) { /* * Due to the byte spacing expected by the h() function * we can pick the bytes directly from the key K. * As we use bytes, we never have the little/big endian * problem. * * Note that we apply the rotation function only to simple * variables, as the rotation macro might evaluate its argument * more than once. */ A = h( i , K , kCycles ); B = h( i+1, K+4, kCycles ); B = ROL32( B, 8 ); /* Compute and store the round keys. */ A += B; B += A; xkey->K[i] = A; xkey->K[i+1] = ROL32( B, 9 ); } /* Wipe variables that contained key material. */ A=B=0; /* * And now the dreaded RS multiplication that few seem to understand. * The RS matrix is not random, and is specially designed to compute the * RS matrix multiplication in a simple way. * * We work in the field GF(2)[x]/x^8+x^6+x^3+x^2+1. Note that this is a * different field than used for the MDS matrix. * (At least, it is a different representation because all GF(2^8) * representations are equivalent in some form.) * * We take 8 consecutive bytes of the key and interpret them as * a polynomial k_0 + k_1 y + k_2 y^2 + ... + k_7 y^7 where * the k_i bytes are the key bytes and are elements of the finite field. * We multiply this polynomial by y^4 and reduce it modulo * y^4 + (x + 1/x)y^3 + (x)y^2 + (x + 1/x)y + 1. * using straightforward polynomial modulo reduction. * The coefficients of the result are the result of the RS * matrix multiplication. When we wrote the Twofish specification, * the original RS definition used the polynomials, * but that requires much more mathematical knowledge. * We were already using matrix multiplication in a finite field for * the MDS matrix, so I re-wrote the RS operation as a matrix * multiplication to reduce the difficulty of understanding it. * Some implementors have not picked up on this simpler method of * computing the RS operation, even though it is mentioned in the * specifications. * * It is possible to perform these computations faster by using 32-bit * word operations, but that is not portable and this is not a speed- * critical area. * * We explained the 1/x computation when we did the MDS matrix. * * The S vector is stored in K[32..64]. * The S vector has to be reversed, so we loop cross-wise. * * Note the weird byte spacing of the S-vector, to match the even * or odd key words arrays. See the discussion at the Hxx macros for * details. */ kptr = K + 8*kCycles; /* Start at end of key */ sptr = K + 32; /* Start at start of S */ /* Loop over all key material */ while( kptr > K ) { kptr -= 8; /* * Initialise the polynimial in sptr[0..12] * The first four coefficients are 0 as we have to multiply by y^4. * The next 8 coefficients are from the key material. */ memset( sptr, 0, 4 ); memcpy( sptr+4, kptr, 8 ); /* * The 12 bytes starting at sptr are now the coefficients of * the polynomial we need to reduce. */ /* Loop over the polynomial coefficients from high to low */ t = sptr+11; /* Keep looping until polynomial is degree 3; */ while( t > sptr+3 ) { /* Pick up the highest coefficient of the poly. */ b = *t; /* * Compute x and (x+1/x) times this coefficient. * See the MDS matrix implementation for a discussion of * multiplication by x and 1/x. We just use different * constants here as we are in a * different finite field representation. * * These two statements set * bx = (x) * b * bxx= (x + 1/x) * b */ bx = (Twofish_Byte)((b<<1) ^ rs_poly_const[ b>>7 ]); bxx= (Twofish_Byte)((b>>1) ^ rs_poly_div_const[ b&1 ] ^ bx); /* * Subtract suitable multiple of * y^4 + (x + 1/x)y^3 + (x)y^2 + (x + 1/x)y + 1 * from the polynomial, except that we don't bother * updating t[0] as it will become zero anyway. */ t[-1] ^= bxx; t[-2] ^= bx; t[-3] ^= bxx; t[-4] ^= b; /* Go to the next coefficient. */ t--; } /* Go to next S-vector word, obeying the weird spacing rules. */ sptr += 8; } /* Wipe variables that contained key material. */ b = bx = bxx = 0; /* And finally, we can compute the key-dependent S-boxes. */ fill_keyed_sboxes( &K[32], kCycles, xkey ); /* Wipe array that contained key material. */ memset( K, 0, sizeof( K ) ); return SUCCESS; } /* * We can now start on the actual encryption and decryption code. * As these are often speed-critical we will use a lot of macros. */ /* * The g() function is the heart of the round function. * We have two versions of the g() function, one without an input * rotation and one with. * The pre-computed S-boxes make this pretty simple. */ #define g0(X,xkey) \ (xkey->s[0][b0(X)]^xkey->s[1][b1(X)]^xkey->s[2][b2(X)]^xkey->s[3][b3(X)]) #define g1(X,xkey) \ (xkey->s[0][b3(X)]^xkey->s[1][b0(X)]^xkey->s[2][b1(X)]^xkey->s[3][b2(X)]) /* * A single round of Twofish. The A,B,C,D are the four state variables, * T0 and T1 are temporaries, xkey is the expanded key, and r the * round number. * * Note that this macro does not implement the swap at the end of the round. */ #define ENCRYPT_RND( A,B,C,D, T0, T1, xkey, r ) \ T0 = g0(A,xkey); T1 = g1(B,xkey);\ C ^= T0+T1+xkey->K[8+2*(r)]; C = ROR32(C,1);\ D = ROL32(D,1); D ^= T0+2*T1+xkey->K[8+2*(r)+1] /* * Encrypt a single cycle, consisting of two rounds. * This avoids the swapping of the two halves. * Parameter r is now the cycle number. */ #define ENCRYPT_CYCLE( A, B, C, D, T0, T1, xkey, r ) \ ENCRYPT_RND( A,B,C,D,T0,T1,xkey,2*(r) );\ ENCRYPT_RND( C,D,A,B,T0,T1,xkey,2*(r)+1 ) /* Full 16-round encryption */ #define ENCRYPT( A,B,C,D,T0,T1,xkey ) \ ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 0 );\ ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 1 );\ ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 2 );\ ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 3 );\ ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 4 );\ ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 5 );\ ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 6 );\ ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 7 ) /* * A single round of Twofish for decryption. It differs from * ENCRYTP_RND only because of the 1-bit rotations. */ #define DECRYPT_RND( A,B,C,D, T0, T1, xkey, r ) \ T0 = g0(A,xkey); T1 = g1(B,xkey);\ C = ROL32(C,1); C ^= T0+T1+xkey->K[8+2*(r)];\ D ^= T0+2*T1+xkey->K[8+2*(r)+1]; D = ROR32(D,1) /* * Decrypt a single cycle, consisting of two rounds. * This avoids the swapping of the two halves. * Parameter r is now the cycle number. */ #define DECRYPT_CYCLE( A, B, C, D, T0, T1, xkey, r ) \ DECRYPT_RND( A,B,C,D,T0,T1,xkey,2*(r)+1 );\ DECRYPT_RND( C,D,A,B,T0,T1,xkey,2*(r) ) /* Full 16-round decryption. */ #define DECRYPT( A,B,C,D,T0,T1, xkey ) \ DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 7 );\ DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 6 );\ DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 5 );\ DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 4 );\ DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 3 );\ DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 2 );\ DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 1 );\ DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 0 ) /* * A macro to read the state from the plaintext and do the initial key xors. * The koff argument allows us to use the same macro * for the decryption which uses different key words at the start. */ #define GET_INPUT( src, A,B,C,D, xkey, koff ) \ A = GET32(src )^xkey->K[ koff]; B = GET32(src+ 4)^xkey->K[1+koff]; \ C = GET32(src+ 8)^xkey->K[2+koff]; D = GET32(src+12)^xkey->K[3+koff] /* * Similar macro to put the ciphertext in the output buffer. * We xor the keys into the state variables before we use the PUT32 * macro as the macro might use its argument multiple times. */ #define PUT_OUTPUT( A,B,C,D, dst, xkey, koff ) \ A ^= xkey->K[ koff]; B ^= xkey->K[1+koff]; \ C ^= xkey->K[2+koff]; D ^= xkey->K[3+koff]; \ PUT32( A, dst ); PUT32( B, dst+ 4 ); \ PUT32( C, dst+8 ); PUT32( D, dst+12 ) /* * Twofish block encryption * * Arguments: * xkey expanded key array * p 16 bytes of plaintext * c 16 bytes in which to store the ciphertext */ void Twofish_encrypt( Twofish_key * xkey, Twofish_Byte p[16], Twofish_Byte c[16]) { Twofish_UInt32 A,B,C,D,T0,T1; /* Working variables */ /* Get the four plaintext words xorred with the key */ GET_INPUT( p, A,B,C,D, xkey, 0 ); /* Do 8 cycles (= 16 rounds) */ ENCRYPT( A,B,C,D,T0,T1,xkey ); /* Store them with the final swap and the output whitening. */ PUT_OUTPUT( C,D,A,B, c, xkey, 4 ); } /* * Twofish block decryption. * * Arguments: * xkey expanded key array * p 16 bytes of plaintext * c 16 bytes in which to store the ciphertext */ void Twofish_decrypt( Twofish_key * xkey, Twofish_Byte c[16], Twofish_Byte p[16]) { Twofish_UInt32 A,B,C,D,T0,T1; /* Working variables */ /* Get the four plaintext words xorred with the key */ GET_INPUT( c, A,B,C,D, xkey, 4 ); /* Do 8 cycles (= 16 rounds) */ DECRYPT( A,B,C,D,T0,T1,xkey ); /* Store them with the final swap and the output whitening. */ PUT_OUTPUT( C,D,A,B, p, xkey, 0 ); } /* * Using the macros it is easy to make special routines for * CBC mode, CTR mode etc. The only thing you might want to * add is a XOR_PUT_OUTPUT which xors the outputs into the * destinationa instead of overwriting the data. This requires * a XOR_PUT32 macro as well, but that should all be trivial. * * I thought about including routines for the separate cipher * modes here, but it is unclear which modes should be included, * and each encryption or decryption routine takes up a lot of code space. * Also, I don't have any test vectors for any cipher modes * with Twofish. */ libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/twofish_cfb.c0000755000175000017500000000320411570305710021654 0ustar dyfetdyfet#include #include #include "twofish.h" void Twofish_cfb128_encrypt(Twofish_key* keyCtx, Twofish_Byte* in, Twofish_Byte* out, size_t len, Twofish_Byte* ivec, int32_t *num) { uint32_t n; n = *num; do { while (n && len) { *(out++) = ivec[n] ^= *(in++); --len; n = (n+1) % 16; } while (len>=16) { Twofish_encrypt(keyCtx, ivec, ivec); for (n=0; n<16; n+=sizeof(size_t)) { *(size_t*)(out+n) = *(size_t*)(ivec+n) ^= *(size_t*)(in+n); } len -= 16; out += 16; in += 16; } n = 0; if (len) { Twofish_encrypt(keyCtx, ivec, ivec); while (len--) { out[n] = ivec[n] ^= in[n]; ++n; } } *num = n; return; } while (0); } void Twofish_cfb128_decrypt(Twofish_key* keyCtx, Twofish_Byte* in, Twofish_Byte* out, size_t len, Twofish_Byte* ivec, int32_t *num) { uint32_t n; n = *num; do { while (n && len) { unsigned char c; *(out++) = ivec[n] ^ (c = *(in++)); ivec[n] = c; --len; n = (n+1) % 16; } while (len>=16) { Twofish_encrypt(keyCtx, ivec, ivec); for (n=0; n<16; n+=sizeof(size_t)) { size_t t = *(size_t*)(in+n); *(size_t*)(out+n) = *(size_t*)(ivec+n) ^ t; *(size_t*)(ivec+n) = t; } len -= 16; out += 16; in += 16; } n = 0; if (len) { Twofish_encrypt(keyCtx, ivec, ivec); while (len--) { unsigned char c; out[n] = ivec[n] ^ (c = in[n]); ivec[n] = c; ++n; } } *num = n; return; } while (0); } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/TwoCFB.cpp0000755000175000017500000000523011570305710021004 0ustar dyfetdyfet/* Copyright (C) 2011 by Werner Dittmann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ /** Copyright (C) 2011 * * @author Werner Dittmann */ #include #include #include static int initialized = 0; void twoCfbEncrypt(uint8_t* key, int32_t keyLength, uint8_t* IV, uint8_t *data, int32_t dataLength) { Twofish_key keyCtx; int usedBytes = 0; if (!initialized) { Twofish_initialise(); initialized = 1; } memset(&keyCtx, 0, sizeof(Twofish_key)); Twofish_prepare_key(key, keyLength, &keyCtx); Twofish_cfb128_encrypt(&keyCtx, (Twofish_Byte*)data, (Twofish_Byte*)data, (size_t)dataLength, (Twofish_Byte*)IV, &usedBytes); } void twoCfbDecrypt(uint8_t* key, int32_t keyLength, const uint8_t* IV, uint8_t *data, int32_t dataLength) { Twofish_key keyCtx; int usedBytes = 0; if (!initialized) { Twofish_initialise(); initialized = 1; } memset(&keyCtx, 0, sizeof(Twofish_key)); Twofish_prepare_key(key, keyLength, &keyCtx); Twofish_cfb128_decrypt(&keyCtx, (Twofish_Byte*)data, (Twofish_Byte*)data, (size_t)dataLength, (Twofish_Byte*)IV, &usedBytes); } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/twoCFB.h0000755000175000017500000000466611570305710020525 0ustar dyfetdyfet/* 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 */ #ifndef _TWOCFB_H__ #define _TWOCFB_H__ #include /** * @file aesCFB.h * @brief Function that provide AES CFB mode support * * @ingroup GNU_ZRTP * @{ */ #ifndef TWO_BLOCK_SIZE #define TWO_BLOCK_SIZE 16 #endif /** * Encrypt data with Twofish CFB mode, full block feedback size. * * This functions takes one data chunk and encrypts it with * Twofish CFB mode. The lenght of the data may be arbitrary and * it is not needed to be a multiple of Twofish blocksize. * * @param key * Points to the key bytes. * @param keyLength * Length of the key in bytes * @param IV * The initialization vector which must be TWO_BLOCKSIZE (16) bytes. * @param data * Points to a buffer that contains and receives the computed * the data (in-place encryption). * @param dataLength * Length of the data in bytes */ void twoCfbEncrypt(uint8_t* key, int32_t keyLength, uint8_t* IV, uint8_t *data, int32_t dataLength); /** * Decrypt data with Twofish CFB mode, full block feedback size. * * This functions takes one data chunk and decrypts it with * Twofish CFB mode. The lenght of the data may be arbitrary and * it is not needed to be a multiple of Twofish blocksize. * * @param key * Points to the key bytes. * @param keyLength * Length of the key in bytes * @param IV * The initialization vector which must be TWO_BLOCKSIZE (16) bytes. * @param data * Points to a buffer that contains and receives the computed * the data (in-place decryption). * @param dataLength * Length of the data in bytes */ void twoCfbDecrypt(uint8_t* key, int32_t keyLength, const uint8_t* IV, uint8_t *data, int32_t dataLength); /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/openssl/0000755000175000017500000000000011570305710020674 5ustar dyfetdyfetlibzrtpcpp-2.0.0/src/libzrtpcpp/crypto/openssl/ZrtpDH.cpp0000644000175000017500000003743211570305710022564 0ustar dyfetdyfet/* Copyright (C) 2006, 2009 by Werner Dittmann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ /** Copyright (C) 2006, 2009 * * @author Werner Dittmann */ #include #include #include #include #include #include #include #include #include #include #include #include // extern void initializeOpenSSL(); static BIGNUM* bnP2048 = NULL; static BIGNUM* bnP3072 = NULL; // static BIGNUM* bnP4096 = NULL; static BIGNUM* bnP2048MinusOne = NULL; static BIGNUM* bnP3072MinusOne = NULL; // static BIGNUM* bnP4096MinusOne = NULL; static uint8_t dhinit = 0; void randomZRTP(uint8_t *buf, int32_t length) { // initializeOpenSSL(); RAND_bytes(buf, length); } static const uint8_t P2048[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static const uint8_t P3072[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* ************** static const uint8_t P4096[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; *************** */ ZrtpDH::ZrtpDH(const char* type) { uint8_t random[64]; // Well - the algo type is only 4 char thus cast to int32 and compare if (*(int32_t*)type == *(int32_t*)dh2k) { pkType = DH2K; } else if (*(int32_t*)type == *(int32_t*)dh3k) { pkType = DH3K; } else if (*(int32_t*)type == *(int32_t*)ec25) { pkType = EC25; } else if (*(int32_t*)type == *(int32_t*)ec38) { pkType = EC38; } else { return; } // initializeOpenSSL(); if (!dhinit) { bnP2048 = BN_bin2bn(P2048,sizeof(P2048),NULL); bnP3072 = BN_bin2bn(P3072,sizeof(P3072),NULL); // bnP4096 = BN_bin2bn(P4096,sizeof(P4096),NULL); bnP2048MinusOne = BN_dup(bnP2048); BN_sub_word(bnP2048MinusOne, 1); bnP3072MinusOne = BN_dup(bnP3072); BN_sub_word(bnP3072MinusOne, 1); // bnP4096MinusOne = BN_dup(bnP4096); // BN_sub_word(bnP4096MinusOne, 1); dhinit = 1; } DH* tmpCtx = NULL; switch (pkType) { case DH2K: case DH3K: ctx = static_cast(DH_new()); tmpCtx = static_cast(ctx); tmpCtx->g = BN_new(); BN_set_word(tmpCtx->g, DH_GENERATOR_2); if (pkType == DH2K) { tmpCtx->p = BN_dup(bnP2048); RAND_bytes(random, 32); tmpCtx->priv_key = BN_bin2bn(random, 32, NULL); } else if (pkType == DH3K) { tmpCtx->p = BN_dup(bnP3072); RAND_bytes(random, 64); tmpCtx->priv_key = BN_bin2bn(random, 32, NULL); } break; case EC25: ctx = static_cast(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); break; case EC38: ctx = static_cast(EC_KEY_new_by_curve_name(NID_secp384r1)); break; } } ZrtpDH::~ZrtpDH() { if (ctx == NULL) return; switch (pkType) { case DH2K: case DH3K: DH_free(static_cast(ctx)); break; case EC25: case EC38: EC_KEY_free(static_cast(ctx)); break; } } int32_t ZrtpDH::computeSecretKey(uint8_t *pubKeyBytes, uint8_t *secret) { if (pkType == DH2K || pkType == DH3K) { DH* tmpCtx = static_cast(ctx); if (tmpCtx->pub_key != NULL) { BN_free(tmpCtx->pub_key); } tmpCtx->pub_key = BN_bin2bn(pubKeyBytes, getDhSize(), NULL); return DH_compute_key(secret, tmpCtx->pub_key, tmpCtx); } if (pkType == EC25 || pkType == EC38) { uint8_t buffer[100]; int32_t ret; int32_t len = getPubKeySize(); buffer[0] = POINT_CONVERSION_UNCOMPRESSED; memcpy(buffer+1, pubKeyBytes, len); EC_POINT* point = EC_POINT_new(EC_KEY_get0_group(static_cast(ctx))); EC_POINT_oct2point(EC_KEY_get0_group(static_cast(ctx)), point, buffer, len+1, NULL); ret = ECDH_compute_key(secret, getDhSize(), point, static_cast(ctx), NULL); EC_POINT_free(point); return ret; } return -1; } int32_t ZrtpDH::generatePublicKey() { if (pkType == DH2K || pkType == DH3K) return DH_generate_key(static_cast(ctx)); if (pkType == EC25 || pkType == EC38) return EC_KEY_generate_key(static_cast(ctx)); return 0; } int32_t ZrtpDH::getDhSize() const { if (pkType == DH2K || pkType == DH3K) return DH_size(static_cast(ctx)); if (pkType == EC25) return 32; if (pkType == EC38) return 48; return 0; } int32_t ZrtpDH::getPubKeySize() const { if (pkType == DH2K || pkType == DH3K) return BN_num_bytes(static_cast(ctx)->pub_key); if (pkType == EC25 || pkType == EC38) return EC_POINT_point2oct(EC_KEY_get0_group(static_cast(ctx)), EC_KEY_get0_public_key(static_cast(ctx)), POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL) - 1; return 0; } int32_t ZrtpDH::getPubKeyBytes(uint8_t *buf) const { if (pkType == DH2K || pkType == DH3K) { // get len of pub_key, prepend with zeros to DH size int32_t prepend = getDhSize() - getPubKeySize(); if (prepend > 0) { memset(buf, 0, prepend); } return BN_bn2bin(static_cast(ctx)->pub_key, buf + prepend); } if (pkType == EC25 || pkType == EC38) { uint8_t buffer[100]; int len = EC_POINT_point2oct(EC_KEY_get0_group(static_cast(ctx)), EC_KEY_get0_public_key(static_cast(ctx)), POINT_CONVERSION_UNCOMPRESSED, buffer, 100, NULL); memcpy(buf, buffer+1, len-1); return len-1; } return 0; } int32_t ZrtpDH::checkPubKey(uint8_t *pubKeyBytes) const { if (pkType == EC25 || pkType == EC38) { uint8_t buffer[100]; int32_t ret; int32_t len = getPubKeySize(); buffer[0] = POINT_CONVERSION_UNCOMPRESSED; memcpy(buffer+1, pubKeyBytes, len); EC_POINT* point = EC_POINT_new(EC_KEY_get0_group(static_cast(ctx))); EC_POINT_oct2point(EC_KEY_get0_group(static_cast(ctx)), point, buffer, len+1, NULL); EC_KEY* chkKey = EC_KEY_new(); EC_KEY_set_group(chkKey, EC_KEY_get0_group(static_cast(ctx))); EC_KEY_set_public_key(chkKey, point); ret = EC_KEY_check_key(chkKey); EC_POINT_free(point); EC_KEY_free(chkKey); return ret; } BIGNUM* pubKeyOther = BN_bin2bn(pubKeyBytes, getDhSize(), NULL); if (pkType == DH2K) { if (BN_cmp(bnP2048MinusOne, pubKeyOther) == 0) return 0; } else if (pkType == DH3K) { if (BN_cmp(bnP3072MinusOne, pubKeyOther) == 0) return 0; } else { // if (BN_cmp(bnP4096MinusOne, pubKeyOther) == 0) return 0; } int one = BN_is_one(pubKeyOther); if (one == 1) return 0; BN_free(pubKeyOther); return 1; } const char* ZrtpDH::getDHtype() { switch (pkType) { case DH2K: return dh2k; break; case DH3K: return dh3k; break; case EC25: return ec25; break; case EC38: return ec38; break; } return NULL; } /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/openssl/sha256.cpp0000644000175000017500000000565511570305710022423 0ustar dyfetdyfet/* Copyright (C) 2005, 2004 Erik Eliasson, Johan Bilien This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ /** * @author Erik Eliasson * Johan Bilien * Werner Dittmann */ #include #include #include void sha256(unsigned char *data, unsigned int data_length, unsigned char *digest ) { SHA256(data, data_length, digest); } void sha256(unsigned char * data_chunks[], unsigned int data_chunck_length[], unsigned char *digest) { SHA256_CTX ctx; SHA256_Init( &ctx); while(*data_chunks) { SHA256_Update(&ctx, *data_chunks, *data_chunck_length); data_chunks++; data_chunck_length++; } SHA256_Final(digest, &ctx); } void* createSha256Context() { SHA256_CTX* ctx = (SHA256_CTX*)malloc(sizeof (SHA256_CTX)); SHA256_Init(ctx); return (void*)ctx; } void closeSha256Context(void* ctx, unsigned char* digest) { SHA256_CTX* hd = (SHA256_CTX*)ctx; if (digest != NULL) { SHA256_Final(digest, hd); } free(hd); } void sha256Ctx(void* ctx, unsigned char* data, unsigned int dataLength) { SHA256_CTX* hd = (SHA256_CTX*)ctx; SHA256_Update(hd, data, dataLength); } void sha256Ctx(void* ctx, unsigned char* dataChunks[], unsigned int dataChunkLength[]) { SHA256_CTX* hd = (SHA256_CTX*)ctx; while (*dataChunks) { SHA256_Update (hd, *dataChunks, *dataChunkLength); dataChunks++; dataChunkLength++; } } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/openssl/sha384.cpp0000644000175000017500000000565511570305710022425 0ustar dyfetdyfet/* Copyright (C) 2005, 2004 Erik Eliasson, Johan Bilien This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ /** * @author Erik Eliasson * Johan Bilien * Werner Dittmann */ #include #include #include void sha384(unsigned char *data, unsigned int data_length, unsigned char *digest ) { SHA384(data, data_length, digest); } void sha384(unsigned char * data_chunks[], unsigned int data_chunck_length[], unsigned char *digest) { SHA512_CTX ctx; SHA384_Init( &ctx); while(*data_chunks) { SHA384_Update(&ctx, *data_chunks, *data_chunck_length); data_chunks++; data_chunck_length++; } SHA384_Final(digest, &ctx); } void* createSha384Context() { SHA512_CTX* ctx = (SHA512_CTX*)malloc(sizeof (SHA512_CTX)); SHA384_Init(ctx); return (void*)ctx; } void closeSha384Context(void* ctx, unsigned char* digest) { SHA512_CTX* hd = (SHA512_CTX*)ctx; if (digest != NULL) { SHA384_Final(digest, hd); } free(hd); } void sha384Ctx(void* ctx, unsigned char* data, unsigned int dataLength) { SHA512_CTX* hd = (SHA512_CTX*)ctx; SHA384_Update(hd, data, dataLength); } void sha384Ctx(void* ctx, unsigned char* dataChunks[], unsigned int dataChunkLength[]) { SHA512_CTX* hd = (SHA512_CTX*)ctx; while (*dataChunks) { SHA384_Update (hd, *dataChunks, *dataChunkLength); dataChunks++; dataChunkLength++; } } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/openssl/InitializeOpenSSL.cpp0000755000175000017500000001310111570305710024704 0ustar dyfetdyfet/* Copyright (C) 2006 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 2, 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, write to the Free Software Foundation, Inc., 59 Temple Place, Boston, MA 02111. */ #include #include #include #ifdef _MSWINDOWS_ #include #endif #if defined SOLARIS && !defined HAVE_PTHREAD_H #include #include #endif #if !defined _MSWINDOWS_ && !defined SOLARIS #include #endif #ifdef const #undef const #endif static void threadLockSetup(void); static void threadLockCleanup(void); static void myLockingCallback(int, int, const char *, int); /** * Implement the locking callback functions for openSSL. * * Unfortunatly we can't use the Commonc++ Mutex here because the * Mutex may use (for some cases) the Commonc++ Thread class. OpenSSL * does not use this Thread class. */ static int initialized = 0; int initializeOpenSSL () { if (initialized) { return 1; } initialized = 1; threadLockSetup(); return 1; } int finalizeOpenSSL () { if(!initialized) return 1; initialized = 0; threadLockCleanup(); return 1; } #ifdef _MSWINDOWS_ static HANDLE *lock_cs; static void threadLockSetup(void) { int i; lock_cs=(HANDLE*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(HANDLE)); for (i = 0; i < CRYPTO_num_locks(); i++) { lock_cs[i] = CreateMutex(NULL,FALSE,NULL); } CRYPTO_set_locking_callback((void (*)(int,int,const char *,int))myLockingCallback); /* id callback defined */ } static void threadLockCleanup(void) { int i; CRYPTO_set_locking_callback(NULL); for (i = 0; i < CRYPTO_num_locks(); i++) { CloseHandle(lock_cs[i]); } OPENSSL_free(lock_cs); } static void myLockingCallback(int mode, int type, const char *file, int line) { if (mode & CRYPTO_LOCK) { WaitForSingleObject(lock_cs[type], INFINITE); } else { ReleaseMutex(lock_cs[type]); } } #endif /* OPENSSL_SYS_WIN32 */ #if defined SOLARIS && !defined HAVE_PTHREAD_H static mutex_t *lock_cs; static long *lock_count; static void threadLockSetup(void) { int i; lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(mutex_t)); lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long)); for (i = 0; i < CRYPTO_num_locks(); i++) { lock_count[i] = 0; /* rwlock_init(&(lock_cs[i]),USYNC_THREAD,NULL); */ mutex_init(&(lock_cs[i]), USYNC_THREAD, NULL); } CRYPTO_set_locking_callback((void (*)(int, int ,const char *, int))myLockingCallback); } static void threadLockCleanup(void) { int i; CRYPTO_set_locking_callback(NULL); fprintf(stderr,"cleanup\n"); for (i = 0; i < CRYPTO_num_locks(); i++) { /* rwlock_destroy(&(lock_cs[i])); */ mutex_destroy(&(lock_cs[i])); fprintf(stderr,"%8ld:%s\n",lock_count[i],CRYPTO_get_lock_name(i)); } OPENSSL_free(lock_cs); OPENSSL_free(lock_count); } static void myLockingCallback(int mode, int type, const char *file, int line) { #ifdef undef fprintf(stderr,"thread=%4d mode=%s lock=%s %s:%d\n", CRYPTO_thread_id(), (mode&CRYPTO_LOCK)?"l":"u", (type&CRYPTO_READ)?"r":"w",file,line); #endif /* if (CRYPTO_LOCK_SSL_CERT == type) fprintf(stderr,"(t,m,f,l) %ld %d %s %d\n", CRYPTO_thread_id(), mode,file,line); */ if (mode & CRYPTO_LOCK) { mutex_lock(&(lock_cs[type])); lock_count[type]++; } else { mutex_unlock(&(lock_cs[type])); } } static unsigned long solaris_thread_id(void) { unsigned long ret; ret=(unsigned long)thr_self(); return(ret); } #endif /* SOLARIS */ static pthread_mutex_t* lock_cs; static long* lock_count; static void threadLockSetup(void) { int i; lock_cs = (pthread_mutex_t*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)); lock_count = (long*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long)); for (i = 0; i < CRYPTO_num_locks(); i++) { lock_count[i] = 0; pthread_mutex_init(&(lock_cs[i]),NULL); } // CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id); CRYPTO_set_locking_callback((void (*)(int,int,const char *, int))myLockingCallback); } static void threadLockCleanup(void) { int i; CRYPTO_set_locking_callback(NULL); fprintf(stderr,"cleanup\n"); for (i = 0; i < CRYPTO_num_locks(); i++) { pthread_mutex_destroy(&(lock_cs[i])); fprintf(stderr,"%8ld:%s\n",lock_count[i], CRYPTO_get_lock_name(i)); } OPENSSL_free(lock_cs); OPENSSL_free(lock_count); } static void myLockingCallback(int mode, int type, const char *file, int line) { #ifdef undef fprintf(stderr,"thread=%4d mode=%s lock=%s %s:%d\n", CRYPTO_thread_id(), (mode&CRYPTO_LOCK)?"l":"u", (type&CRYPTO_READ)?"r":"w",file,line); #endif if (mode & CRYPTO_LOCK) { pthread_mutex_lock(&(lock_cs[type])); lock_count[type]++; } else { pthread_mutex_unlock(&(lock_cs[type])); } } /* static unsigned long pthreads_thread_id(void) { unsigned long ret; ret = (unsigned long)pthread_self(); return(ret); } */ libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/openssl/hmac384.cpp0000644000175000017500000000472311570305710022555 0ustar dyfetdyfet/* Copyright (C) 2005, 2004 Erik Eliasson, Johan Bilien This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ /* * Authors: Erik Eliasson * Johan Bilien */ #include #include void hmac_sha384(uint8_t* key, uint32_t key_length, uint8_t* data, int32_t data_length, uint8_t* mac, uint32_t* mac_length) { unsigned int tmp; HMAC( EVP_sha384(), key, key_length, data, data_length, mac, &tmp ); *mac_length = tmp; } void hmac_sha384(uint8_t* key, uint32_t key_length, uint8_t* data_chunks[], uint32_t data_chunck_length[], uint8_t* mac, uint32_t* mac_length ) { unsigned int tmp; HMAC_CTX ctx; HMAC_CTX_init( &ctx ); HMAC_Init_ex( &ctx, key, key_length, EVP_sha384(), NULL ); while( *data_chunks ){ HMAC_Update( &ctx, *data_chunks, *data_chunck_length ); data_chunks ++; data_chunck_length ++; } HMAC_Final( &ctx, mac, &tmp); *mac_length = tmp; HMAC_CTX_cleanup( &ctx ); } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/openssl/AesCFB.cpp0000644000175000017500000000550011570305710022423 0ustar dyfetdyfet/* Copyright (C) 2006, 2007 by Werner Dittmann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ /** Copyright (C) 2006, 2007 * * @author Werner Dittmann */ #include #include #include #include // extern void initializeOpenSSL(); void aesCfbEncrypt(uint8_t* key, int32_t keyLength, uint8_t* IV, uint8_t *data, int32_t dataLength) { AES_KEY aesKey; int usedBytes = 0; // initializeOpenSSL(); memset(&aesKey, 0, sizeof( AES_KEY ) ); if (keyLength == 16) { AES_set_encrypt_key(key, 128, &aesKey); } else if (keyLength == 32) { AES_set_encrypt_key(key, 256, &aesKey); } else { return; } AES_cfb128_encrypt(data, data, dataLength, &aesKey, IV, &usedBytes, AES_ENCRYPT); } void aesCfbDecrypt(uint8_t* key, int32_t keyLength, const uint8_t* IV, uint8_t *data, int32_t dataLength) { AES_KEY aesKey; int usedBytes = 0; // initializeOpenSSL(); memset(&aesKey, 0, sizeof( AES_KEY ) ); if (keyLength == 16) { AES_set_encrypt_key(key, 128, &aesKey); } else if (keyLength == 32) { AES_set_encrypt_key(key, 256, &aesKey); } else { return; } AES_cfb128_encrypt(data, data, dataLength, &aesKey, (unsigned char*)IV, &usedBytes, AES_DECRYPT); } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/openssl/hmac256.cpp0000644000175000017500000000472311570305710022553 0ustar dyfetdyfet/* Copyright (C) 2005, 2004 Erik Eliasson, Johan Bilien This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ /* * Authors: Erik Eliasson * Johan Bilien */ #include #include void hmac_sha256(uint8_t* key, uint32_t key_length, uint8_t* data, int32_t data_length, uint8_t* mac, uint32_t* mac_length) { unsigned int tmp; HMAC( EVP_sha256(), key, key_length, data, data_length, mac, &tmp ); *mac_length = tmp; } void hmac_sha256(uint8_t* key, uint32_t key_length, uint8_t* data_chunks[], uint32_t data_chunck_length[], uint8_t* mac, uint32_t* mac_length ) { unsigned int tmp; HMAC_CTX ctx; HMAC_CTX_init( &ctx ); HMAC_Init_ex( &ctx, key, key_length, EVP_sha256(), NULL ); while( *data_chunks ){ HMAC_Update( &ctx, *data_chunks, *data_chunck_length ); data_chunks ++; data_chunck_length ++; } HMAC_Final( &ctx, mac, &tmp); *mac_length = tmp; HMAC_CTX_cleanup( &ctx ); } libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/hmac256.h0000644000175000017500000000555011570305710020534 0ustar dyfetdyfet/* Copyright (C) 2006, 2005, 2004 Erik Eliasson, Johan Bilien, Werner Dittmann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * Methods to compute a SHA256 HMAC. * * @author Erik Eliasson * @author Johan Bilien * @author Werner Dittmann */ #ifndef HMAC_SHA256_H #define HMAC_SHA256_H /** * @file hmac256.h * @brief Function that provide SHA256 HMAC support * * @ingroup GNU_ZRTP * @{ */ #include #ifndef SHA256_DIGEST_LENGTH #define SHA256_DIGEST_LENGTH 32 #endif /** * Compute SHA256 HMAC. * * This functions takes one data chunk and computes its SHA256 HMAC. * * @param key * The MAC key. * @param key_length * Lneght of the MAC key in bytes * @param data * Points to the data chunk. * @param data_length * Length of the data in bytes * @param mac * Points to a buffer that receives the computed digest. This * buffer must have a size of at least 32 bytes (SHA256_DIGEST_LENGTH). * @param mac_length * Point to an integer that receives the length of the computed HMAC. */ void hmac_sha256( uint8_t* key, uint32_t key_length, uint8_t* data, int32_t data_length, uint8_t* mac, uint32_t* mac_length ); /** * Compute SHA256 HMAC over several data cunks. * * This functions takes several data chunk and computes the SHA256 HAMAC. It * uses the openSSL HAMAC SHA256 implementation. * * @param key * The MAC key. * @param key_length * Lneght of the MAC key in bytes * @param data * Points to an array of pointers that point to the data chunks. A NULL * pointer in an array element terminates the data chunks. * @param data_length * Points to an array of integers that hold the length of each data chunk. * @param mac * Points to a buffer that receives the computed digest. This * buffer must have a size of at least 32 bytes (SHA256_DIGEST_LENGTH). * @param mac_length * Point to an integer that receives the length of the computed HMAC. */ void hmac_sha256( uint8_t* key, uint32_t key_length, uint8_t* data[], uint32_t data_length[], uint8_t* mac, uint32_t* mac_length ); /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/hmac384.h0000644000175000017500000000555611570305710020544 0ustar dyfetdyfet/* Copyright (C) 2009, 2006, 2005, 2004 Erik Eliasson, Johan Bilien, Werner Dittmann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * Methods to compute a SHA384 HMAC. * * @author Erik Eliasson * @author Johan Bilien * @author Werner Dittmann */ #ifndef HMAC_SHA384_H #define HMAC_SHA384_H /** * @file hmac384.h * @brief Function that provide SHA384 HMAC support * * @ingroup GNU_ZRTP * @{ */ #include #ifndef SHA384_DIGEST_LENGTH #define SHA384_DIGEST_LENGTH 48 #endif /** * Compute SHA384 HMAC. * * This functions takes one data chunk and computes its SHA384 HMAC. * * @param key * The MAC key. * @param key_length * Lneght of the MAC key in bytes * @param data * Points to the data chunk. * @param data_length * Length of the data in bytes * @param mac * Points to a buffer that receives the computed digest. This * buffer must have a size of at least 48 bytes (SHA384_DIGEST_LENGTH). * @param mac_length * Point to an integer that receives the length of the computed HMAC. */ void hmac_sha384( uint8_t* key, uint32_t key_length, uint8_t* data, int32_t data_length, uint8_t* mac, uint32_t* mac_length ); /** * Compute SHA384 HMAC over several data cunks. * * This functions takes several data chunk and computes the SHA384 HAMAC. It * uses the openSSL HAMAC SHA384 implementation. * * @param key * The MAC key. * @param key_length * Lneght of the MAC key in bytes * @param data * Points to an array of pointers that point to the data chunks. A NULL * pointer in an array element terminates the data chunks. * @param data_length * Points to an array of integers that hold the length of each data chunk. * @param mac * Points to a buffer that receives the computed digest. This * buffer must have a size of at least 48 bytes (SHA384_DIGEST_LENGTH). * @param mac_length * Point to an integer that receives the length of the computed HMAC. */ void hmac_sha384( uint8_t* key, uint32_t key_length, uint8_t* data[], uint32_t data_length[], uint8_t* mac, uint32_t* mac_length ); /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/aesCFB.h0000644000175000017500000000463611570305710020456 0ustar dyfetdyfet/* 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 */ #ifndef _AESCFB_H__ #define _AESCFB_H__ #include /** * @file aesCFB.h * @brief Function that provide AES CFB mode support * * @ingroup GNU_ZRTP * @{ */ #ifndef AES_BLOCK_SIZE #define AES_BLOCK_SIZE 16 #endif /** * Encrypt data with AES CFB mode, full block feedback size. * * This functions takes one data chunk and encrypts it with * AES CFB mode. The lenght of the data may be arbitrary and * it is not needed to be a multiple of AES blocksize. * * @param key * Points to the key bytes. * @param keyLength * Length of the key in bytes * @param IV * The initialization vector which must be AES_BLOCKSIZE (16) bytes. * @param data * Points to a buffer that contains and receives the computed * the data (in-place encryption). * @param dataLength * Length of the data in bytes */ void aesCfbEncrypt(uint8_t* key, int32_t keyLength, uint8_t* IV, uint8_t *data, int32_t dataLength); /** * Decrypt data with AES CFB mode, full block feedback size. * * This functions takes one data chunk and decrypts it with * AES CFB mode. The lenght of the data may be arbitrary and * it is not needed to be a multiple of AES blocksize. * * @param key * Points to the key bytes. * @param keyLength * Length of the key in bytes * @param IV * The initialization vector which must be AES_BLOCKSIZE (16) bytes. * @param data * Points to a buffer that contains and receives the computed * the data (in-place decryption). * @param dataLength * Length of the data in bytes */ void aesCfbDecrypt(uint8_t* key, int32_t keyLength, const uint8_t* IV, uint8_t *data, int32_t dataLength); /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/sha384.h0000644000175000017500000001033311570305710020374 0ustar dyfetdyfet/* 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 . */ /** * Functions to compute SHA384 digest. * * @author: Werner Dittmann */ #ifndef _SHA384_H #define _SHA384_H /** * @file sha384.h * @brief Function that provide SHA384 support * * @ingroup GNU_ZRTP * @{ */ #include #ifndef SHA384_DIGEST_LENGTH #define SHA384_DIGEST_LENGTH 48 #endif /** * Compute SHA384 digest. * * This functions takes one data chunk and computes its SHA384 digest. This * function creates and deletes an own SHA384 context to perform the SHA384 * operations. * * @param data * Points to the data chunk. * @param data_length * Length of the data in bytes * @param digest * Points to a buffer that receives the computed digest. This * buffer must have a size of at least 48 bytes (SHA384_DIGEST_LENGTH). */ void sha384(unsigned char *data, unsigned int data_length, unsigned char *digest); /** * Compute SHA384 digest over several data cunks. * * This functions takes several data chunks and computes the SHA384 digest. * This function creates and deletes an own SHA384 context to perform the * SHA384 operations. * * @param data * Points to an array of pointers that point to the data chunks. A NULL * pointer in an array element terminates the data chunks. * @param data_length * Points to an array of integers that hold the length of each data chunk. * @param digest * Points to a buffer that receives the computed digest. This * buffer must have a size of at least 48 bytes (SHA384_DIGEST_LENGTH). */ void sha384(unsigned char *data[], unsigned int data_length[], unsigned char *digest); /** * Create and initialize a SHA384 context. * * An application uses this context to hash several data into one SHA384 * digest. See also sha384Ctx(...) and closeSha384Context(...). * * @return Returns a pointer to the initialized SHA384 context */ void* createSha384Context(); /** * Compute a digest and close the SHA384 digest. * * An application uses this function to compute the SHA384 digest and to * close the SHA384 context. * * @param ctx * Points to the SHA384 context. * @param digest * If this pointer is not NULL then it must point to a byte array that * is big enough to hold the SHA384 digest (384 bit = 48 Bytes). If this * pointer is NULL then the functions does not compute the digest but * closes the context only. The context cannot be used anymore. */ void closeSha384Context(void* ctx, unsigned char* digest); /** * Update the SHA384 context with data. * * This functions updates the SHA384 context with some data. * See also CloseSha384Context(...) how to get the digest. * * @param ctx * Points to the SHA384 context. * @param data * Points to the data to update the context. * @param dataLength * The length of the data in bytes. */ void sha384Ctx(void* ctx, unsigned char* data, unsigned int dataLength); /** * Update the SHA384 context with several data chunks. * * This functions updates the SHA384 context with some data. * See also CloseSha384Context(...) how to get the digest. * * @param ctx * Points to the SHA384 context. * @param dataChunks * Points to an array of pointers that point to the data chunks. A NULL * pointer in an array element terminates the data chunks. * @param dataChunkLength * Points to an array of integers that hold the length of each data chunk. * */ void sha384Ctx(void* ctx, unsigned char* dataChunks[], unsigned int dataChunkLength[]); /** * @} */ #endif libzrtpcpp-2.0.0/src/libzrtpcpp/crypto/twofish.h0000755000175000017500000002151711570305710021056 0ustar dyfetdyfet/* * Fast, portable, and easy-to-use Twofish implementation, * Version 0.3. * Copyright (c) 2002 by Niels Ferguson. * * See the twofish.c file for the details of the how and why of this code. * * The author hereby grants a perpetual license to everybody to * use this code for any purpose as long as the copyright message is included * in the source code of this or any derived work. */ /* * PLATFORM FIXES * ============== * * The following definitions have to be fixed for each particular platform * you work on. If you have a multi-platform program, you no doubt have * portable definitions that you can substitute here without changing * the rest of the code. * * The defaults provided here should work on most PC compilers. */ #ifndef TWOFISH_H #define TWOFISH_H #ifdef __cplusplus extern "C" { #endif /** * @file twofish.h * @brief Function that provide basic Twofish crypto support * * @ingroup GNU_ZRTP * @{ */ /** * A Twofish_Byte must be an unsigned 8-bit integer. * * It must also be the elementary data size of your C platform, * i.e. sizeof( Twofish_Byte ) == 1. */ typedef unsigned char Twofish_Byte; /** * A Twofish_UInt32 must be an unsigned integer of at least 32 bits. * * This type is used only internally in the implementation, so ideally it * would not appear in the header file, but it is used inside the * Twofish_key structure which means it has to be included here. */ typedef unsigned int Twofish_UInt32; /* * END OF PLATFORM FIXES * ===================== * * You should not have to touch the rest of this file, but the code * in twofish.c has a few things you need to fix too. */ /** * Return codes */ #define SUCCESS 1 #define ERR_UINT32 -2 #define ERR_BYTE -3 #define ERR_GET32 -4 #define ERR_PUT32 -5 #define ERR_ROLR -6 #define ERR_BSWAP -7 #define ERR_SELECTB -8 #define ERR_TEST_ENC -9 #define ERR_TEST_DEC -10 #define ERR_SEQ_ENC -11 #define ERR_SEQ_DEC -12 #define ERR_ODD_KEY -13 #define ERR_INIT -14 #define ERR_KEY_LEN -15 #define ERR_ILL_ARG -16 /** * Structure that contains a prepared Twofish key. * * A cipher key is used in two stages. In the first stage it is converted * form the original form to an internal representation. * This internal form is then used to encrypt and decrypt data. * This structure contains the internal form. It is rather large: 4256 bytes * on a platform with 32-bit unsigned values. * * Treat this as an opague structure, and don't try to manipulate the * elements in it. I wish I could hide the inside of the structure, * but C doesn't allow that. */ typedef struct { Twofish_UInt32 s[4][256]; /* pre-computed S-boxes */ Twofish_UInt32 K[40]; /* Round key words */ } Twofish_key; /** * Initialise and test the Twofish implementation. * * This function MUST be called before any other function in the * Twofish implementation is called. * It only needs to be called once. * * Apart from initialising the implementation it performs a self test. * If the Twofish_fatal function is not called, the code passed the test. * (See the twofish.c file for details on the Twofish_fatal function.) * * @returns a negative number if an error happend, +1 otherwise */ extern int Twofish_initialise(); /** * Convert a cipher key to the internal form used for * encryption and decryption. * * The cipher key is an array of bytes; the Twofish_Byte type is * defined above to a type suitable on your platform. * * Any key must be converted to an internal form in the Twofisk_key structure * before it can be used. * The encryption and decryption functions only work with the internal form. * The conversion to internal form need only be done once for each key value. * * Be sure to wipe all key storage, including the Twofish_key structure, * once you are done with the key data. * A simple memset( TwofishKey, 0, sizeof( TwofishKey ) ) will do just fine. * * Unlike most implementations, this one allows any key size from 0 bytes * to 32 bytes. According to the Twofish specifications, * irregular key sizes are handled by padding the key with zeroes at the end * until the key size is 16, 24, or 32 bytes, whichever * comes first. Note that each key of irregular size is equivalent to exactly * one key of 16, 24, or 32 bytes. * * WARNING: Short keys have low entropy, and result in low security. * Anything less than 8 bytes is utterly insecure. For good security * use at least 16 bytes. I prefer to use 32-byte keys to prevent * any collision attacks on the key. * * The key length argument key_len must be in the proper range. * If key_len is not in the range 0,...,32 this routine attempts to generate * a fatal error (depending on the code environment), * and at best (or worst) returns without having done anything. * * @param key Array of key bytes * @param key_len Number of key bytes, must be in the range 0,1,...,32. * @para xkey Pointer to an Twofish_key structure that will be filled * with the internal form of the cipher key. * @returns a negative number if an error happend, +1 otherwise */ extern int Twofish_prepare_key( Twofish_Byte key[], int key_len, Twofish_key * xkey ); /** * Encrypt a single block of data. * * This function encrypts a single block of 16 bytes of data. * If you want to encrypt a larger or variable-length message, * you will have to use a cipher mode, such as CBC or CTR. * These are outside the scope of this implementation. * * The xkey structure is not modified by this routine, and can be * used for further encryption and decryption operations. * * @param xkey pointer to Twofish_key, internal form of the key * produces by Twofish_prepare_key() * @param p Plaintext to be encrypted * @param c Place to store the ciphertext */ extern void Twofish_encrypt( Twofish_key * xkey, Twofish_Byte p[16], Twofish_Byte c[16] ); /** * Decrypt a single block of data. * * This function decrypts a single block of 16 bytes of data. * If you want to decrypt a larger or variable-length message, * you will have to use a cipher mode, such as CBC or CTR. * These are outside the scope of this implementation. * * The xkey structure is not modified by this routine, and can be * used for further encryption and decryption operations. * * @param xkey pointer to Twofish_key, internal form of the key * produces by Twofish_prepare_key() * @param c Ciphertext to be decrypted * @param p Place to store the plaintext */ extern void Twofish_decrypt( Twofish_key * xkey, Twofish_Byte c[16], Twofish_Byte p[16] ); /** * Encrypt data in CFB mode. * * This function encrypts data in CFB mode. * * The key structure is not modified by this routine, and can be * used for further encryption and decryption operations. * * @param keyCtx pointer to Twofish_key, internal form of the key * produced by Twofish_prepare_key() * @param in Plaintext to be encrypted * @param out Place to store the ciphertext * @param len number of bytes to encrypt. * @param iv initialization vector for this CFB mode encryption. */ void Twofish_cfb128_encrypt(Twofish_key* keyCtx, Twofish_Byte* in, Twofish_Byte* out, size_t len, Twofish_Byte* ivec, int *num); /** * Decrypt data in CFB mode. * * This function decrypts data in CFB. * * The key structure is not modified by this routine, and can be * used for further encryption and decryption operations. * * @param keyCtx pointer to Twofish_key, internal form of the key * produced by Twofish_prepare_key() * @param in Ciphertext to be decrypted * @param out Place to store the plaintext * @param len number of bytes to decrypt. * @param iv initialization vector for this CFB mode encryption. */ void Twofish_cfb128_decrypt(Twofish_key* keyCtx, Twofish_Byte* in, Twofish_Byte* out, size_t len, Twofish_Byte* ivec, int *num); /** * @} */ #ifdef __cplusplus } #endif #endif libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketHelloAck.h0000644000175000017500000000266611570305710021546 0ustar dyfetdyfet/* 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 . */ #ifndef _ZRTPPACKETHELLOACK_H_ #define _ZRTPPACKETHELLOACK_H_ /** * @file ZrtpPacketHelloAck.h * @brief The ZRTP HelloAck message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the HelloAck packet. * * The ZRTP simple message HelloAck. The implementation sends this * after receiving a Hello packet. * * @author Werner Dittmann */ class __EXPORT ZrtpPacketHelloAck : public ZrtpPacketBase { public: /// Creates a HelloAck packet with default data ZrtpPacketHelloAck(); /// Creates a HelloAck packet from received data ZrtpPacketHelloAck(uint8_t* data); virtual ~ZrtpPacketHelloAck(); private: HelloAckPacket_t data; }; /** * @} */ #endif // ZRTPPACKETHELLOACK libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpQueue.h0000644000175000017500000007240311570305710020014 0ustar dyfetdyfet/* Copyright (C) 2006-2009 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 . */ #ifndef _ZRTPQUEUE_H_ #define _ZRTPQUEUE_H_ #include #include #include #include #include class __EXPORT ZrtpUserCallback; class __EXPORT ZRtp; NAMESPACE_COMMONCPP /** * GNU ccRTP extension to support GNU ZRTP. * * ZRTP was developed by Phil Zimmermann and provides functions to * negotiate keys and other necessary data (crypto data) to set-up * the Secure RTP (SRTP) crypto context. Refer to Phil's ZRTP * specification at his Zfone * project site to get more detailed imformation about the * capabilities of ZRTP. * * Short overview of the ZRTP implementation * * ZRTP is a specific protocol to negotiate encryption algorithms * and the required key material. ZRTP uses a RTP session to * exchange its protocol messages. * * A complete GNU ZRTP implementation consists of two parts, the * GNU ZRTP core and specific code that binds the GNU ZRTP core to * the underlying RTP/SRTP stack and the operating system: *
    *
  • * The GNU ZRTP core is independent of a specific RTP/SRTP * stack and the operationg system and consists of the ZRTP * protocol state engine, the ZRTP protocol messages, and the * GNU ZRTP engine. The GNU ZRTP engine provides methods to * setup ZRTP message and to analyze received ZRTP messages, * to compute the crypto data required for SRTP, and to * maintain the required hashes and HMAC. *
  • *
  • * The second part of an implementation is specific * glue code the binds the GNU ZRTP core to the * actual RTP/SRTP implementation and other operating system * specific services such as timers. *
  • *
* * The GNU ZRTP core uses a callback interface class (refer to * ZrtpCallback) to access RTP/SRTP or operating specific methods, * for example to send data via the RTP/SRTP stack, to access * timers, provide mutex handling, and to report events to the * application. * * The ZrtpQueue * * ZrtpQueue implements code that is specific to the GNU ccRTP * implementation. ZrtpQueue also implements the specific code to * provide the mutex and timeout handling to the GNU ZRTP * core. Both, the mutex and the timeout handling, use the GNU * Common C++ library to stay independent of the operating * seystem. For more information refer to the GNU * Common C++ web site. * * To perform its tasks ZrtpQueue *
    *
  • extends GNU ccRTP classes to use the underlying * ccRTP methods and the RTP/SRTP send and receive queues *
  • *
  • implements the ZrtpCallback interface to provide ccRTP * access and other specific services (timer, mutex) to GNU * ZRTP *
  • *
  • provides ZRTP specific methods that applications may use * to control and setup GNU ZRTP *
  • *
  • can register and use an application specific callback * class (refer to ZrtpUserCallback) *
  • *
* * After instantiating a GNU ZRTP session (see below for a short * example) applications may use the ZRTP specific methods of * ZrtpQueue to control and setup GNU ZRTP, for example enable or * disable ZRTP processing or getting ZRTP status information. * * GNU ZRTP provides a ZrtpUserCallback class that an application * may extend and register with ZrtpQueue. GNU ZRTP and ZrtpQueue * use the ZrtpUserCallback methods to report ZRTP events to the * application. The application may display this information to * the user or act otherwise. * * The following figure depicts the relationships between * ZrtpQueue, ccRTP RTP/SRTP implementation, the GNU ZRTP core, * and an application that provides an ZrtpUserCallback class. * @verbatim +----------+ | ccRTP | | RTP/SRTP | | | +----------+ ^ | extends | +----------------+ +-----+------+ | Application | | | +-----------------+ | instantiates | uses | ZrtpQueue | uses | | | a ZRTP Session +------+ implements +------+ GNU ZRTP | | and provides | |ZrtpCallback| | core | |ZrtpUserCallback| | | | implementation | +----------------+ +------------+ | (ZRtp et al) | | | +-----------------+ @endverbatim * * Because ZrtpQueue extends the ccRTP RTP/SRTP implementation * (AVPQueue) all public methods defined by ccRTP are also * available for a ZRTP session. ZrtpQueue overwrites some of the * public methods of ccRTP (AVPQueue) to implement ZRTP specific * code. * * GNU ZRTP provides a SymmetricZRTPSession type to * simplify its use. An application uses this type in the same way * as it would use the normal ccRTP SymmetricRTPSession * type. The following short code snippets show how an application * could instantiate ccRTP and GNU ZRTP sessions. The first * snippet shows how to instantiate a ccRTP session: * * @code * ... * #include * ... * SymmetricRTPSession tx(pattern.getSsrc(), * InetHostAddress("localhost")); * ... * * @endcode * * The same code as above but using a GNU ZRTP session this time: * @code * ... * #include * ... * SymmetricZRTPSession tx(pattern.getSsrc(), * InetHostAddress("localhost")); * ... * * @endcode * * The only differences are the different include statements and * the different session types. * * The demo folder contains a small example that shows * how to use GNU ZRTP. * * Please refer to the GNU ccRTP documentation for a description * of ccRTP methods and functions. This ZrtpQueue documentation * shows the ZRTP specific extensions and describes overloaded * methods and a possible different behaviour. * * @author Werner Dittmann */ class __EXPORT ZrtpQueue : public AVPQueue, ZrtpCallback { public: /** * Initialize the ZrtpQueue. * * Before an application can use ZRTP it has to initialize the * ZRTP implementation. This method initializes the timeout * thread and opens a file that contains ZRTP specific * information such as the applications ZID (ZRTP id) and its * retained shared secrets. * * If one application requires several ZRTP sessions all * sessions use the same timeout thread and use the same ZID * file. Therefore an application does not need to do any * synchronisation regading ZID files or timeouts. This is * managed by the ZRTP implementation. * * The current implementation of ZrtpQueue does not support * different ZID files for one application instance. This * restriction may be removed in later versions. * * The application may specify its own ZID file name. If no * ZID file name is specified it defaults to * $HOME/.GNUccRTP.zid if the HOME * environment variable is set. If it is not set the current * directory is used. * * If the method could set up the timeout thread and open the ZID * file then it enables ZRTP processing and returns. * * @param zidFilename * The name of the ZID file, can be a relative or absolut * filename. * * @param autoEnable * if set to true the method automatically sets enableZrtp to * true. This enables the ZRTP auto-sense mode. Default is true. * * @param config * this parameter points to ZRTP configuration data. If it is * NULL then ZrtpQueue uses a default setting. Default is NULL. * * @return * 1 on success, ZRTP processing enabled, -1 on failure, * ZRTP processing disabled. * */ int32_t initialize(const char *zidFilename, bool autoEnable = true, ZrtpConfigure* config = NULL); /* * Applications use the following methods to control ZRTP, for example * to enable ZRTP, set flags etc. */ /** * Enable or disable ZRTP processing. * * Call this method to enable or disable ZRTP processing after * calling initialize(). This can be done before * using a RTP session or at any time during a RTP session. * * Existing SRTP sessions or currently active ZRTP processing will * not be stopped or disconnected. * * If the application enables ZRTP then: *
    *
  • ZrtpQueue starts to send ZRTP Hello packets after at least * one RTP packet was sent and received on the associated RTP * session. Thus if an application enables ZRTP and ZrtpQueue * detects traffic on the RTP session then ZrtpQueue automatically * starts the ZRTP protocol. This automatic start is convenient * for applications that negotiate RTP parameters and set up RTP * sessions but the actual RTP traffic starts some time later. *
  • *
  • ZrtpQueue analyses incoming packets to detect ZRTP * messages. If ZRTP was started, either via automatic start (see * above) or explicitly via startZrtp(), then ZrtpQueue * forwards ZRTP packets to the GNU ZRTP core. *
* * @param onOff * @c true to enable ZRTP, @c false to disable ZRTP */ void setEnableZrtp(bool onOff); /** * Return the state of ZRTP enable state. * * @return @c true if ZRTP processing is enabled, @c false * otherwise. */ bool isEnableZrtp(); /** * Set SAS as verified. * * The application may call this method if the user confirmed * (verfied) the Short Authentication String (SAS) with the peer. * * ZRTP calls ZrtpUserCallback#showSAS after it computed the SAS * and the application registered a user callback class. The * application should display the SAS and provide a mechanism at * the user interface that enables the user to confirm the SAS. * * ZRTP remembers the SAS confirmation status together with the * retained secrets data. If both parties confirmed the SAS then * ZRTP informs the application about this status on the next ZRTP * session. * * For more detailed information regarding SAS please refer to the * ZRTP specification, chapter 8. */ void SASVerified(); /** * Reset the SAS verfied flag for the current user's retained secrets. * */ void resetSASVerified(); /** * To confirm a go clear request. * * Call this method if the user confirmed a go clear (secure mode off). */ void goClearOk(); /** * Request to switch off secure mode. * * Call this method is the user itself wants to switch off secure * mode (go clear). After sending the "go clear" request to the peer * ZRTP immediatly switch off SRTP processing. Every RTP data is sent * in clear after the go clear request. */ void requestGoClear(); /** * Set the auxilliary secret. * * Use this method to set the srtps secret data. Refer to ZRTP * specification, chapter 5.3 ff * * @param data * Points to the auxilliary secret data. * @param length * Length of the auxilliary secrect in bytes */ void setAuxSecret(uint8_t* data, int32_t length); /** * Set the other secret. * * Use this method to set the other secret data. Refer to ZRTP * specification, chapter 5.3 ff * * @param data * Points to the other secret data. * @param length * The length in bytes of the data. */ void setPbxSecret(uint8* data, int32 length); /** * Set the application's callback class. * * The destructor of ZrtpQueue also destorys the user callback * class if it was set. The application must not delete the * callback object or use/reference the callback object after * ZrtpQueue was destroyed. * * @param ucb * Implementation of the application's ZrtpUserCallback class */ void setUserCallback(ZrtpUserCallback* ucb); /** * Set the client ID for ZRTP Hello message. * * The GNU ccRTP client may set its id to identify itself in the * ZRTP Hello message. The maximum length is 16 characters. A * shorter id string is possible, it will be filled with blanks. A * longer id string will be truncated to 16 characters. The * standard client id is 'GNU ccRTP ZRTP ' (without * the quotes). * * Setting the client's id must be done before calling * ZrtpQueue#initialize() or ZrtpQueue#startZrtp() . * * @param id * The client's id string */ void setClientId(std::string id); /** * Get the ZRTP Hello Hash data. * * Use this method to get the ZRTP Hello Hash data. The method * returns the data as a string containing hex-digits. Refer * to ZRTP specification, chapter 9.1. * * @return * a std:string containing the Hello hash value as hex-digits. The * hello hash is available immediatly after calling * ZrtpQueue#startZrtp. If ZRTP was not started the method returns * an empty string. */ std::string getHelloHash(); /** * Get Multi-stream parameters. * * Use this method to get the Multi-stream that were computed during * the ZRTP handshake. An application may use these parameters to * enable multi-stream processing for an associated SRTP session. * * Refer to chapter 5.4.2 in the ZRTP specification for further details * and restriction how and when to use multi-stream mode. * * @return * a string that contains the multi-stream parameters. The application * must not modify the contents of this string, it is opaque data. The * application may hand over this string to a new ZrtpQueue instance * to enable multi-stream processing for this ZrtpQueue. If ZRTP was * not started or ZRTP is not yet in secure state the method returns an * empty string. * * @see setMultiStrParams() */ std::string getMultiStrParams(); /** * Set Multi-stream parameters. * * Use this method to set the parameters required to enable Multi-stream * processing of ZRTP. The multi-stream parameters must be set before the * application starts the ZRTP protocol engine. * * Refer to chapter 5.4.2 in the ZRTP specification for further details * of multi-stream mode. * * @param parameters * A string that contains the multi-stream parameters that this * new ZrtpQueue instanace shall use. * * @see getMultiStrParams() */ void setMultiStrParams(std::string parameters); /** * Check if this ZRTP use Multi-stream. * * Use this method to check if this ZRTP instance uses multi-stream. Even * if the application provided multi-stram parameters it may happen that * full DH mode was used. Refer to chapters 5.2 and 5.4.2 in the ZRTP # * when this may happen. * * @return * True if multi-stream is used, false otherwise. */ bool isMultiStream(); /** * Check if the other ZRTP client supports Multi-stream. * * Use this method to check if the other ZRTP client supports * Multi-stream mode. * * @return * True if multi-stream is available, false otherwise. */ bool isMultiStreamAvailable(); /** * Accept a PBX enrollment request. * * If a PBX service asks to enroll the MiTM key and the user accepts this * requtes, for example by pressing an OK button, the client application * shall call this method and set the parameter accepted to * true. If the user does not accept the request set the parameter to * false. * * @param accepted * True if the enrollment request is accepted, false otherwise. */ void acceptEnrollment(bool accepted); /** * Set signature data * * This functions stores signature data and transmitts it during ZRTP * processing to the other party as part of the Confirm packets. Refer to * chapters 6.7 and 8.2 in the ZRTP specification. * * @param data * The signature data including the signature type block. The method * copies this data into the Confirm packet at signature type block. * @param length * The length of the signature data in bytes. This length must be * multiple of 4. * @return * True if the method stored the data, false otherwise. */ bool setSignatureData(uint8* data, int32 length); /** * Get signature data * * This functions returns signature data that was receivied during ZRTP * processing. Refer to chapters 6.7 and 8.2. * * The signature data can be retrieved after ZRTP enters secure state. * start(). * * @param data * Pointer to a data buffer. This buffer must be large enough to * hold the signature data. Refer to getSignatureLength() * to get the length of the received signature data. * @return * Number of bytes copied into the data buffer */ int32 getSignatureData(uint8* data); /** * Get length of signature data * * This functions returns the length of signature data that was receivied * during ZRTP processing. Refer to chapters 6.7 and 8.2. * * @return * Length in bytes of the received signature data. The method returns * zero if no signature data avilable. */ int32 getSignatureLength(); /** * Enable PBX enrollment * * The application calls this method to allow or disallow PBX enrollment. * If the applications allows PBX enrollment then the ZRTP implementation * honors the PBX enrollment flag in Confirm packets. Refer to chapter 8.3 * for further details of PBX enrollment. * * @param yesNo * If set to true then ZRTP honors the PBX enrollment flag in Commit * packets and calls the appropriate user callback methods. If * the parameter is set to false ZRTP ignores the PBX enrollment flags. */ void setPBXEnrollment(bool yesNo); /** * Put data into the RTP output queue. * * This is used to create a data packet in the send queue. * Sometimes a "NULL" or empty packet will be used instead, and * these are known as "silent" packets. "Silent" packets are * used simply to "push" the scheduler along more accurately * by giving the appearence that a next packet is waiting to * be sent and to provide a valid timestamp for that packet. * * This method overrides the same method in OutgoingDataQueue class. * During ZRTP processing it may be necessary to control the * flow of outgoing RTP payload packets (GoClear processing). * * @param stamp Timestamp for expected send time of packet. * @param data Value or NULL if special "silent" packet. * @param len May be 0 to indicate a default by payload type. **/ void putData(uint32 stamp, const unsigned char* data = NULL, size_t len = 0); /** * Immediatly send a data packet. * * This is used to create a data packet and send it immediately. * Sometimes a "NULL" or empty packet will be used instead, and * these are known as "silent" packets. "Silent" packets are * used simply to "push" the scheduler along more accurately * by giving the appearence that a next packet is waiting to * be sent and to provide a valid timestamp for that packet. * * This method overrides the same method in OutgoingDataQueue * class. During ZRTP processing it may be necessary to * control the flow of outgoing RTP payload packets (GoClear * processing). * * @param stamp Timestamp immediate send time of packet. * @param data Value or NULL if special "silent" packet. * @param len May be 0 to indicate a default by payload type. **/ void sendImmediate(uint32 stamp, const unsigned char* data = NULL, size_t len = 0); /** * Starts the ZRTP protocol engine. * * Applications may call this method to immediatly start the ZRTP protocol * engine any time after initializing ZRTP and setting optinal parameters, * for example client id or multi-stream parameters. * * If the application does not call this method but sucessfully initialized * the ZRTP engine using initialize() then ZRTP also starts * after the application sent and received RTP packets. An application can * disable this automatic, delayed start of the ZRTP engine using * setEnableZrtp(false) before sending or receiving RTP * packets. * */ void startZrtp(); /** * Stops the ZRTP protocol engine. * * Applications call this method to stop the ZRTP protocol * engine. * */ void stopZrtp(); /** * Get other party's ZID (ZRTP Identifier) data * * This functions returns the other party's ZID that was receivied * during ZRTP processing. * * The ZID data can be retrieved after ZRTP receive the first Hello * packet from the other party. The application may call this method * for example during SAS processing in showSAS(...) user callback * method. * * @param data * Pointer to a data buffer. This buffer must have a size of * at least 12 bytes (96 bit) (ZRTP Identifier, see chap. 4.9) * @return * Number of bytes copied into the data buffer - must be equivalent * to 96 bit, usually 12 bytes. */ int32 getZid(uint8* data); protected: friend class TimeoutProvider; /** * A hook that gets called if the decoding of an incoming SRTP * was erroneous * * @param pkt * The SRTP packet with error. * @param errorCode * The error code: -1 - SRTP authentication failure, -2 - replay * check failed * @return * True: put the packet in incoming queue for further processing * by the applications; false: dismiss packet. The default * implementation returns false. */ virtual bool onSRTPPacketError(IncomingRTPPkt& pkt, int32 errorCode); /** * Handle timeout event forwarded by the TimeoutProvider. * * Just call the ZRTP engine for further processing. */ void handleTimeout(const std::string &c); /** * This function is used by the service thread to process * the next incoming packet and place it in the receive list. * * This class overloads the function of IncomingDataQueue * implementation. * * @return number of payload bytes received, <0 if error. */ virtual size_t takeInDataPacket(); /* * The following methods implement the GNU ZRTP callback interface. * For detailed documentation refer to file ZrtpCallback.h */ int32_t sendDataZRTP(const unsigned char* data, int32_t length); int32_t activateTimer(int32_t time); int32_t cancelTimer(); void sendInfo(GnuZrtpCodes::MessageSeverity severity, int32_t subCode); bool srtpSecretsReady(SrtpSecret_t* secrets, EnableSecurity part); void srtpSecretsOff(EnableSecurity part); void srtpSecretsOn(std::string c, std::string s, bool verified); void handleGoClear(); void zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity severity, int32_t subCode); void zrtpNotSuppOther(); void synchEnter(); void synchLeave(); void zrtpAskEnrollment(std::string info); void zrtpInformEnrollment(std::string info); void signSAS(std::string sas); bool checkSASSignature(std::string sas); /* * End of ZrtpCallback functions. */ ZrtpQueue(uint32 size = RTPDataQueue::defaultMembersHashSize, RTPApplication& app = defaultApplication()); /** * Local SSRC is given instead of computed by the queue. */ ZrtpQueue(uint32 ssrc, uint32 size = RTPDataQueue::defaultMembersHashSize, RTPApplication& app = defaultApplication()); virtual ~ZrtpQueue(); private: void init(); size_t rtpDataPacket(unsigned char* packet, int32 rtn, InetHostAddress network_address, tpport_t transport_port); ZRtp *zrtpEngine; ZrtpUserCallback* zrtpUserCallback; std::string clientIdString; bool enableZrtp; int32 secureParts; // CryptoContext* recvCryptoContext; // CryptoContext* senderCryptoContext; int16 senderZrtpSeqNo; ost::Mutex synchLock; // Mutex for ZRTP (used by ZrtpStateClass) uint32 peerSSRC; bool started; }; class IncomingZRTPPkt : public IncomingRTPPkt { public: /** * Build a ZRTP packet object from a data buffer. * * @param block pointer to the buffer the whole packet is stored in. * @param len length of the whole packet, expressed in octets. * **/ IncomingZRTPPkt(const unsigned char* block, size_t len); ~IncomingZRTPPkt() { } uint32 getZrtpMagic() const; uint32 getSSRC() const; }; class OutgoingZRTPPkt : public OutgoingRTPPkt { public: /** * Construct a new ZRTP packet to be sent. * * A new copy in memory (holding all this components * along with the fixed header) is created. * * @param hdrext whole header extension. * @param hdrextlen size of whole header extension, in octets. **/ OutgoingZRTPPkt(const unsigned char* const hdrext, uint32 hdrextlen); ~OutgoingZRTPPkt() { } }; END_NAMESPACE #endif /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpCallbackWrapper.h0000644000175000017500000000514411570305710021763 0ustar dyfetdyfet/* This class maps the ZRTP C++ callback methods to C callback methods. Copyright (C) 2010 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 . */ #ifndef ZRTPCALLBACKWRAPPER_H #define ZRTPCALLBACKWRAPPER_H #include #include #include #include /** * * @file ZrtpCallbackWrapper.h * @brief C-Wrapper helper * * This is a helper class for for the C wrapper and implements * the GNU ZRTP callback interface.For detailed documentation about * the callback method refer to file ZrtpCallback * @ingroup GNU_ZRTP * @{ * * @see ZrtpCallback */ class __EXPORT ZrtpCallbackWrapper : public ZrtpCallback { public: /** * Construct a class that implements ZrtpCallback and uses a C structure * the call C functions that implement the callbacks. * * @param cb * The C callback structure that hold the addresses of the C methods * that implement the actual callback functions. */ ZrtpCallbackWrapper(zrtp_Callbacks* cb, ZrtpContext* ctx); int32_t sendDataZRTP ( const unsigned char* data, int32_t length ); int32_t activateTimer ( int32_t time ); int32_t cancelTimer(); void sendInfo ( GnuZrtpCodes::MessageSeverity severity, int32_t subCode ); bool srtpSecretsReady ( SrtpSecret_t* secrets, EnableSecurity part ); void srtpSecretsOff ( EnableSecurity part ); void srtpSecretsOn ( std::string c, std::string s, bool verified ); void handleGoClear(); void zrtpNegotiationFailed ( GnuZrtpCodes::MessageSeverity severity, int32_t subCode ); void zrtpNotSuppOther(); void synchEnter(); void synchLeave(); void zrtpAskEnrollment ( std::string info ); void zrtpInformEnrollment ( std::string info ); void signSAS ( std::string sas ); bool checkSASSignature ( std::string sas ); private: void init(); zrtp_Callbacks *c_callbacks; ZrtpContext* zrtpCtx; }; /** * @} */ #endif // ZRTPCALLBACKWRAPPER_H libzrtpcpp-2.0.0/src/libzrtpcpp/ZrtpPacketCommit.h0000644000175000017500000001162611570305710021310 0ustar dyfetdyfet/* 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 */ #ifndef _ZRTPPACKETCOMMIT_H_ #define _ZRTPPACKETCOMMIT_H_ /** * @file ZrtpPacketCommit.h * @brief The ZRTP Commit message * * @ingroup GNU_ZRTP * @{ */ #include /** * Implement the Commit packet. * * The ZRTP message Commit. The ZRTP implementation sends or receives * this message to commit the crypto parameters offered during a Hello * message. * * * @author Werner Dittmann */ class __EXPORT ZrtpPacketCommit : public ZrtpPacketBase { protected: Commit_t* commitHeader; ///< Points to Commit message part public: /// Creates a Commit packet with default data ZrtpPacketCommit(); /// Creates a Commit packet from received data ZrtpPacketCommit(uint8_t* data); /// Normal destructor virtual ~ZrtpPacketCommit(); /// Get pointer to hash algorithm type field, a fixed length character array uint8_t* getHashType() { return commitHeader->hash; }; /// Get pointer to cipher algorithm type field, a fixed length character array uint8_t* getCipherType() { return commitHeader->cipher; }; /// Get pointer to SRTP authentication algorithm type field, a fixed length character array uint8_t* getAuthLen() { return commitHeader->authlengths; }; /// Get pointer to key agreement algorithm type field, a fixed length character array uint8_t* getPubKeysType() { return commitHeader->pubkey; }; /// Get pointer to SAS algorithm type field, a fixed length character array uint8_t* getSasType() { return commitHeader->sas; }; /// Get pointer to ZID field, a fixed length byte array uint8_t* getZid() { return commitHeader->zid; }; /// Get pointer to HVI field, a fixed length byte array uint8_t* getHvi() { return commitHeader->hvi; }; /// Get pointer to NONCE field, a fixed length byte array, overlaps HVI field uint8_t* getNonce() { return commitHeader->hvi; }; /// Get pointer to hashH2 field, a fixed length byte array uint8_t* getH2() { return commitHeader->hashH2; }; /// Get pointer to MAC field, a fixed length byte array uint8_t* getHMAC() { return commitHeader->hmac; }; /// Get pointer to MAC field during multi-stream mode, a fixed length byte array uint8_t* getHMACMulti() { return commitHeader->hmac-4*ZRTP_WORD_SIZE; }; /// Set hash algorithm type field, fixed length character field void setHashType(uint8_t* text) { memcpy(commitHeader->hash, text, ZRTP_WORD_SIZE); }; /// Set cipher algorithm type field, fixed length character field void setCipherType(uint8_t* text) { memcpy(commitHeader->cipher, text, ZRTP_WORD_SIZE); }; /// Set SRTP authentication algorithm algorithm type field, fixed length character field void setAuthLen(uint8_t* text) { memcpy(commitHeader->authlengths, text, ZRTP_WORD_SIZE); }; /// Set key agreement algorithm type field, fixed length character field void setPubKeyType(uint8_t* text) { memcpy(commitHeader->pubkey, text, ZRTP_WORD_SIZE); }; /// Set SAS algorithm type field, fixed length character field void setSasType(uint8_t* text) { memcpy(commitHeader->sas, text, ZRTP_WORD_SIZE); }; /// Set ZID field, a fixed length byte array void setZid(uint8_t* text) { memcpy(commitHeader->zid, text, sizeof(commitHeader->zid)); }; /// Set HVI field, a fixed length byte array void setHvi(uint8_t* text) { memcpy(commitHeader->hvi, text, sizeof(commitHeader->hvi)); }; /// Set conce field, a fixed length byte array, overlapping HVI field void setNonce(uint8_t* text); /// Set hashH2 field, a fixed length byte array void setH2(uint8_t* hash) { memcpy(commitHeader->hashH2, hash, sizeof(commitHeader->hashH2)); }; /// Set MAC field, a fixed length byte array void setHMAC(uint8_t* hash) { memcpy(commitHeader->hmac, hash, sizeof(commitHeader->hmac)); }; /// Set MAC field during multi-stream mode, a fixed length byte array void setHMACMulti(uint8_t* hash) { memcpy(commitHeader->hmac-4*ZRTP_WORD_SIZE, hash, sizeof(commitHeader->hmac)); }; private: CommitPacket_t data; }; /** * @} */ #endif // ZRTPPACKETCOMMIT libzrtpcpp-2.0.0/src/ZrtpStateClass.cpp0000644000175000017500000013446411570305710017146 0ustar dyfetdyfet/* Copyright (C) 2006-2008 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 . */ /** * @author Werner Dittmann */ #include #include #include #include #include using namespace std; using namespace GnuZrtpCodes; state_t states[numberOfStates] = { {Initial, &ZrtpStateClass::evInitial }, {Detect, &ZrtpStateClass::evDetect }, {AckDetected, &ZrtpStateClass::evAckDetected }, {AckSent, &ZrtpStateClass::evAckSent }, {WaitCommit, &ZrtpStateClass::evWaitCommit }, {CommitSent, &ZrtpStateClass::evCommitSent }, {WaitDHPart2, &ZrtpStateClass::evWaitDHPart2 }, {WaitConfirm1, &ZrtpStateClass::evWaitConfirm1 }, {WaitConfirm2, &ZrtpStateClass::evWaitConfirm2 }, {WaitConfAck, &ZrtpStateClass::evWaitConfAck }, {WaitClearAck, &ZrtpStateClass::evWaitClearAck }, {SecureState, &ZrtpStateClass::evSecureState }, {WaitErrorAck, &ZrtpStateClass::evWaitErrorAck } }; ZrtpStateClass::ZrtpStateClass(ZRtp *p) { parent = p; engine = new ZrtpStates(states, numberOfStates, Initial); commitPkt = NULL; multiStream = false; // 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; } 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; } void ZrtpStateClass::processEvent(Event_t *ev) { event = ev; char *msg, first, middle, last; uint8_t *pkt; parent->synchEnter(); if (event->type == ZrtpPacket) { pkt = event->packet; msg = (char *)pkt + 4; first = tolower(*msg); middle = tolower(*(msg+4)); last = tolower(*(msg+7)); // 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(eapkt)); event->type = ErrorPkt; } else if (first == 'p' && middle == ' ' && last == ' ') { ZrtpPacketPing ppkt(pkt); ZrtpPacketPingAck* ppktAck = parent->preparePingAck(&ppkt); parent->sendPacketZRTP(static_cast(ppktAck)); 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(); } void ZrtpStateClass::evInitial(void) { DEBUGOUT((cout << "Checking for match in Initial.\n")); if (event->type == ZrtpInitial) { ZrtpPacketHello* hello = parent->prepareHello(); // remember packet for easy resend in case timer triggers sentPacket = static_cast(hello); if (!parent->sendPacketZRTP(sentPacket)) { sendFailed(); // returns to state Initial return; } if (startTimer(&T1) <= 0) { timerFailed(SevereNoTimer); // returns to state Initial return; } nextState(Detect); } } /* * Detect state. * * When in this state the protocol engine sent an initial Hello packet * to the peer. * * When entering this state transition function then: * - Assume Initiator mode, mode may change later on peer reaction * - Instance variable sentPacket contains the sent Hello packet * - Hello timer T1 may be active. This is the case if the other peer * has prepared its RTP session and answers our Hello packets nearly * immediately, i.e. before the Hello timeout counter expires. If the * other peer does not send a Hello during this time the state engine * reports "other peer does not support ZRTP" but stays * in state Detect with no active timer (passiv mode). Staying in state * Detect allows another peer to start its detect phase any time later. * * This restart capability is the reason why we use "startTimer(&T1)" in * case we received a Hello packet from another peer. This effectively * restarts the Hello timeout counter. * * In this state we also handle ZrtpInitialize event. This forces a * restart of ZRTP discovery if an application calls ZrtpQueue#startZrtp * again. This may happen after a previous discovery phase were not * successful. * * Usually applications use some sort of signaling protocol, for example * SIP, to negotiate the RTP parameters. Thus the RTP sessions setup is * fairly sychronized and thus also the ZRTP detection phase. Applications * that use some other ways to setup the RTP sessions this restart capability * comes in handy because no RTP setup sychronization is necessary. * * Possible events in this state are: * - timeout for sent Hello packet: causes a resend check and * repeat sending of Hello packet * - received a HelloAck: stop active timer, prepare and send Hello packet, * switch to state AckDeteced. * - received a Hello: stop active timer, send HelloAck, prepare Commit * packet, switch to state AckSent. * */ 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) */ if (first == 'h' && last =='k') { cancelTimer(); sentPacket = NULL; nextState(AckDetected); return; } /* * Hello: * - send HelloAck packet to acknowledge the received Hello packet * - 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 ==' ') { cancelTimer(); ZrtpPacketHelloAck* helloAck = parent->prepareHelloAck(); if (!parent->sendPacketZRTP(static_cast(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 ZrtpPacketHello hpkt(pkt); 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 call 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); } } /* * AckSent state. * * The protocol engine got a Hello packet from peer and answered with a * HelloAck response. According to the protocol we must also send a * Hello after HelloAck (refer to figure 1 in ZRTP RFC xxxx, message * HelloACK (F2) must be followed by Hello (F3)). We use the timeout in * this state to send the required Hello (F3). * * Our peer must acknowledge the Hello with HelloAck. In earlier versions * also a Commit was a valid packet thus the code covers this. * Figure 1 in the RFC shows the HelloAck, chapter 7 states that a Commit * may be send to acknowledge Hello. There is one constraint when using a Commit to * acknowledge Hello: refer to chapter 4.1 that requires that both parties * have completed the Hello/HelloAck discovery handshake. This implies that * only message F4 may be replaced by a Commit. This constraint guarantees * that both peers have seen at least one Hello. * * When entering this transition function: * - The instance variabe sentPacket contains own Hello packet * - The instance variabe commitPkt points to prepared Commit packet * - Timer T1 is active * * Possible events in this state are: * - timeout for sent Hello packet: causes a resend check and repeat sending * of Hello packet * - HelloAck: The peer answered with HelloAck to own HelloAck/Hello. Send * prepared Commit packet and try Initiator mode. * - Commit: The peer answered with Commit to HelloAck/Hello, thus switch to * responder mode. * - Hello: If the protcol engine receives another Hello it repeats the * HelloAck/Hello response until Timer T1 exceeds its maximum. This may * happen if the other peer sends Hello only (maybe due to network problems) */ 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(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(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') { 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(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(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); } } /* * AckDetected state. * * The protocol engine received a HelloAck in state Detect, thus the peer * acknowledged our the Hello. According to ZRT RFC xxxx our peer must send * its Hello until our protocol engine sees it (refer also to comment for * state AckSent). This protocol sequence gurantees that both peers got at * least one Hello. * * When entering this transition function * - instance variable sentPacket is NULL, Hello timer stopped * * Possible events in this state are: * Hello: we have to choices * 1) we can acknowledge the peer's Hello with a HelloAck * 2) we can acknowledge the peer's Hello with a Commit * Both choices are implemented and may be enabled by setting a compile * time #if (see code below). Currently we use choice 1) here because * it's more aligned to the ZRTP specification */ 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 peers 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(helloAck); if (!parent->sendPacketZRTP(static_cast(helloAck))) { sendFailed(); } } #else /* * Implementation for choice 2) * Hello: * - Acknowledge peers 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') { // 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(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); } } /* * WaitCommit state. * * This state is only used if we use choice 1) in AckDetected. * * When entering this transition function * - instance variable sentPacket contains a HelloAck packet * * Possible events in this state are: * - Hello: just resend our HelloAck * - Commit: prepare and send our DHPart1 message to start first * half of DH key agreement. Switch to state WaitDHPart2, don't * start any timer, we a Responder. */ 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') { 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') { 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(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(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); } } /* * CommitSent state. * * This state either handles a DH1Part1 message to start the first * half of DH key agreement or it handles a Commit clash. If handling a * Commit clash it may happen that we change our role from Initiator to * Responder. * * When entering this transition function * - assume Initiator mode, may change if we reveice a Commit here * - sentPacket contains Commit packet * - Commit timer (T2) active * * Possible events in this state are: * - timeout for sent Commit packet: causes a resend check and repeat sending * of Commit packet * - Commit: This is a Commit clash. Break the tie accroding to chapter 5.2 * - DHPart1: start first half of DH key agreement. Perpare and send own DHPart2 * and switch to state WaitConfirm1. */ void ZrtpStateClass::evCommitSent(void) { DEBUGOUT((cout << "Checking for match in CommitSend.\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)); /* * 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' && (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(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(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') { 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(dhPart2); nextState(WaitConfirm1); if (!parent->sendPacketZRTP(sentPacket)) { sendFailed(); // returns to state Initial return; } if (startTimer(&T2) <= 0) { timerFailed(SevereNoTimer); // switches to state Initial } return; } 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(confirm); if (!parent->sendPacketZRTP(sentPacket)) { sendFailed(); // returns to state Initial return; } if (startTimer(&T2) <= 0) { timerFailed(SevereNoTimer); // returns to state Initial } // 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); } } /* * WaitDHPart2 state. * * This state handles the second part of SH key agreement. Only the Resonder * can enter this state. * * When entering this transition function * - sentPacket contains DHPart1 packet, no timer active * * Possible events in this state are: * - Commit: Our peer didn't receive out DHPart1 thus the peer sends Commit again. * Just repeat our DHPart1. * - DHPart2: start second half of DH key agreement. Perpare and send own Confirm1 * and switch to state WaitConfirm2. */ void ZrtpStateClass::evWaitDHPart2(void) { DEBUGOUT((cout << "Checking for match in DHPart2.\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)); /* * Commit: * - resend DHPart1 * - stay in state */ if (first == 'c') { 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') { ZrtpPacketDHPart dpkt(pkt); ZrtpPacketConfirm* confirm = parent->prepareConfirm1(&dpkt, &errorCode); if (confirm == NULL) { if (errorCode != IgnorePacket) { sendErrorPacket(errorCode); } return; } nextState(WaitConfirm2); sentPacket = static_cast(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); } } /* * WaitConirm1 state. * * This state handles a received Confirm1 message and only the Initiator * can enter this state. * * When entering this transition function in DH mode: * - Initiator mode * - sentPacket contains DHPart2 packet, DHPart2 timer active * * When entering this transition function in Multi stream mode via AckSent: * - Initiator mode * - sentPacket contains my Commit packet, Commit timer active * * Possible events in this state are: * - timeout for sent DHPart2 packet: causes a resend check and repeat sending * of DHPart2 packet. * - Confirm1: Check Confirm1 message. If it is ok then prepare and send own * Confirm2 packet and switch to state WaitConfAck. */ 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; } nextState(WaitConfAck); sentPacket = static_cast(confirm); if (!parent->sendPacketZRTP(sentPacket)) { sendFailed(); // returns to state Initial return; } if (startTimer(&T2) <= 0) { timerFailed(SevereNoTimer); // returns to state Initial } // 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; } } } 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); } } /* * WaitConfirm2 state. * * Handles the Confirm2 message that closes the key agreement handshake. Only * the Responder can enter this state. If the Confirm2 message is ok send a * Conf2Ack to our peer. Switch to secure mode after sending Conf2Ack, our * peer switches to secure mode after receiving Conf2Ack. * * When entering this transition function * - Responder mode * - sentPacket contains Confirm1 packet, no timer active * * Possible events in this state are: * - DHPart2: Our peer didn't receive our Confirm1 thus sends DHPart2 again. * Just repeat our Confirm1. * - Confirm2: close DH key agreement. Perpare and send own Conf2Ack * and switch to state SecureState. */ void ZrtpStateClass::evWaitConfirm2(void) { DEBUGOUT((cout << "Checking for match in WaitConfirm2.\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)); /* * DHPart2 or Commit in multi stream mode: * - resend Confirm1 packet * - stay in state */ if (first == 'd' || (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(confack); if (!parent->sendPacketZRTP(sentPacket)) { sendFailed(); // returns to state Initial return; } if (!parent->srtpSecretsReady(ForSender) || !parent->srtpSecretsReady(ForReceiver)) { 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); } } /* * WaitConf2Ack state. * * This state handles the Conf2Ack message that acknowledges the successfull * processing of Confirm2. Only the Initiator can enter this state. Switch on * secure mode and switch to state SecureState. * * When entering this transition function * - Initiator mode * - sentPacket contains Confirm2 packet, Confirm2 timer active * - receiver security switched on * * Possible events in this state are: * - timeout for sent Confirm2 packet: causes a resend check and repeat sending * of Confirm2 packet * - Conf2Ack: Key agreement was successfull, switch to secure mode. */ 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') { 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); } } /* * When entering this transition function * - sentPacket contains GoClear packet, GoClear timer active */ void ZrtpStateClass::evWaitClearAck(void) { DEBUGOUT((cout << "Checking for match in ClearAck.\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)); /* * ClearAck: * - stop resending GoClear, * - switch to state AckDetected, wait for peer's Hello */ if (first == 'c' && 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); } } /* * WaitErrorAck state. * * This state belongs to the "error handling state overlay" and handle * ErrorAck message. Most of the ZRTP states can send Error message for * example if they detect wrong packets. After sending an Error message * the protocol engine switches to WaitErrorAck state. Receiving an * ErrorAck message completes the ZRTP error handling. * * When entering this transition function * - sentPacket contains Error packet, Error timer active * * Possible events in this state are: * - timeout for sent Error packet: causes a resend check and repeat sending * of Error packet * - ErrorAck: Stop timer and switch to state Initial. */ 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); } } void ZrtpStateClass::evSecureState(void) { DEBUGOUT((cout << "Checking for match in SecureState.\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)); /* * 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(clearAck))) { return; } // TODO Timeout to resend clear ack until user user confirmation } } else { // unknown Event type for this state (covers Error and ZrtpClose) sentPacket = NULL; parent->srtpSecretsOff(ForSender); parent->srtpSecretsOff(ForReceiver); nextState(Initial); if (event->type != ZrtpClose) { parent->zrtpNegotiationFailed(Severe, SevereProtocolError); } parent->sendInfo(Info, InfoSecureStateOff); } } int32_t ZrtpStateClass::startTimer(zrtpTimer_t *t) { t->time = t->start; t->counter = 0; return parent->activateTimer(t->time); } 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); } void ZrtpStateClass::sendErrorPacket(uint32_t errorCode) { cancelTimer(); ZrtpPacketError* err = parent->prepareError(errorCode); parent->zrtpNegotiationFailed(ZrtpError, errorCode); sentPacket = static_cast(err); nextState(WaitErrorAck); if (!parent->sendPacketZRTP(static_cast(err)) || (startTimer(&T2) <= 0)) { sendFailed(); } } void ZrtpStateClass::sendFailed() { sentPacket = NULL; nextState(Initial); parent->zrtpNegotiationFailed(Severe, SevereCannotSend); } void ZrtpStateClass::timerFailed(int32_t subCode) { sentPacket = NULL; nextState(Initial); parent->zrtpNegotiationFailed(Severe, subCode); } void ZrtpStateClass::setMultiStream(bool multi) { multiStream = multi; } bool ZrtpStateClass::isMultiStream() { return multiStream; } /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/ZrtpTextData.cpp0000644000175000017500000000523411570305710016606 0ustar dyfetdyfet/* Copyright (C) 2006-2008 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 // 1 // 1234567890123456 char clientId[] = "GNU ZRTP 1.6.0 "; // 16 chars max. char zrtpVersion[] = "1.10"; // must be 4 chars /** * */ char HelloMsg[] = "Hello "; char HelloAckMsg[] = "HelloACK"; char CommitMsg[] = "Commit "; char DHPart1Msg[] = "DHPart1 "; char DHPart2Msg[] = "DHPart2 "; char Confirm1Msg[] = "Confirm1"; char Confirm2Msg[] = "Confirm2"; char Conf2AckMsg[] = "Conf2ACK"; char ErrorMsg[] = "Error "; char ErrorAckMsg[] = "ErrorACK"; char GoClearMsg[] = "GoClear "; char ClearAckMsg[] = "ClearACK"; char PingMsg[] = "Ping "; char PingAckMsg[] = "PingACK "; char responder[] = "Responder"; char initiator[] = "Initiator"; char iniMasterKey[] = "Initiator SRTP master key"; char iniMasterSalt[] = "Initiator SRTP master salt"; char respMasterKey[] = "Responder SRTP master key"; char respMasterSalt[] = "Responder SRTP master salt"; char iniHmacKey[] = "Initiator HMAC key"; char respHmacKey[] = "Responder HMAC key"; char retainedSec[] = "retained secret"; char iniZrtpKey[] = "Initiator ZRTP key"; char respZrtpKey[] = "Responder ZRTP key"; char sasString[] = "SAS"; char KDFString[] = "ZRTP-HMAC-KDF"; char zrtpSessionKey[] = "ZRTP Session Key"; char zrtpMsk[] = "ZRTP MSK"; char s256[] = "S256"; char s384[] = "S384"; const char* mandatoryHash = s256; char aes3[] = "AES3"; char aes2[] = "AES2"; char aes1[] = "AES1"; char two3[] = "2FS3"; char two2[] = "2FS2"; char two1[] = "2FS1"; const char* mandatoryCipher = aes1; char dh2k[] = "DH2k"; char ec25[] = "EC25"; char dh3k[] = "DH3k"; char ec38[] = "EC38"; char mult[] = "Mult"; const char* mandatoryPubKey = dh3k; char b32[] = "B32 "; const char* mandatorySasType = b32; char hs32[] = "HS32"; char hs80[] = "HS80"; char sk32[] = "SK32"; char sk64[] = "SK64"; const char* mandatoryAuthLen_1 = hs32; const char* mandatoryAuthLen_2 = hs80; libzrtpcpp-2.0.0/src/ZRtp.cpp0000755000175000017500000023065311570305710015117 0ustar dyfetdyfet/* Copyright (C) 2006-2009 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 . */ /*F * Authors: Werner Dittmann */ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace GnuZrtpCodes; /* disabled...but used in testing and debugging, probably should have a controlling #define... * 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, std::string id, ZrtpConfigure* config): callback(cb), dhContext(NULL), DHss(NULL), auxSecret(NULL), auxSecretLength(0), rs1Valid(false), rs2Valid(false), msgShaContext(NULL), multiStream(false), multiStreamAvailable(false), PBXEnrollment(false), configureAlgos(*config) { // setup the implicit hash function pointers and length hashLengthImpl = SHA256_DIGEST_LENGTH; hashFunctionImpl = sha256; hashListFunctionImpl = sha256; hmacFunctionImpl = hmac_sha256; hmacListFunctionImpl = hmac_sha256; /* * Generate H0 as a random number (256 bits, 32 bytes) and then * the hash chain, refer to chapter 10. 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 zrtpHello.configureHello(&configureAlgos); zrtpHello.setH3(H3); // set H3 in Hello, included in helloHash memcpy(zid, myZid, ZID_SIZE); zrtpHello.setZid(zid); setClientId(id); // set id, compute HMAC and final helloHash stateEngine = new ZrtpStateClass(this); } 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; } 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); } void ZRtp::processZrtpMessage(uint8_t *message, uint32_t pSSRC) { Event_t ev; peerSSRC = pSSRC; ev.type = ZrtpPacket; ev.packet = message; if (stateEngine != NULL) { stateEngine->processEvent(&ev); } } void ZRtp::processTimeout() { Event_t ev; ev.type = Timer; if (stateEngine != NULL) { stateEngine->processEvent(&ev); } } #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.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 (stateEngine != NULL) { ev.type = ZrtpClose; stateEngine->processEvent(&ev); } } bool ZRtp::inState(int32_t state) { if (stateEngine != NULL) { return stateEngine->inState(state); } else { return false; } } ZrtpPacketHello* ZRtp::prepareHello() { return &zrtpHello; } ZrtpPacketHelloAck* ZRtp::prepareHelloAck() { return &zrtpHelloAck; } /* * 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, InfoHelloReceived); 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, zid, ZID_SIZE) == 0) { // peers have same ZID???? *errMsg = EqualZIDHello; return NULL; } memcpy(peerH3, hello->getH3(), HASH_IMAGE_SIZE); /* * 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) { authLength = findBestAuthLen(hello); pubKey = findBestPubkey(hello); cipher = findBestCipher(hello, pubKey); hash = findBestHash(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(); // pubKeyLen = dhContext->getPubKeySize(); 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 * 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), 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(zid); 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(), hello->getLength() * ZRTP_WORD_SIZE); 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; } ZrtpPacketCommit* ZRtp::prepareCommitMultiStream(ZrtpPacketHello *hello) { randomZRTP(hvi, ZRTP_WORD_SIZE*4); // This is the Multi-Stream NONCE size zrtpCommit.setZid(zid); 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(); hashCtxFunction(msgShaContext, (unsigned char*)hello->getHeaderBase(), hello->getLength() * ZRTP_WORD_SIZE); 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; } /* * 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 our * peer's HVI then 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 prepared DH data, message * hash SHA context */ 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); ZIDRecord zidRec(peerZid); ZIDFile *zidFile = ZIDFile::getInstance(); zidFile->getRecord(&zidRec); // 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; } 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 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), 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); 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; } /* * At this point we will take the role of the Initiator. */ 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; // To compute the keys 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 generateKeysInitiator(dhPart1, zidRec); zid->saveRecord(&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; } /* * At this point we are Responder. */ 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, &zrtpHello); 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; // To compute the Keys 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. */ generateKeysResponder(dhPart2, zidRec); zid->saveRecord(&zidRec); delete dhContext; dhContext = NULL; // Fill in Confirm1 packet. zrtpConfirm1.setMessageType((uint8_t*)Confirm1Msg); // TODO: at this point sas hash is ready, perform signSAS callback and fill in signature if available zrtpConfirm1.setSignatureLength(0); // Check if user verfied the SAS in a previous call and thus verfied // the retained secret. if (zidRec.isSasVerified()) { zrtpConfirm1.setSASFlag(); } 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 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; } /* * At this point we are Responder. */ 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*)zrtpHello.getHeaderBase(), zrtpHello.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); // TODO: at this point sas hash is ready, perform signSAS callback and fill in signature if available zrtpConfirm1.setSignatureLength(0); 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; } /* * At this point we are Initiator. */ 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(), confirm1->getIv(), confirm1->getHashH0(), hmlen); std::string cs(cipher->getReadable()); cs.append("/").append(pubKey->getName()); // 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.1 and chapter 10. if (!checkMsgHmac(confirm1->getHashH0())) { sendInfo(Severe, SevereDH1HMACFailed); *errMsg = CriticalSWError; return NULL; } // TODO: here we have a SAS signature from reponder, call checkSASsignature (save / compare in case of resend) /* * 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 bool sasVerified = zidRec.isSasVerified(); callback->srtpSecretsOn(cs, SAS, sasVerified); // 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 zrtpConfirm2.setMessageType((uint8_t*)Confirm2Msg); // TODO: set signature data if available zrtpConfirm2.setSignatureLength(0); zrtpConfirm2.setHashH0(H0); if (sasFlag) { zrtpConfirm2.setSASFlag(); } 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; } /* * At this point we are Initiator. */ 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; } cipher->getDecrypt()(zrtpKeyR, cipher->getKeylen(), confirm1->getIv(), confirm1->getHashH0(), hmlen); std::string cs(cipher->getReadable()); // 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; } // TODO: here we have a SAS signature from reponder, call checkSASsignature (save / compare in case of resend) // Inform GUI about security state, don't show SAS and its state std::string cs1(""); callback->srtpSecretsOn(cs, cs1, true); // now generate my Confirm2 message zrtpConfirm2.setMessageType((uint8_t*)Confirm2Msg); // TODO: set signature data if available zrtpConfirm2.setSignatureLength(0); 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; } /* * At this point we are Responder. */ 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; } cipher->getDecrypt()(zrtpKeyI, cipher->getKeylen(), confirm2->getIv(), confirm2->getHashH0(), hmlen); std::string cs(cipher->getReadable()); 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; } /* * 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 bool sasVerified = zidRec.isSasVerified(); cs.append("/").append(pubKey->getName()); callback->srtpSecretsOn(cs, SAS, sasVerified); // save new RS1, this inherits the verified flag from old RS1 zidRec.setNewRs1((const uint8_t*)newRs1); zid->saveRecord(&zidRec); } 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; } std::string cs1(""); // Inform GUI about security state, don't show SAS and its state callback->srtpSecretsOn(cs, cs1, true); } // TODO: clear responders signature data in, prepare a call to do same for initiaor (called by state engine) return &zrtpConf2Ack; } ZrtpPacketErrorAck* ZRtp::prepareErrorAck(ZrtpPacketError* epkt) { sendInfo(ZrtpError, epkt->getErrorCode() * -1); return &zrtpErrorAck; } ZrtpPacketError* ZRtp::prepareError(uint32_t errMsg) { zrtpError.setErrorCode(errMsg); return &zrtpError; } ZrtpPacketPingAck* ZRtp::preparePingAck(ZrtpPacketPing* ppkt) { // 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(zid); zrtpPingAck.setRemoteEpHash(ppkt->getEpHash()); zrtpPingAck.setSSRC(peerSSRC); return &zrtpPingAck; } // TODO Implement GoClear handling ZrtpPacketClearAck* ZRtp::prepareClearAck(ZrtpPacketGoClear* gpkt) { sendInfo(Warning, WarningGoClearReceived); return &zrtpClearAck; } ZrtpPacketGoClear* ZRtp::prepareGoClear(uint32_t errMsg) { 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 the mandatory algorithm. * - Build a list of algorithm names and ids from configuration data. If * the configuration data does not contain a mandatory algorithm append * the mandatory algorithm to the list and ids. * - Build a list of algorithm names from the Hello message. If * the Hello message does not contain a mandatory algorithm append * the mandatory algorithm to the list. * - Lookup a matching algorithm. The list built from Hello takes * precedence in the lookup (indexed by the outermost loop). * * This guarantees that we always return a supported alogrithm respecting * the order of algorithms in the Hello message * * 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) * */ AlgorithmEnum* ZRtp::findBestHash(ZrtpPacketHello *hello) { int i; int ii; int numAlgosOffered; AlgorithmEnum* algosOffered[ZrtpConfigure::maxNoOfAlgos+1]; int numAlgosConf; AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+1]; bool mandatoryFound = false; // 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); if (*(int32_t*)(algosConf[i]->getName()) == *(int32_t*)mandatoryHash) { mandatoryFound = true; } } if (!mandatoryFound) { algosConf[numAlgosConf++] = &zrtpHashes.getByName(mandatoryHash); } // Build list of offered known algos in Hello, append mandatory algos if necessary mandatoryFound = false; for (numAlgosOffered = 0, i = 0; i < num; i++) { algosOffered[numAlgosOffered] = &zrtpHashes.getByName((const char*)hello->getHashType(i)); if(!algosOffered[numAlgosOffered]->isValid()) continue; if (*(int32_t*)(algosOffered[numAlgosOffered++]->getName()) == *(int32_t*)mandatoryHash) { mandatoryFound = true; } } if (!mandatoryFound) { algosOffered[numAlgosOffered++] = &zrtpHashes.getByName(mandatoryHash); } // 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); } 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]; bool mandatoryFound = false; 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, append mandatory algos // if necessary. numAlgosConf = configureAlgos.getNumConfiguredAlgos(CipherAlgorithm); for (i = 0; i < numAlgosConf; i++) { algosConf[i] = &configureAlgos.getAlgoAt(CipherAlgorithm, i); if (*(int32_t*)(algosConf[i]->getName()) == *(int32_t*)mandatoryCipher) { mandatoryFound = true; } } if (!mandatoryFound) { algosConf[numAlgosConf++] = &zrtpSymCiphers.getByName(mandatoryCipher); } // Build list of offered known algos names in Hello, append mandatory algos if // necessary mandatoryFound = false; for (numAlgosOffered = 0, i = 0; i < num; i++) { algosOffered[numAlgosOffered] = &zrtpSymCiphers.getByName((const char*)hello->getCipherType(i)); if(!algosOffered[numAlgosOffered]->isValid()) continue; if (*(int32_t*)(algosOffered[numAlgosOffered++]->getName()) == *(int32_t*)mandatoryCipher) { mandatoryFound = true; } } if (!mandatoryFound) { algosOffered[numAlgosOffered++] = &zrtpSymCiphers.getByName(mandatoryCipher); } // 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 &zrtpSymCiphers.getByName(mandatoryCipher); } AlgorithmEnum* ZRtp::findBestPubkey(ZrtpPacketHello *hello) { int i; int ii; int numAlgosOffered; AlgorithmEnum* algosOffered[ZrtpConfigure::maxNoOfAlgos+1]; int numAlgosConf; AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+1]; bool mandatoryFound = false; int num = hello->getNumPubKeys(); if (num == 0) { return &zrtpPubKeys.getByName(mandatoryPubKey); } // Build list of configured pubkey algorithm names, append mandatory algos // if necessary. // 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) { continue; // skip multi-stream mode } if (*(int32_t*)(algosConf[ii++]->getName()) == *(int32_t*)mandatoryPubKey) { mandatoryFound = true; } } numAlgosConf = ii; if (!mandatoryFound) { algosConf[numAlgosConf++] = &zrtpPubKeys.getByName(mandatoryPubKey); } // Build list of offered known algos in Hello, append mandatory algos if necessary mandatoryFound = false; for (numAlgosOffered = 0, i = 0; i < num; i++) { algosOffered[numAlgosOffered] = &zrtpPubKeys.getByName((const char*)hello->getPubKeyType(i)); if(!algosOffered[numAlgosOffered]->isValid()) continue; if (*(int32_t*)(algosOffered[numAlgosOffered++]->getName()) == *(int32_t*)mandatoryPubKey) { mandatoryFound = true; } } if (!mandatoryFound) { algosOffered[numAlgosOffered++] = &zrtpPubKeys.getByName(mandatoryPubKey); } // 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 &zrtpPubKeys.getByName(mandatoryPubKey); } AlgorithmEnum* ZRtp::findBestSASType(ZrtpPacketHello *hello) { int i; int ii; int numAlgosOffered; AlgorithmEnum* algosOffered[ZrtpConfigure::maxNoOfAlgos+1]; int numAlgosConf; AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+1]; bool mandatoryFound = false; int num = hello->getNumSas(); if (num == 0) { return &zrtpSasTypes.getByName(mandatorySasType); } // Buildlist of configured SAS algorithm names, append mandatory algos // if necessary. numAlgosConf = configureAlgos.getNumConfiguredAlgos(SasType); for (i = 0; i < numAlgosConf; i++) { algosConf[i] = &configureAlgos.getAlgoAt(SasType, i); if (*(int32_t*)(algosConf[i]->getName()) == *(int32_t*)mandatorySasType) { mandatoryFound = true; } } if (!mandatoryFound) { algosConf[numAlgosConf++] = &zrtpSasTypes.getByName(mandatorySasType); } // Build list of offered known algos in Hello, append mandatory algos if necessary for (numAlgosOffered = 0, i = 0; i < num; i++) { algosOffered[numAlgosOffered] = &zrtpSasTypes.getByName((const char*)hello->getSasType(i++)); if(!algosOffered[numAlgosOffered]->isValid()) continue; if (*(int32_t*)(algosOffered[numAlgosOffered++]->getName()) == *(int32_t*)mandatorySasType) { mandatoryFound = true; } } if (!mandatoryFound) { algosOffered[numAlgosOffered++] = &zrtpSasTypes.getByName(mandatorySasType); } // 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 &zrtpSasTypes.getByName(mandatorySasType); } AlgorithmEnum* ZRtp::findBestAuthLen(ZrtpPacketHello *hello) { int i; int ii; int numAlgosOffered; AlgorithmEnum* algosOffered[ZrtpConfigure::maxNoOfAlgos+2]; int numAlgosConf; AlgorithmEnum* algosConf[ZrtpConfigure::maxNoOfAlgos+2]; bool mandatoryFound_1 = false; bool mandatoryFound_2 = false; int num = hello->getNumAuth(); if (num == 0) { return &zrtpAuthLengths.getByName(mandatoryAuthLen_1); } // Build list of configured SAS algorithm names, append mandatory algos // if necessary. numAlgosConf = configureAlgos.getNumConfiguredAlgos(AuthLength); for (i = 0; i < numAlgosConf; i++) { algosConf[i] = &configureAlgos.getAlgoAt(AuthLength, i); if (*(int32_t*)(algosConf[i]->getName()) == *(int32_t*)mandatoryAuthLen_1) { mandatoryFound_1 = true; } if (*(int32_t*)(algosConf[i]->getName()) == *(int32_t*)mandatoryAuthLen_2) { mandatoryFound_2 = true; } } if (!mandatoryFound_1) { algosConf[numAlgosConf++] = &zrtpAuthLengths.getByName(mandatoryAuthLen_1); } if (!mandatoryFound_2) { algosConf[numAlgosConf++] = &zrtpAuthLengths.getByName(mandatoryAuthLen_2); } // Build list of offered known algos in Hello, append mandatory algos if necessary for (numAlgosOffered = 0, i = 0; i < num; i++) { algosOffered[numAlgosOffered] = &zrtpAuthLengths.getByName((const char*)hello->getAuthLen(i)); if(!algosOffered[numAlgosOffered]->isValid()) continue; if (*(int32_t*)(algosOffered[numAlgosOffered]->getName()) == *(int32_t*)mandatoryAuthLen_1) { mandatoryFound_1 = true; } if (*(int32_t*)(algosOffered[numAlgosOffered++]->getName()) == *(int32_t*)mandatoryAuthLen_2) { mandatoryFound_2 = true; } } if (!mandatoryFound_1) { algosOffered[numAlgosOffered++] = &zrtpAuthLengths.getByName(mandatoryAuthLen_1); } if (!mandatoryFound_2) { algosOffered[numAlgosOffered++] = &zrtpAuthLengths.getByName(mandatoryAuthLen_2); } // 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 &zrtpAuthLengths.getByName(mandatoryAuthLen_1); } 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; } 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; } 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; } 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; 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); } 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); } /* * 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. */ 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); 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); } /* * 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 in the specification). * When using this method then we are in Initiator role. */ void ZRtp::generateKeysInitiator(ZrtpPacketDHPart *dhPart, ZIDRecord& zidRec) { const uint8_t* setD[3]; int32_t rsFound = 0; setD[0] = setD[1] = setD[2] = NULL; /* * 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. */ int matchingSecrets = 0; if (memcmp(rs1IDr, dhPart->getRs1Id(), HMAC_SIZE) == 0) { setD[matchingSecrets++] = zidRec.getRs1(); rsFound = 0x1; } else if (memcmp(rs1IDr, dhPart->getRs2Id(), HMAC_SIZE) == 0) { setD[matchingSecrets++] = zidRec.getRs1(); rsFound = 0x2; } else if (memcmp(rs2IDr, dhPart->getRs1Id(), HMAC_SIZE) == 0) { setD[matchingSecrets++] = zidRec.getRs2(); rsFound = 0x4; } else if (memcmp(rs2IDr, dhPart->getRs2Id(), HMAC_SIZE) == 0) { setD[matchingSecrets++] = zidRec.getRs2(); rsFound = 0x8; } /* *** Not yet supported if (memcmp(auxSecretIDr, dhPart->getAuxSecretId(), 8) == 0) { DEBUGOUT((fprintf(stdout, "%c: Match for aux secret found\n", zid[0]))); setD[matchingSecrets++] = auxSecret; } if (memcmp(pbxSecretIDr, dhPart->getPbxSecretId(), 8) == 0) { DEBUGOUT((fprintf(stdout, "%c: Match for Other_secret found\n", zid[0]))); setD[matchingSecrets++] = ; } */ // 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 = htonl(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] = zid; 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 = htonl(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); } /* * 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::generateKeysResponder(ZrtpPacketDHPart *dhPart, ZIDRecord& zidRec) { const uint8_t* setD[3]; int32_t rsFound = 0; setD[0] = setD[1] = setD[2] = NULL; /* * Select the real secrets into setD */ int matchingSecrets = 0; if (memcmp(rs1IDi, dhPart->getRs1Id(), HMAC_SIZE) == 0) { setD[matchingSecrets++] = zidRec.getRs1(); rsFound = 0x1; } else if (memcmp(rs1IDi, dhPart->getRs2Id(), HMAC_SIZE) == 0) { setD[matchingSecrets++] = zidRec.getRs1(); rsFound = 0x2; } else if (memcmp(rs2IDi, dhPart->getRs2Id(), HMAC_SIZE) == 0) { setD[matchingSecrets++] = zidRec.getRs2(); rsFound |= 0x4; } else if (memcmp(rs2IDi, dhPart->getRs1Id(), HMAC_SIZE) == 0) { setD[matchingSecrets++] = zidRec.getRs2(); rsFound |= 0x8; } /* ***** not yet supported if (memcmp(auxSecretIDi, dhPart->getauxSecretId(), 8) == 0) { DEBUGOUT((fprintf(stdout, "%c: Match for aux secret found\n", zid[0]))); setD[matchingSecrets++] = ; } if (memcmp(pbxSecretIDi, dhPart->getPbxSecretId(), 8) == 0) { DEBUGOUT((fprintf(stdout, "%c: Match for PBX secret found\n", zid[0]))); setD[matchingSecrets++] = ; } */ // 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 = htonl(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] = zid; 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 = htonl(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); } 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 = htonl(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 = htonl(L); data[pos] = (unsigned char*)&len; length[pos++] = sizeof(uint32_t); data[pos] = NULL; // Use negotiated hash. // TODO: variable digest length hmacListFunction(key, keyLength, data, length, output, &maclen); } // Compute the Multi Stream mode s0 void ZRtp::generateKeysMultiStream() { // allocate the maximum size, compute real size to use uint8_t KDFcontext[sizeof(peerZid)+sizeof(zid)+sizeof(messageHash)]; int32_t kdfSize = sizeof(peerZid)+sizeof(zid)+hashLength; if (myRole == Responder) { memcpy(KDFcontext, peerZid, sizeof(peerZid)); memcpy(KDFcontext+sizeof(peerZid), zid, sizeof(zid)); } else { memcpy(KDFcontext, zid, sizeof(zid)); memcpy(KDFcontext+sizeof(zid), peerZid, sizeof(peerZid)); } memcpy(KDFcontext+sizeof(zid)+sizeof(peerZid), messageHash, hashLength); KDF(zrtpSession, hashLength, (unsigned char*)zrtpMsk, strlen(zrtpMsk)+1, KDFcontext, kdfSize, hashLength*8, s0); memset(KDFcontext, 0, sizeof(KDFcontext)); computeSRTPKeys(); } void ZRtp::computeSRTPKeys() { // allocate the maximum size, compute real size to use uint8_t KDFcontext[sizeof(peerZid)+sizeof(zid)+sizeof(messageHash)]; int32_t kdfSize = sizeof(peerZid)+sizeof(zid)+hashLength; int32_t keyLen = cipher->getKeylen() * 8; if (myRole == Responder) { memcpy(KDFcontext, peerZid, sizeof(peerZid)); memcpy(KDFcontext+sizeof(peerZid), zid, sizeof(zid)); } else { memcpy(KDFcontext, zid, sizeof(zid)); memcpy(KDFcontext+sizeof(zid), peerZid, sizeof(peerZid)); } memcpy(KDFcontext+sizeof(zid)+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); 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 SAS 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; SAS = Base32(sasBytes, 20).getEncoded(); } memset(KDFcontext, 0, sizeof(KDFcontext)); } 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; return callback->srtpSecretsReady(&sec, part); } 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; } } 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); } void ZRtp::sendInfo(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) { callback->sendInfo(severity, subCode); } void ZRtp::zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) { callback->zrtpNegotiationFailed(severity, subCode); } void ZRtp::zrtpNotSuppOther() { callback->zrtpNotSuppOther(); } void ZRtp::synchEnter() { callback->synchEnter(); } void ZRtp::synchLeave() { callback->synchLeave(); } int32_t ZRtp::sendPacketZRTP(ZrtpPacketBase *packet) { return ((packet == NULL) ? 0 : callback->sendDataZRTP(packet->getHeaderBase(), (packet->getLength() * 4) + 4)); } int32_t ZRtp::activateTimer(int32_t tm) { return (callback->activateTimer(tm)); } int32_t ZRtp::cancelTimer() { return (callback->cancelTimer()); } void ZRtp::setAuxSecret(uint8_t* data, int32_t length) { if (length > 0) { auxSecret = new uint8_t[length]; auxSecretLength = length; memcpy(auxSecret, data, length); } } void ZRtp::setPbxSecret(uint8_t* data, int32_t length) { } void ZRtp::setClientId(std::string id) { const char* tmp = " "; if (id.size() < ZID_SIZE) { zrtpHello.setClientId((unsigned char*)tmp); } zrtpHello.setClientId((unsigned char*)id.c_str()); int32_t len = zrtpHello.getLength() * ZRTP_WORD_SIZE; // Hello packet is 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); // 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); } void ZRtp::storeMsgTemp(ZrtpPacketBase* pkt) { int32_t length = pkt->getLength() * ZRTP_WORD_SIZE; memset(tempMsgBuffer, 0, sizeof(tempMsgBuffer)); memcpy(tempMsgBuffer, (uint8_t*)pkt->getHeaderBase(), length); lengthOfMsgData = length; } 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); } std::string ZRtp::getHelloHash() { std::ostringstream stm; uint8_t* hp = helloHash; stm << zrtpVersion; stm << " "; stm.fill('0'); stm << hex; for (int i = 0; i < hashLengthImpl; i++) { stm.width(2); stm << static_cast(*hp++); } return stm.str(); } 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; } 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); } bool ZRtp::isMultiStream() { return multiStream; } bool ZRtp::isMultiStreamAvailable() { return multiStreamAvailable; } void ZRtp::acceptEnrollment(bool accepted) { return; } bool ZRtp::setSignatureData(uint8_t* data, int32_t length) { return false; } void ZRtp::conf2AckSecure() { Event_t ev; ev.type = ZrtpPacket; ev.packet = (uint8_t*)&zrtpConf2Ack; if (stateEngine != NULL) { stateEngine->processEvent(&ev); } } int32_t ZRtp::getSignatureData(uint8_t* data) { return 0; } int32_t ZRtp::getSignatureLength() { return 0; } int32_t ZRtp::compareCommit(ZrtpPacketCommit *commit) { // TODO: enhance to compare according to rules defined in chapter 4.2 int32_t len = 0; len = !multiStream ? HVI_SIZE : (4 * ZRTP_WORD_SIZE); return (memcmp(hvi, commit->getHvi(), len)); } void ZRtp:: setPBXEnrollment(bool yesNo) { PBXEnrollment = yesNo; } int32_t ZRtp::getZid(uint8_t* data) { memcpy(data, peerZid, IDENTIFIER_LEN); return IDENTIFIER_LEN; } /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/ZrtpPacketGoClear.cpp0000644000175000017500000000303111570305710017525 0ustar dyfetdyfet/* 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 . */ /* Copyright (C) 2006 * * Authors: Werner Dittmann */ #include ZrtpPacketGoClear::ZrtpPacketGoClear() { DEBUGOUT((fprintf(stdout, "Creating GoClear packet without data\n"))); zrtpHeader = &data.hdr; // the standard header clearHeader = &data.goClear; setZrtpId(); setLength((sizeof(GoClearPacket_t) / ZRTP_WORD_SIZE) - 1); setMessageType((uint8_t*)GoClearMsg); } ZrtpPacketGoClear::ZrtpPacketGoClear(uint8_t *data) { DEBUGOUT((fprintf(stdout, "Creating GoClear packet from data\n"))); zrtpHeader = (zrtpPacketHeader_t *)&((GoClearPacket_t *)data)->hdr; // the standard header clearHeader = (GoClear_t *)&((GoClearPacket_t *)data)->goClear; } ZrtpPacketGoClear::~ZrtpPacketGoClear() { DEBUGOUT((fprintf(stdout, "Deleting GoClear packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpQueue.cpp0000644000175000017500000005633511570305710016164 0ustar dyfetdyfet/* Copyright (C) 2006-2009 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 static TimeoutProvider* staticTimeoutProvider = NULL; NAMESPACE_COMMONCPP using namespace GnuZrtpCodes; ZrtpQueue::ZrtpQueue(uint32 size, RTPApplication& app) : AVPQueue(size,app) { init(); } ZrtpQueue::ZrtpQueue(uint32 ssrc, uint32 size, RTPApplication& app) : AVPQueue(ssrc,size,app) { init(); } void ZrtpQueue::init() { zrtpUserCallback = NULL; enableZrtp = false; started = false; zrtpEngine = NULL; senderZrtpSeqNo = 1; clientIdString = clientId; peerSSRC = 0; } ZrtpQueue::~ZrtpQueue() { endQueue(); stopZrtp(); if (zrtpUserCallback != NULL) { delete zrtpUserCallback; zrtpUserCallback = NULL; } } int32_t 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; if (staticTimeoutProvider == NULL) { staticTimeoutProvider = new TimeoutProvider(); staticTimeoutProvider->start(); } ZIDFile* zf = ZIDFile::getInstance(); 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); } if (configOwn != NULL) { delete configOwn; } synchLeave(); return ret; } void ZrtpQueue::startZrtp() { if (zrtpEngine != NULL) { zrtpEngine->startZrtpEngine(); started = true; } } void ZrtpQueue::stopZrtp() { if (zrtpEngine != NULL) { delete zrtpEngine; zrtpEngine = NULL; started = false; } } /* * The takeInDataPacket implementation for ZRTPQueue. */ size_t 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) { // 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(packet->getHdrExtContent()); extHeader -= 4; // store peer's SSRC, used when creating the CryptoContext peerSSRC = packet->getSSRC(); zrtpEngine->processZrtpMessage(extHeader, peerSSRC); } delete packet; return 0; } size_t 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; } bool ZrtpQueue::onSRTPPacketError(IncomingRTPPkt& pkt, int32 errorCode) { if (errorCode == -1) { sendInfo(Warning, WarningSRTPauthError); } else { sendInfo(Warning, WarningSRTPreplayError); } return false; } void ZrtpQueue::putData(uint32 stamp, const unsigned char* data, size_t len) { OutgoingDataQueue::putData(stamp, data, len); } void ZrtpQueue::sendImmediate(uint32 stamp, const unsigned char* data, size_t len) { OutgoingDataQueue::sendImmediate(stamp, data, len); } /* * Here the callback methods required by the ZRTP implementation */ 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; } bool ZrtpQueue::srtpSecretsReady(SrtpSecret_t* secrets, EnableSecurity part) { CryptoContext* pcc; CryptoContext* recvCryptoContext; CryptoContext* senderCryptoContext; 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 } 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 } if (senderCryptoContext == NULL) { return false; } // Create a SRTP crypto context for real SSRC sender stream. // Note: key derivation can be done at this time only if the // key derivation rate is 0 (disabled). For ZRTP this is the // case: the key derivation is defined as 2^48 // which is effectively 0. pcc = senderCryptoContext->newCryptoContextForSSRC(getLocalSSRC(), 0, 0L); if (pcc == NULL) { return false; } pcc->deriveSrtpKeys(0L); setOutQueueCryptoContext(pcc); } 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 } 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 } if (recvCryptoContext == NULL) { return false; } // Create a SRTP crypto context for real SSRC input stream. // If the sender didn't provide a SSRC just insert the template // into the queue. After we received the first packet the real // crypto context will be created. // // Note: key derivation can be done at this time only if the // key derivation rate is 0 (disabled). For ZRTP this is the // case: the key derivation is defined as 2^48 // which is effectively 0. if (peerSSRC != 0) { pcc = recvCryptoContext->newCryptoContextForSSRC(peerSSRC, 0, 0L); if (pcc == NULL) { return false; } pcc->deriveSrtpKeys(0L); setInQueueCryptoContext(pcc); } else { setInQueueCryptoContext(recvCryptoContext); } } return true; } void ZrtpQueue::srtpSecretsOn(std::string c, std::string s, bool verified) { if (zrtpUserCallback != NULL) { zrtpUserCallback->secureOn(c); if (!s.empty()) { zrtpUserCallback->showSAS(s, verified); } } } void ZrtpQueue::srtpSecretsOff(EnableSecurity part) { if (part == ForSender) { removeOutQueueCryptoContext(NULL); } if (part == ForReceiver) { removeInQueueCryptoContext(NULL); } if (zrtpUserCallback != NULL) { zrtpUserCallback->secureOff(); } } int32_t ZrtpQueue::activateTimer(int32_t time) { std::string s("ZRTP"); if (staticTimeoutProvider != NULL) { staticTimeoutProvider->requestTimeout(time, this, s); } return 1; } int32_t ZrtpQueue::cancelTimer() { std::string s("ZRTP"); if (staticTimeoutProvider != NULL) { staticTimeoutProvider->cancelRequest(this, s); } return 1; } void ZrtpQueue::handleTimeout(const std::string &c) { if (zrtpEngine != NULL) { zrtpEngine->processTimeout(); } } void ZrtpQueue::handleGoClear() { fprintf(stderr, "Need to process a GoClear message!"); } void ZrtpQueue::sendInfo(MessageSeverity severity, int32_t subCode) { if (zrtpUserCallback != NULL) { zrtpUserCallback->showMessage(severity, subCode); } } void ZrtpQueue::zrtpNegotiationFailed(MessageSeverity severity, int32_t subCode) { if (zrtpUserCallback != NULL) { zrtpUserCallback->zrtpNegotiationFailed(severity, subCode); } } void ZrtpQueue::zrtpNotSuppOther() { if (zrtpUserCallback != NULL) { zrtpUserCallback->zrtpNotSuppOther(); } } void ZrtpQueue::synchEnter() { synchLock.enter(); } void ZrtpQueue::synchLeave() { synchLock.leave(); } void ZrtpQueue::zrtpAskEnrollment(std::string info) { if (zrtpUserCallback != NULL) { zrtpUserCallback->zrtpAskEnrollment(info); } } void ZrtpQueue::zrtpInformEnrollment(std::string info) { if (zrtpUserCallback != NULL) { zrtpUserCallback->zrtpInformEnrollment(info); } } void ZrtpQueue::signSAS(std::string sas) { if (zrtpUserCallback != NULL) { zrtpUserCallback->signSAS(sas); } } bool ZrtpQueue::checkSASSignature(std::string sas) { if (zrtpUserCallback != NULL) { return zrtpUserCallback->checkSASSignature(sas); } return false; } void ZrtpQueue::setEnableZrtp(bool onOff) { enableZrtp = onOff; } bool ZrtpQueue::isEnableZrtp() { return enableZrtp; } void ZrtpQueue::SASVerified() { if (zrtpEngine != NULL) zrtpEngine->SASVerified(); } void ZrtpQueue::resetSASVerified() { if (zrtpEngine != NULL) zrtpEngine->resetSASVerified(); } void ZrtpQueue::goClearOk() { } void ZrtpQueue::requestGoClear() { } void ZrtpQueue::setAuxSecret(uint8* data, int32_t length) { if (zrtpEngine != NULL) zrtpEngine->setAuxSecret(data, length); } void ZrtpQueue::setPbxSecret(uint8* data, int32 length) { if (zrtpEngine != NULL) zrtpEngine->setPbxSecret(data, length); } void ZrtpQueue::setUserCallback(ZrtpUserCallback* ucb) { zrtpUserCallback = ucb; } void ZrtpQueue::setClientId(std::string id) { clientIdString = id; } std::string ZrtpQueue::getHelloHash() { if (zrtpEngine != NULL) return zrtpEngine->getHelloHash(); else return std::string(); } std::string ZrtpQueue::getMultiStrParams() { if (zrtpEngine != NULL) return zrtpEngine->getMultiStrParams(); else return std::string(); } void ZrtpQueue::setMultiStrParams(std::string parameters) { if (zrtpEngine != NULL) zrtpEngine->setMultiStrParams(parameters); } bool ZrtpQueue::isMultiStream() { if (zrtpEngine != NULL) return zrtpEngine->isMultiStream(); return false; } bool ZrtpQueue::isMultiStreamAvailable() { if (zrtpEngine != NULL) return zrtpEngine->isMultiStreamAvailable(); return false; } void ZrtpQueue::acceptEnrollment(bool accepted) { if (zrtpEngine != NULL) zrtpEngine->acceptEnrollment(accepted); } bool ZrtpQueue::setSignatureData(uint8* data, int32 length) { if (zrtpEngine != NULL) return zrtpEngine->setSignatureData(data, length); return 0; } int32 ZrtpQueue::getSignatureData(uint8* data) { if (zrtpEngine != NULL) return zrtpEngine->getSignatureData(data); return 0; } int32 ZrtpQueue::getSignatureLength() { if (zrtpEngine != NULL) return zrtpEngine->getSignatureLength(); return 0; } void ZrtpQueue::setPBXEnrollment(bool yesNo) { if (zrtpEngine != NULL) zrtpEngine->setPBXEnrollment(yesNo); } int32 ZrtpQueue::getZid(uint8* data) { if (data == NULL) return 0; if (zrtpEngine != NULL) return zrtpEngine->getZid(data); return 0; } IncomingZRTPPkt::IncomingZRTPPkt(const unsigned char* const block, size_t len) : IncomingRTPPkt(block,len) { } uint32 IncomingZRTPPkt::getZrtpMagic() const { return ntohl(getHeader()->timestamp); } uint32 IncomingZRTPPkt::getSSRC() const { return ntohl(getHeader()->sources[0]); } 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); } END_NAMESPACE /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/ZrtpPacketHello.cpp0000644000175000017500000001036211570305710017261 0ustar dyfetdyfet/* 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 ZrtpPacketHello::ZrtpPacketHello() { DEBUGOUT((fprintf(stdout, "Creating Hello packet without data\n"))); } 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); setVersion((uint8_t*)zrtpVersion); 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()); } helloHeader->flagLength = htonl(lenField); } 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 temp = ntohl(helloHeader->flagLength); nHash = (temp & (0xf << 16)) >> 16; nCipher = (temp & (0xf << 12)) >> 12; nAuth = (temp & (0xf << 8)) >> 8; nPubkey = (temp & (0xf << 4)) >> 4; nSas = temp & 0xf; 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 } ZrtpPacketHello::~ZrtpPacketHello() { DEBUGOUT((fprintf(stdout, "Deleting Hello packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpPacketError.cpp0000644000175000017500000000301511570305710017304 0ustar dyfetdyfet/* 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 . */ /* Copyright (C) 2006 * * Authors: Werner Dittmann */ #include ZrtpPacketError::ZrtpPacketError() { DEBUGOUT((fprintf(stdout, "Creating Error packet without data\n"))); zrtpHeader = &data.hdr; // the standard header errorHeader = &data.error; setZrtpId(); setLength((sizeof(ErrorPacket_t) / ZRTP_WORD_SIZE) - 1); setMessageType((uint8_t*)ErrorMsg); } ZrtpPacketError::ZrtpPacketError(uint8_t *data) { DEBUGOUT((fprintf(stdout, "Creating Error packet from data\n"))); allocated = NULL; zrtpHeader = (zrtpPacketHeader_t *)&((ErrorPacket_t *)data)->hdr; // the standard header errorHeader = (Error_t *)&((ErrorPacket_t *)data)->error; } ZrtpPacketError::~ZrtpPacketError() { DEBUGOUT((fprintf(stdout, "Deleting Error packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpPacketConf2Ack.cpp0000644000175000017500000000265011570305710017605 0ustar dyfetdyfet/* 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 ZrtpPacketConf2Ack::ZrtpPacketConf2Ack() { DEBUGOUT((fprintf(stdout, "Creating Conf2Ack packet without data\n"))); zrtpHeader = &data.hdr; // the standard header setZrtpId(); setLength((sizeof (Conf2AckPacket_t) / ZRTP_WORD_SIZE) - 1); setMessageType((uint8_t*)Conf2AckMsg); } ZrtpPacketConf2Ack::ZrtpPacketConf2Ack(char *data) { DEBUGOUT((fprintf(stdout, "Creating Conf2Ack packet from data\n"))); zrtpHeader = (zrtpPacketHeader_t *)&((Conf2AckPacket_t*)data)->hdr; // the standard header } ZrtpPacketConf2Ack::~ZrtpPacketConf2Ack() { DEBUGOUT((fprintf(stdout, "Deleting Conf2Ack packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpPacketClearAck.cpp0000644000175000017500000000265211570305710017666 0ustar dyfetdyfet/* 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 . */ /* * @author: Werner Dittmann */ #include ZrtpPacketClearAck::ZrtpPacketClearAck() { DEBUGOUT((fprintf(stdout, "Creating ClearAck packet without data\n"))); zrtpHeader = &data.hdr; // the standard header setZrtpId(); setLength((sizeof(ClearAckPacket_t) / ZRTP_WORD_SIZE) - 1); setMessageType((uint8_t*)ClearAckMsg); } ZrtpPacketClearAck::ZrtpPacketClearAck(uint8_t *data) { DEBUGOUT((fprintf(stdout, "Creating Conf2Ack packet from data\n"))); zrtpHeader = (zrtpPacketHeader_t *)&((ClearAckPacket_t*)data)->hdr; // the standard header } ZrtpPacketClearAck::~ZrtpPacketClearAck() { DEBUGOUT((fprintf(stdout, "Deleting ClearAck packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpCallbackWrapper.cpp0000644000175000017500000001073111570305710020123 0ustar dyfetdyfet/* This class maps the ZRTP C++ callback methods to C callback methods. Copyright (C) 2010 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 . */ #include ZrtpCallbackWrapper::ZrtpCallbackWrapper(zrtp_Callbacks* cb, ZrtpContext* ctx) : c_callbacks(cb), zrtpCtx(ctx) { init(); } void ZrtpCallbackWrapper::init() { } /* * The following methods implement the GNU ZRTP callback interface. * For detailed documentation refer to file ZrtpCallback.h */ int32_t ZrtpCallbackWrapper::sendDataZRTP(const unsigned char* data, int32_t length) { return c_callbacks->zrtp_sendDataZRTP(zrtpCtx, data, length); } int32_t ZrtpCallbackWrapper::activateTimer (int32_t time) { c_callbacks->zrtp_activateTimer(zrtpCtx, time); return 1; } int32_t ZrtpCallbackWrapper::cancelTimer() { c_callbacks->zrtp_cancelTimer(zrtpCtx); return 0; } void ZrtpCallbackWrapper::sendInfo (GnuZrtpCodes::MessageSeverity severity, int32_t subCode) { c_callbacks->zrtp_sendInfo(zrtpCtx, (int32_t)severity, subCode); } bool ZrtpCallbackWrapper::srtpSecretsReady(SrtpSecret_t* secrets, EnableSecurity part) { C_SrtpSecret_t* cs = new C_SrtpSecret_t; cs->symEncAlgorithm = (zrtp_SrtpAlgorithms)secrets->symEncAlgorithm; cs->initKeyLen = secrets->initKeyLen; cs->initSaltLen = secrets->initSaltLen; cs->keyInitiator = secrets->keyInitiator; cs->keyResponder = secrets->keyResponder; cs->respKeyLen = secrets->respKeyLen; cs->respSaltLen = secrets->respSaltLen; cs->role = (int32_t)secrets->role; cs->saltInitiator = secrets->saltInitiator; cs->saltResponder = secrets->saltResponder; cs->sas = new char [secrets->sas.size()+1]; strcpy(cs->sas, secrets->sas.c_str()); cs->authAlgorithm = (zrtp_SrtpAlgorithms)secrets->authAlgorithm; cs->srtpAuthTagLen = secrets->srtpAuthTagLen; bool retval = (c_callbacks->zrtp_srtpSecretsReady(zrtpCtx, cs, (int32_t)part) == 0) ? false : true ; delete cs->sas; delete cs; return retval; } void ZrtpCallbackWrapper::srtpSecretsOff (EnableSecurity part ) { c_callbacks->zrtp_srtpSecretsOff(zrtpCtx, (int32_t)part); } void ZrtpCallbackWrapper::srtpSecretsOn ( std::string c, std::string s, bool verified ) { char* cc = new char [c.size()+1]; char* cs = new char [s.size()+1]; strcpy(cc, c.c_str()); if(!s.empty()) strcpy(cs, s.c_str()); else *cs = '\0'; c_callbacks->zrtp_rtpSecretsOn(zrtpCtx, cc, cs, verified?1:0); delete[] cc; delete[] cs; } void ZrtpCallbackWrapper::handleGoClear() { } void ZrtpCallbackWrapper::zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) { c_callbacks->zrtp_zrtpNegotiationFailed(zrtpCtx, (int32_t)severity, subCode); } void ZrtpCallbackWrapper::zrtpNotSuppOther() { c_callbacks->zrtp_zrtpNotSuppOther(zrtpCtx); } void ZrtpCallbackWrapper::synchEnter() { c_callbacks->zrtp_synchEnter(zrtpCtx); } void ZrtpCallbackWrapper::synchLeave() { c_callbacks->zrtp_synchLeave(zrtpCtx); } void ZrtpCallbackWrapper::zrtpAskEnrollment(std::string info) { char* cc = new char [info.size()+1]; strcpy(cc, info.c_str()); c_callbacks->zrtp_zrtpAskEnrollment(zrtpCtx, cc); delete[] cc; } void ZrtpCallbackWrapper::zrtpInformEnrollment(std::string info) { char* cc = new char [info.size()+1]; strcpy(cc, info.c_str()); c_callbacks->zrtp_zrtpInformEnrollment(zrtpCtx, cc); delete[] cc; } void ZrtpCallbackWrapper::signSAS(std::string sas) { char* cc = new char [sas.size()+1]; strcpy(cc, sas.c_str()); c_callbacks->zrtp_signSAS(zrtpCtx, cc); delete[] cc; } bool ZrtpCallbackWrapper::checkSASSignature(std::string sas ) { char* cc = new char [sas.size()+1]; strcpy(cc, sas.c_str()); bool retval = (c_callbacks->zrtp_checkSASSignature(zrtpCtx, cc) == 0) ? false : true; delete[] cc; return retval; } libzrtpcpp-2.0.0/src/ZIDFile.cpp0000644000175000017500000003041211570305710015432 0ustar dyfetdyfet/* Copyright (C) 2006-2008 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 */ // #define UNIT_TEST #include #include #include #include static ZIDFile* instance; static int errors = 0; // maybe we will use as member of ZIDFile later... void ZIDFile::createZIDFile(char* name) { zidFile = fopen(name, "wb+"); // New file, generate an associated random ZID and save // it as first record if (zidFile != NULL) { unsigned int* ip; ip = (unsigned int*) associatedZid; srand(time(NULL)); *ip++ = rand(); *ip++ = rand(); *ip = rand(); ZIDRecord rec(associatedZid); rec.setOwnZIDRecord(); fseek(zidFile, 0L, SEEK_SET); if (fwrite(rec.getRecordData(), rec.getRecordLength(), 1, zidFile) < 1) ++errors; fflush(zidFile); } } /** * Migrate old ZID file format to new one. * * If ZID file is old format: * - close it, rename it, then re-open * - create ZID file for new format * - copy over contents and flags. */ void ZIDFile::checkDoMigration(char* name) { FILE* fdOld; unsigned char inb[2]; zidrecord1_t recOld; fseek(zidFile, 0L, SEEK_SET); if (fread(inb, 2, 1, zidFile) < 1) { ++errors; inb[0] = 0; } if (inb[0] > 0) { // if it's new format just return return; } fclose(zidFile); // close old ZID file zidFile = NULL; // create save file name, rename and re-open // if rename fails, just unlink old ZID file and create a brand new file // just a little inconnvenience for the user, need to verify new SAS std::string fn = std::string(name) + std::string(".save"); if (rename(name, fn.c_str()) < 0) { unlink(name); createZIDFile(name); return; } fdOld = fopen(fn.c_str(), "rb"); // reopen old format in read only mode // Get first record from old file - is the own ZID fseek(fdOld, 0L, SEEK_SET); if (fread(&recOld, sizeof(zidrecord1_t), 1, fdOld) != 1) { fclose(fdOld); return; } if (recOld.ownZid != 1) { fclose(fdOld); return; } zidFile = fopen(name, "wb+"); // create new format file in binary r/w mode if (zidFile == NULL) { return; } // create ZIDRecord in new format, copy over own ZID and write the record ZIDRecord rec(recOld.identifier); rec.setOwnZIDRecord(); if (fwrite(rec.getRecordData(), rec.getRecordLength(), 1, zidFile) < 1) ++errors; // now copy over all valid records from old ZID file format. // Sequentially read old records, sequentially write new records int numRead; do { numRead = fread(&recOld, sizeof(zidrecord1_t), 1, fdOld); if (numRead == 0) { // all old records processed break; } // skip own ZID record and invalid records if (recOld.ownZid == 1 || recOld.recValid == 0) { continue; } ZIDRecord rec2(recOld.identifier); rec2.setValid(); if (recOld.rs1Valid & SASVerified) { rec2.setSasVerified(); } rec2.setNewRs1(recOld.rs2Data); rec2.setNewRs1(recOld.rs1Data); if (fwrite(rec2.getRecordData(), rec2.getRecordLength(), 1, zidFile) < 1) ++errors; } while (numRead == 1); fflush(zidFile); } ZIDFile::~ZIDFile() { close(); } ZIDFile* ZIDFile::getInstance() { if (instance == NULL) { instance = new ZIDFile(); } return instance; } int ZIDFile::open(char* name) { // check for an already active ZID file if (zidFile != NULL) { return 0; } if ((zidFile = fopen(name, "rb+")) == NULL) { createZIDFile(name); } else { checkDoMigration(name); if (zidFile != NULL) { ZIDRecord rec; fseek(zidFile, 0L, SEEK_SET); if (fread(rec.getRecordData(), rec.getRecordLength(), 1, zidFile) != 1) { fclose(zidFile); zidFile = NULL; return -1; } if (!rec.isOwnZIDRecord()) { fclose(zidFile); zidFile = NULL; return -1; } memcpy(associatedZid, rec.getIdentifier(), IDENTIFIER_LEN); } } return ((zidFile == NULL) ? -1 : 1); } void ZIDFile::close() { if (zidFile != NULL) { fclose(zidFile); zidFile = NULL; } } unsigned int ZIDFile::getRecord(ZIDRecord* zidRecord) { unsigned long pos; ZIDRecord rec; int numRead; // set read pointer behind first record ( fseek(zidFile, rec.getRecordLength(), SEEK_SET); do { pos = ftell(zidFile); numRead = fread(rec.getRecordData(), rec.getRecordLength(), 1, zidFile); if (numRead == 0) { break; } // skip own ZID record and invalid records if (rec.isOwnZIDRecord() || !rec.isValid()) { continue; } } while (numRead == 1 && memcmp(zidRecord->getIdentifier(), rec.getIdentifier(), IDENTIFIER_LEN) != 0); // If we reached end of file, then no record with the ZID // found. We need to create a new ZID record. if (numRead == 0) { // create new record ZIDRecord rec1(zidRecord->getIdentifier()); rec1.setValid(); if (fwrite(rec1.getRecordData(), rec1.getRecordLength(), 1, zidFile) < 1) ++errors; memcpy(zidRecord->getRecordData(), rec1.getRecordData(), rec1.getRecordLength()); } else { // Copy the read data into caller's the record storage memcpy(zidRecord->getRecordData(), rec.getRecordData(), rec.getRecordLength()); } // remember position of record in file for save operation zidRecord->setPosition(pos); return 1; } unsigned int ZIDFile::saveRecord(ZIDRecord *zidRecord) { fseek(zidFile, zidRecord->getPosition(), SEEK_SET); if (fwrite(zidRecord->getRecordData(), zidRecord->getRecordLength(), 1, zidFile) < 1) ++errors; fflush(zidFile); return 1; } #ifdef UNIT_TEST #include #include using namespace std; 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"); } int main(int argc, char *argv[]) { unsigned char myId[IDENTIFIER_LEN]; ZIDFile *zid = ZIDFile::getInstance(); unlink("testzid2"); zid->open("testzid2"); hexdump("My ZID: ", zid->getZid(), IDENTIFIER_LEN); memcpy(myId, zid->getZid(), IDENTIFIER_LEN); zid->close(); zid->open("testzid2"); if (memcmp(myId, zid->getZid(), IDENTIFIER_LEN) != 0) { cerr << "Wrong ZID in testfile" << endl; return 1; } // Create a new ZID record for peer ZID "123456789012" ZIDRecord zr3((unsigned char*) "123456789012"); zid->getRecord(&zr3); if (!zr3.isValid()) { cerr << "New ZID record '123456789012' not set to valid" << endl; return 1; } zid->saveRecord(&zr3); // create a second record with peer ZID "210987654321" ZIDRecord zr4((unsigned char*) "210987654321"); zid->getRecord(&zr4); if (!zr4.isValid()) { cerr << "New ZID record '210987654321' not set to valid" << endl; return 1; } zid->saveRecord(&zr4); // now set a first RS1 with default expiration interval, check // if set correctly, valid flag and expiration interval zr3.setNewRs1((unsigned char*) "11122233344455566677788899900012"); if (memcmp(zr3.getRs1(), "11122233344455566677788899900012", RS_LENGTH) != 0) { cerr << "RS1 was not set (111...012)" << endl; return 1; } if (!zr3.isRs1Valid()) { cerr << "RS1 was not set to valid state (111...012)" << endl; return 1; } if (!zr3.isRs1NotExpired()) { cerr << "RS1 expired (111...012)" << endl; return 1; } if (zr3.isRs2Valid()) { cerr << "RS2 was set to valid state (111...012)" << endl; return 1; } zid->saveRecord(&zr3); // create a second RS1, RS2 will become the first RS1, check // if set correctly, valid flag and expiration interval for both // RS1 and RS2 zr3.setNewRs1((unsigned char*) "00099988877766655544433322211121"); if (memcmp(zr3.getRs1(), "00099988877766655544433322211121", RS_LENGTH) != 0) { cerr << "RS1 was not set (000...121)" << endl; return 1; } if (!zr3.isRs1Valid()) { cerr << "RS1 was not set to valid state (000...121)" << endl; return 1; } if (!zr3.isRs1NotExpired()) { cerr << "RS1 expired (000...121)" << endl; return 1; } if (memcmp(zr3.getRs2(), "11122233344455566677788899900012", RS_LENGTH) != 0) { cerr << "RS2 was not set (111...012)" << endl; return 1; } if (!zr3.isRs2Valid()) { cerr << "RS2 was not set to valid state (111...012)" << endl; return 1; } if (!zr3.isRs2NotExpired()) { cerr << "RS2 expired (111...012)" << endl; return 1; } zid->saveRecord(&zr3); zid->close(); // Reopen, check if first record is still valid, RSx vaild and // not expired. Then manipulate 2nd record. zid->open("testzid2"); ZIDRecord zr3a((unsigned char*) "123456789012"); zid->getRecord(&zr3a); if (!zr3a.isValid()) { cerr << "Re-read ZID record '123456789012' not set to valid" << endl; return 1; } if (memcmp(zr3a.getRs1(), "00099988877766655544433322211121", RS_LENGTH) != 0) { cerr << "re-read RS1 was not set (000...121)" << endl; return 1; } if (!zr3a.isRs1Valid()) { cerr << "Re-read RS1 was not set to valid state (000...121)" << endl; return 1; } if (!zr3a.isRs1NotExpired()) { cerr << "re-read RS1 expired (000...121)" << endl; return 1; } if (memcmp(zr3a.getRs2(), "11122233344455566677788899900012", RS_LENGTH) != 0) { cerr << "re-read RS2 was not set (111...012)" << endl; return 1; } if (!zr3a.isRs2Valid()) { cerr << "Re-read RS2 was not set to valid state (111...012)" << endl; return 1; } if (!zr3a.isRs2NotExpired()) { cerr << "Re-read RS2 expired (111...012)" << endl; return 1; } ZIDRecord zr5((unsigned char*) "210987654321"); zid->getRecord(&zr5); // set new RS1 with expire interval of 5 second, then check immediatly zr5.setNewRs1((unsigned char*) "aaa22233344455566677788899900012", 5); if (!zr5.isValid()) { cerr << "Re-read ZID record '210987654321' not set to valid" << endl; return 1; } if (memcmp(zr5.getRs1(), "aaa22233344455566677788899900012", RS_LENGTH) != 0) { cerr << "RS1 (2) was not set (aaa...012)" << endl; return 1; } if (!zr5.isRs1Valid()) { cerr << "RS1 (2) was not set to valid state (aaa...012)" << endl; return 1; } if (!zr5.isRs1NotExpired()) { cerr << "RS1 (2) expired (aaa...012)" << endl; return 1; } // wait for 6 second, now the expire check shall fail sleep(6); if (zr5.isRs1NotExpired()) { cerr << "RS1 (2) is not expired after defined interval (aaa...012)" << endl; return 1; } zr5.setNewRs1((unsigned char*) "bbb99988877766655544433322211121", 256); zid->saveRecord(&zr5); zid->close(); // Test migration zid->open("testzidOld"); zid->close(); } #endif /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/Base32.cpp0000644000175000017500000002664011570305710015233 0ustar dyfetdyfet/** * * Copyright (c) 2002 Bryce "Zooko" Wilcox-O'Hearn Permission is hereby * granted, free of charge, to any person obtaining a copy of this software to * deal in this software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of this software, and to permit persons to whom this software * is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of this software. * * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER * DEALINGS IN THIS SOFTWARE. * * Converted to C++ by: * @author Werner Dittmann */ #ifndef UNIT_TEST #include #else #include "libzrtpcpp/Base32.h" #endif int divceil(int a, int b) { int c; if (a>0) { if (b>0) c=a+b-1; else c=a; } else { if (b>0) c=a; else c=a+b+1; } return c/b; } // 1 2 3 // 01234567890123456789012345678901 static const char* const chars= "ybndrfg8ejkmcpqxot1uwisza345h769"; /* * revchars: index into this table with the ASCII value of the char. * The result is the value of that quintet. */ static const unsigned char revchars[]= { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 18, 255, 25, 26, 27, 30, 29, 7, 31, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 24, 1, 12, 3, 8, 5, 6, 28, 21, 9, 10, 255, 11, 2, 16, 13, 14, 4, 22, 17, 19, 255, 20, 15, 0, 23, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; Base32::Base32(const string encoded): binaryResult(NULL), resultLength(0) { a2b_l(encoded, encoded.size(), (encoded.size()*5/8)*8); } Base32::Base32(const string encoded, int noOfBits): binaryResult(NULL), resultLength(0) { a2b_l(encoded, divceil(noOfBits, 5), noOfBits); } Base32::Base32(const unsigned char* data, int noOfBits): binaryResult(NULL), resultLength(0) { b2a_l(data, (noOfBits+7)/8, noOfBits); } Base32::~Base32() { if (binaryResult != NULL && binaryResult != smallBuffer) { delete [] binaryResult; } binaryResult = NULL; } const unsigned char* Base32::getDecoded(int &length) { length = resultLength; return binaryResult; } void Base32::b2a_l(const unsigned char* os, int len, const size_t lengthinbits) { /* if lengthinbits is not a multiple of 8 then this is allocating * space for 0, 1, or 2 extra quintets that will be truncated at the * end of this function if they are not needed */ string result(divceil(len*8, 5), ' '); /* index into the result buffer, initially pointing to the * "one-past-the-end" quintet */ int resp = result.size(); /* pointer into the os buffer, initially pointing to the * "one-past-the-end" octet */ const unsigned char* osp = os + len; /* Now this is a real live Duff's device. You gotta love it. */ unsigned long x = 0; // to hold up to 32 bits worth of the input switch ((osp - os) % 5) { case 0: do { x = *--osp; result[--resp] = chars[x % 32]; /* The least sig 5 bits go into the final quintet. */ x /= 32; /* ... now we have 3 bits worth in x... */ case 4: x |= ((unsigned long)(*--osp)) << 3; /* ... now we have 11 bits worth in x... */ result[--resp] = chars[x % 32]; x /= 32; /* ... now we have 6 bits worth in x... */ result[--resp] = chars[x % 32]; x /= 32; /* ... now we have 1 bits worth in x... */ case 3: x |= ((unsigned long)(*--osp)) << 1; /* The 8 bits from the 2-indexed octet. So now we have 9 bits worth in x... */ result[--resp] = chars[x % 32]; x /= 32; /* ... now we have 4 bits worth in x... */ case 2: x |= ((unsigned long)(*--osp)) << 4; /* The 8 bits from the 1-indexed octet. So now we have 12 bits worth in x... */ result[--resp] = chars[x%32]; x /= 32; /* ... now we have 7 bits worth in x... */ result[--resp] = chars[x%32]; x /= 32; /* ... now we have 2 bits worth in x... */ case 1: x |= ((unsigned long)(*--osp)) << 2; /* The 8 bits from the 0-indexed octet. So now we have 10 bits worth in x... */ result[--resp] = chars[x%32]; x /= 32; /* ... now we have 5 bits worth in x... */ result[--resp] = chars[x]; } while (osp > os); } /* switch ((osp - os.buf) % 5) */ /* truncate any unused trailing zero quintets */ encoded = result.substr(0, divceil(lengthinbits, 5)); return; } void Base32::a2b_l(const string cs, size_t size, const size_t lengthinbits ) { unsigned long x = 0; // to hold up to 32 bits worth of the input int len = divceil(size*5, 8); /* if lengthinbits is not a multiple of 5 then this is * allocating space for 0 or 1 extra octets that will be * truncated at the end of this function if they are * not needed */ if (len < 128) { binaryResult = smallBuffer; } else { binaryResult = new unsigned char[len]; } /* pointer into the result buffer, initially pointing to * the "one-past-the-end" octet */ unsigned char* resp = binaryResult + len; /* index into the input buffer, initially pointing to the * "one-past-the-end" character */ int csp = size; /* Now this is a real live Duff's device. You gotta love it. */ switch (csp % 8) { case 0: do { x = revchars[cs[--csp]&0xff]; /* 5 bits... */ case 7: x |= revchars[cs[--csp]&0xff] << 5; /* 10 bits... */ *--resp = x % 256; x /= 256; /* 2 bits... */ case 6: x |= revchars[cs[--csp]&0xff] << 2; /* 7 bits... */ case 5: x |= revchars[cs[--csp]&0xff] << 7; /* 12 bits... */ *--resp = x % 256; x /= 256; /* 4 bits... */ case 4: x |= revchars[cs[--csp]&0xff] << 4; /* 9 bits... */ *--resp = x % 256; x /= 256; /* 1 bit... */ case 3: x |= revchars[cs[--csp]&0xff] << 1; /* 6 bits... */ case 2: x |= revchars[cs[--csp]&0xff] << 6; /* 11 bits... */ *--resp = x % 256; x /= 256; /* 3 bits... */ case 1: x |= revchars[cs[--csp]&0xff] << 3; /* 8 bits... */ *--resp = x % 256; } while (csp); } /* switch ((csp - cs.buf) % 8) */ /* truncate any unused trailing zero octets */ resultLength = divceil(lengthinbits, 8); return; } #ifdef UNIT_TEST #include static uint8_t *randz(const size_t len) { uint8_t* result = (uint8_t*)malloc(len); size_t i; for (i=0; igetDecoded(resLen); if (resLen != 5 && memcmp(ones, zrecovered, 5)) { printf("Failed basic 5 ones recovery test.\n"); return -1; } delete y; a = Base32(ones, 15).getEncoded(); cout << "Encoded 5 ones, 15 bits only: '" << a << "', Expected: 'yry'" << endl; // now decode 15 bits (out of 40 possible) y = new Base32(a, 15); zrecovered = y->getDecoded(resLen); printf("Decoded 15 bits, result length: %d (should be 2)\n", resLen); printf("Decoded bytes: %x %x (should be 1 0)\n", zrecovered[0], zrecovered[1]); delete y; // Encode 20 bits of the test vectors a = Base32(zrtpVec01, 20).getEncoded(); cout << "Encoded ZRTP vector 01: '" << a << "', Expected: 'yyyy'" << endl; a = Base32(zrtpVec02, 20).getEncoded(); cout << "Encoded ZRTP vector 02: '" << a << "', Expected: 'oyyy'" << endl; a = Base32(zrtpVec03, 20).getEncoded(); cout << "Encoded ZRTP vector 02: '" << a << "', Expected: 'eyyy'" << endl; a = Base32(zrtpVec04, 20).getEncoded(); cout << "Encoded ZRTP vector 04: '" << a << "', Expected: 'ayyy'" << endl; a = Base32(zrtpVec05, 20).getEncoded(); cout << "Encoded ZRTP vector 05: '" << a << "', Expected: 'yyyy'" << endl; a = Base32(zrtpVec06, 20).getEncoded(); cout << "Encoded ZRTP vector 06: '" << a << "', Expected: 'onyy'" << endl; a = Base32(zrtpVec07, 20).getEncoded(); cout << "Encoded ZRTP vector 07: '" << a << "', Expected: 'tqre'" << endl; a = Base32(zrtpVec08, 20).getEncoded(); cout << "Encoded ZRTP vector 08: '" << a << "', Expected: '6n9h'" << endl; a = Base32(zrtpVec09, 20).getEncoded(); cout << "Encoded ZRTP vector 09: '" << a << "', Expected: '4t7y'" << endl; a = Base32(zrtpVec10, 20).getEncoded(); cout << "Encoded ZRTP vector 10: '" << a << "', Expected: '6im5'" << endl; // test the 30 bit output of same data as 20 bit a = Base32(zrtpVec10, 30).getEncoded(); cout << "Encoded ZRTP vector 10 (30bit): '" << a << "', Expected: '6im5sd'" << endl; for (int i = 0; i < 2; i++) { uint8_t* z = randz(16); a = Base32(z, 16*8).getEncoded(); // cout << "Result: " << a << endl; assert (a.size() == Base32::b2alen(16*8)); zrecovered = Base32(a).getDecoded(resLen); if (resLen != 16 && memcmp(z, zrecovered, 16)) { printf("Failed basic recovery test.\n"); return -1; } free((void*)z); } } #endif libzrtpcpp-2.0.0/src/ZrtpPacketPing.cpp0000644000175000017500000000276411570305710017122 0ustar dyfetdyfet/* Copyright (C) 2006-2009 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 . */ /* * @author: Werner Dittmann */ #include ZrtpPacketPing::ZrtpPacketPing() { DEBUGOUT((fprintf(stdout, "Creating Ping packet without data\n"))); zrtpHeader = &data.hdr; // the standard header pingHeader = &data.ping; setZrtpId(); setLength((sizeof(PingPacket_t) / ZRTP_WORD_SIZE) - 1); setMessageType((uint8_t*)PingMsg); setVersion((uint8_t*)zrtpVersion); } ZrtpPacketPing::ZrtpPacketPing(uint8_t *data) { DEBUGOUT((fprintf(stdout, "Creating Ping packet from data\n"))); zrtpHeader = (zrtpPacketHeader_t *)&((PingPacket_t*)data)->hdr; // the standard header pingHeader = (Ping_t *)&((PingPacket_t *)data)->ping; } ZrtpPacketPing::~ZrtpPacketPing() { DEBUGOUT((fprintf(stdout, "Deleting Ping packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpConfigure.cpp0000644000175000017500000003147511570305710017017 0ustar dyfetdyfet#include #include #include #include AlgorithmEnum::AlgorithmEnum(const AlgoTypes type, const char* name, int32_t klen, const char* ra, encrypt_t en, decrypt_t de, SrtpAlgorithms alId): algoType(type) , algoName(name), keyLen(klen), readable(ra), encrypt(en), decrypt(de), algoId(alId) { } AlgorithmEnum::~AlgorithmEnum() { } const char* AlgorithmEnum::getName() { return algoName.c_str(); } const char* AlgorithmEnum::getReadable() { return readable.c_str(); } int AlgorithmEnum::getKeylen() { return keyLen; } SrtpAlgorithms AlgorithmEnum::getAlgoId() { return algoId; } encrypt_t AlgorithmEnum::getEncrypt() { return encrypt; } decrypt_t AlgorithmEnum::getDecrypt() { return decrypt; } AlgoTypes AlgorithmEnum::getAlgoType() { return algoType; } bool AlgorithmEnum::isValid() { return (algoType != Invalid); } static AlgorithmEnum invalidAlgo(Invalid, "", 0, "", NULL, NULL, None); EnumBase::EnumBase(AlgoTypes a) : algoType(a) { } EnumBase::~EnumBase() {} void EnumBase::insert(const char* name) { if (!name) return; AlgorithmEnum* e = new AlgorithmEnum(algoType, name, 0, "", NULL, NULL, None); algos.push_back(e); } void EnumBase::insert(const char* name, int32_t klen, const char* ra, encrypt_t enc, decrypt_t dec, SrtpAlgorithms alId) { if (!name) return; AlgorithmEnum* e = new AlgorithmEnum(algoType, name, klen, ra, enc, dec, alId); algos.push_back(e); } int EnumBase::getSize() { return algos.size(); } AlgoTypes EnumBase::getAlgoType() { return algoType; } AlgorithmEnum& EnumBase::getByName(const char* name) { std::vector::iterator b = algos.begin(); std::vector::iterator e = algos.end(); for (; b != e; b++) { if (strncmp((*b)->getName(), name, 4) == 0) { return *(*b); } } return invalidAlgo; } AlgorithmEnum& EnumBase::getByOrdinal(int ord) { std::vector::iterator b = algos.begin(); std::vector::iterator e = algos.end(); for (int i = 0; b != e; ++b) { if (i == ord) { return *(*b); } i++; } return invalidAlgo; } int EnumBase::getOrdinal(AlgorithmEnum& algo) { std::vector::iterator b = algos.begin(); std::vector::iterator e = algos.end(); for (int i = 0; b != e; ++b) { if (strncmp((*b)->getName(), algo.getName(), 4) == 0) { return i; } i++; } return -1; } std::list* EnumBase::getAllNames() { std::vector::iterator b = algos.begin(); std::vector::iterator e = algos.end(); std::list* strg = new std::list(); for (; b != e; b++) { std::string s((*b)->getName()); strg->push_back(s); } return strg; } /** * Set up the enumeration list for available hash algorithms */ HashEnum::HashEnum() : EnumBase(HashAlgorithm) { insert(s256); insert(s384); } HashEnum::~HashEnum() {} /** * Set up the enumeration list for available symmetric cipher algorithms */ SymCipherEnum::SymCipherEnum() : EnumBase(CipherAlgorithm) { insert(aes3, 32, "AES-CM-256", aesCfbEncrypt, aesCfbDecrypt, Aes); insert(aes1, 16, "AES-CM-128", aesCfbEncrypt, aesCfbDecrypt, Aes); insert(two3, 32, "TWO-CM-256", twoCfbEncrypt, twoCfbDecrypt, TwoFish); insert(two1, 16, "TWO-CM-128", twoCfbEncrypt, twoCfbDecrypt, TwoFish); } SymCipherEnum::~SymCipherEnum() {} /** * Set up the enumeration list for available public key algorithms */ PubKeyEnum::PubKeyEnum() : EnumBase(PubKeyAlgorithm) { insert(dh2k); insert(dh3k); insert(mult); insert(ec25); insert(ec38); } PubKeyEnum::~PubKeyEnum() {} /** * Set up the enumeration list for available SAS algorithms */ SasTypeEnum::SasTypeEnum() : EnumBase(SasType) { insert(b32); } SasTypeEnum::~SasTypeEnum() {} /** * Set up the enumeration list for available SRTP authentications */ AuthLengthEnum::AuthLengthEnum() : EnumBase(AuthLength) { insert(hs32, 32, "", NULL, NULL, Sha1); insert(hs80, 80, "", NULL, NULL, Sha1); insert(sk32, 32, "", NULL, NULL, Skein); insert(sk64, 64, "", NULL, NULL, Skein); } AuthLengthEnum::~AuthLengthEnum() {} /* * Here the global accessible enumerations for all implemented algorithms. */ HashEnum zrtpHashes; SymCipherEnum zrtpSymCiphers; PubKeyEnum zrtpPubKeys; SasTypeEnum zrtpSasTypes; AuthLengthEnum zrtpAuthLengths; /* * The public methods are mainly a facade to the private methods. */ ZrtpConfigure::ZrtpConfigure() {} ZrtpConfigure::~ZrtpConfigure() {} void ZrtpConfigure::setStandardConfig() { clear(); addAlgo(HashAlgorithm, zrtpHashes.getByName(s384)); addAlgo(HashAlgorithm, zrtpHashes.getByName(s256)); addAlgo(CipherAlgorithm, zrtpSymCiphers.getByName(two3)); addAlgo(CipherAlgorithm, zrtpSymCiphers.getByName(aes3)); addAlgo(CipherAlgorithm, zrtpSymCiphers.getByName(two1)); addAlgo(CipherAlgorithm, zrtpSymCiphers.getByName(aes1)); addAlgo(PubKeyAlgorithm, zrtpPubKeys.getByName(ec25)); addAlgo(PubKeyAlgorithm, zrtpPubKeys.getByName(dh3k)); addAlgo(PubKeyAlgorithm, zrtpPubKeys.getByName(ec38)); addAlgo(PubKeyAlgorithm, zrtpPubKeys.getByName(dh2k)); addAlgo(PubKeyAlgorithm, zrtpPubKeys.getByName(mult)); addAlgo(SasType, zrtpSasTypes.getByName(b32)); addAlgo(AuthLength, zrtpAuthLengths.getByName(sk32)); addAlgo(AuthLength, zrtpAuthLengths.getByName(sk64)); addAlgo(AuthLength, zrtpAuthLengths.getByName(hs32)); addAlgo(AuthLength, zrtpAuthLengths.getByName(hs80)); } void ZrtpConfigure::setMandatoryOnly() { clear(); addAlgo(HashAlgorithm, zrtpHashes.getByName(s256)); addAlgo(CipherAlgorithm, zrtpSymCiphers.getByName(aes1)); addAlgo(PubKeyAlgorithm, zrtpPubKeys.getByName(dh3k)); addAlgo(PubKeyAlgorithm, zrtpPubKeys.getByName(mult)); addAlgo(SasType, zrtpSasTypes.getByName(b32)); addAlgo(AuthLength, zrtpAuthLengths.getByName(hs32)); addAlgo(AuthLength, zrtpAuthLengths.getByName(hs80)); } void ZrtpConfigure::clear() { hashes.clear(); symCiphers.clear(); publicKeyAlgos.clear(); sasTypes.clear(); authLengths.clear(); } int32_t ZrtpConfigure::addAlgo(AlgoTypes algoType, AlgorithmEnum& algo) { return addAlgo(getEnum(algoType), algo); } int32_t ZrtpConfigure::addAlgoAt(AlgoTypes algoType, AlgorithmEnum& algo, int32_t index) { return addAlgoAt(getEnum(algoType), algo, index); } AlgorithmEnum& ZrtpConfigure::getAlgoAt(AlgoTypes algoType, int32_t index) { return getAlgoAt(getEnum(algoType), index); } int32_t ZrtpConfigure::removeAlgo(AlgoTypes algoType, AlgorithmEnum& algo) { return removeAlgo(getEnum(algoType), algo); } int32_t ZrtpConfigure::getNumConfiguredAlgos(AlgoTypes algoType) { return getNumConfiguredAlgos(getEnum(algoType)); } bool ZrtpConfigure::containsAlgo(AlgoTypes algoType, AlgorithmEnum& algo) { return containsAlgo(getEnum(algoType), algo); } void ZrtpConfigure::printConfiguredAlgos(AlgoTypes algoType) { return printConfiguredAlgos(getEnum(algoType)); } /* * The next methods are the private methods that implement the real * details. */ AlgorithmEnum& ZrtpConfigure::getAlgoAt(std::vector& a, int32_t index) { if (index >= (int)a.size()) return invalidAlgo; std::vector::iterator b = a.begin(); std::vector::iterator e = a.end(); for (int i = 0; b != e; ++b) { if (i == index) { return *(*b); } i++; } return invalidAlgo; } int32_t ZrtpConfigure::addAlgo(std::vector& a, AlgorithmEnum& algo) { int size = (int)a.size(); if (size >= maxNoOfAlgos) return -1; if (!algo.isValid()) return -1; if (containsAlgo(a, algo)) return (maxNoOfAlgos - size); a.push_back(&algo); return (maxNoOfAlgos - (int)a.size()); } int32_t ZrtpConfigure::addAlgoAt(std::vector& a, AlgorithmEnum& algo, int32_t index) { if (index >= maxNoOfAlgos) return -1; int size = (int)a.size(); if (!algo.isValid()) return -1; // a[index] = &algo; if (index >= size) { a.push_back(&algo); return maxNoOfAlgos - (int)a.size(); } std::vector::iterator b = a.begin(); std::vector::iterator e = a.end(); for (int i = 0; b != e; ++b) { if (i == index) { a.insert(b, &algo); break; } i++; } return (maxNoOfAlgos - (int)a.size()); } int32_t ZrtpConfigure::removeAlgo(std::vector& a, AlgorithmEnum& algo) { if ((int)a.size() == 0 || !algo.isValid()) return maxNoOfAlgos; std::vector::iterator b = a.begin(); std::vector::iterator e = a.end(); for (; b != e; ++b) { if (strcmp((*b)->getName(), algo.getName()) == 0) { a.erase(b); break; } } return (maxNoOfAlgos - (int)a.size()); } int32_t ZrtpConfigure::getNumConfiguredAlgos(std::vector& a) { return (int32_t)a.size(); } bool ZrtpConfigure::containsAlgo(std::vector& a, AlgorithmEnum& algo) { if ((int)a.size() == 0 || !algo.isValid()) return false; std::vector::iterator b = a.begin(); std::vector::iterator e = a.end(); for (; b != e; ++b) { if (strcmp((*b)->getName(), algo.getName()) == 0) { return true; } } return false; } void ZrtpConfigure::printConfiguredAlgos(std::vector& a) { std::vector::iterator b = a.begin(); std::vector::iterator e = a.end(); for (; b != e; ++b) { printf("print configured: name: %s\n", (*b)->getName()); } } std::vector& ZrtpConfigure::getEnum(AlgoTypes algoType) { switch(algoType) { case HashAlgorithm: return hashes; break; case CipherAlgorithm: return symCiphers; break; case PubKeyAlgorithm: return publicKeyAlgos; break; case SasType: return sasTypes; break; case AuthLength: return authLengths; break; default: break; } return hashes; } void ZrtpConfigure::setTrustedMitM(bool yesNo) { enableTrustedMitM = yesNo; } bool ZrtpConfigure::isTrustedMitM() { return enableTrustedMitM; } void ZrtpConfigure::setSasSignature(bool yesNo) { enableSasSignature = yesNo; } bool ZrtpConfigure::isSasSignature() { return enableSasSignature; } #if 0 ZrtpConfigure config; main() { printf("Start\n"); printf("size: %d\n", zrtpHashes.getSize()); AlgorithmEnum e = zrtpHashes.getByName("S256"); printf("algo name: %s\n", e.getName()); printf("algo type: %d\n", e.getAlgoType()); std::list* names = zrtpHashes.getAllNames(); printf("size of name list: %d\n", names->size()); printf("first name: %s\n", names->front().c_str()); printf("last name: %s\n", names->back().c_str()); printf("free slots: %d (expected 6)\n", config.addAlgo(HashAlgorithm, e)); AlgorithmEnum e1(HashAlgorithm, "SHA384"); printf("free slots: %d (expected 5)\n", config.addAlgoAt(HashAlgorithm, e1, 0)); AlgorithmEnum e2 = config.getAlgoAt(HashAlgorithm, 0); printf("algo name: %s (expected SHA384)\n", e2.getName()); printf("Num of configured algos: %d (expected 2)\n", config.getNumConfiguredAlgos(HashAlgorithm)); config.printConfiguredAlgos(HashAlgorithm); printf("free slots: %d (expected 6)\n", config.removeAlgo(HashAlgorithm, e2)); e2 = config.getAlgoAt(HashAlgorithm, 0); printf("algo name: %s (expected SHA256)\n", e2.getName()); printf("clearing config\n"); config.clear(); printf("size: %d\n", zrtpHashes.getSize()); e = zrtpHashes.getByName("S256"); printf("algo name: %s\n", e.getName()); printf("algo type: %d\n", e.getAlgoType()); } #endif /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/ZrtpCrc32.cpp0000755000175000017500000002136211570305710015747 0ustar dyfetdyfet/* SCTP kernel reference Implementation * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2003 International Business Machines, Corp. * * SCTP Checksum functions * * The SCTP reference implementation 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 2, or (at your option) * any later version. * * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Written or modified by: * Dinakaran Joseph * Jon Grimm * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ /* The following code has been taken directly from * draft-ietf-tsvwg-sctpcsum-03.txt * * The code has now been modified by Werner.Dittmann@t-online.de for use * inside the ZRTP implementation. */ #include #include #include #define CRC32C_POLY 0x1EDC6F41 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Copyright 2001, D. Otis. Use this program, code or tables */ /* extracted from it, as desired without restriction. */ /* */ /* 32 Bit Reflected CRC table generation for SCTP. */ /* To accommodate serial byte data being shifted out least */ /* significant bit first, the table's 32 bit words are reflected */ /* which flips both byte and bit MS and LS positions. The CRC */ /* is calculated MS bits first from the perspective of the serial*/ /* stream. The x^32 term is implied and the x^0 term may also */ /* be shown as +1. The polynomial code used is 0x1EDC6F41. */ /* Castagnoli93 */ /* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+ */ /* x^11+x^10+x^9+x^8+x^6+x^0 */ /* Guy Castagnoli Stefan Braeuer and Martin Herrman */ /* "Optimization of Cyclic Redundancy-Check Codes */ /* with 24 and 32 Parity Bits", */ /* IEEE Transactions on Communications, Vol.41, No.6, June 1993 */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static const uint32_t crc_c[256] = { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, }; bool zrtpCheckCksum(uint8_t *buffer, uint16_t length, uint32_t crc32) { uint32_t chksum = zrtpGenerateCksum(buffer, length); chksum = zrtpEndCksum(chksum); // fprintf(stderr, "Received crc %x, computed crc: %x\n", crc32, chksum); return (crc32 == chksum); } uint32_t zrtpGenerateCksum(uint8_t *buffer, uint16_t length) { uint32_t crc32 = ~(uint32_t) 0; uint32_t i; // fprintf(stderr, "Buffer %xl, length: %d\n", buffer, length); /* Calculate the CRC. */ for (i = 0; i < length ; i++) CRC32C(crc32, buffer[i]); return crc32; } uint32_t zrtpEndCksum(uint32_t crc32) { uint32_t result; uint8_t byte0, byte1, byte2, byte3; result = ~crc32; /* result now holds the negated polynomial remainder; * since the table and algorithm is "reflected" [williams95]. * That is, result has the same value as if we mapped the message * to a polyomial, computed the host-bit-order polynomial * remainder, performed final negation, then did an end-for-end * bit-reversal. * Note that a 32-bit bit-reversal is identical to four inplace * 8-bit reversals followed by an end-for-end byteswap. * In other words, the bytes of each bit are in the right order, * but the bytes have been byteswapped. So we now do an explicit * byteswap. On a little-endian machine, this byteswap and * the final ntohl cancel out and could be elided. */ byte0 = result & 0xff; byte1 = (result>>8) & 0xff; byte2 = (result>>16) & 0xff; byte3 = (result>>24) & 0xff; crc32 = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); // fprintf(stderr, "Computed crc32: %x\n", crc32); return crc32; } #ifdef UNIT_TEST uint8_t test_data[48] = { 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFE, 0x60, 0xAC, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; int main( int argc, char * argv[] ) { crc32c = sctp_update_cksum(test_data, 48); printf("Hello World, expected result: 0x664f75eb\n"); printf("Result is: 0x%x\n", crc32c); } #endif /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/ZrtpPacketErrorAck.cpp0000644000175000017500000000265311570305710017732 0ustar dyfetdyfet/* 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 ZrtpPacketErrorAck::ZrtpPacketErrorAck() { DEBUGOUT((fprintf(stdout, "Creating ErrorAck packet without data\n"))); zrtpHeader = &data.hdr; // the standard header setZrtpId(); setLength((sizeof (ErrorAckPacket_t) / ZRTP_WORD_SIZE) - 1); setMessageType((uint8_t*)ErrorAckMsg); } ZrtpPacketErrorAck::ZrtpPacketErrorAck(uint8_t *data) { DEBUGOUT((fprintf(stdout, "Creating ErrorAck packet from data\n"))); zrtpHeader = (zrtpPacketHeader_t *)&((ErrorAckPacket_t*)data)->hdr; // the standard header } ZrtpPacketErrorAck::~ZrtpPacketErrorAck() { DEBUGOUT((fprintf(stdout, "Deleting ErrorAck packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/CMakeLists.txt0000755000175000017500000000412411570305710016244 0ustar dyfetdyfetcmake_minimum_required (VERSION 2.6) # add_subdirectory(libzrtpcpp) # add_subdirectory(libzrtpcpp/crypto) include_directories (${CMAKE_CURRENT_SOURCE_DIR}) set(gcrypt_src libzrtpcpp/crypto/gcrypt/gcryptZrtpDH.cpp libzrtpcpp/crypto/gcrypt/gcrypthmac256.cpp libzrtpcpp/crypto/gcrypt/gcryptsha256.cpp libzrtpcpp/crypto/gcrypt/gcrypthmac384.cpp libzrtpcpp/crypto/gcrypt/gcryptsha384.cpp libzrtpcpp/crypto/gcrypt/gcryptAesCFB.cpp libzrtpcpp/crypto/gcrypt/InitializeGcrypt.cpp) set(openssl_src libzrtpcpp/crypto/openssl/ZrtpDH.cpp libzrtpcpp/crypto/openssl/hmac256.cpp libzrtpcpp/crypto/openssl/sha256.cpp libzrtpcpp/crypto/openssl/hmac384.cpp libzrtpcpp/crypto/openssl/sha384.cpp libzrtpcpp/crypto/openssl/AesCFB.cpp libzrtpcpp/crypto/openssl/InitializeOpenSSL.cpp) if (GCRYPT_FOUND) set(crypto_src ${gcrypt_src}) endif() if (OPENSSL_FOUND) set(crypto_src ${openssl_src}) endif() if(enable_ccrtp) set(ccrtp_src ZrtpQueue.cpp) endif() set(twofish_srcs libzrtpcpp/crypto/twofish.c libzrtpcpp/crypto/twofish_cfb.c libzrtpcpp/crypto/TwoCFB.cpp) set(zrtp_src ZrtpCallbackWrapper.cpp ZIDFile.cpp ZIDRecord.cpp ZRtp.cpp ZrtpCrc32.cpp ZrtpPacketCommit.cpp ZrtpPacketConf2Ack.cpp ZrtpPacketConfirm.cpp ZrtpPacketDHPart.cpp ZrtpPacketGoClear.cpp ZrtpPacketClearAck.cpp ZrtpPacketHelloAck.cpp ZrtpPacketHello.cpp ZrtpPacketError.cpp ZrtpPacketErrorAck.cpp ZrtpPacketPingAck.cpp ZrtpPacketPing.cpp ZrtpStateClass.cpp ZrtpTextData.cpp ZrtpConfigure.cpp ZrtpCWrapper.cpp Base32.cpp) set(zrtpcpp_src ${zrtp_src} ${ccrtp_src} ${crypto_src} ${twofish_srcs}) if(BUILD_STATIC AND NOT BUILD_SHARED) set(LIBRARY_BUILD_TYPE STATIC) else() set(LIBRARY_BUILD_TYPE SHARED) endif() add_library(zrtpcpp ${LIBRARY_BUILD_TYPE} ${zrtpcpp_src}) set_target_properties(zrtpcpp PROPERTIES VERSION ${VERSION} SOVERSION ${SOVERSION}) target_link_libraries(zrtpcpp ${LIBS}) add_dependencies(zrtpcpp ccrtp) add_subdirectory(libzrtpcpp) install(TARGETS zrtpcpp DESTINATION ${LIBDIRNAME}) libzrtpcpp-2.0.0/src/ZrtpPacketHelloAck.cpp0000644000175000017500000000265511570305710017706 0ustar dyfetdyfet/* 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 ZrtpPacketHelloAck::ZrtpPacketHelloAck() { DEBUGOUT((fprintf(stdout, "Creating HelloAck packet without data\n"))); zrtpHeader = &data.hdr; // the standard header setZrtpId(); setLength((sizeof(HelloAckPacket_t) / ZRTP_WORD_SIZE) - 1); setMessageType((uint8_t*)HelloAckMsg); } ZrtpPacketHelloAck::ZrtpPacketHelloAck(uint8_t *data) { DEBUGOUT((fprintf(stdout, "Creating HelloAck packet from data\n"))); zrtpHeader = (zrtpPacketHeader_t *)&((HelloAckPacket_t *)data)->hdr; // the standard header } ZrtpPacketHelloAck::~ZrtpPacketHelloAck() { DEBUGOUT((fprintf(stdout, "Deleting HelloAck packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpPacketCommit.cpp0000644000175000017500000000327311570305710017451 0ustar dyfetdyfet/* 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 . */ /* * @author: Werner Dittmann */ #include ZrtpPacketCommit::ZrtpPacketCommit() { DEBUGOUT((fprintf(stdout, "Creating commit packet without data\n"))); zrtpHeader = &data.hdr; // the standard header commitHeader = &data.commit; setZrtpId(); setLength((sizeof (CommitPacket_t) / ZRTP_WORD_SIZE) - 1); setMessageType((uint8_t*)CommitMsg); } void ZrtpPacketCommit::setNonce(uint8_t* text) { memcpy(commitHeader->hvi, text, sizeof(commitHeader->hvi-4*ZRTP_WORD_SIZE)); uint16_t len = getLength(); len -= 4; setLength(len); } ZrtpPacketCommit::ZrtpPacketCommit(uint8_t *data) { DEBUGOUT((fprintf(stdout, "Creating commit packet from data\n"))); zrtpHeader = (zrtpPacketHeader_t *)&((CommitPacket_t *)data)->hdr; // the standard header commitHeader = (Commit_t *)&((CommitPacket_t *)data)->commit; } ZrtpPacketCommit::~ZrtpPacketCommit() { DEBUGOUT((fprintf(stdout, "Deleting commit packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpPacketPingAck.cpp0000644000175000017500000000305511570305710017533 0ustar dyfetdyfet/* Copyright (C) 2006-2009 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 . */ /* * @author: Werner Dittmann */ #include ZrtpPacketPingAck::ZrtpPacketPingAck() { DEBUGOUT((fprintf(stdout, "Creating PingAck packet without data\n"))); zrtpHeader = &data.hdr; // the standard header pingAckHeader = &data.pingAck; setZrtpId(); setLength((sizeof(PingAckPacket_t) / ZRTP_WORD_SIZE) - 1); setMessageType((uint8_t*)PingAckMsg); setVersion((uint8_t*)zrtpVersion); } ZrtpPacketPingAck::ZrtpPacketPingAck(uint8_t *data) { DEBUGOUT((fprintf(stdout, "Creating PingAck packet from data\n"))); zrtpHeader = (zrtpPacketHeader_t *)&((PingAckPacket_t*)data)->hdr; // the standard header pingAckHeader = (PingAck_t *)&((PingAckPacket_t *)data)->pingAck; } ZrtpPacketPingAck::~ZrtpPacketPingAck() { DEBUGOUT((fprintf(stdout, "Deleting PingAck packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpCWrapper.cpp0000644000175000017500000002605111570305710016613 0ustar dyfetdyfet/* This class maps the ZRTP C calls to ZRTP C++ methods. Copyright (C) 2010 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 . */ #include #include #include #include #include #include #include static int32_t initialized = 0; static int32_t zrtp_initZidFile(const char* zidFilename); ZrtpContext* zrtp_CreateWrapper() { ZrtpContext* zc = new ZrtpContext; zc->configure = 0; return zc; } void zrtp_initializeZrtpEngine(ZrtpContext* zrtpContext, zrtp_Callbacks *cb, char* id, const char* zidFilename, void* userData) { std::string clientIdString(id); zrtpContext->zrtpCallback = new ZrtpCallbackWrapper(cb, zrtpContext); zrtpContext->userData = userData; if (zrtpContext->configure == 0) { zrtpContext->configure = new ZrtpConfigure(); zrtpContext->configure->setStandardConfig(); } // Initialize ZID file (cache) and get my own ZID zrtp_initZidFile(zidFilename); ZIDFile* zf = ZIDFile::getInstance(); const unsigned char* myZid = zf->getZid(); zrtpContext->zrtpEngine = new ZRtp((uint8_t*)myZid, zrtpContext->zrtpCallback, clientIdString, zrtpContext->configure); initialized = 1; } void zrtp_DestroyWrapper(ZrtpContext* zrtpContext) { if (zrtpContext == NULL) return; delete zrtpContext->zrtpEngine; zrtpContext->zrtpEngine = NULL; delete zrtpContext->zrtpCallback; zrtpContext->zrtpCallback = NULL; delete zrtpContext->configure; zrtpContext->configure = NULL; delete zrtpContext; } static int32_t zrtp_initZidFile(const char* zidFilename) { ZIDFile* zf = ZIDFile::getInstance(); 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("GNUccRTP.zid"); zidFilename = fname.c_str(); } return zf->open((char *)zidFilename); } return 0; } int32_t zrtp_CheckCksum(uint8_t* buffer, uint16_t temp, uint32_t crc) { return zrtpCheckCksum(buffer, temp, crc); } uint32_t zrtp_GenerateCksum(uint8_t* buffer, uint16_t temp) { return zrtpGenerateCksum(buffer, temp); } uint32_t zrtp_EndCksum(uint32_t crc) { return zrtpEndCksum(crc); } /* * Applications use the following methods to control ZRTP, for example * to enable ZRTP, set flags etc. */ void zrtp_startZrtpEngine(ZrtpContext* zrtpContext) { if (initialized) zrtpContext->zrtpEngine->startZrtpEngine(); } void zrtp_stopZrtpEngine(ZrtpContext* zrtpContext) { if (initialized) zrtpContext->zrtpEngine->stopZrtp(); } void zrtp_processZrtpMessage(ZrtpContext* zrtpContext, uint8_t *extHeader, uint32_t peerSSRC) { if (initialized) zrtpContext->zrtpEngine->processZrtpMessage(extHeader, peerSSRC); } void zrtp_processTimeout(ZrtpContext* zrtpContext) { if (initialized) zrtpContext->zrtpEngine->processTimeout(); } //int32_t zrtp_handleGoClear(ZrtpContext* zrtpContext, uint8_t *extHeader) //{ // if (initialized) // return zrtpContext->zrtpEngine->handleGoClear(extHeader) ? 1 : 0; // // return 0; //} void zrtp_setAuxSecret(ZrtpContext* zrtpContext, uint8_t* data, int32_t length) { if (initialized) zrtpContext->zrtpEngine->setAuxSecret(data, length); } void zrtp_setPbxSecret(ZrtpContext* zrtpContext, uint8_t* data, int32_t length) { if (initialized) zrtpContext->zrtpEngine->setPbxSecret(data, length); } int32_t zrtp_inState(ZrtpContext* zrtpContext, int32_t state) { if (initialized) return zrtpContext->zrtpEngine->inState(state) ? 1 : 0; return 0; } void zrtp_SASVerified(ZrtpContext* zrtpContext) { if (initialized) zrtpContext->zrtpEngine->SASVerified(); } void zrtp_resetSASVerified(ZrtpContext* zrtpContext) { if (initialized) zrtpContext->zrtpEngine->resetSASVerified(); } char* zrtp_getHelloHash(ZrtpContext* zrtpContext) { std::string ret; if (initialized) ret = zrtpContext->zrtpEngine->getHelloHash(); else return NULL; if (ret.size() == 0) return NULL; char* retval = (char*)malloc(ret.size()+1); strcpy(retval, ret.c_str()); return retval; } char* zrtp_getMultiStrParams(ZrtpContext* zrtpContext, int32_t *length) { std::string ret; *length = 0; if (initialized) ret = zrtpContext->zrtpEngine->getMultiStrParams(); else return NULL; if (ret.size() == 0) return NULL; *length = ret.size(); char* retval = (char*) malloc(ret.size()); ret.copy(retval, ret.size(), 0); return retval; } void zrtp_setMultiStrParams(ZrtpContext* zrtpContext, char* parameters, int32_t length) { if (!initialized) return; if (parameters == NULL) return; std::string str(""); str.assign(parameters, length); // set chars (bytes) to the string zrtpContext->zrtpEngine->setMultiStrParams(str); } int32_t zrtp_isMultiStream(ZrtpContext* zrtpContext) { if (initialized) return zrtpContext->zrtpEngine->isMultiStream() ? 1 : 0; return 0; } int32_t zrtp_isMultiStreamAvailable(ZrtpContext* zrtpContext) { if (initialized) return zrtpContext->zrtpEngine->isMultiStreamAvailable() ? 1 : 0; return 0; } void zrtp_acceptEnrollment(ZrtpContext* zrtpContext, int32_t accepted) { if (initialized) return zrtpContext->zrtpEngine->acceptEnrollment(accepted == 0 ? false : true); } void zrtp_setPBXEnrollment(ZrtpContext* zrtpContext, int32_t yesNo) { if (initialized) return zrtpContext->zrtpEngine->setPBXEnrollment(yesNo == 0 ? false : true); } int32_t zrtp_setSignatureData(ZrtpContext* zrtpContext, uint8_t* data, int32_t length) { if (initialized) return zrtpContext->zrtpEngine->setSignatureData(data, length) ? 1 : 0; return 0; } int32_t zrtp_getSignatureData(ZrtpContext* zrtpContext, uint8_t* data) { if (initialized) return zrtpContext->zrtpEngine->getSignatureData(data); return 0; } int32_t zrtp_getSignatureLength(ZrtpContext* zrtpContext) { if (initialized) return zrtpContext->zrtpEngine->getSignatureLength(); return 0; } void zrtp_conf2AckSecure(ZrtpContext* zrtpContext) { if (initialized) zrtpContext->zrtpEngine->conf2AckSecure(); } int32_t zrtp_getZid(ZrtpContext* zrtpContext, uint8_t* data) { if (data == NULL) return 0; if (initialized) return zrtpContext->zrtpEngine->getZid(data); return 0; } /* * The following methods wrap the ZRTP Configure functions */ int32_t zrtp_InitializeConfig (ZrtpContext* zrtpContext) { zrtpContext->configure = new ZrtpConfigure(); return 1; } static EnumBase* getEnumBase(zrtp_AlgoTypes type) { switch(type) { case zrtp_HashAlgorithm: return &zrtpHashes; break; case zrtp_CipherAlgorithm: return &zrtpSymCiphers; break; case zrtp_PubKeyAlgorithm: return &zrtpPubKeys; break; case zrtp_SasType: return &zrtpSasTypes; break; case zrtp_AuthLength: return &zrtpAuthLengths; break; default: return NULL; } } char** zrtp_getAlgorithmNames(ZrtpContext* zrtpContext, Zrtp_AlgoTypes type) { std::list* names = NULL; EnumBase* base = getEnumBase(type); if (!base) return NULL; names = base->getAllNames(); int size = base->getSize(); char** cNames = new char* [size+1]; cNames[size] = NULL; std::list::iterator b = names->begin(); std::list::iterator e = names->end(); for (int i = 0; b != e; b++, i++) { cNames[i] = new char [(*b).size()+1]; strcpy(cNames[i], (*b).c_str()); } return cNames; } void zrtp_freeAlgorithmNames(char** names) { if (!names) return; for (char** cp = names; *cp; cp++) delete *cp; delete names; } void zrtp_setStandardConfig(ZrtpContext* zrtpContext) { zrtpContext->configure->setStandardConfig(); } void zrtp_setMandatoryOnly(ZrtpContext* zrtpContext) { zrtpContext->configure->setMandatoryOnly(); } int32_t zrtp_addAlgo(ZrtpContext* zrtpContext, zrtp_AlgoTypes algoType, const char* algo) { EnumBase* base = getEnumBase(algoType); AlgorithmEnum& a = base->getByName(algo); return zrtpContext->configure->addAlgo((AlgoTypes)algoType, a); } int32_t zrtp_addAlgoAt(ZrtpContext* zrtpContext, zrtp_AlgoTypes algoType, const char* algo, int32_t index) { EnumBase* base = getEnumBase(algoType); AlgorithmEnum& a = base->getByName(algo); return zrtpContext->configure->addAlgoAt((AlgoTypes)algoType, a, index); } int32_t zrtp_removeAlgo(ZrtpContext* zrtpContext, zrtp_AlgoTypes algoType, const char* algo) { EnumBase* base = getEnumBase(algoType); AlgorithmEnum& a = base->getByName(algo); return zrtpContext->configure->removeAlgo((AlgoTypes)algoType, a); } int32_t zrtp_getNumConfiguredAlgos(ZrtpContext* zrtpContext, zrtp_AlgoTypes algoType) { return zrtpContext->configure->getNumConfiguredAlgos((AlgoTypes)algoType); } const char* zrtp_getAlgoAt(ZrtpContext* zrtpContext, Zrtp_AlgoTypes algoType, int32_t index) { AlgorithmEnum& a = zrtpContext->configure->getAlgoAt((AlgoTypes)algoType, index); return a.getName(); } int32_t zrtp_containsAlgo(ZrtpContext* zrtpContext, Zrtp_AlgoTypes algoType, const char* algo) { EnumBase* base = getEnumBase(algoType); AlgorithmEnum& a = base->getByName(algo); return zrtpContext->configure->containsAlgo((AlgoTypes)algoType, a) ? 1 : 0; } void zrtp_setTrustedMitM(ZrtpContext* zrtpContext, int32_t yesNo) { zrtpContext->configure->setTrustedMitM(yesNo ? true : false); } int32_t zrtp_isTrustedMitM(ZrtpContext* zrtpContext) { return zrtpContext->configure->isTrustedMitM() ? 1 : 0; } void zrtp_setSasSignature(ZrtpContext* zrtpContext, int32_t yesNo) { zrtpContext->configure->setSasSignature(yesNo ? true : false); } int32_t zrtp_isSasSignature(ZrtpContext* zrtpContext) { return zrtpContext->configure->isSasSignature() ? 1 : 0; } libzrtpcpp-2.0.0/src/ZIDRecord.cpp0000644000175000017500000000527511570305710016002 0ustar dyfetdyfet/* 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 void ZIDRecord::setNewRs1(const unsigned char* data, int32_t expire) { // shift RS1 data into RS2 position memcpy(record.rs2Data, record.rs1Data, RS_LENGTH); memcpy(record.rs2Interval, record.rs1Interval, TIME_LENGTH); // now propagate flags as well if (isRs1Valid()) { setRs2Valid(); } // set new RS1 data memcpy(record.rs1Data, data, RS_LENGTH); time_t validThru; if (expire == -1) { validThru = -1; } else if (expire <= 0) { validThru = 0; } else { validThru = time(NULL) + expire; } if (sizeof(time_t) == 4) { long long temp = validThru; memcpy(record.rs1Interval, (unsigned char*)&temp, TIME_LENGTH); } else { memcpy(record.rs1Interval, (unsigned char*)&validThru, TIME_LENGTH); } setRs1Valid(); } const bool ZIDRecord::isRs1NotExpired() { time_t current = time(NULL); time_t validThru; if (sizeof(time_t) == 4) { long long temp; memcpy((unsigned char*)&temp, record.rs1Interval, TIME_LENGTH); validThru = temp; } else { memcpy((unsigned char*)&validThru, record.rs1Interval, TIME_LENGTH); } if (validThru == -1) return true; if (validThru == 0) return false; return (current <= validThru) ? true : false; } const bool ZIDRecord::isRs2NotExpired() { time_t current = time(NULL); time_t validThru; if (sizeof(time_t) == 4) { long long temp; memcpy((unsigned char*)&temp, record.rs2Interval, TIME_LENGTH); validThru = temp; } else { memcpy((unsigned char*)&validThru, record.rs2Interval, TIME_LENGTH); } if (validThru == -1) return true; if (validThru == 0) return false; return (current <= validThru) ? true : false; } void ZIDRecord::setMiTMData(const unsigned char* data) { memcpy(record.mitmKey, data, RS_LENGTH); setMITMKeyAvailable(); } /** EMACS ** * Local variables: * mode: c++ * c-default-style: ellemtel * c-basic-offset: 4 * End: */ libzrtpcpp-2.0.0/src/ZrtpPacketDHPart.cpp0000644000175000017500000000575111570305710017346 0ustar dyfetdyfet/* 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 ZrtpPacketDHPart::ZrtpPacketDHPart() { DEBUGOUT((fprintf(stdout, "Creating DHPart packet without data and pkt type\n"))); initialize(); } ZrtpPacketDHPart::ZrtpPacketDHPart(const char* pkt) { DEBUGOUT((fprintf(stdout, "Creating DHPart packet without data\n"))); initialize(); setPubKeyType(pkt); } void ZrtpPacketDHPart::initialize() { void* allocated = &data; memset(allocated, 0, sizeof(data)); zrtpHeader = (zrtpPacketHeader_t *)&((DHPartPacket_t *)allocated)->hdr; // the standard header DHPartHeader = (DHPart_t *)&((DHPartPacket_t *)allocated)->dhPart; pv = ((uint8_t*)allocated) + sizeof(DHPartPacket_t); // point to the public key value setZrtpId(); } // The fixed numbers below are taken from ZRTP specification, chap 5.1.5 void ZrtpPacketDHPart::setPubKeyType(const char* pkt) { // Well - the algo type is only 4 char thus cast to int32 and compare if (*(int32_t*)pkt == *(int32_t*)dh2k) { dhLength = 256; } else if (*(int32_t*)pkt == *(int32_t*)dh3k) { dhLength = 384; } else if (*(int32_t*)pkt == *(int32_t*)ec25) { dhLength = 64; } else if (*(int32_t*)pkt == *(int32_t*)ec38) { dhLength = 96; } else return; int length = sizeof(DHPartPacket_t) + dhLength + (2 * ZRTP_WORD_SIZE); // HMAC field is 2*ZRTP_WORD_SIZE setLength(length / ZRTP_WORD_SIZE); } ZrtpPacketDHPart::ZrtpPacketDHPart(uint8_t *data) { DEBUGOUT((fprintf(stdout, "Creating DHPart packet from data\n"))); zrtpHeader = (zrtpPacketHeader_t *)&((DHPartPacket_t *)data)->hdr; // the standard header DHPartHeader = (DHPart_t *)&((DHPartPacket_t *)data)->dhPart; int16_t len = getLength(); DEBUGOUT((fprintf(stdout, "DHPart length: %d\n", len))); if (len == 85) { dhLength = 256; } else if (len == 117) { dhLength = 384; } else if (len == 37) { dhLength = 64; } else if (len == 45) { dhLength = 96; } else { pv = NULL; return; } pv = data + sizeof(DHPartPacket_t); // point to the public key value } ZrtpPacketDHPart::~ZrtpPacketDHPart() { DEBUGOUT((fprintf(stdout, "Deleting DHPart packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/src/ZrtpPacketConfirm.cpp0000644000175000017500000000517111570305710017615 0ustar dyfetdyfet/* 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 ZrtpPacketConfirm::ZrtpPacketConfirm() { DEBUGOUT((fprintf(stdout, "Creating Confirm packet without data, no sl data\n"))); initialize(); setSignatureLength(0); } ZrtpPacketConfirm::ZrtpPacketConfirm(uint32_t sl) { DEBUGOUT((fprintf(stdout, "Creating Confirm packet without data\n"))); initialize(); setSignatureLength(sl); } void ZrtpPacketConfirm::initialize() { void* allocated = &data; memset(allocated, 0, sizeof(data)); zrtpHeader = (zrtpPacketHeader_t *)&((ConfirmPacket_t *)allocated)->hdr; // the standard header confirmHeader = (Confirm_t *)&((ConfirmPacket_t *)allocated)->confirm; setZrtpId(); } void ZrtpPacketConfirm::setSignatureLength(uint32_t sl) { sl &= 0x1ff; // make sure it is max 9 bits int32_t length = sizeof(ConfirmPacket_t) + (sl * ZRTP_WORD_SIZE); confirmHeader->sigLength = sl; // sigLength is a uint byte if (sl & 0x100) { // check the 9th bit confirmHeader->filler[1] = 1; // and set it if necessary } setLength(length / 4); } uint32_t ZrtpPacketConfirm::getSignatureLength() { uint32_t sl = confirmHeader->sigLength; if (confirmHeader->filler[1] == 1) { // do we have a 9th bit sl |= 0x100; } return sl; } ZrtpPacketConfirm::ZrtpPacketConfirm(uint8_t* data) { DEBUGOUT((fprintf(stdout, "Creating Confirm packet from data\n"))); allocated = NULL; zrtpHeader = (zrtpPacketHeader_t *)&((ConfirmPacket_t *)data)->hdr; // the standard header confirmHeader = (Confirm_t *)&((ConfirmPacket_t *)data)->confirm; } ZrtpPacketConfirm::~ZrtpPacketConfirm() { DEBUGOUT((fprintf(stdout, "Deleting Confirm packet: alloc: %x\n", allocated))); } libzrtpcpp-2.0.0/COPYING0000644000175000017500000010437411570305710013755 0ustar dyfetdyfet GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . libzrtpcpp-2.0.0/AUTHORS0000644000175000017500000000022311570305710013756 0ustar dyfetdyfetAuthors of GNU ZRTP Werner.Dittmann@t-online.de Werner Dittmann designed and implimented GNU ZRTP based on Phil Zimmermann's ZRTP specification. libzrtpcpp-2.0.0/README0000644000175000017500000000265511570305710013601 0ustar dyfetdyfetThis package provides a library that adds ZRTP support to the GNU ccRTP stack. Phil Zimmermann developed ZRTP to allow ad-hoc, easy to use key negotiation to setup Secure RTP (SRTP) sessions. GNU ZRTP together with GNU ccRTP (1.5.0 or later) provides a ZRTP implementation that can be directly embedded into client and server applications. The GNU ZRTP implementation is compliant to the basic functions of ZRTP as described in ''draft-zimmermann-avt-zrtp-08x''. Currently GNU ZRTP supports the basic features and multi-stream mode , not the enhanced features like PBX SAS relay or preshared mode. The GNU ZRTP implementation already defines the necessary external interfaces and functions for these enhanced features but they are not yet implemented (stubs only). You may access the ZRTP specification at this URL: [http://zfoneproject.com/zrtp_ietf.html] The first application to demonstrate this capability was the 0.8.2 release of the Twinkle softphone client. All following versions of Twinkle support GNU ZRTP as well. Please note, this library is licensed under the GNU GPL, version 3 or later, and has been copyright assigned to the Free Software Foundation. For further information refer to the ZRTP FAQ and the GNU ZRTP How-To. Both are part of the GNU Telephony wiki and are located in its documentation category. Here are the URLs: http://www.gnutelephony.org/index.php/GNU_ZRTP_How_To http://www.gnutelephony.org/index.php/ZRTP_FAQ libzrtpcpp-2.0.0/m4/0000755000175000017500000000000011570305710013231 5ustar dyfetdyfetlibzrtpcpp-2.0.0/libzrtpcpp.spec.cmake0000644000175000017500000000727011570331472017047 0ustar dyfetdyfet# # spec file for package libzrtpcpp (Version @VERSION@) # # Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via http://bugs.opensuse.org/ # Name: libzrtpcpp Summary: A ccrtp extension for ZRTP support BuildRequires: gcc-c++ @BUILD_REQ@ pkgconfig cmake BuildRequires: libccrtp-devel >= 2.0.0 Version: @VERSION@ Release: 0 License: GPL v3 or later Group: Development/Libraries/Other Url: http://www.gnu.org/software/commoncpp/commoncpp.html Source0: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build %description This library is a GPL licensed extension to the GNU RTP Stack, ccrtp, that offers compatibility with Phil Zimmermann's zrtp/Zfone voice encryption, and which can be directly embedded into telephony applications. %package devel License: GPL v3 or later Group: Development/Libraries/Other Summary: Headers and link library for libzrtpcpp Requires: libzrtpcpp = %{version} libccrtp-devel >= 2.0.0 %description devel This package provides the header files, link libraries, and documentation for building applications that use libzrtpcpp. %prep %setup -q %build %{__mkdir} build cd build cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \ -DSYSCONFDIR=%{_sysconfdir} \ -DMANDIR=%{_mandir} \ -DCMAKE_VERBOSE_MAKEFILE=TRUE \ -DCMAKE_C_FLAGS_RELEASE:STRING="$RPM_OPT_FLAGS" \ -DCMAKE_CXX_FLAGS_RELEASE:STRING="$RPM_OPT_FLAGS" \ .. %{__make} %{?_smp_mflags} %install cd build %{__rm} -rf %{buildroot} make install DESTDIR=%{buildroot} %clean %{__rm} -rf %{buildroot} %files -n libzrtpcpp %defattr(-,root,root,0755) %doc AUTHORS COPYING README %{_libdir}/*.so.* %files devel %defattr(-,root,root,0755) %{_libdir}/*.so %{_libdir}/pkgconfig/*.pc %{_includedir}/libzrtpcpp/*.h %dir %{_includedir}/libzrtpcpp %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %changelog * Mon Dec 27 2010 - Werner Dittmann - Add Skein MAC authentication algorithm - lots of documentation added (doxygen ready) - some code cleanup * Sun Oct 11 2009 - Werner Dittmann - Fix multistream problem - add DH2048 mode - update cipher selection to match latest draft (15x) - Test with zfone3 with Ping packet mode enabled - some code cleanup * Wed Jun 24 2009 - David Sugar - Spec updated per current Fedora & CentOS policies. - Updated release 1.4.5 has all mandatory IETF interop requirements. * Fri Jan 26 2009 - Werner Dittmann - Update to version 1.4.2 to support the latest ZRTP specification draft-zimmermann-avt-zrtp-12 * Fri Aug 22 2008 - David Sugar - Adapted for newer library naming conventions. * Tue Dec 11 2007 - Werner Dittmann - this is the first spec file for version 1.x.x - remove the .la file in devel package - use default file atttribute instead of 755 * Sat Apr 18 2007 - Werner Dittmann - set version to 1.1.0 - GNU ZRTP is compatible with the latest Zfone Beta from April 2 2007 libzrtpcpp-2.0.0/cmake/0000755000175000017500000000000011570305710013771 5ustar dyfetdyfetlibzrtpcpp-2.0.0/cmake/cmake_uninstall.cmake.in0000644000175000017500000000147411570305710020557 0ustar dyfetdyfetIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) STRING(REGEX REPLACE "\n" ";" files "${files}") FOREACH(file ${files}) MESSAGE(STATUS "Uninstalling ${file}") IF(EXISTS "${file}") EXEC_PROGRAM(@CMAKE_COMMAND@ -E remove "${file}" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing ${file}") ENDIF(NOT "${rm_retval}" STREQUAL 0) ELSE(EXISTS "$ENV{DESTDIR}${file}") MESSAGE(STATUS "File ${file} does not exist.") ENDIF(EXISTS "${file}") ENDFOREACH(file) libzrtpcpp-2.0.0/cmake/Modules/0000755000175000017500000000000011570311660015402 5ustar dyfetdyfetlibzrtpcpp-2.0.0/cmake/Modules/SourceDistribution.cmake0000755000175000017500000001745611570305710022263 0ustar dyfetdyfet# - a CMake module that helps to create a source distribution # # This module provide some macros that setup a source distribution. # In contrast to standard CPack processing this is a very lightweight # module that works very fast. The source distribution module enables # the Cmake user to add indivdiual files and directories and thus # provides a more fine grained control than CPack. # # The module works similar to the standard CMake INSTALL command: the # macros of this module prepare CMake files (cmake_src_dist.cmake) that # contain all necessary commands to create the distribution directoy. # The make target 'src_dist' executes the commands and builds the # compressed tar file of the source distribution. # # Usage: # src_distribution_init([NOT_INCLUDE_DEFAULT] []) # Initializes the source distribution functions. Each CMakeList.txt # that distributes sources must call this macro before it can use # other source distrbution macros. # Only the first call from the top level CMakeLists.txt uses the # distribution name argument. All subsequent call silently ignore it. # The macro sets the distribution name to ${PROJECT_NAME}-{VERSION} # if no distribution name is provided. # The macro automatically includes some default files and directories # into the distribution: CMakeLists.txt and the cmake directory. # Set NOT_INCLUDE_DEFAULT to disable this function. # The macro creates a make target 'src_dist'. This target executes # all operations to create the distribution directory structure and # to create the compressed tar file .tar.gz. The # source distribution directory can be deleted afterwards. # # add_src_dist_dirs( []*) # Works imilar to the normal add_subdirectory command of CMake. # This call adds a subdirectory that contains sources or other # files that go into a source distribution. The subdirecty must # contain a CMakeLists.txt file that also uses the source distrbution # macros. # # add_src_dist_files( []*) # Adds one or more files to the source distrbution. # # Eaxample: # # include(SourceDistrbution) # # The following call initializes the module and sets the distrbution's # name to 'mySourceDist'. The macro creates a directory with this name # in the current build directory and include the standard CMakeLists.txt # file and the 'cmake' directory (it it exists) into the distribution. # # src_distribution_init(mySourceDist) # # Now add some files (assumes ${src_files} was set previously): # add_src_dist_files(README LICENSE ${src_files}) # # Now add a subdirectoy, in this case an include directory: # add_src_dist_dirs(include) # # # ---- internal macros ---- # # This macro gets the current directory relative to CMAKE_SOURCE_DIR # and sets an internal variable to the current distribution directory. # Another variable holds the current path to the CMake command file. # Other macros use these variable to construct commands # to build the distribution structure. # MACRO (_set_src_dist_scope_vars) STRING(REPLACE "${CMAKE_SOURCE_DIR}" "" _src_dist_subdir "${CMAKE_CURRENT_SOURCE_DIR}") if (NOT _src_dist_subdir) set(_src_dist_fulldir ${SRC_DIST_DIR}) else() set(_src_dist_fulldir ${SRC_DIST_DIR}${_src_dist_subdir}) endif() set(_src_dist_cmd_file_path ${CMAKE_CURRENT_BINARY_DIR}/${_SRC_DIST_CMD_FILE_NAME}) ENDMACRO() # # Check for the NOT_INCLUDE_DEFAULT option. # MACRO(_src_dist_parse_options _result _default _length) set(${_default} TRUE) foreach(_arg ${ARGN}) if (_arg STREQUAL "NOT_INCLUDE_DEFAULT") set(${_default} FALSE) endif() endforeach() set(${_result} ${ARGN}) list(LENGTH ${_result} ${_length}) if (${_length} GREATER 0) list(REMOVE_ITEM ${_result} "NOT_INCLUDE_DEFAULT") endif() # recompute length of list list(LENGTH ${_result} ${_length}) ENDMACRO() # # This macro initializes the source distribution package. # Only the top-level initialization macro init_src_distribution() # calls this internal macro. # MACRO (_src_dist_internal_init) # internal variable for distribution cmake file set(_SRC_DIST_CMD_FILE_NAME "cmake_src_dist.cmake") if (${_src_dist_dirlist_length} EQUAL 0) set(_src_dist_tardir ${PROJECT_NAME}-${VERSION}) else() list(GET _src_dist_dirlist 0 _src_dist_tardir) endif() set(SRC_DIST_DIR ${CMAKE_BINARY_DIR}/${_src_dist_tardir}) message(STATUS "Source distribution direcrory set to: ${SRC_DIST_DIR}") _set_src_dist_scope_vars() file(REMOVE ${_src_dist_cmd_file_path}) # fill in first commands into the distribution cmake file. Calling # 'make src_dist' executes the stored commands and prepares the source # distrubtion. # file(APPEND ${_src_dist_cmd_file_path} " # clear contents of an existing distribution directory file(REMOVE_RECURSE ${SRC_DIST_DIR}) ") add_custom_target(src_dist COMMAND ${CMAKE_COMMAND} -P ${_src_dist_cmd_file_path} COMMAND ${CMAKE_COMMAND} -E tar cfj ${SRC_DIST_DIR}.tar.bz2 ${_src_dist_tardir} COMMAND ${CMAKE_COMMAND} -E remove_directory ${SRC_DIST_DIR} ) ENDMACRO() ################# User visible macros ################### # MACRO(src_distribution_init) # clear old src distribution cmake command file _src_dist_parse_options(_src_dist_dirlist _src_dist_default _src_dist_dirlist_length ${ARGN}) if (NOT DEFINED _SRC_DIST_INIT) _src_dist_internal_init() set(_SRC_DIST_INIT TRUE) else() _set_src_dist_scope_vars() file(REMOVE ${_src_dist_cmd_file_path}) endif() if(_src_dist_default) if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(_src_dist_list_tmp) # Get all files names in cmake subdir # Unfortunately CMake also globs all directories and files that start # with . - that is not the same as shell behaviour file(GLOB_RECURSE _src_dist_names_tmp RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/*) # # Remove all file names that contain a name that start with . foreach(_nm ${_src_dist_names_tmp}) string(REGEX REPLACE .*/\\..* "" _nm ${_nm}) set(_src_dist_list_tmp ${_src_dist_list_tmp} ${_nm}) endforeach() add_src_dist_files(${_src_dist_list_tmp}) endif() if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt") file(APPEND ${_src_dist_cmd_file_path} " FILE(INSTALL DESTINATION \"${_src_dist_fulldir}\" TYPE FILE FILES \"${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt\") ") endif() endif() ENDMACRO() # Add a subdirectory to the src distribution # MACRO(add_src_dist_dirs) foreach(_dir ${ARGN}) if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_dir}/CMakeLists.txt) message(FATAL_ERROR "Soure distribution subdirectory \"${CMAKE_CURRENT_SOURCE_DIR}/${_dir}\" does not contain a CMakeLists.txt") endif() # include subdirectory's distribution cmake command file file(APPEND ${_src_dist_cmd_file_path} " include(\"${CMAKE_CURRENT_BINARY_DIR}/${_dir}/${_SRC_DIST_CMD_FILE_NAME}\") ") endforeach() ENDMACRO() # # Add files to the src distribution. The handles and install files # that are in the same directory as the current source as well as files # in sub directories of the current source (with relative path). # MACRO(add_src_dist_files) foreach(_file ${ARGN}) get_filename_component(_src_dist_tmp_path ${_file} PATH) # string(REPLACE "${CMAKE_SOURCE_DIR}" "" _src_dist_tmp_path "${_src_dist_tmp_path}") if(_src_dist_tmp_path) set(_src_dist_tmp_path ${_src_dist_fulldir}/${_src_dist_tmp_path}) else () set(_src_dist_tmp_path ${_src_dist_fulldir}) endif() file(APPEND ${_src_dist_cmd_file_path} " FILE(INSTALL DESTINATION \"${_src_dist_tmp_path}\" TYPE FILE FILES \"${CMAKE_CURRENT_SOURCE_DIR}/${_file}\") ") endforeach() ENDMACRO() libzrtpcpp-2.0.0/cmake/Modules/LibFindMacros.cmake0000755000175000017500000001004211570305710021057 0ustar dyfetdyfet# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments # used for the current package. For this to work, the first parameter must be the # prefix of the current package, then the prefix of the new package etc, which are # passed to find_package. macro (libfind_package PREFIX) set (LIBFIND_PACKAGE_ARGS ${ARGN}) if (${PREFIX}_FIND_QUIETLY) set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET) endif (${PREFIX}_FIND_QUIETLY) if (${PREFIX}_FIND_REQUIRED) set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED) endif (${PREFIX}_FIND_REQUIRED) find_package(${LIBFIND_PACKAGE_ARGS}) endmacro (libfind_package) # CMake developers made the UsePkgConfig system deprecated in the same release (2.6) # where they added pkg_check_modules. Consequently I need to support both in my scripts # to avoid those deprecated warnings. Here's a helper that does just that. # Works identically to pkg_check_modules, except that no checks are needed prior to use. macro (libfind_pkg_check_modules PREFIX PKGNAME) if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) include(UsePkgConfig) pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) find_package(PkgConfig) if (PKG_CONFIG_FOUND) pkg_check_modules(${PREFIX} ${PKGNAME}) endif (PKG_CONFIG_FOUND) endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) endmacro (libfind_pkg_check_modules) # Do the final processing once the paths have been detected. # If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain # all the variables, each of which contain one include directory. # Ditto for ${PREFIX}_PROCESS_LIBS and library files. # Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. # Also handles errors in case library detection was required, etc. macro (libfind_process PREFIX) # Skip processing if already processed during this run if (NOT ${PREFIX}_FOUND) # Start with the assumption that the library was found set (${PREFIX}_FOUND TRUE) # Process all includes and set _FOUND to false if any are missing foreach (i ${${PREFIX}_PROCESS_INCLUDES}) if (${i}) set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) mark_as_advanced(${i}) else (${i}) set (${PREFIX}_FOUND FALSE) endif (${i}) endforeach (i) # Process all libraries and set _FOUND to false if any are missing foreach (i ${${PREFIX}_PROCESS_LIBS}) if (${i}) set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) mark_as_advanced(${i}) else (${i}) set (${PREFIX}_FOUND FALSE) endif (${i}) endforeach (i) # Print message and/or exit on fatal error if (${PREFIX}_FOUND) if (NOT ${PREFIX}_FIND_QUIETLY) message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") endif (NOT ${PREFIX}_FIND_QUIETLY) else (${PREFIX}_FOUND) if (${PREFIX}_FIND_REQUIRED) foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) message("${i}=${${i}}") endforeach (i) message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") endif (${PREFIX}_FIND_REQUIRED) endif (${PREFIX}_FOUND) endif (NOT ${PREFIX}_FOUND) endmacro (libfind_process) macro(libfind_library PREFIX basename) set(TMP "") if(MSVC80) set(TMP -vc80) endif(MSVC80) if(MSVC90) set(TMP -vc90) endif(MSVC90) set(${PREFIX}_LIBNAMES ${basename}${TMP}) if(${ARGC} GREATER 2) set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2}) string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES}) set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP}) endif(${ARGC} GREATER 2) find_library(${PREFIX}_LIBRARY NAMES ${${PREFIX}_LIBNAMES} PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS} ) endmacro(libfind_library) libzrtpcpp-2.0.0/cmake/Modules/FindGcryptConfig.cmake0000755000175000017500000002376011570311660021616 0ustar dyfetdyfet# - a gcrypt-config module for CMake # # Usage: # gcrypt_check( [REQUIRED] ) # checks if gcrypt is avialable # # When the 'REQUIRED' argument was set, macros will fail with an error # when gcrypt could not be found. # # It sets the following variables: # GCRYPT_CONFIG_FOUND ... true if libgcrypt-config works on the system # GCRYPT_CONFIG_EXECUTABLE ... pathname of the libgcrypt-config program # _FOUND ... set to 1 if libgcrypt exist # _LIBRARIES ... the libraries # _CFLAGS ... all required cflags # _ALGORITHMS ... the algorithms that this libgcrypt supports # _VERSION ... gcrypt's version # # Examples: # gcrypt_check (GCRYPT gcrypt) # Check if a version of gcrypt is available, issues a warning # if not. # # gcrypt_check (GCRYPT REQUIRED gcrypt) # Check if a version of gcrypt is available and fails # if not. # # gcrypt_check (GCRYPT gcrypt>=1.4) # requires at least version 1.4 of gcrypt and defines e.g. # GCRYPT_VERSION=1.4.4. Issues a warning if a lower version # is available only. # # gcrypt_check (GCRYPT REQUIRED gcrypt>=1.4.4) # requires at least version 1.4.4 of gcrypt and fails if # only gcrypt 1.4.3 or lower is available only. # # Copyright (C) 2010 Werner Dittmann # # Redistribution and use, with or without modification, are permitted # provided that the following conditions are met: # # 1. Redistributions must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. The name of the author may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # This is a much edited and simplified variant of the original UsePkgConfig.cmake # from Enrico Scholz # Copyright (C) 2006 Enrico Scholz # ### Common stuff #### set(GCR_CONFIG_VERSION 1) set(GCR_CONFIG_FOUND 0) find_program(GCR_CONFIG_EXECUTABLE NAMES libgcrypt-config --version DOC "libgcrypt-config executable") mark_as_advanced(GCR_CONFIG_EXECUTABLE) if(GCR_CONFIG_EXECUTABLE) set(GCR_CONFIG_FOUND 1) endif(GCR_CONFIG_EXECUTABLE) # Unsets the given variables macro(_gcrconfig_unset var) set(${var} "" CACHE INTERNAL "") endmacro(_gcrconfig_unset) macro(_gcrconfig_set var value) set(${var} ${value} CACHE INTERNAL "") endmacro(_gcrconfig_set) # Invokes libgcrypt-config, cleans up the result and sets variables macro(_gcrconfig_invoke _gcrlist _prefix _varname _regexp) set(_gcrconfig_invoke_result) execute_process( COMMAND ${GCR_CONFIG_EXECUTABLE} ${ARGN} OUTPUT_VARIABLE _gcrconfig_invoke_result RESULT_VARIABLE _gcrconfig_failed) if (_gcrconfig_failed) set(_gcrconfig_${_varname} "") _gcrconfig_unset(${_prefix}_${_varname}) else(_gcrconfig_failed) string(REGEX REPLACE "[\r\n]" " " _gcrconfig_invoke_result "${_gcrconfig_invoke_result}") string(REGEX REPLACE " +$" "" _gcrconfig_invoke_result "${_gcrconfig_invoke_result}") if (NOT ${_regexp} STREQUAL "") string(REGEX REPLACE "${_regexp}" " " _gcrconfig_invoke_result "${_gcrconfig_invoke_result}") endif(NOT ${_regexp} STREQUAL "") separate_arguments(_gcrconfig_invoke_result) #message(STATUS " ${_varname} ... ${_gcrconfig_invoke_result}") set(_gcrconfig_${_varname} ${_gcrconfig_invoke_result}) _gcrconfig_set(${_prefix}_${_varname} "${_gcrconfig_invoke_result}") endif(_gcrconfig_failed) endmacro(_gcrconfig_invoke) macro(_gcrconfig_invoke_dyn _gcrlist _prefix _varname cleanup_regexp) _gcrconfig_invoke("${_gcrlist}" ${_prefix} ${_varname} "${cleanup_regexp}" ${ARGN}) endmacro(_gcrconfig_invoke_dyn) # Splits given arguments into options and a package list macro(_gcrconfig_parse_options _result _is_req) set(${_is_req} 0) foreach(_gcr ${ARGN}) if (_gcr STREQUAL "REQUIRED") set(${_is_req} 1) endif (_gcr STREQUAL "REQUIRED") endforeach(_gcr ${ARGN}) set(${_result} ${ARGN}) list(REMOVE_ITEM ${_result} "REQUIRED") endmacro(_gcrconfig_parse_options) ### macro(_gcr_check_modules_internal _is_required _is_silent _prefix) _gcrconfig_unset(${_prefix}_FOUND) _gcrconfig_unset(${_prefix}_VERSION) _gcrconfig_unset(${_prefix}_PREFIX) _gcrconfig_unset(${_prefix}_LIBDIR) _gcrconfig_unset(${_prefix}_LIBRARIES) _gcrconfig_unset(${_prefix}_CFLAGS) _gcrconfig_unset(${_prefix}_ALGORITHMS) # create a better addressable variable of the modules and calculate its size set(_gcr_check_modules_list ${ARGN}) list(LENGTH _gcr_check_modules_list _gcr_check_modules_cnt) if(GCR_CONFIG_EXECUTABLE) # give out status message telling checked module if (NOT ${_is_silent}) message(STATUS "checking for module '${_gcr_check_modules_list}'") endif(NOT ${_is_silent}) # iterate through module list and check whether they exist and match the required version foreach (_gcr_check_modules_gcr ${_gcr_check_modules_list}) # check whether version is given if (_gcr_check_modules_gcr MATCHES ".*(>=|=|<=).*") string(REGEX REPLACE "(.*[^><])(>=|=|<=)(.*)" "\\1" _gcr_check_modules_gcr_name "${_gcr_check_modules_gcr}") string(REGEX REPLACE "(.*[^><])(>=|=|<=)(.*)" "\\2" _gcr_check_modules_gcr_op "${_gcr_check_modules_gcr}") string(REGEX REPLACE "(.*[^><])(>=|=|<=)(.*)" "\\3" _gcr_check_modules_gcr_ver "${_gcr_check_modules_gcr}") else(_gcr_check_modules_gcr MATCHES ".*(>=|=|<=).*") set(_gcr_check_modules_gcr_name "${_gcr_check_modules_gcr}") set(_gcr_check_modules_gcr_op) set(_gcr_check_modules_gcr_ver) endif(_gcr_check_modules_gcr MATCHES ".*(>=|=|<=).*") set(_gcr_check_prefix "${_prefix}") _gcrconfig_invoke(${_gcr_check_modules_gcr_name} "${_gcr_check_prefix}" VERSION "" --version ) # _gcrconfig_invoke(${_gcr_check_modules_gcr_name} "${_gcr_check_prefix}" PREFIX "" --prefix ) _gcrconfig_invoke(${_gcr_check_modules_gcr_name} "${_gcr_check_prefix}" LIBRARIES "" --libs ) _gcrconfig_invoke(${_gcr_check_modules_gcr_name} "${_gcr_check_prefix}" CFLAGS "" --cflags ) _gcrconfig_invoke(${_gcr_check_modules_gcr_name} "${_gcr_check_prefix}" ALGORITHMS "" --algorithms ) message(STATUS " found ${_gcr_check_modules_gcr}, version ${_gcrconfig_VERSION}") # handle the operands set(_gcr_wrong_version 0) if (_gcr_check_modules_gcr_op STREQUAL ">=") if(_gcr_check_modules_gcr_ver VERSION_EQUAL _gcrconfig_VERSION) message(STATUS " gcrypt wrong version: required: ${_gcr_check_modules_gcr_op}${_gcr_check_modules_gcr_ver}, found: ${_gcrconfig_VERSION}") set(_gcr_wrong_version 1) endif() if(_gcrconfig_VERSION VERSION_LESS _gcr_check_modules_gcr_ver ) message(STATUS " gcrypt wrong version: required: ${_gcr_check_modules_gcr_op}${_gcr_check_modules_gcr_ver}, found: ${_gcrconfig_VERSION}") set(_gcr_wrong_version 1) endif() endif(_gcr_check_modules_gcr_op STREQUAL ">=") if (_gcr_check_modules_gcr_op STREQUAL "=") if(_gcr_check_modules_gcr_ver VERSION_EQUAL _gcrconfig_VERSION) message(STATUS " gcrypt wrong version: required: ${_gcr_check_modules_gcr_op}${_gcr_check_modules_gcr_ver}, found: ${_gcrconfig_VERSION}") set(_gcr_wrong_version 1) endif() endif(_gcr_check_modules_gcr_op STREQUAL "=") if (_gcr_check_modules_gcr_op STREQUAL "<=") if(_gcr_check_modules_gcr_ver VERSION_EQUAL _gcrconfig_VERSION) message(STATUS " gcrypt wrong version: required: ${_gcr_check_modules_gcr_op}${_gcr_check_modules_gcr_ver}, found: ${_gcrconfig_VERSION}") set(_gcr_wrong_version 1) endif() if(_gcrconfig_VERSION VERSION_GREATER _gcr_check_modules_gcr_ver) message(STATUS " gcrypt wrong version: required: ${_gcr_check_modules_gcr_op}${_gcr_check_modules_gcr_ver}, found: ${_gcrconfig_VERSION}") set(_gcr_wrong_version 1) endif() endif(_gcr_check_modules_gcr_op STREQUAL "<=") if (${_is_required} AND _gcr_wrong_version) message(FATAL_ERROR "") endif() endforeach(_gcr_check_modules_gcr) _gcrconfig_set(${_prefix}_FOUND 1) else(GCR_CONFIG_EXECUTABLE) if (${_is_required}) message(FATAL_ERROR "libgcrypt-config tool not found") endif (${_is_required}) endif(GCR_CONFIG_EXECUTABLE) endmacro(_gcr_check_modules_internal) ### ### User visible macro starts here ### ### macro(gcr_check _prefix _module0) # check cached value if (NOT DEFINED __gcr_config_checked_${_prefix} OR __gcr_config_checked_${_prefix} LESS ${GCR_CONFIG_VERSION} OR NOT ${_prefix}_FOUND) _gcrconfig_parse_options (_gcr_modules _gcr_is_required "${_module0}" ${ARGN}) _gcr_check_modules_internal("${_gcr_is_required}" 0 "${_prefix}" ${_gcr_modules}) _gcrconfig_set(__gcr_config_checked_${_prefix} ${GCR_CONFIG_VERSION}) endif(NOT DEFINED __gcr_config_checked_${_prefix} OR __gcr_config_checked_${_prefix} LESS ${GCR_CONFIG_VERSION} OR NOT ${_prefix}_FOUND) endmacro(gcr_check) ### ### Local Variables: ### mode: cmake ### End: libzrtpcpp-2.0.0/cmake/Modules/UseRPMTools.cmake0000644000175000017500000001404311570305710020541 0ustar dyfetdyfet# # - Find tools needed for building RPM Packages # on Linux systems and defines macro that helps to # build source or binary RPM, the MACRO assumes # CMake 2.4.x which includes CPack support. # CPack is used to build tar.gz source tarball # which may be used by a custom user-made spec file. # # - Define RPMTools_ADD_RPM_TARGETS which defines # two (top-level) CUSTOM targets for building # source and binary RPMs # # Those CMake macros are provided by the TSP Developer Team # https://savannah.nongnu.org/projects/tsp # # Modified by Werner to use the SoureDistribution variables and # files instead of CPack stuff. Only minor changes. IF (WIN32) MESSAGE(STATUS "RPM tools not available on Win32 systems") ENDIF(WIN32) IF (UNIX) # Look for RPM builder executable FIND_PROGRAM(RPMTools_RPMBUILD_EXECUTABLE NAMES rpmbuild PATHS "/usr/bin;/usr/lib/rpm" PATH_SUFFIXES bin DOC "The RPM builder tool") IF (RPMTools_RPMBUILD_EXECUTABLE) MESSAGE(STATUS "Looking for RPMTools... - found rpmuild is ${RPMTools_RPMBUILD_EXECUTABLE}") SET(RPMTools_RPMBUILD_FOUND "YES") GET_FILENAME_COMPONENT(RPMTools_BINARY_DIRS ${RPMTools_RPMBUILD_EXECUTABLE} PATH) ELSE (RPMTools_RPMBUILD_EXECUTABLE) SET(RPMTools_RPMBUILD_FOUND "NO") MESSAGE(STATUS "Looking for RPMTools... - rpmbuild NOT FOUND") ENDIF (RPMTools_RPMBUILD_EXECUTABLE) # Detect if CourceDistribution was initialized or not IF (NOT DEFINED "SRC_DIST_DIR") MESSAGE(FATAL_ERROR "SourceDistribution was not initialized") ENDIF (NOT DEFINED "SRC_DIST_DIR") IF (RPMTools_RPMBUILD_FOUND) SET(RPMTools_FOUND TRUE) # # - first arg (ARGV0) is RPM name # - second arg (ARGV1) is the RPM spec file path [optional] # - third arg (ARGV2) is the RPM ROOT DIRECTORY used to build RPMs [optional] # MACRO(RPMTools_ADD_RPM_TARGETS RPMNAME) # # If no spec file is provided create a minimal one # IF ("${ARGV1}" STREQUAL "") SET(SPECFILE_PATH "${CMAKE_BINARY_DIR}/${RPMNAME}.spec") ELSE ("${ARGV1}" STREQUAL "") SET(SPECFILE_PATH "${ARGV1}") ENDIF("${ARGV1}" STREQUAL "") # Verify whether if RPM_ROOTDIR was provided or not IF("${ARGV2}" STREQUAL "") SET(RPM_ROOTDIR ${CMAKE_BINARY_DIR}/RPM) ELSE ("${ARGV2}" STREQUAL "") SET(RPM_ROOTDIR "${ARGV2}") ENDIF("${ARGV2}" STREQUAL "") MESSAGE(STATUS "RPMTools:: Using RPM_ROOTDIR=${RPM_ROOTDIR}") # Prepare RPM build tree FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/tmp) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/BUILD) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/RPMS) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/SOURCES) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/SPECS) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/SRPMS) # # We check whether if the provided spec file is # to be configure or not. # IF ("${ARGV1}" STREQUAL "") SET(SPECFILE_PATH "${RPM_ROOTDIR}/SPECS/${RPMNAME}.spec") SET(SPECFILE_NAME "${RPMNAME}.spec") MESSAGE(STATUS "No Spec file given generate a minimal one --> ${RPM_ROOTDIR}/SPECS/${RPMNAME}.spec") FILE(WRITE ${RPM_ROOTDIR}/SPECS/${RPMNAME}.spec "# -*- rpm-spec -*- Summary: ${RPMNAME} Name: ${RPMNAME} Version: ${PACKAGE_VERSION} Release: 1 License: Unknown Group: Unknown Source: ${SRC_DIST_DIR}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: cmake %define prefix /opt/${RPMNAME}-%{version} %define rpmprefix $RPM_BUILD_ROOT%{prefix} %define srcdirname %{name}-%{version}-Source %description ${RPMNAME} : No description for now %prep %setup -q -n %{srcdirname} %build cd .. rm -rf build_tree mkdir build_tree cd build_tree cmake -DCMAKE_INSTALL_PREFIX=%{rpmprefix} ../%{srcdirname} make %install cd ../build_tree make install %clean rm -rf %{srcdirname} rm -rf build_tree %files %defattr(-,root,root,-) %dir %{prefix} %{prefix}/* %changelog * Wed Feb 28 2007 Erk Generated by CMake UseRPMTools macros" ) ELSE ("${ARGV1}" STREQUAL "") SET(SPECFILE_PATH "${ARGV1}") GET_FILENAME_COMPONENT(SPECFILE_EXT ${SPECFILE_PATH} EXT) IF ("${SPECFILE_EXT}" STREQUAL ".spec") # This is a 'ready-to-use' spec file which does not need to be CONFIGURED GET_FILENAME_COMPONENT(SPECFILE_NAME ${SPECFILE_PATH} NAME) MESSAGE(STATUS "Simple copy spec file <${SPECFILE_PATH}> --> <${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}>") CONFIGURE_FILE( ${SPECFILE_PATH} ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME} COPYONLY) ELSE ("${SPECFILE_EXT}" STREQUAL ".spec") # This is a to-be-configured spec file GET_FILENAME_COMPONENT(SPECFILE_NAME ${SPECFILE_PATH} NAME_WE) SET(SPECFILE_NAME "${SPECFILE_NAME}.spec") MESSAGE(STATUS "Configuring spec file <${SPECFILE_PATH}> --> <${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}>") CONFIGURE_FILE( ${SPECFILE_PATH} ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME} @ONLY) ENDIF ("${SPECFILE_EXT}" STREQUAL ".spec") ENDIF("${ARGV1}" STREQUAL "") ADD_CUSTOM_TARGET(${RPMNAME}_srpm COMMAND ${CMAKE_BUILD_TOOL} src_dist COMMAND ${CMAKE_COMMAND} -E copy ${SRC_DIST_DIR}.tar.gz ${RPM_ROOTDIR}/SOURCES COMMAND ${RPMTools_RPMBUILD_EXECUTABLE} -bs --define=\"_topdir ${RPM_ROOTDIR}\" --buildroot=${RPM_ROOTDIR}/tmp ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME} ) ADD_CUSTOM_TARGET(${RPMNAME}_rpm COMMAND ${CMAKE_BUILD_TOOL} src_dist COMMAND ${CMAKE_COMMAND} -E copy ${SRC_DIST_DIR}.tar.gz ${RPM_ROOTDIR}/SOURCES COMMAND ${RPMTools_RPMBUILD_EXECUTABLE} -bb --define=\"_topdir ${RPM_ROOTDIR}\" --buildroot=${RPM_ROOTDIR}/tmp ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME} ) ENDMACRO(RPMTools_ADD_RPM_TARGETS) ELSE (RPMTools_RPMBUILD_FOUND) SET(RPMTools FALSE) ENDIF (RPMTools_RPMBUILD_FOUND) ENDIF (UNIX) libzrtpcpp-2.0.0/cmake/Modules/GeneratePackage.cmake0000644000175000017500000000403511570305710021413 0ustar dyfetdyfet MACRO(GENERATE_PACKAGING PACKAGE VERSION) # The following components are regex's to match anywhere (unless anchored) # in absolute path + filename to find files or directories to be excluded # from source tarball. SET (CPACK_SOURCE_IGNORE_FILES #svn files "\\\\.svn/" "\\\\.cvsignore$" # temporary files "\\\\.swp$" # backup files "~$" # eclipse files "\\\\.cdtproject$" "\\\\.cproject$" "\\\\.project$" "\\\\.settings/" "\\\\.kdev4/" "\\\\.kdev4$" # others "\\\\.#" "/#" "/build/" "/autom4te\\\\.cache/" "/_build/" "/\\\\.git/" # used before "/CVS/" "/\\\\.libs/" "/\\\\.deps/" "\\\\.o$" "\\\\.lo$" "\\\\.la$" "\\\\.sh$" "Makefile\\\\.in$" ) SET(CPACK_PACKAGE_VENDOR "Werner Dittmann") #SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/ReadMe.txt") #SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt") #SET(CPACK_PACKAGE_VERSION_MAJOR ${version_major}) #SET(CPACK_PACKAGE_VERSION_MINOR ${version_minor}) #SET(CPACK_PACKAGE_VERSION_PATCH ${version_patch}) SET( CPACK_GENERATOR "TBZ2") SET( CPACK_SOURCE_GENERATOR "TBZ2") SET( CPACK_SOURCE_PACKAGE_FILE_NAME "${PACKAGE}-${VERSION}" ) INCLUDE(CPack) # SPECFILE() ADD_CUSTOM_TARGET( svncheck COMMAND cd $(CMAKE_SOURCE_DIR) && LC_ALL=C git status | grep -q "nothing to commit .working directory clean." ) SET( AUTOBUILD_COMMAND COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/package/*.tar.bz2 COMMAND ${CMAKE_MAKE_PROGRAM} package_source COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2 ${CMAKE_BINARY_DIR}/package COMMAND ${CMAKE_COMMAND} -E remove ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2 # COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/package/${PACKAGE}.changes" "${CMAKE_BINARY_DIR}/package/${PACKAGE}.changes" ) ADD_CUSTOM_TARGET( srcpackage_local ${AUTOBUILD_COMMAND} ) ADD_CUSTOM_TARGET( srcpackage COMMAND ${CMAKE_MAKE_PROGRAM} svncheck ${AUTOBUILD_COMMAND} ) ENDMACRO(GENERATE_PACKAGING) libzrtpcpp-2.0.0/cmake/Modules/AutoArgs.cmake0000644000175000017500000000203411570305710020127 0ustar dyfetdyfetmacro (enable_arg _enable_name _enable_default) if (${ARGC} GREATER 2) set(_auto_arg_help ${_AUTO_ARG_HELP} "-Denable-${_enable_name}=[true|false] -- ${ARGV2} (default: ${_enable_default})" ) endif() if(NOT DEFINED enable-${_enable_name} AND NOT DEFINED disable-${_enable_name}) set(enable_${_enable_name} ${_enable_default}) elseif(DEFINED enable-${_enable_name}) if(enable-${_enable_name}) set(enable_${_enable_name} true) else() set(enable_${_enable_name} false) endif() unset(enable-${_enable_name}) unset(enable-${_enable_name} CACHE) elseif(DEFINED disable-${_enable_name}) if(disable-${_enable_name}) set(enable_${_enable_name} false) else() set(enable_${_enable_name} true) endif() unset(disable-${_enable_name}) unset(disable-${_enable_name} CACHE) endif() endmacro() macro(args_help) if(DEFINED help-args) message("Control arguments:") foreach(_args_help ${_AUTO_ARG_HELP}) message(${_args_help}) endforeach() unset(help-args) unset(help-args CACHE) endif() endmacro() libzrtpcpp-2.0.0/INSTALL0000755000175000017500000000174111570305710013750 0ustar dyfetdyfet === Configure, build and install GNU ZRTP 1.4.x === After uninstalling the prevoius version you can build and install the new version. Building and installation of the GNU ZRTP 1.1.0 uses the usual triplet of ''./configure; make; sudo make install''. By default GNU ZRTP install its files into the ''/usr/local'' hierarchy. Don't forget to run ''/sbin/ldconfig'' if you use the ''make install''. Some distributions may offer GNU ZRTP packets and it is usally much simpler and more safe to use the preconfigured packets than to build the software from the source. Don't forget to install the ''developer'' packets if you plan to develop or if you already developed own application that use GNU ZRTP. If you need to re-create the ''configure'' and the Makefiles then just use your system's ''autoreconf'' command to re-create these files. No specific reconfiguration script is necessary. After installation of GNU ZRTP you need to adapt your applications and re-compile and re-build them. libzrtpcpp-2.0.0/doc/0000755000175000017500000000000011570305710013456 5ustar dyfetdyfetlibzrtpcpp-2.0.0/doc/gpl.texi0000644000175000017500000004400711570305710015140 0ustar dyfetdyfet@node GNU General Public License @appendixsec GNU GENERAL PUBLIC LICENSE @center Version 2, June 1991 @c This file is intended to be included in another file. @display Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @end display @appendixsubsec Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software---to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. @iftex @appendixsubsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @end iftex @ifinfo @center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @end ifinfo @enumerate 0 @item This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The ``Program'', below, refers to any such program or work, and a ``work based on the Program'' means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term ``modification''.) Each licensee is addressed as ``you''. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. @item You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. @item You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: @enumerate a @item You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. @item You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. @item If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) @end enumerate These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. @item You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: @enumerate a @item Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, @item Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, @item Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) @end enumerate The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. @item You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. @item You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. @item Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. @item If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. @item If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. @item The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and ``any later version'', you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. @item If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. @iftex @heading NO WARRANTY @end iftex @ifinfo @center NO WARRANTY @end ifinfo @item BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. @item IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. @end enumerate @iftex @heading END OF TERMS AND CONDITIONS @end iftex @ifinfo @center END OF TERMS AND CONDITIONS @end ifinfo @page @appendixsubsec Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the ``copyright'' line and a pointer to where the full notice is found. @smallexample @var{one line to give the program's name and a brief idea of what it does.} Copyright (C) @var{yyyy} @var{name of author} 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @end smallexample Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: @smallexample Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author} Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @end smallexample The hypothetical commands @samp{show w} and @samp{show c} should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than @samp{show w} and @samp{show c}; they could even be mouse-clicks or menu items---whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a ``copyright disclaimer'' for the program, if necessary. Here is a sample; alter the names: @example Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. @var{signature of Ty Coon}, 1 April 1989 Ty Coon, President of Vice @end example This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. libzrtpcpp-2.0.0/doc/fdlnotice.texi0000644000175000017500000000056211570305710016323 0ustar dyfetdyfetPermission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". libzrtpcpp-2.0.0/doc/Doxymini0000644000175000017500000015163111570305710015210 0ustar dyfetdyfet# Doxyfile 1.5.3 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "ZRTP for ccRTP " # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = NO # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be extracted # and appear in the documentation as a namespace called 'anonymous_namespace{file}', # where file will be replaced with the base name of the file that contains the anonymous # namespace. By default anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../src \ ../src/libzrtpcpp \ ../src/libzrtpcpp/crypto # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = config.h \ macros.h \ namespace.h # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH # then you must also enable this option. If you don't then doxygen will produce # a warning and turn it on anyway SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = . # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the number # of direct children of the root node in a graph is already larger than # MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO libzrtpcpp-2.0.0/doc/fdl.texi0000644000175000017500000005100211570305710015114 0ustar dyfetdyfet @node GNU Free Documentation License @appendixsec GNU Free Documentation License @cindex FDL, GNU Free Documentation License @center Version 1.2, November 2002 @display Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @end display @enumerate 0 @item PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document @dfn{free} in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of ``copyleft'', which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. @item APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The ``Document'', below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as ``you''. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A ``Modified Version'' of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A ``Secondary Section'' is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The ``Invariant Sections'' are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The ``Cover Texts'' are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A ``Transparent'' copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not ``Transparent'' is called ``Opaque''. Examples of suitable formats for Transparent copies include plain @sc{ascii} without markup, Texinfo input format, La@TeX{} input format, @acronym{SGML} or @acronym{XML} using a publicly available @acronym{DTD}, and standard-conforming simple @acronym{HTML}, PostScript or @acronym{PDF} designed for human modification. Examples of transparent image formats include @acronym{PNG}, @acronym{XCF} and @acronym{JPG}. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, @acronym{SGML} or @acronym{XML} for which the @acronym{DTD} and/or processing tools are not generally available, and the machine-generated @acronym{HTML}, PostScript or @acronym{PDF} produced by some word processors for output purposes only. The ``Title Page'' means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, ``Title Page'' means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section ``Entitled XYZ'' means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as ``Acknowledgements'', ``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' of such a section when you modify the Document means that it remains a section ``Entitled XYZ'' according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. @item VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. @item COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. @item MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: @enumerate A @item Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. @item List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. @item State on the Title page the name of the publisher of the Modified Version, as the publisher. @item Preserve all the copyright notices of the Document. @item Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. @item Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. @item Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. @item Include an unaltered copy of this License. @item Preserve the section Entitled ``History'', Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled ``History'' in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. @item Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the ``History'' section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. @item For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. @item Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. @item Delete any section Entitled ``Endorsements''. Such a section may not be included in the Modified Version. @item Do not retitle any existing section to be Entitled ``Endorsements'' or to conflict in title with any Invariant Section. @item Preserve any Warranty Disclaimers. @end enumerate If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled ``Endorsements'', provided it contains nothing but endorsements of your Modified Version by various parties---for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. @item COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled ``History'' in the various original documents, forming one section Entitled ``History''; likewise combine any sections Entitled ``Acknowledgements'', and any sections Entitled ``Dedications''. You must delete all sections Entitled ``Endorsements.'' @item COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. @item AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an ``aggregate'' if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. @item TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warrany Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled ``Acknowledgements'', ``Dedications'', or ``History'', the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. @item TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. @item FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See @uref{http://www.gnu.org/copyleft/}. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License ``or any later version'' applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. @end enumerate @page @appendixsubsec ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: @smallexample @group Copyright (C) @var{year} @var{your name}. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end group @end smallexample If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the ``with...Texts.'' line with this: @smallexample @group with the Invariant Sections being @var{list their titles}, with the Front-Cover Texts being @var{list}, and with the Back-Cover Texts being @var{list}. @end group @end smallexample If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. @c Local Variables: @c ispell-local-pdict: "ispell-dict" @c End: libzrtpcpp-2.0.0/NEWS0000755000175000017500000001727311570305710013425 0ustar dyfetdyfet== GNU ZRTP 1.5.4 == The changes in this release affect the ZRTP Configure mechanism only. Some housekeeping stuff (desctructors) was added and the C Wrapper how support ZRTP configure as well. Because of some API changes (added destructors) clients must be compiled and linked with the new library. == GNU ZRTP 1.5.2 == Quite a lot of enhancements: - a CMake based build process was added - a C wrapper was added to enable C programs to use GNU ZRTP - some fixes in the code (race condition solved) - better support of multi-stream mode - change the old cxx file extension to cpp, some build system don't like the old cxx (Android NDK for example) - and much more Because of API changes clients must be compiled and linked with the new library. == GNU ZRTP 1.5.0 == Adds a first version of a ZrtpConfigure class that provides applications to select which crypto and hash methods to use. Because of API changes clients must be compiled and linked with the new library. == GNU ZRTP 1.4.5 == Modify the Hello repeat timer handling to accomodate slow connections and/or slow devices. Fix a problem when the other party sends only ZRTP packets at the beginning of a RTP session. === Interface changes in 1.4.5 === No external interfaces were changed, external API and ABI remain stable. Internal interface modifications only to implement Ping/PingAck handling. == GNU ZRTP 1.4.4 == Implement the Ping/PingAck packets and associated protocol extensions as defined in [http://tools.ietf.org/html/draft-zimmermann-avt-zrtp-15]. === Interface changes in 1.4.4 === No external interfaces were changed, external API and ABI remain stable. Internal interface modifications only to implement Ping/PingAck handling. == GNU ZRTP 1.4.2 == Introduce the Key Derivation Function (KDF) as defined in [http://tools.ietf.org/html/draft-zimmermann-avt-zrtp-12]. The ZRTP protocol version was updated to 1.10. === Interface changes in 1.4.2 === No interfaces were changed, API and ABI remain stable. == GNU ZRTP 1.4.0 == This is the first release that is conformant to the ZRTP specification that eventually will become a RFC. See: [http://tools.ietf.org/html/draft-zimmermann-avt-zrtp-10] The ZRTP protocol version was updated to 1.00. === Interface changes in 1.4.0 === The ZrtpQueue and ZRtp classes implement a new method to get the other party's ZID (ZRTP identifier). An application, for example a SIP or XMPP client, may use this method to get the other party's ZID and store it together in a contact list. This enable the application to check the ZID if the user calls the other party again. A client shall implement such a feature to enhance security if user's don't compare the SAS on every call after they confirmed a SAS once. Clients must be compiled and linked with the new library. == GNU ZRTP 1.3.1 == This is an update to version 1.3.0 and implements the ZRTP multi-stream mode handshake. The ZRTP protocl version was updated to 0.90 and interoperability tests using the latest Zfone build and Zfone Beta (dated September 6, 2008) were successful. No changes in the external API and ABI with respect to 1.3.0 - thus no recompile or rebuild of clients are necessary if they use 1.3.0. To checkout version 1.3.1 specify revision 494 (-r 494). == GNU ZRTP 1.3.0 == This version is and update to version 1.1.0 an implements the latest changes define in the ZRTP draft. The changes resulted in an update of the API, therefore existing applications must be recompiled. This version of GNU ZRTP is compatible to and was tested to work with the latest Zfone beta (dated June, 10, see Zfone project site). Only in one specific error case is a slight incompatibility that will be fixed with the next Zfone beta. This incompatibility results in a severe error information at the client. The error only happens if someone modified the first retained shared secret entry in the retained secret cache, for example disk/storage read error. This is a very unlikely situation. === Interface changes in Version 1.3.0 === The Method ''setSipsSecret(...)'' is no longer available. ZRTP does not support this additional secret anymore. The method ''setOtherSecret(...)'' was renamed to ''setPbxSecret(...)'' to reflect the modification in the draft. The methos ''setSrtpsSecret(...)'' is was renamed to ''setAuxSecret(...)'' to reflect the modification in the draft. == GNU ZRTP 1.1.0 == GNU ZRTP 1.1.0 implements the basic ZRTP as specificied in the document ''draft-zimmermann-avt-zrtp-06x''. You may access this at this URL: [http://zfoneproject.com/zrtp_ietf.html] This version of GNU ZRTP does not support the additiona featur of ZRTP such as Multi-stream mode, Pre-shared mode, PBX enrollement, and SAS Signature. However, to keep the external interface as stable as possible I already implmented stubs for the additional features. Some later versions may have these features implemented, depending if they are required by the community. The current version of GNU ZRTP is compatible and was tested to work with the latest Zfone beta (dated April, 2nd) (see Zfone project site). === Interface changes == The ''SymmetricZRTPSession'' implements some new methods to control ZRTP and its new features. An application usually uses only a few methods to setup GNU ZRTP. All others are optional and an application may use them only if it requires a special feature (which are not yet implemented :-) ). The ''ZrtpUserCallback'' class was modified as well. From an application's point of view * The methods in ''ZrtpUserCallback'' are not pure virtual anymore but just virtual and have a default implementation, usually a simple return. An application may extend this class and overwrite only those methods it requires. * Change of the constructor - remove the queue parameter thus we have a very simple standard constructor. This modifcation may requires a small change in the application or class that uses or extends ''ZrtpUserCallback''. * The method showSAS has an additional parameter: showSAS(std::string sas, bool verified); the verified flag is set to true in SAS is verified, false if not verified. This allows a more flexible support to display the SAS even if SAS is verified. Formerly ZRTP did not call "showSAS()" if SAS was verified. Now ZRTP always calls showSAS and provides the verification information explicitly. * The siganture of the following user callback methods was changed: showMessage(GnuZrtpCodes::MessageSeverity sev, int32_t subCode) zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity severity, int32_t subCode) The GNU ZRTP core and the ZRTP ccRTP extension do not contain message strings anymore. Both use codes to inform an application about events, problems or failure. The folder ''demo'' contains a small demo program that shows one way how to map the codes to strings. Delegating string handling and formating to the application simplifies internationalization etc. Plaese note: some new callback methods and ''SymmetricZRTPSession'' methods are only stubs in the currect version. The real implementation (filling the stubs with real code) will be done some time later (see above about unsupported features). === Header files === The new version greatly reduces the number of header files installed in the include directory. In the new version I decoupled the internal header files and implementation from the external classes and interfaces an application requires. Only six header files are installed in GNU ZRTP's include directory (libzrtpcpp subdirectory in the usual include paths) == Demo program == The new folder ''demo'' contains a small demo program that shows various ways how to use GNU ZRTP to setup secure RTP (SRTP) sessions even without signaling protocols libzrtpcpp-2.0.0/libzrtpcpp.pc.cmake0000644000175000017500000000045711570305710016513 0ustar dyfetdyfetprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ pkglibdir=${libdir}/@PACKAGE@ includedir=@includedir@ pkgincludedir=${includedir}/@PACKAGE@ Name: libzrtpcpp Description: GNU ZRTP core library Version: @VERSION@ Requires: @CRYPTOBACKEND@ Libs: -L${libdir} -lzrtpcpp Cflags: -I${includedir} libzrtpcpp-2.0.0/CMakeLists.txt0000755000175000017500000001137211570324727015471 0ustar dyfetdyfet# Copyright (C) 2009 Werner Dittman # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # cmake_minimum_required(VERSION 2.6) PROJECT(libzrtpcpp) SET(CPACK_PACKAGE_VERSION_MAJOR 2) SET(CPACK_PACKAGE_VERSION_MINOR 0) SET(CPACK_PACKAGE_VERSION_PATCH 0) set (VERSION 2.0.0) set (SOVERSION 2) set (PACKAGE libzrtpcpp) if(MSVC60) set(BUILD_STATIC ON CACHE BOOL "static linking only" FORCE) MARK_AS_ADVANCED(BUILD_STATIC) else() option(BUILD_STATIC "Set to OFF to build shared libraries" OFF) endif() # set to true for debug and trace during CMakeLists development set(CMAKE_VERBOSE_MAKEFILE FALSE) MESSAGE( STATUS "Configuring GNU ${PROJECT_NAME} ${VERSION}...") # include most of the fine stuff we need include(cmake/Modules/FindGcryptConfig.cmake) include(FindPkgConfig) include(CheckLibraryExists) include(CheckIncludeFiles) include(cmake/Modules/AutoArgs.cmake) if(${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME}) include(cmake/Modules/GeneratePackage.cmake) GENERATE_PACKAGING(${PACKAGE} ${VERSION}) endif() # check the -Denable-ccrtp setting, defaults to true enable_arg(ccrtp true "Enable GNU ccRTP support for GNU ZRTP") args_help() # this caused problems in debian where it has to always be lib.... set(LIBDIRNAME "lib") if (NOT EXISTS /etc/debian_version) if ( "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" ) set(LIBDIRNAME "lib64") endif() endif() # setup the Thread include and lib find_package(Threads) if(CMAKE_HAVE_PTHREAD_H) set(HAVE_PTHREAD_H TRUE) endif() set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) if(enable_ccrtp) if (USES_CCRTP_INCLUDE_DIRS) message(STATUS " Using local commoncpp dependency") else() find_package(PkgConfig) pkg_check_modules(USES_CCRTP libccrtp>=2.0.0) endif() include_directories(${USES_CCRTP_INCLUDE_DIRS}) link_directories(${USES_CRTP_LIBRARY_DIRS}) add_definitions(${USES_CCRTP_CFLAGS}) set (LIBS ${LIBS} ${USES_CCRTP_LDFLAGS} ${USES_CCRTP_LIBRARIES}) endif() # now get info about crypto libraries gcr_check(GCRYPT gcrypt) #if(GCRYPT_FOUND) # check_include_files(gcrypt.h HAVE_GCRYPT_H) # set(LIBS ${LIBS} ${GCRYPT_LIBRARIES}) # set(BUILD_REQ "libgcrypt-devel") # set(CRYPTOBACKEND="") # set(PACKAGE_REQ "libgcrypt") #else() pkg_check_modules(OPENSSL libcrypto>=0.9.8) if (OPENSSL_FOUND) check_include_files(openssl/bn.h HAVE_OPENSSL_BN_H) check_include_files(openssl/aes.h HAVE_OPENSSL_AES_H) check_include_files(openssl/sha.h HAVE_OPENSSL_SHA_H) check_library_exists(crypto EVP_CipherInit_ex "" HAVE_SSL_CRYPT) set(LIBS ${LIBS} -lcrypto) set(CRYPTOBACKEND "libcrypto >= 0.9.8") set(BUILD_REQ "libopenssl-devel >= 0.9.8") set(PACKAGE_REQ "libopenssl >= 0.9.8") else() message(FATAL_ERROR "No crypto library found") endif() #endif() check_include_files(stdlib.h HAVE_STDLIB_H) check_include_files(string.h HAVE_STRING_H) # necessary and required modules checked, ready to generate config.h configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) # the following set(...) commands are only to have backward # compatibility with autoconf stuff to generate the pc file set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix ${prefix}/bin) set(libdir ${prefix}/lib) set(includedir ${prefix}/include) set(PACKAGE pkgconfig) configure_file(libzrtpcpp.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libzrtpcpp.pc @ONLY) configure_file(libzrtpcpp.spec.cmake ${CMAKE_CURRENT_BINARY_DIR}/libzrtpcpp.spec @ONLY) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src) add_definitions(-g -O2 -fno-strict-aliasing) if(CMAKE_COMPILER_IS_GNUCXX) add_definitions(-Wno-long-long -Wno-char-subscripts) add_definitions(-Wall -ansi -pedantic) endif() add_subdirectory(src) add_subdirectory(demo) if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/package/) MESSAGE(STATUS "package dir not found") file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/package/) endif() ########### install files ############### install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libzrtpcpp.pc DESTINATION ${LIBDIRNAME}/pkgconfig) if(${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME}) ########### Add uninstall target ############### configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") endif() libzrtpcpp-2.0.0/libzrtpcpp.spec0000644000175000017500000000727611570331500015766 0ustar dyfetdyfet# # spec file for package libzrtpcpp (Version 2.0.0) # # Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via http://bugs.opensuse.org/ # Name: libzrtpcpp Summary: A ccrtp extension for ZRTP support BuildRequires: gcc-c++ libopenssl-devel >= 0.9.8 pkgconfig cmake BuildRequires: libccrtp-devel >= 2.0.0 Version: 2.0.0 Release: 0 License: GPL v3 or later Group: Development/Libraries/Other Url: http://www.gnu.org/software/commoncpp/commoncpp.html Source0: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build %description This library is a GPL licensed extension to the GNU RTP Stack, ccrtp, that offers compatibility with Phil Zimmermann's zrtp/Zfone voice encryption, and which can be directly embedded into telephony applications. %package devel License: GPL v3 or later Group: Development/Libraries/Other Summary: Headers and link library for libzrtpcpp Requires: libzrtpcpp = %{version} libccrtp-devel >= 2.0.0 %description devel This package provides the header files, link libraries, and documentation for building applications that use libzrtpcpp. %prep %setup -q %build %{__mkdir} build cd build cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \ -DSYSCONFDIR=%{_sysconfdir} \ -DMANDIR=%{_mandir} \ -DCMAKE_VERBOSE_MAKEFILE=TRUE \ -DCMAKE_C_FLAGS_RELEASE:STRING="$RPM_OPT_FLAGS" \ -DCMAKE_CXX_FLAGS_RELEASE:STRING="$RPM_OPT_FLAGS" \ .. %{__make} %{?_smp_mflags} %install cd build %{__rm} -rf %{buildroot} make install DESTDIR=%{buildroot} %clean %{__rm} -rf %{buildroot} %files -n libzrtpcpp %defattr(-,root,root,0755) %doc AUTHORS COPYING README %{_libdir}/*.so.* %files devel %defattr(-,root,root,0755) %{_libdir}/*.so %{_libdir}/pkgconfig/*.pc %{_includedir}/libzrtpcpp/*.h %dir %{_includedir}/libzrtpcpp %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %changelog * Mon Dec 27 2010 - Werner Dittmann - Add Skein MAC authentication algorithm - lots of documentation added (doxygen ready) - some code cleanup * Sun Oct 11 2009 - Werner Dittmann - Fix multistream problem - add DH2048 mode - update cipher selection to match latest draft (15x) - Test with zfone3 with Ping packet mode enabled - some code cleanup * Wed Jun 24 2009 - David Sugar - Spec updated per current Fedora & CentOS policies. - Updated release 1.4.5 has all mandatory IETF interop requirements. * Fri Jan 26 2009 - Werner Dittmann - Update to version 1.4.2 to support the latest ZRTP specification draft-zimmermann-avt-zrtp-12 * Fri Aug 22 2008 - David Sugar - Adapted for newer library naming conventions. * Tue Dec 11 2007 - Werner Dittmann - this is the first spec file for version 1.x.x - remove the .la file in devel package - use default file atttribute instead of 755 * Sat Apr 18 2007 - Werner Dittmann - set version to 1.1.0 - GNU ZRTP is compatible with the latest Zfone Beta from April 2 2007 libzrtpcpp-2.0.0/ChangeLog0000644000175000017500000000050011570305710014456 0ustar dyfetdyfet1.5.2: - a C wrapper was added to enable C programs to use GNU ZRTP - some fixes in the code (race condition solved) - better support of multi-stream mode - change the old cxx file extension to cpp, some build system don't like the old cxx (Android NDK for example) - and much more -- Add CMake configuration files.