![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
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.