Shadowrun: Awakened 29 September 2011 - Build 871
EasyHandshake.hpp
Go to the documentation of this file.
00001 /*
00002     Copyright (c) 2009-2010 Christopher A. Taylor.  All rights reserved.
00003 
00004     Redistribution and use in source and binary forms, with or without
00005     modification, are permitted provided that the following conditions are met:
00006 
00007     * Redistributions of source code must retain the above copyright notice,
00008       this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright notice,
00010       this list of conditions and the following disclaimer in the documentation
00011       and/or other materials provided with the distribution.
00012     * Neither the name of LibCat nor the names of its contributors may be used
00013       to endorse or promote products derived from this software without
00014       specific prior written permission.
00015 
00016     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00017     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00019     ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00020     LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00021     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00022     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00023     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00024     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00025     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00026     POSSIBILITY OF SUCH DAMAGE.
00027 */
00028 
00029 #ifndef CAT_EASY_HANDSHAKE_HPP
00030 #define CAT_EASY_HANDSHAKE_HPP
00031 
00032 #include <cat/crypt/tunnel/KeyAgreementInitiator.hpp>
00033 #include <cat/crypt/tunnel/KeyAgreementResponder.hpp>
00034 #include <cat/crypt/cookie/CookieJar.hpp>
00035 
00036 namespace cat {
00037 
00038 
00039 /*
00040     The EasyHandshake classes implement a simplified version of my Tunnel protocol.
00041 
00042     This only works for single-threaded servers and only produces a single authenticated encryption
00043     object for each handshake.  Explanations on how to use the library with a multi-threaded
00044     server, and how to use one handshake to secure several TCP streams, are documented in the
00045     comments of these classes.
00046 
00047 
00048     Over the network, the handshake will look like this:
00049 
00050     client --> server : CHALLENGE (64 random-looking bytes)
00051 
00052     server --> client : ANSWER (128 random-looking bytes)
00053 
00054     client --> server : PROOF (32 random-looking bytes) + first encrypted packet can be appended here
00055 
00056 
00057     As far as coding goes, the function calls fit into the protocol like this:
00058 
00059     server is offline:
00060 
00061         During startup, both the client and server should initialize the library.
00062         This is necessary also just for generating keys:
00063         ----------------------------------------------------------------
00064         #include <cat/AllTunnel.hpp>
00065         using namespace cat;
00066 
00067         if (!EasyHandshake::Initialize())
00068         {
00069             printf("ERROR:Unable to initialize crypto subsystem\n");
00070         }
00071         ----------------------------------------------------------------
00072 
00073         Generate the server public and private key pairs:
00074         ----------------------------------------------------------------
00075         u8 public_key[EasyHandshake::PUBLIC_KEY_BYTES];
00076         u8 private_key[EasyHandshake::PRIVATE_KEY_BYTES];
00077 
00078         EasyHandshake temp;
00079         temp.GenerateServerKey(public_key, private_key);
00080         ----------------------------------------------------------------
00081 
00082         (keys are stored to disk for reading on start-up)
00083 
00084         (public key is given to the client somehow)
00085             + built into the client code
00086             + provided by a trusted server
00087 
00088     server comes online:
00089 
00090         ----------------------------------------------------------------
00091         ServerEasyHandshake server_handshake;
00092 
00093         server_handshake.Initialize(public_key, private_key);
00094         ----------------------------------------------------------------
00095 
00096     client comes online:
00097 
00098         ----------------------------------------------------------------
00099         ClientEasyHandshake client_handshake;
00100 
00101         client_handshake.Initialize(public_key);
00102 
00103         u8 challenge[EasyHandshake::CHALLENGE_BYTES];
00104 
00105         client_handshake.GenerateChallenge(challenge);
00106         ----------------------------------------------------------------
00107 
00108     client --> server : CHALLENGE (64 random-looking bytes)
00109 
00110         ----------------------------------------------------------------
00111         AuthenticatedEncryption server_e;
00112 
00113         u8 answer[EasyHandshake::ANSWER_BYTES];
00114 
00115         server_handshake.ProcessChallenge(challenge, answer, &server_e);
00116         ----------------------------------------------------------------
00117 
00118     server --> client : ANSWER (128 random-looking bytes)
00119 
00120         ----------------------------------------------------------------
00121         AuthenticatedEncryption client_e;
00122 
00123         client_handshake.ProcessAnswer(answer, &client_e);
00124 
00125         u8 proof[EasyHandshake::PROOF_BYTES];
00126 
00127         client_e.GenerateProof(proof, EasyHandshake::PROOF_BYTES);
00128         ----------------------------------------------------------------
00129 
00130         Encryption example:
00131         ----------------------------------------------------------------
00132         // Example message encryption of "Hello".  Note that encryption
00133         // inflates the size of the message by OVERHEAD_BYTES.
00134         const int PLAINTEXT_BYTES = 5;
00135         const int BUFFER_BYTES = \
00136             PLAINTEXT_BYTES + AuthenticatedEncryption::OVERHEAD_BYTES;
00137         int msg_bytes = PLAINTEXT_BYTES;
00138 
00139         // Note that it makes room for message inflation
00140         const u8 message[CIPHERTEXT_BYTES] = {
00141             'H', 'e', 'l', 'l', 'o'
00142         };
00143 
00144         // Note the second parameter is the size of the buffer, and
00145         // the third parameter will be adjusted to the size of the
00146         // encrypted message:
00147 
00148         if (client_e.Encrypt(message, BUFFER_BYTES, msg_bytes))
00149         {
00150             // msg_bytes is now adjusted to be the size of the ciphertext
00151         }
00152         ----------------------------------------------------------------
00153 
00154     client --> server : PROOF (32 random-looking bytes) + first encrypted packet can be appended here
00155 
00156         ----------------------------------------------------------------
00157         server_e.ValidateProof(proof, EasyHandshake::PROOF_BYTES);
00158         ----------------------------------------------------------------
00159 
00160         Decryption example:
00161         ----------------------------------------------------------------
00162         int buf_bytes = msg_bytes;
00163 
00164         // The second parameter is the number of bytes in the encrypted message
00165         if (server_e.Decrypt(message, buf_bytes))
00166         {
00167             // buf_bytes is now adjusted to be the size of the plaintext
00168         }
00169         ----------------------------------------------------------------
00170 
00171         During program termination, the client and server should clean up:
00172         ----------------------------------------------------------------
00173         EasyHandshake::Shutdown();
00174         ----------------------------------------------------------------
00175 
00176     NOTES:
00177 
00178         Once the authenticated encryption objects are created, if the messages received are always
00179         guaranteed to be in order, then the following flag can be set to make the object reject
00180         packets received out of order, which would indicate tampering:
00181             auth_enc.AllowOutOfOrder(false);
00182         By default the messages are assumed to arrive in any order up to 1024 messages out of order.
00183 
00184         The server similarly can encrypt messages the same way the client does in the examples.
00185 
00186         Encrypted messages are inflated by 11 random-looking bytes for a MAC and an IV.
00187         Modifications to the code can allow lower overhead if needed.
00188 
00189         The EasyHandshake classes are *NOT* THREAD-SAFE.
00190 
00191         The AuthenticatedEncryption class is *NOT* THREAD-SAFE.  Simultaneously, only ONE thread
00192         can be encrypting messages.  And only ONE thread can be decrypting messages.  Encryption
00193         and decryption are separate and safe to perform simultaneously.
00194 */
00195 
00196 
00197 /*
00198     Common data needed for handshaking
00199 */
00200 class EasyHandshake
00201 {
00202 protected:
00203     // Normally these would be created per-thread.
00204     // To free memory associated with these objects just delete them.
00205     BigTwistedEdwards *tls_math;
00206     FortunaOutput *tls_csprng;
00207 
00208 public:
00209     static const int BITS = 256;
00210     static const int BYTES = BITS / 8;
00211     static const int PUBLIC_KEY_BYTES = BYTES * 2;
00212     static const int PRIVATE_KEY_BYTES = BYTES;
00213     static const int CHALLENGE_BYTES = BYTES * 2; // Packet # 1 in handshake, sent to server
00214     static const int ANSWER_BYTES = BYTES * 4; // Packet # 2 in handshake, sent to client
00215     static const int PROOF_BYTES = BYTES; // Packet # 3 in handshake, sent to server
00216 
00217 public:
00218     // Demonstrates how to allocate and free the math and prng objects
00219     EasyHandshake();
00220     ~EasyHandshake();
00221 
00222 public:
00223     static bool Initialize();
00224     static void Shutdown();
00225 
00226 public:
00227     // Generate a server (public, private) key pair
00228     // Connecting clients will need to know the public key in order to connect
00229     bool GenerateServerKey(void *out_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */,
00230                            void *out_private_key /* EasyHandshake::PRIVATE_KEY_BYTES */);
00231 };
00232 
00233 /*
00234     Implements the simple case of a server that performs handshakes with clients
00235     from a single thread.  Note that this implementation is not thread-safe.
00236 */
00237 class ServerEasyHandshake : public EasyHandshake
00238 {
00239     KeyAgreementResponder tun_server;
00240 
00241 public:
00242     ServerEasyHandshake();
00243     ~ServerEasyHandshake();
00244 
00245     // Prepare a cookie jar for hungry consumers
00246     void FillCookieJar(CookieJar *jar);
00247 
00248     // Provide the public and private key for the server, previously generated offline
00249     bool Initialize(const void *in_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */,
00250                     const void *in_private_key /* EasyHandshake::PRIVATE_KEY_BYTES */);
00251 
00252     // Process a client challenge and generate a server answer
00253     // Returns false if challenge was invalid
00254     bool ProcessChallenge(const void *in_challenge /* EasyHandshake::CHALLENGE_BYTES */,
00255                           void *out_answer /* EasyHandshake::ANSWER_BYTES */,
00256                           AuthenticatedEncryption *auth_enc);
00257 };
00258 
00259 /*
00260     Implements the simple case of a client that performs handshakes with servers
00261     from a single thread.  Note that this implementation is not thread-safe.
00262 */
00263 class ClientEasyHandshake : public EasyHandshake
00264 {
00265     KeyAgreementInitiator tun_client;
00266 
00267 public:
00268     ClientEasyHandshake();
00269     ~ClientEasyHandshake();
00270 
00271     // Provide the public key for the server, acquired through some secure means
00272     bool Initialize(const void *in_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */);
00273 
00274     // Generate a challenge for the server to answer
00275     bool GenerateChallenge(void *out_challenge /* EasyHandshake::CHALLENGE_BYTES */);
00276 
00277     // Process a server answer to our challenge
00278     // Returns false if answer was invalid
00279     bool ProcessAnswer(const void *in_answer /* EasyHandshake::ANSWER_BYTES */,
00280                        AuthenticatedEncryption *auth_enc);
00281 };
00282 
00283 
00284 } // namespace cat
00285 
00286 #endif // CAT_EASY_HANDSHAKE_HPP

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net