From 669109e369a1be69ff7c4108eb545eff4c5c26d9 Mon Sep 17 00:00:00 2001 From: Mark Purcell Date: Tue, 9 Jul 2013 15:55:55 +0100 Subject: libzrtpcpp (2.3.4-1) unstable; urgency=medium * New upstream release - Fixes "CVE-2013-2221 CVE-2013-2222 CVE-2013-2223" (Closes: #714650) # imported from the archive --- src/libzrtpcpp/Base32.h | 228 +++ src/libzrtpcpp/CMakeLists.txt | 9 + src/libzrtpcpp/TimeoutProvider.h | 303 ++++ src/libzrtpcpp/ZIDFile.h | 157 ++ src/libzrtpcpp/ZIDRecord.h | 307 ++++ src/libzrtpcpp/ZRtp.h | 1292 +++++++++++++++ src/libzrtpcpp/ZrtpCWrapper.h | 1339 +++++++++++++++ src/libzrtpcpp/ZrtpCallback.h | 367 +++++ src/libzrtpcpp/ZrtpCallbackWrapper.h | 101 ++ src/libzrtpcpp/ZrtpCodes.h | 164 ++ src/libzrtpcpp/ZrtpConfigure.h | 551 +++++++ src/libzrtpcpp/ZrtpCrc32.h | 75 + src/libzrtpcpp/ZrtpPacketBase.h | 147 ++ src/libzrtpcpp/ZrtpPacketClearAck.h | 54 + src/libzrtpcpp/ZrtpPacketCommit.h | 134 ++ src/libzrtpcpp/ZrtpPacketConf2Ack.h | 60 + src/libzrtpcpp/ZrtpPacketConfirm.h | 125 ++ src/libzrtpcpp/ZrtpPacketDHPart.h | 120 ++ src/libzrtpcpp/ZrtpPacketError.h | 68 + src/libzrtpcpp/ZrtpPacketErrorAck.h | 56 + src/libzrtpcpp/ZrtpPacketGoClear.h | 72 + src/libzrtpcpp/ZrtpPacketHello.h | 191 +++ src/libzrtpcpp/ZrtpPacketHelloAck.h | 59 + src/libzrtpcpp/ZrtpPacketPing.h | 67 + src/libzrtpcpp/ZrtpPacketPingAck.h | 74 + src/libzrtpcpp/ZrtpPacketRelayAck.h | 56 + src/libzrtpcpp/ZrtpPacketSASrelay.h | 113 ++ src/libzrtpcpp/ZrtpQueue.h | 917 +++++++++++ src/libzrtpcpp/ZrtpStateClass.h | 324 ++++ src/libzrtpcpp/ZrtpStates.h | 90 + src/libzrtpcpp/ZrtpTextData.h | 124 ++ src/libzrtpcpp/ZrtpUserCallback.h | 234 +++ src/libzrtpcpp/crypto/TwoCFB.cpp | 79 + src/libzrtpcpp/crypto/ZrtpDH.h | 168 ++ src/libzrtpcpp/crypto/aesCFB.h | 87 + src/libzrtpcpp/crypto/gcrypt/InitializeGcrypt.cpp | 130 ++ src/libzrtpcpp/crypto/gcrypt/gcryptAesCFB.cpp | 77 + src/libzrtpcpp/crypto/gcrypt/gcryptZrtpDH.cpp | 349 ++++ src/libzrtpcpp/crypto/gcrypt/gcrypthmac256.cpp | 68 + src/libzrtpcpp/crypto/gcrypt/gcrypthmac384.cpp | 68 + src/libzrtpcpp/crypto/gcrypt/gcryptsha256.cpp | 89 + src/libzrtpcpp/crypto/gcrypt/gcryptsha384.cpp | 89 + src/libzrtpcpp/crypto/hmac256.h | 96 ++ src/libzrtpcpp/crypto/hmac384.h | 96 ++ src/libzrtpcpp/crypto/openssl/AesCFB.cpp | 89 + .../crypto/openssl/InitializeOpenSSL.cpp | 242 +++ src/libzrtpcpp/crypto/openssl/ZrtpDH.cpp | 426 +++++ src/libzrtpcpp/crypto/openssl/hmac256.cpp | 67 + src/libzrtpcpp/crypto/openssl/hmac384.cpp | 67 + src/libzrtpcpp/crypto/openssl/sha256.cpp | 97 ++ src/libzrtpcpp/crypto/openssl/sha384.cpp | 97 ++ src/libzrtpcpp/crypto/sha256.h | 144 ++ src/libzrtpcpp/crypto/sha384.h | 144 ++ src/libzrtpcpp/crypto/twoCFB.h | 87 + src/libzrtpcpp/crypto/twofish.c | 1733 ++++++++++++++++++++ src/libzrtpcpp/crypto/twofish.h | 265 +++ src/libzrtpcpp/crypto/twofish_cfb.c | 82 + src/libzrtpcpp/zrtpPacket.h | 342 ++++ src/libzrtpcpp/zrtpccrtp.h | 76 + 59 files changed, 13332 insertions(+) create mode 100644 src/libzrtpcpp/Base32.h create mode 100755 src/libzrtpcpp/CMakeLists.txt create mode 100644 src/libzrtpcpp/TimeoutProvider.h create mode 100644 src/libzrtpcpp/ZIDFile.h create mode 100644 src/libzrtpcpp/ZIDRecord.h create mode 100644 src/libzrtpcpp/ZRtp.h create mode 100644 src/libzrtpcpp/ZrtpCWrapper.h create mode 100644 src/libzrtpcpp/ZrtpCallback.h create mode 100644 src/libzrtpcpp/ZrtpCallbackWrapper.h create mode 100755 src/libzrtpcpp/ZrtpCodes.h create mode 100644 src/libzrtpcpp/ZrtpConfigure.h create mode 100755 src/libzrtpcpp/ZrtpCrc32.h create mode 100644 src/libzrtpcpp/ZrtpPacketBase.h create mode 100644 src/libzrtpcpp/ZrtpPacketClearAck.h create mode 100644 src/libzrtpcpp/ZrtpPacketCommit.h create mode 100644 src/libzrtpcpp/ZrtpPacketConf2Ack.h create mode 100644 src/libzrtpcpp/ZrtpPacketConfirm.h create mode 100644 src/libzrtpcpp/ZrtpPacketDHPart.h create mode 100644 src/libzrtpcpp/ZrtpPacketError.h create mode 100644 src/libzrtpcpp/ZrtpPacketErrorAck.h create mode 100644 src/libzrtpcpp/ZrtpPacketGoClear.h create mode 100644 src/libzrtpcpp/ZrtpPacketHello.h create mode 100644 src/libzrtpcpp/ZrtpPacketHelloAck.h create mode 100644 src/libzrtpcpp/ZrtpPacketPing.h create mode 100644 src/libzrtpcpp/ZrtpPacketPingAck.h create mode 100644 src/libzrtpcpp/ZrtpPacketRelayAck.h create mode 100644 src/libzrtpcpp/ZrtpPacketSASrelay.h create mode 100644 src/libzrtpcpp/ZrtpQueue.h create mode 100644 src/libzrtpcpp/ZrtpStateClass.h create mode 100644 src/libzrtpcpp/ZrtpStates.h create mode 100644 src/libzrtpcpp/ZrtpTextData.h create mode 100644 src/libzrtpcpp/ZrtpUserCallback.h create mode 100755 src/libzrtpcpp/crypto/TwoCFB.cpp create mode 100644 src/libzrtpcpp/crypto/ZrtpDH.h create mode 100644 src/libzrtpcpp/crypto/aesCFB.h create mode 100644 src/libzrtpcpp/crypto/gcrypt/InitializeGcrypt.cpp create mode 100644 src/libzrtpcpp/crypto/gcrypt/gcryptAesCFB.cpp create mode 100644 src/libzrtpcpp/crypto/gcrypt/gcryptZrtpDH.cpp create mode 100644 src/libzrtpcpp/crypto/gcrypt/gcrypthmac256.cpp create mode 100644 src/libzrtpcpp/crypto/gcrypt/gcrypthmac384.cpp create mode 100644 src/libzrtpcpp/crypto/gcrypt/gcryptsha256.cpp create mode 100644 src/libzrtpcpp/crypto/gcrypt/gcryptsha384.cpp create mode 100644 src/libzrtpcpp/crypto/hmac256.h create mode 100644 src/libzrtpcpp/crypto/hmac384.h create mode 100644 src/libzrtpcpp/crypto/openssl/AesCFB.cpp create mode 100755 src/libzrtpcpp/crypto/openssl/InitializeOpenSSL.cpp create mode 100644 src/libzrtpcpp/crypto/openssl/ZrtpDH.cpp create mode 100644 src/libzrtpcpp/crypto/openssl/hmac256.cpp create mode 100644 src/libzrtpcpp/crypto/openssl/hmac384.cpp create mode 100644 src/libzrtpcpp/crypto/openssl/sha256.cpp create mode 100644 src/libzrtpcpp/crypto/openssl/sha384.cpp create mode 100644 src/libzrtpcpp/crypto/sha256.h create mode 100644 src/libzrtpcpp/crypto/sha384.h create mode 100755 src/libzrtpcpp/crypto/twoCFB.h create mode 100644 src/libzrtpcpp/crypto/twofish.c create mode 100755 src/libzrtpcpp/crypto/twofish.h create mode 100755 src/libzrtpcpp/crypto/twofish_cfb.c create mode 100644 src/libzrtpcpp/zrtpPacket.h create mode 100644 src/libzrtpcpp/zrtpccrtp.h (limited to 'src/libzrtpcpp') diff --git a/src/libzrtpcpp/Base32.h b/src/libzrtpcpp/Base32.h new file mode 100644 index 0000000..fbe2983 --- /dev/null +++ b/src/libzrtpcpp/Base32.h @@ -0,0 +1,228 @@ +#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 diff --git a/src/libzrtpcpp/CMakeLists.txt b/src/libzrtpcpp/CMakeLists.txt new file mode 100755 index 0000000..099a233 --- /dev/null +++ b/src/libzrtpcpp/CMakeLists.txt @@ -0,0 +1,9 @@ + +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) + diff --git a/src/libzrtpcpp/TimeoutProvider.h b/src/libzrtpcpp/TimeoutProvider.h new file mode 100644 index 0000000..9f0edf7 --- /dev/null +++ b/src/libzrtpcpp/TimeoutProvider.h @@ -0,0 +1,303 @@ +/* + 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: + */ diff --git a/src/libzrtpcpp/ZIDFile.h b/src/libzrtpcpp/ZIDFile.h new file mode 100644 index 0000000..0637c27 --- /dev/null +++ b/src/libzrtpcpp/ZIDFile.h @@ -0,0 +1,157 @@ +/* + 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: + */ diff --git a/src/libzrtpcpp/ZIDRecord.h b/src/libzrtpcpp/ZIDRecord.h new file mode 100644 index 0000000..eb2d190 --- /dev/null +++ b/src/libzrtpcpp/ZIDRecord.h @@ -0,0 +1,307 @@ +/* + 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 + +#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; + + +#ifndef __EXPORT + #if __GNUC__ >= 4 + #define __EXPORT __attribute__ ((visibility("default"))) + #define __LOCAL __attribute__ ((visibility("hidden"))) + #elif defined _WIN32 || defined __CYGWIN__ + #define __EXPORT __declspec(dllimport) + #define __LOCAL + #else + #define __EXPORT + #define __LOCAL + #endif +#endif + +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; + +/** + * 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 + */ +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: + */ diff --git a/src/libzrtpcpp/ZRtp.h b/src/libzrtpcpp/ZRtp.h new file mode 100644 index 0000000..4e03f28 --- /dev/null +++ b/src/libzrtpcpp/ZRtp.h @@ -0,0 +1,1292 @@ +/* + 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 +#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, bool mitmm= false, bool sasSignSupport= false); + + /** + * 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); + + /** + * 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 the peer's ZRTP Hello Hash data. + * + * Use this method to get the peer's ZRTP Hello Hash data. The method + * returns the data as a string containing the ZRTP protocol version and + * hex-digits. + * + * The peer's hello hash is available only after ZRTP received a hello. If + * no data is available the function returns an empty string. + * + * Refer to ZRTP specification, chapter 8. + * + * @return + * a std:string containing the Hello version and the hello hash as hex digits. + */ + std::string getPeerHelloHash(); + + /** + * 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); + + /** + * Check the state of the enrollment mode. + * + * If true then we will set the enrollment flag (E) in the confirm + * packets and perform the enrollment actions. A MitM (PBX) enrollment service + * started this ZRTP session. Can be set to true only if mitmMode is also true. + * + * @return status of the enrollmentMode flag. + */ + bool isEnrollmentMode(); + + /** + * Set the state of the enrollment mode. + * + * If true then we will set the enrollment flag (E) in the confirm + * packets and perform the enrollment actions. A MitM (PBX) enrollment + * service must sets this mode to true. + * + * Can be set to true only if mitmMode is also true. + * + * @param enrollmentMode defines the new state of the enrollmentMode flag + */ + void setEnrollmentMode(bool enrollmentMode); + + /** + * Check if a peer's cache entry has a vaild MitM key. + * + * If true then the other peer ha a valid MtiM key, i.e. the peer has performed + * the enrollment procedure. A PBX ZRTP Back-2-Back application can use this function + * to check which of the peers is enrolled. + * + * @return True if the other peer has a valid Mitm key (is enrolled). + */ + bool isPeerEnrolled(); + + /** + * Send the SAS relay packet. + * + * The method creates and sends a SAS relay packet according to the ZRTP + * specifications. Usually only a MitM capable user agent (PBX) uses this + * function. + * + * @param sh the full SAS hash value, 32 bytes + * @param render the SAS rendering algorithm + */ + bool sendSASRelayPacket(uint8_t* sh, std::string render); + + /** + * Get the commited SAS rendering algorithm for this ZRTP session. + * + * @return the commited SAS rendering algorithm + */ + std::string getSasType(); + + /** + * Get the computed SAS hash for this ZRTP session. + * + * A PBX ZRTP back-to-Back function uses this function to get the SAS + * hash of an enrolled client to construct the SAS relay packet for + * the other client. + * + * @return a pointer to the byte array that contains the full + * SAS hash. + */ + uint8_t* getSasHash(); + + /** + * 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 a pointer to the signature data that was receivied + * during ZRTP processing. Refer to chapters 5.7 and 7.2. + * + * The returned pointer points to volatile data that is valid only during the + * checkSASSignature() callback funtion. The application must copy + * the signature data if it will be used after the callback function returns. + * + * The signature data can be retrieved after ZRTP enters secure state. + * start(). + * + * @return + * Pointer to signature data. + */ + const uint8_t* getSignatureData(); + + /** + * Get length of signature data in number of bytes. + * + * 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 is 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 getPeerZid(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]; + + uint8_t peerHelloHash[IMPL_MAX_DIGEST_LENGTH]; + uint8_t peerHelloVersion[ZRTP_WORD_SIZE + 1]; // +1 for nul byte + + // 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; + + /** + * Enable MitM (PBX) enrollment + * + * 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. + */ + bool enableMitmEnrollment; + + /** + * True if a valid trusted MitM key of the other peer is available, i.e. enrolled. + */ + bool peerIsEnrolled; + + /** + * Set to true if the Hello packet contained the M-flag (MitM flag). + * We use this later to check some stuff for SAS Relay processing + */ + bool mitmSeen; + + /** + * Temporarily store computed pbxSecret, if user accepts enrollment then + * it will copied to our ZID record of the PBX (MitM) + */ + uint8_t* pbxSecretTmp; + uint8_t pbxSecretTmpBuffer[MAX_DIGEST_LENGTH]; + + /** + * If true then we will set the enrollment flag (E) in the confirm + * packets. Set to true if the PBX enrollment service started this ZRTP + * session. Can be set to true only if mitmMode is also true. + */ + bool enrollmentMode; + + /** + * 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; + ZrtpPacketSASrelay zrtpSasRelay; + ZrtpPacketRelayAck zrtpRelayAck; + + /** + * 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 + */ + const uint8_t* signatureData; // will be set when needed + int32_t signatureLength; // overall length in bytes + + /** + * Is true if the other peer signaled SAS signature support in its Hello packet. + */ + bool signSasSeen; + + uint32_t peerSSRC; // peer's SSRC, required to setup PingAck packet + + /** + * Enable or disable paranoid mode. + * + * The Paranoid mode controls the behaviour and handling of the SAS verify flag. If + * Panaoid mode is set to flase then ZRtp applies the normal handling. If Paranoid + * mode is set to true then the handling is: + * + *
    + *
  • Force the SAS verify flag to be false at srtpSecretsOn() callback. This gives + * the user interface (UI) the indication to handle the SAS as not verified. + * See implementation note below.
  • + *
  • Don't set the SAS verify flag in the Confirm packets, thus the other + * also must report the SAS as not verified.
  • + *
  • ignore the SASVerified() function, thus do not set the SAS to verified + * in the ZRTP cache.
  • + *
  • Disable the Trusted PBX MitM feature. Just send the SASRelay packet + * but do not process the relayed data. This protects the user from a malicious + * "trusted PBX".
  • + *
+ * ZRtp performs alls other steps during the ZRTP negotiations as usual, in particular it + * computes, compares, uses, and stores the retained secrets. This avoids unnecessary warning + * messages. The user may enable or disable the Paranoid mode on a call-by-call basis without + * breaking the key continuity data. + * + * Implementation note:
+ * An application shall always display the SAS code if the SAS verify flag is false. + * The application shall also use mechanisms to remind the user to compare the SAS code, for + * example useing larger fonts, different colours and other display features. + */ + bool paranoidMode; + + /** + * 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); + + /** + * Save the computed MitM secret to the ZID record of the peer + */ + void writeEnrollmentPBX(); + + /** + * 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 computePBXSecret(); + + 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 the RelayAck packet. + * + * This method prepares the RelayAck packet. The input to this method is the + * SASrelay packet received from the peer. + */ + ZrtpPacketRelayAck* prepareRelayAck(ZrtpPacketSASrelay* srly, uint32_t* errMsg); + + /** + * 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 + diff --git a/src/libzrtpcpp/ZrtpCWrapper.h b/src/libzrtpcpp/ZrtpCWrapper.h new file mode 100644 index 0000000..0126545 --- /dev/null +++ b/src/libzrtpcpp/ZrtpCWrapper.h @@ -0,0 +1,1339 @@ +/* + 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 */ +}; + +/** + * Information codes for the Enrollment user callbacks. + */ +enum zrtp_InfoEnrollment { + zrtp_EnrollmentRequest, //!< Aks user to confirm or deny an Enrollemnt request + zrtp_EnrollmentCanceled, //!< User did not confirm the PBX enrollement + zrtp_EnrollmentFailed, //!< Enrollment process failed, no PBX secret available + zrtp_EnrollmentOk //!< Enrollment process for this PBX was ok +}; + +/* 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 +#pragma GCC visibility push(default) +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. + * The ZRTP packet will have to be created using the provided ZRTP message. + * + * @param ctx + * Pointer to the opaque ZrtpContext structure. + * @param data + * Points to ZRTP message to send. + * @param length + * The length in bytes of the data + * @return + * zero if sending failed, one if packet was sent + */ + 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 themselves are obtained 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 mutex 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 + * specific 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, int32_t 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, int32_t 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 and + * 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 + * Pointer to the 32 byte SAS hash to sign. + * + */ + void (*zrtp_signSAS)(ZrtpContext* ctx, uint8_t* 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 + * Pointer to the 32 byte SAS hash that was signed by the other peer. + * @return + * true if the signature was ok, false otherwise. + * + */ + int32_t (*zrtp_checkSASSignature) (ZrtpContext* ctx, uint8_t* 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 + * calls 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. + * @param mitmMode + * A trusted Mitm (PBX) must set this to true. The ZRTP engine sets + * the M Flag in the Hello packet to announce a trusted MitM. + * @returns + * Pointer to the ZrtpContext + * + * @see zrtp_InitializeConfig + */ + void zrtp_initializeZrtpEngine(ZrtpContext* zrtpContext, + zrtp_Callbacks *cb, + const char* id, + const char* zidFilename, + void* userData, + int32_t mitmMode); + + /** + * 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: An 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: An 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); + + /** + * Check current state of the ZRTP state engine + * + * NOTE: application usually don't call this method. Only + * the m-odule 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 if 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 the peer's ZRTP Hello Hash data. + * + * Use this method to get the peer's ZRTP Hello Hash data. The method + * returns the data as a string containing the ZRTP protocol version and + * hex-digits. + * + * The peer's hello hash is available only after ZRTP received a hello. If + * no data is available the function returns an empty string. + * + * Refer to ZRTP specification, chapter 8. + * + * @return + * a std:string containing the Hello version and the hello hash as hex digits. + */ + char* zrtp_getPeerHelloHash(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 instance 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); + + /** + * Check the state of the enrollment mode. + * + * If true then we will set the enrollment flag (E) in the confirm + * packets and performs the enrollment actions. A MitM (PBX) enrollment service + * started this ZRTP session. Can be set to true only if mitmMode is also true. + * + * @param zrtpContext + * Pointer to the opaque ZrtpContext structure. + * @return status of the enrollmentMode flag. + */ + int32_t zrtp_isEnrollmentMode(ZrtpContext* zrtpContext); + + /** + * Check the state of the enrollment mode. + * + * If true then we will set the enrollment flag (E) in the confirm + * packets and perform the enrollment actions. A MitM (PBX) enrollment + * service must sets this mode to true. + * + * Can be set to true only if mitmMode is also true. + * + * @param zrtpContext + * Pointer to the opaque ZrtpContext structure. + * @param enrollmentMode defines the new state of the enrollmentMode flag + */ + void zrtp_setEnrollmentMode(ZrtpContext* zrtpContext, int32_t enrollmentMode); + + /** + * Check if a peer's cache entry has a vaild MitM key. + * + * If true then the other peer ha a valid MtiM key, i.e. the peer has performed + * the enrollment procedure. A PBX ZRTP Back-2-Back application can use this function + * to check which of the peers is enrolled. + * + * @return True if the other peer has a valid Mitm key (is enrolled). + */ + int32_t isPeerEnrolled(ZrtpContext* zrtpContext); + + /** + * Send the SAS relay packet. + * + * The method creates and sends a SAS relay packet according to the ZRTP + * specifications. Usually only a MitM capable user agent (PBX) uses this + * function. + * + * @param zrtpContext + * Pointer to the opaque ZrtpContext structure. + * @param sh the full SAS hash value + * @param render the SAS rendering algorithm + */ + int32_t zrtp_sendSASRelayPacket(ZrtpContext* zrtpContext, uint8_t* sh, char* render); + + /** + * Get the commited SAS rendering algorithm for this ZRTP session. + * + * @param zrtpContext + * Pointer to the opaque ZrtpContext structure. + * @return the commited SAS rendering algorithm + */ + const char* zrtp_getSasType(ZrtpContext* zrtpContext); + + /** + * Get the computed SAS hash for this ZRTP session. + * + * A PBX ZRTP back-to-Back function uses this function to get the SAS + * hash of an enrolled client to construct the SAS relay packet for + * the other client. + * + * @param zrtpContext + * Pointer to the opaque ZrtpContext structure. + * @return a pointer to the byte array that contains the full + * SAS hash. + */ + uint8_t* zrtp_getSasHash(ZrtpContext* zrtpContext); + + /** + * 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. + * @return + * Number of bytes copied into the data buffer + */ + const uint8_t* zrtp_getSignatureData(ZrtpContext* zrtpContext); + + /** + * 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_getPeerZid(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 +} +#pragma GCC visibility pop +#endif + +/** + * @} + */ +#endif diff --git a/src/libzrtpcpp/ZrtpCallback.h b/src/libzrtpcpp/ZrtpCallback.h new file mode 100644 index 0000000..957c4dd --- /dev/null +++ b/src/libzrtpcpp/ZrtpCallback.h @@ -0,0 +1,367 @@ +/* + 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 + +#ifndef __EXPORT + #if __GNUC__ >= 4 + #define __EXPORT __attribute__ ((visibility("default"))) + #define __LOCAL __attribute__ ((visibility("hidden"))) + #elif defined _WIN32 || defined __CYGWIN__ + #define __EXPORT __declspec(dllimport) + #define __LOCAL + #else + #define __EXPORT + #define __LOCAL + #endif +#endif + +/** + * 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(GnuZrtpCodes::InfoEnrollment 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 information to the user about the result + * of an enrollment. + */ + virtual void zrtpInformEnrollment(GnuZrtpCodes::InfoEnrollment 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 sasHash + * The SAS hash to sign. + * + */ + virtual void signSAS(uint8_t* sasHash) =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 sasHash + * The SAS hash that was signed by the other peer. + * @return + * true if the signature was ok, false otherwise. + * + */ + virtual bool checkSASSignature(uint8_t* sasHash) =0; +}; + +#endif // ZRTPCALLBACK + +/** + * @} + */ +/** EMACS ** + * Local variables: + * mode: c++ + * c-default-style: ellemtel + * c-basic-offset: 4 + * End: + */ diff --git a/src/libzrtpcpp/ZrtpCallbackWrapper.h b/src/libzrtpcpp/ZrtpCallbackWrapper.h new file mode 100644 index 0000000..dd739e0 --- /dev/null +++ b/src/libzrtpcpp/ZrtpCallbackWrapper.h @@ -0,0 +1,101 @@ +/* + 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 + * @see ZrtpCWrapper + */ +class __EXPORT ZrtpCallbackWrapper : public ZrtpCallback +{ +public: + /** + * Construct a class that implements ZrtpCallback and uses a C structure + * to 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. + * @param ctx + * Pointer to the ZrtpContext + */ + 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 (GnuZrtpCodes::InfoEnrollment info ); + + void zrtpInformEnrollment (GnuZrtpCodes::InfoEnrollment info ); + + void signSAS (uint8_t* sasHash ); + + bool checkSASSignature (uint8_t* sasHash ); + +private: + void init(); + zrtp_Callbacks *c_callbacks; + ZrtpContext* zrtpCtx; + +}; + +/** + * @} + */ + +#endif // ZRTPCALLBACKWRAPPER_H diff --git a/src/libzrtpcpp/ZrtpCodes.h b/src/libzrtpcpp/ZrtpCodes.h new file mode 100755 index 0000000..a1bb6fc --- /dev/null +++ b/src/libzrtpcpp/ZrtpCodes.h @@ -0,0 +1,164 @@ +/** @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 +}; + +/** + * Information codes for the Enrollment user callbacks. + */ +enum InfoEnrollment { + EnrollmentRequest, //!< Aks user to confirm or deny an Enrollemnt request + EnrollmentCanceled, //!< User did not confirm the PBX enrollement + EnrollmentFailed, //!< Enrollment process failed, no PBX secret available + EnrollmentOk //!< Enrollment process for this PBX was ok +}; + +} + +/** + * @} + */ +#endif diff --git a/src/libzrtpcpp/ZrtpConfigure.h b/src/libzrtpcpp/ZrtpConfigure.h new file mode 100644 index 0000000..33a824f --- /dev/null +++ b/src/libzrtpcpp/ZrtpConfigure.h @@ -0,0 +1,551 @@ +/* + 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. + * @param klen + * The key length for this algorihm in byte, for example 16 or 32 + * @param ra + * A human readable short string that describes the algorihm. + * @param en + * Pointer to the encryption function of this algorithn + * @param de + * Pointer to the decryption funtions of this algorithm. + * @param alId + * The algorithm id used by SRTP to identify an algorithm type, for + * example Skein, Sha1, Aes, ... + * + * @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(); + + /** + * Enables or disables paranoid mode. + * + * For further explanation of paranoid mode refer to the documentation + * of ZRtp class. + * + * @param yesNo + * If set to true then paranoid mode is enabled. + */ + void setParanoidMode(bool yesNo); + + /** + * Check status of paranoid mode. + * + * @return + * Returns true if paranoid mode is enabled. + */ + bool isParanoidMode(); + + /// 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; + bool enableParanoidMode; + + + 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: + */ diff --git a/src/libzrtpcpp/ZrtpCrc32.h b/src/libzrtpcpp/ZrtpCrc32.h new file mode 100755 index 0000000..ad57edd --- /dev/null +++ b/src/libzrtpcpp/ZrtpCrc32.h @@ -0,0 +1,75 @@ +/* + 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 diff --git a/src/libzrtpcpp/ZrtpPacketBase.h b/src/libzrtpcpp/ZrtpPacketBase.h new file mode 100644 index 0000000..f0d2944 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketBase.h @@ -0,0 +1,147 @@ +/* + 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 + +#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) +#include +#else +#include +#endif + +#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 diff --git a/src/libzrtpcpp/ZrtpPacketClearAck.h b/src/libzrtpcpp/ZrtpPacketClearAck.h new file mode 100644 index 0000000..992f6d8 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketClearAck.h @@ -0,0 +1,54 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketCommit.h b/src/libzrtpcpp/ZrtpPacketCommit.h new file mode 100644 index 0000000..b23b23d --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketCommit.h @@ -0,0 +1,134 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketConf2Ack.h b/src/libzrtpcpp/ZrtpPacketConf2Ack.h new file mode 100644 index 0000000..a7c2567 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketConf2Ack.h @@ -0,0 +1,60 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketConfirm.h b/src/libzrtpcpp/ZrtpPacketConfirm.h new file mode 100644 index 0000000..b2dfbf4 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketConfirm.h @@ -0,0 +1,125 @@ +/* + 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 if SAS verify flag is set + const bool isSASFlag() { return confirmHeader->flags & 0x4; } + + /// Check if PBXEnrollment flag is set + const bool isPBXEnrollment() { return confirmHeader->flags & 0x8; } + + /// 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 pointer to signature data, variable length, refer to getSignatureLength() + const uint8_t* getSignatureData() { return ((uint8_t*)&confirmHeader->expTime) + 4; } + + /// get the signature length in words + int32_t getSignatureLength(); + + /// set SAS verified flag + void setSASFlag() { confirmHeader->flags |= 0x4; } + + /// set setPBXEnrollment flag + void setPBXEnrollment() { confirmHeader->flags |= 0x8; } + + /// 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 data, length of the signature data in bytes and must be a multiple of 4. + bool setSignatureData(uint8_t* data, int32_t length); + + /// Set signature length in words + bool 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 + diff --git a/src/libzrtpcpp/ZrtpPacketDHPart.h b/src/libzrtpcpp/ZrtpPacketDHPart.h new file mode 100644 index 0000000..d0ea4ba --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketDHPart.h @@ -0,0 +1,120 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketError.h b/src/libzrtpcpp/ZrtpPacketError.h new file mode 100644 index 0000000..d775801 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketError.h @@ -0,0 +1,68 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketErrorAck.h b/src/libzrtpcpp/ZrtpPacketErrorAck.h new file mode 100644 index 0000000..e64c8a6 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketErrorAck.h @@ -0,0 +1,56 @@ +/* + 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_ diff --git a/src/libzrtpcpp/ZrtpPacketGoClear.h b/src/libzrtpcpp/ZrtpPacketGoClear.h new file mode 100644 index 0000000..10c3be6 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketGoClear.h @@ -0,0 +1,72 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketHello.h b/src/libzrtpcpp/ZrtpPacketHello.h new file mode 100644 index 0000000..0cc7403 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketHello.h @@ -0,0 +1,191 @@ +/* + 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 + + 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 helloHeader->flags & 0x10; }; + + /// Check if MitM flag is set + bool isMitmMode() { return helloHeader->flags & 0x20; }; + + /// Check if SAS sign flag is set + bool isSasSign() { return helloHeader->flags & 0x40; }; + + /// 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; } + + /// set MitM flag + void setMitmMode() { helloHeader->flags |= 0x20; } + + /// set SAS sign flag + void setSasSign() { helloHeader->flags |= 0x40; } + + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketHelloAck.h b/src/libzrtpcpp/ZrtpPacketHelloAck.h new file mode 100644 index 0000000..345a071 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketHelloAck.h @@ -0,0 +1,59 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketPing.h b/src/libzrtpcpp/ZrtpPacketPing.h new file mode 100644 index 0000000..840df62 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketPing.h @@ -0,0 +1,67 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketPingAck.h b/src/libzrtpcpp/ZrtpPacketPingAck.h new file mode 100644 index 0000000..51ad8c8 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketPingAck.h @@ -0,0 +1,74 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpPacketRelayAck.h b/src/libzrtpcpp/ZrtpPacketRelayAck.h new file mode 100644 index 0000000..93437e6 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketRelayAck.h @@ -0,0 +1,56 @@ +/* + 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 _ZRTPPACKETRELAYACK_H_ +#define _ZRTPPACKETRELAYACK_H_ + +/** + * @file ZrtpPacketRelayAck.h + * @brief The ZRTP RelayAck message + * + * @ingroup GNU_ZRTP + * @{ + */ + +#include + +/** + * Implement the RelayAck packet. + * + * The ZRTP simple message RelayAck. The implementation sends this + * after receiving and checking the SASrelay message. + * + * @author Werner Dittmann + */ +class __EXPORT ZrtpPacketRelayAck : public ZrtpPacketBase { + + public: + /// Creates a RelayAck packet with default data + ZrtpPacketRelayAck(); + + /// Creates a RelayAck packet from received data + ZrtpPacketRelayAck(uint8_t* data); + virtual ~ZrtpPacketRelayAck(); + + private: + RelayAckPacket_t data; +}; + +/** + * @} + */ +#endif // _ZRTPPACKETRELAYACK_H_ diff --git a/src/libzrtpcpp/ZrtpPacketSASrelay.h b/src/libzrtpcpp/ZrtpPacketSASrelay.h new file mode 100644 index 0000000..427ac28 --- /dev/null +++ b/src/libzrtpcpp/ZrtpPacketSASrelay.h @@ -0,0 +1,113 @@ +/* + Copyright (C) 2006-2011 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 _ZRTPPACKETSASRELAY_H_ +#define _ZRTPPACKETSASRELAY_H_ + +/** + * @file ZrtpPacketSASrelay.h + * @brief The ZRTP SAS Relay 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 ZrtpPacketSASrelay : public ZrtpPacketBase { + + private: + SASrelay_t* sasRelayHeader; ///< Point to the Confirm message part + + public: + /// Creates a Confirm packet with default data + ZrtpPacketSASrelay(); + + /// Creates a Confirm packet with default data and a given signature length + ZrtpPacketSASrelay(uint32_t sl); + + /// Creates a Confirm packet from received data + ZrtpPacketSASrelay(uint8_t* d); + + /// Normal destructor + virtual ~ZrtpPacketSASrelay(); + + /// Check is SAS verify flag is set + const bool isSASFlag() { return sasRelayHeader->flags & 0x4; } + + /// Get pointer to filler bytes (contains one bit of signature length) + const uint8_t* getFiller() { return sasRelayHeader->filler; } + + /// Get pointer to IV data, fixed byte array + const uint8_t* getIv() { return sasRelayHeader->iv; } + + /// Get pointer to MAC data, fixed byte array + const uint8_t* getHmac() { return sasRelayHeader->hmac; } + + /// Get pointer to new SAS rendering algorithm, fixed byte array + const uint8_t* getSas() {return sasRelayHeader->sas; } + + /// Get pointer to new SAS hash data, fixed byte array + const uint8_t* getTrustedSas() { return sasRelayHeader->trustedSasHash; } + + /// get the signature length in words + uint32_t getSignatureLength(); + + /// set SAS verified flag + void setSASFlag() { sasRelayHeader->flags |= 0x4; } + + /// Set MAC data, fixed length byte array + void setHmac(uint8_t* text) { memcpy(sasRelayHeader->hmac, text, sizeof(sasRelayHeader->hmac)); } + + /// Set IV data, fixed length byte array + void setIv(uint8_t* text) { memcpy(sasRelayHeader->iv, text, sizeof(sasRelayHeader->iv)); } + + /// Set SAS rendering algorithm, fixed length byte array + void setSas(uint8_t* text) { memcpy(sasRelayHeader->sas, text, sizeof(sasRelayHeader->sas)); } + + /// Set SAS hash data, fixed length byte array + void setTrustedSas(uint8_t* text) { memcpy(sasRelayHeader->trustedSasHash, text, sizeof(sasRelayHeader->trustedSasHash)); } + + /// 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 // ZRTPPACKETSASRELAY + diff --git a/src/libzrtpcpp/ZrtpQueue.h b/src/libzrtpcpp/ZrtpQueue.h new file mode 100644 index 0000000..0454771 --- /dev/null +++ b/src/libzrtpcpp/ZrtpQueue.h @@ -0,0 +1,917 @@ +/* + 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 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 the peer's ZRTP Hello Hash data. + * + * Use this method to get the peer's ZRTP Hello Hash data. The method + * returns the data as a string containing the ZRTP protocol version and + * hex-digits. + * + * The peer's hello hash is available only after ZRTP received a hello. If + * no data is available the function returns an empty string. + * + * Refer to ZRTP specification, chapter 8. + * + * @return + * a std:string containing the Hello version and the hello hash as hex digits. + */ + std::string getPeerHelloHash(); + + /** + * 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); + + /** + * Get the commited SAS rendering algorithm for this ZRTP session. + * + * @return the commited SAS rendering algorithm + */ + std::string getSasType(); + + /** + * Get the computed SAS hash for this ZRTP session. + * + * A PBX ZRTP back-to-Back function uses this function to get the SAS + * hash of an enrolled client to construct the SAS relay packet for + * the other client. + * + * @return a refernce to the byte array that contains the full + * SAS hash. + */ + uint8_t* getSasHash(); + + /** + * Send the SAS relay packet. + * + * The method creates and sends a SAS relay packet according to the ZRTP + * specifications. Usually only a MitM capable user agent (PBX) uses this + * function. + * + * @param sh the full SAS hash value + * @param render the SAS rendering algorithm + */ + bool sendSASRelayPacket(uint8_t* sh, std::string render); + + /** + * Check the state of the MitM mode flag. + * + * If true then this ZRTP session acts as MitM, usually enabled by a PBX + * client (user agent) + * + * @return state of mitmMode + */ + bool isMitmMode(); + + /** + * Set the state of the MitM mode flag. + * + * If MitM mode is set to true this ZRTP session acts as MitM, usually + * enabled by a PBX client (user agent). + * + * @param mitmMode defines the new state of the mitmMode flag + */ + void setMitmMode(bool mitmMode); + + /** + * Enable or disable paranoid mode. + * + * The Paranoid mode controls the behaviour and handling of the SAS verify flag. If + * Panaoid mode is set to flase then ZRtp applies the normal handling. If Paranoid + * mode is set to true then the handling is: + * + *
    + *
  • always set the SAS verify flag to false at srtpSecretsOn() callback. The + * user interface (UI) must show SAS not verified. See implementation note below.
  • + *
  • don't set the SAS verify flag in the Confirm packets, thus forcing the other + * peer to report SAS not verified.
  • + *
  • ignore the SASVerified() function, thus do not set the SAS verified flag + * in the ZRTP cache.
  • + *
  • Disable the Trusted PBX MitM feature. Just send the SASRelay packet + * but do not process the relayed data. This protects the user from a malicious + * "trusted PBX".
  • + *
+ * ZRtp performs alls other steps during the ZRTP negotiations as usual, in particular it + * computes, compares, uses, and stores the retained secrets. This avoids unnecessary warning + * messages. The user may enable or disable the Paranoid mode on a call-by-call basis without + * breaking the key continuity data. + * + * Implementation note:
+ * An application shall always display the SAS if the SAS verify flag is false. + * The application shall remind the user to compare the SAS code, for example using larger fonts, + * different colours and other display features. + */ + void setParanoidMode(bool yesNo); + + /** + * Check status of paranoid mode. + * + * @return + * Returns true if paranoid mode is enabled. + */ + bool isParanoidMode(); + + /** + * Check the state of the enrollment mode. + * + * If true then we will set the enrollment flag (E) in the confirm + * packets and performs the enrollment actions. A MitM (PBX) enrollment service sets this flagstarted this ZRTP + * session. Can be set to true only if mitmMode is also true. + * @return status of the enrollmentMode flag. + */ + bool isEnrollmentMode(); + + /** + * Check the state of the enrollment mode. + * + * If true then we will set the enrollment flag (E) in the confirm + * packets and perform the enrollment actions. A MitM (PBX) enrollment + * service must sets this mode to true. + * + * Can be set to true only if mitmMode is also true. + * + * @param enrollmentMode defines the new state of the enrollmentMode flag + */ + void setEnrollmentMode(bool enrollmentMode); + + /** + * Backwards compatible api fix... + */ + inline void setPBXEnrollment(bool enrollmentMode) + {setMitmMode(enrollmentMode); setEnrollmentMode(enrollmentMode);} + + /** + * Check if a peer's cache entry has a vaild MitM key. + * + * If true then the other peer ha a valid MtiM key, i.e. the peer has performed + * the enrollment procedure. A PBX ZRTP Back-2-Back application can use this function + * to check which of the peers is enrolled. + * + * @return True if the other peer has a valid Mitm key (is enrolled). + */ + bool isPeerEnrolled(); + + /** + * Set the state of the SAS signature mode flag. + * + * If SAS signature mode is set to true this ZRTP session support SAS signature + * callbacks and signature transfer between clients. + * + * @param sasSignMode defines the new state of the sasSignMode flag + */ + void setSignSas(bool sasSignMode); + + /** + * 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. + * + * @return + * Pointer to signature data. This is a pointer to volatile data that is + * only valid during the checkSASSignature() callback. The application + * shall copy the data if necessary. + */ + const uint8* getSignatureData(); + + /** + * 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(); + + /** + * 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 getPeerZid(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(GnuZrtpCodes::InfoEnrollment info); + + void zrtpInformEnrollment(GnuZrtpCodes::InfoEnrollment info); + + void signSAS(uint8_t* sasHash); + + bool checkSASSignature(uint8_t* sasHash); + + /* + * 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; + + int16 senderZrtpSeqNo; + ost::Mutex synchLock; // Mutex for ZRTP (used by ZrtpStateClass) + uint32 peerSSRC; + bool started; + bool mitmMode; + bool signSas; + bool enableParanoidMode; +}; + +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: + */ + diff --git a/src/libzrtpcpp/ZrtpStateClass.h b/src/libzrtpcpp/ZrtpStateClass.h new file mode 100644 index 0000000..fba061d --- /dev/null +++ b/src/libzrtpcpp/ZrtpStateClass.h @@ -0,0 +1,324 @@ +/* + 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 +}; + +enum SecureSubStates { + Normal, + WaitSasRelayAck, + numberofSecureSubStates +}; + +/// 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; + + // Secure substate to handle SAS relay packets + SecureSubStates secSubstate; + + /** + * Secure Sub state WaitSasRelayAck. + * + * This state belongs to the secure substates and handles + * SAS Relay Ack. + * + * When entering this transition function + * - sentPacket contains Error packet, Error timer active + * + * Possible events in this state are: + * - timeout for sent SAS Relay packet: causes a resend check and repeat sending + * of packet + * - SASRelayAck: Stop timer and switch to secure substate Normal. + */ + bool subEvWaitRelayAck(); + +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(); + + /** + * Send a SAS relay packet. + * + * the functions stores sends the SAS relay packet and stores the pointer in + * the sentPacket variable to enable resending. + * + * The method switches to secure substate WaitSasRelayAck. + * + * @param relay + * Pointer to the SAS relay packet. + */ + void sendSASRelay(ZrtpPacketSASrelay* relay); +}; + +/** + * @} + */ +#endif // _ZRTPSTATECLASS_H_ + diff --git a/src/libzrtpcpp/ZrtpStates.h b/src/libzrtpcpp/ZrtpStates.h new file mode 100644 index 0000000..44662a0 --- /dev/null +++ b/src/libzrtpcpp/ZrtpStates.h @@ -0,0 +1,90 @@ +/* + 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 + diff --git a/src/libzrtpcpp/ZrtpTextData.h b/src/libzrtpcpp/ZrtpTextData.h new file mode 100644 index 0000000..e79cb98 --- /dev/null +++ b/src/libzrtpcpp/ZrtpTextData.h @@ -0,0 +1,124 @@ +/* + 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 SasRelayMsg[]; +extern char RelayAckMsg[]; + +/** + * + */ +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 zrtpTrustedMitm[]; + + +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_ + diff --git a/src/libzrtpcpp/ZrtpUserCallback.h b/src/libzrtpcpp/ZrtpUserCallback.h new file mode 100644 index 0000000..3e4871c --- /dev/null +++ b/src/libzrtpcpp/ZrtpUserCallback.h @@ -0,0 +1,234 @@ +/* + 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(GnuZrtpCodes::InfoEnrollment 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(GnuZrtpCodes::InfoEnrollment 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 sasHash + * Pointer to the 32 byte SAS hash to be signed. + * @see ZrtpQueue#setSignatureData + * + */ + virtual void signSAS(uint8_t* sasHash) { + 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 sasHash + * Pointer to the 32 byte SAS hash that was signed by the other peer. + * @return + * true if the signature was ok, false otherwise. + * + */ + virtual bool checkSASSignature(uint8_t* sasHash) { + return true; + } +}; + +#endif diff --git a/src/libzrtpcpp/crypto/TwoCFB.cpp b/src/libzrtpcpp/crypto/TwoCFB.cpp new file mode 100755 index 0000000..be3dda4 --- /dev/null +++ b/src/libzrtpcpp/crypto/TwoCFB.cpp @@ -0,0 +1,79 @@ +/* + 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); +} diff --git a/src/libzrtpcpp/crypto/ZrtpDH.h b/src/libzrtpcpp/crypto/ZrtpDH.h new file mode 100644 index 0000000..bd32f7f --- /dev/null +++ b/src/libzrtpcpp/crypto/ZrtpDH.h @@ -0,0 +1,168 @@ +/* + 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: + */ diff --git a/src/libzrtpcpp/crypto/aesCFB.h b/src/libzrtpcpp/crypto/aesCFB.h new file mode 100644 index 0000000..6b4ab6e --- /dev/null +++ b/src/libzrtpcpp/crypto/aesCFB.h @@ -0,0 +1,87 @@ +/* + 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 diff --git a/src/libzrtpcpp/crypto/gcrypt/InitializeGcrypt.cpp b/src/libzrtpcpp/crypto/gcrypt/InitializeGcrypt.cpp new file mode 100644 index 0000000..1372578 --- /dev/null +++ b/src/libzrtpcpp/crypto/gcrypt/InitializeGcrypt.cpp @@ -0,0 +1,130 @@ +/* + 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 +#ifdef HAVE_PTHREAD_H +#include +#else +#include +#endif + +static int initialized = 0; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_PTHREAD_H +static int gcry_thread_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_thread_mutex_destroy (void **lock) +{ + int err = pthread_mutex_destroy ((pthread_mutex_t *)*lock); + free (*lock); return err; +} + +static int gcry_thread_mutex_lock (void **lock) +{ + return pthread_mutex_lock ((pthread_mutex_t *)*lock); +} + +static int gcry_thread_mutex_unlock (void **lock) +{ + return pthread_mutex_unlock ((pthread_mutex_t *)*lock); +} + +static struct gcry_thread_cbs gcry_threads = { + GCRY_THREAD_OPTION_PTHREAD, NULL, + gcry_thread_mutex_init, gcry_thread_mutex_destroy, + gcry_thread_mutex_lock, gcry_thread_mutex_unlock +}; + +#else +static int gcry_thread_mutex_init (void **priv) +{ + int err = 0; + CRITICAL_SECTION *lock = (CRITICAL_SECTION *)malloc(sizeof(CRITICAL_SECTION)); + if (!lock) + err = ENOMEM; + if (!err) { + InitializeCriticalSection(lock); + *priv = lock; + } + return err; +} + +static int gcry_thread_mutex_destroy (void **lock) +{ + free(*lock); + return 0; +} + +static int gcry_thread_mutex_lock (void **lock) +{ + EnterCriticalSection((CRITICAL_SECTION *)*lock); + return 0; +} + +static int gcry_thread_mutex_unlock (void **lock) +{ + LeaveCriticalSection((CRITICAL_SECTION *)*lock); + return 0; +} + +static struct gcry_thread_cbs gcry_threads = { + GCRY_THREAD_OPTION_PTHREAD, NULL, + gcry_thread_mutex_init, gcry_thread_mutex_destroy, + gcry_thread_mutex_lock, gcry_thread_mutex_unlock +}; +#endif + +#ifdef __cplusplus +} +#endif + +int initializeGcrypt () +{ + + if (initialized) { + return 1; + } + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads); + gcry_check_version(NULL); + gcry_control(GCRYCTL_DISABLE_SECMEM); + initialized = 1; + return 1; +} diff --git a/src/libzrtpcpp/crypto/gcrypt/gcryptAesCFB.cpp b/src/libzrtpcpp/crypto/gcrypt/gcryptAesCFB.cpp new file mode 100644 index 0000000..3673619 --- /dev/null +++ b/src/libzrtpcpp/crypto/gcrypt/gcryptAesCFB.cpp @@ -0,0 +1,77 @@ +/* + 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); +} diff --git a/src/libzrtpcpp/crypto/gcrypt/gcryptZrtpDH.cpp b/src/libzrtpcpp/crypto/gcrypt/gcryptZrtpDH.cpp new file mode 100644 index 0000000..1aba680 --- /dev/null +++ b/src/libzrtpcpp/crypto/gcrypt/gcryptZrtpDH.cpp @@ -0,0 +1,349 @@ +/* + 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: + */ diff --git a/src/libzrtpcpp/crypto/gcrypt/gcrypthmac256.cpp b/src/libzrtpcpp/crypto/gcrypt/gcrypthmac256.cpp new file mode 100644 index 0000000..3a44504 --- /dev/null +++ b/src/libzrtpcpp/crypto/gcrypt/gcrypthmac256.cpp @@ -0,0 +1,68 @@ +/* + 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); +} diff --git a/src/libzrtpcpp/crypto/gcrypt/gcrypthmac384.cpp b/src/libzrtpcpp/crypto/gcrypt/gcrypthmac384.cpp new file mode 100644 index 0000000..c48813c --- /dev/null +++ b/src/libzrtpcpp/crypto/gcrypt/gcrypthmac384.cpp @@ -0,0 +1,68 @@ +/* + 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); +} diff --git a/src/libzrtpcpp/crypto/gcrypt/gcryptsha256.cpp b/src/libzrtpcpp/crypto/gcrypt/gcryptsha256.cpp new file mode 100644 index 0000000..0c32bd8 --- /dev/null +++ b/src/libzrtpcpp/crypto/gcrypt/gcryptsha256.cpp @@ -0,0 +1,89 @@ +/* + 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++; + } +} diff --git a/src/libzrtpcpp/crypto/gcrypt/gcryptsha384.cpp b/src/libzrtpcpp/crypto/gcrypt/gcryptsha384.cpp new file mode 100644 index 0000000..19c8c5b --- /dev/null +++ b/src/libzrtpcpp/crypto/gcrypt/gcryptsha384.cpp @@ -0,0 +1,89 @@ +/* + 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++; + } +} diff --git a/src/libzrtpcpp/crypto/hmac256.h b/src/libzrtpcpp/crypto/hmac256.h new file mode 100644 index 0000000..f9110a6 --- /dev/null +++ b/src/libzrtpcpp/crypto/hmac256.h @@ -0,0 +1,96 @@ +/* + 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 diff --git a/src/libzrtpcpp/crypto/hmac384.h b/src/libzrtpcpp/crypto/hmac384.h new file mode 100644 index 0000000..223444a --- /dev/null +++ b/src/libzrtpcpp/crypto/hmac384.h @@ -0,0 +1,96 @@ +/* + 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 diff --git a/src/libzrtpcpp/crypto/openssl/AesCFB.cpp b/src/libzrtpcpp/crypto/openssl/AesCFB.cpp new file mode 100644 index 0000000..595d1ff --- /dev/null +++ b/src/libzrtpcpp/crypto/openssl/AesCFB.cpp @@ -0,0 +1,89 @@ +/* + 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); +} diff --git a/src/libzrtpcpp/crypto/openssl/InitializeOpenSSL.cpp b/src/libzrtpcpp/crypto/openssl/InitializeOpenSSL.cpp new file mode 100755 index 0000000..17961c3 --- /dev/null +++ b/src/libzrtpcpp/crypto/openssl/InitializeOpenSSL.cpp @@ -0,0 +1,242 @@ +/* + 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 + +#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) +#undef _MSWINDOWS_ +#define _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_ +#define __LOCKING + +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 && !defined(_MSWINDOWS) +#define __LOCKING + +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 */ + + +#ifndef __LOCKING +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); +} +*/ +#endif diff --git a/src/libzrtpcpp/crypto/openssl/ZrtpDH.cpp b/src/libzrtpcpp/crypto/openssl/ZrtpDH.cpp new file mode 100644 index 0000000..fbd623c --- /dev/null +++ b/src/libzrtpcpp/crypto/openssl/ZrtpDH.cpp @@ -0,0 +1,426 @@ +/* + 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: + */ diff --git a/src/libzrtpcpp/crypto/openssl/hmac256.cpp b/src/libzrtpcpp/crypto/openssl/hmac256.cpp new file mode 100644 index 0000000..a054c02 --- /dev/null +++ b/src/libzrtpcpp/crypto/openssl/hmac256.cpp @@ -0,0 +1,67 @@ +/* + 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 ); +} diff --git a/src/libzrtpcpp/crypto/openssl/hmac384.cpp b/src/libzrtpcpp/crypto/openssl/hmac384.cpp new file mode 100644 index 0000000..10d6fbc --- /dev/null +++ b/src/libzrtpcpp/crypto/openssl/hmac384.cpp @@ -0,0 +1,67 @@ +/* + 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 ); +} diff --git a/src/libzrtpcpp/crypto/openssl/sha256.cpp b/src/libzrtpcpp/crypto/openssl/sha256.cpp new file mode 100644 index 0000000..2163a6d --- /dev/null +++ b/src/libzrtpcpp/crypto/openssl/sha256.cpp @@ -0,0 +1,97 @@ +/* + 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++; + } +} diff --git a/src/libzrtpcpp/crypto/openssl/sha384.cpp b/src/libzrtpcpp/crypto/openssl/sha384.cpp new file mode 100644 index 0000000..9d166e7 --- /dev/null +++ b/src/libzrtpcpp/crypto/openssl/sha384.cpp @@ -0,0 +1,97 @@ +/* + 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++; + } +} diff --git a/src/libzrtpcpp/crypto/sha256.h b/src/libzrtpcpp/crypto/sha256.h new file mode 100644 index 0000000..959a620 --- /dev/null +++ b/src/libzrtpcpp/crypto/sha256.h @@ -0,0 +1,144 @@ +/* + 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 + diff --git a/src/libzrtpcpp/crypto/sha384.h b/src/libzrtpcpp/crypto/sha384.h new file mode 100644 index 0000000..6cb7a70 --- /dev/null +++ b/src/libzrtpcpp/crypto/sha384.h @@ -0,0 +1,144 @@ +/* + 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 + diff --git a/src/libzrtpcpp/crypto/twoCFB.h b/src/libzrtpcpp/crypto/twoCFB.h new file mode 100755 index 0000000..593a59c --- /dev/null +++ b/src/libzrtpcpp/crypto/twoCFB.h @@ -0,0 +1,87 @@ +/* + 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 diff --git a/src/libzrtpcpp/crypto/twofish.c b/src/libzrtpcpp/crypto/twofish.c new file mode 100644 index 0000000..3d390ea --- /dev/null +++ b/src/libzrtpcpp/crypto/twofish.c @@ -0,0 +1,1733 @@ +/* + * 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. + */ + + diff --git a/src/libzrtpcpp/crypto/twofish.h b/src/libzrtpcpp/crypto/twofish.h new file mode 100755 index 0000000..0c8b0d7 --- /dev/null +++ b/src/libzrtpcpp/crypto/twofish.h @@ -0,0 +1,265 @@ +/* + * 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. + * @param 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 ivec initialization vector for this CFB mode encryption. + * @param num pointer to integer that holds number of available crypto bytes. + */ +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 ivec initialization vector for this CFB mode encryption. + * @param num pointer to integer that holds number of available crypto bytes. + */ +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 diff --git a/src/libzrtpcpp/crypto/twofish_cfb.c b/src/libzrtpcpp/crypto/twofish_cfb.c new file mode 100755 index 0000000..7540738 --- /dev/null +++ b/src/libzrtpcpp/crypto/twofish_cfb.c @@ -0,0 +1,82 @@ +#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); +} diff --git a/src/libzrtpcpp/zrtpPacket.h b/src/libzrtpcpp/zrtpPacket.h new file mode 100644 index 0000000..18ba7a1 --- /dev/null +++ b/src/libzrtpcpp/zrtpPacket.h @@ -0,0 +1,342 @@ +/* + 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]; ///< A 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 + uint8_t flags; ///< flag bits (chap 7.2) + uint8_t lengths[3]; ///< 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; + +/** + * SASrelay message + * + * The SASrelay message has a variable length. The following struct + * defines the fixed part only. The SASrelay class initializes the + * variable part. + * + * ZRTP encrypts a part of the SASrelay message, starting at @c hashH0 + * and includes the variable part. + */ +typedef struct SASrelay { + 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 filler[2]; ///< Filler bytes + uint8_t sigLength; ///< Length of an optional signature length (chap 7.2) + uint8_t flags; ///< various flags to control behaviour + uint8_t sas[ZRTP_WORD_SIZE]; ///< SAS algorithm to use + uint8_t trustedSasHash[HASH_IMAGE_SIZE]; ///< New trusted SAS hash for enrolled client +} SASrelay_t; + +/** + * The complete ZRTP SASrelay message. + */ +typedef struct SASrelayPacket { + zrtpPacketHeader_t hdr; ///< ZRTP Header + SASrelay_t sasrelay; ///< SASrelay message fixed part +} SASrelayPacket_t; + +/** + * RelayAck message. + * + * The complete RelayAck message consists of ZRTP message header and + * the CRC which is the only RelayAck specific data. + */ +typedef struct RelayAckPacket { + zrtpPacketHeader_t hdr; ///< ZRTP Header + uint8_t crc[ZRTP_WORD_SIZE]; ///< CRC of ZRTP message +} RelayAckPacket_t; + +#endif // ZRTPPACKET_H + +/** + * @} + */ + +/** EMACS ** + * Local variables: + * mode: c++ + * c-default-style: ellemtel + * c-basic-offset: 4 + * End: + */ diff --git a/src/libzrtpcpp/zrtpccrtp.h b/src/libzrtpcpp/zrtpccrtp.h new file mode 100644 index 0000000..d94ca5a --- /dev/null +++ b/src/libzrtpcpp/zrtpccrtp.h @@ -0,0 +1,76 @@ +/* + 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 + +// Define a dummy variable only to overcome a doxygen problem. +static int dummy __attribute__ ((unused)) = 0; + + +/** + * @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: + */ -- cgit v1.2.3