EasyHandshake.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
  3. Redistribution and use in source and binary forms, with or without
  4. modification, are permitted provided that the following conditions are met:
  5. * Redistributions of source code must retain the above copyright notice,
  6. this list of conditions and the following disclaimer.
  7. * Redistributions in binary form must reproduce the above copyright notice,
  8. this list of conditions and the following disclaimer in the documentation
  9. and/or other materials provided with the distribution.
  10. * Neither the name of LibCat nor the names of its contributors may be used
  11. to endorse or promote products derived from this software without
  12. specific prior written permission.
  13. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  14. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  17. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  23. POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #ifndef CAT_EASY_HANDSHAKE_HPP
  26. #define CAT_EASY_HANDSHAKE_HPP
  27. #include <cat/crypt/tunnel/KeyAgreementInitiator.hpp>
  28. #include <cat/crypt/tunnel/KeyAgreementResponder.hpp>
  29. #include <cat/crypt/cookie/CookieJar.hpp>
  30. namespace cat {
  31. /*
  32. The EasyHandshake classes implement a simplified version of my Tunnel protocol.
  33. This only works for single-threaded servers and only produces a single authenticated encryption
  34. object for each handshake. Explanations on how to use the library with a multi-threaded
  35. server, and how to use one handshake to secure several TCP streams, are documented in the
  36. comments of these classes.
  37. Over the network, the handshake will look like this:
  38. client --> server : CHALLENGE (64 random-looking bytes)
  39. server --> client : ANSWER (128 random-looking bytes)
  40. client --> server : PROOF (32 random-looking bytes) + first encrypted packet can be appended here
  41. As far as coding goes, the function calls fit into the protocol like this:
  42. server is offline:
  43. During startup, both the client and server should initialize the library.
  44. This is necessary also just for generating keys:
  45. ----------------------------------------------------------------
  46. #include <cat/AllTunnel.hpp>
  47. using namespace cat;
  48. if (!EasyHandshake::Initialize())
  49. {
  50. printf("ERROR:Unable to initialize crypto subsystem\n");
  51. }
  52. ----------------------------------------------------------------
  53. Generate the server public and private key pairs:
  54. ----------------------------------------------------------------
  55. u8 public_key[EasyHandshake::PUBLIC_KEY_BYTES];
  56. u8 private_key[EasyHandshake::PRIVATE_KEY_BYTES];
  57. EasyHandshake temp;
  58. temp.GenerateServerKey(public_key, private_key);
  59. ----------------------------------------------------------------
  60. (keys are stored to disk for reading on start-up)
  61. (public key is given to the client somehow)
  62. + built into the client code
  63. + provided by a trusted server
  64. server comes online:
  65. ----------------------------------------------------------------
  66. ServerEasyHandshake server_handshake;
  67. server_handshake.Initialize(public_key, private_key);
  68. ----------------------------------------------------------------
  69. client comes online:
  70. ----------------------------------------------------------------
  71. ClientEasyHandshake client_handshake;
  72. client_handshake.Initialize(public_key);
  73. u8 challenge[EasyHandshake::CHALLENGE_BYTES];
  74. client_handshake.GenerateChallenge(challenge);
  75. ----------------------------------------------------------------
  76. client --> server : CHALLENGE (64 random-looking bytes)
  77. ----------------------------------------------------------------
  78. AuthenticatedEncryption server_e;
  79. u8 answer[EasyHandshake::ANSWER_BYTES];
  80. server_handshake.ProcessChallenge(challenge, answer, &server_e);
  81. ----------------------------------------------------------------
  82. server --> client : ANSWER (128 random-looking bytes)
  83. ----------------------------------------------------------------
  84. AuthenticatedEncryption client_e;
  85. client_handshake.ProcessAnswer(answer, &client_e);
  86. u8 proof[EasyHandshake::PROOF_BYTES];
  87. client_e.GenerateProof(proof, EasyHandshake::PROOF_BYTES);
  88. ----------------------------------------------------------------
  89. Encryption example:
  90. ----------------------------------------------------------------
  91. // Example message encryption of "Hello". Note that encryption
  92. // inflates the size of the message by OVERHEAD_BYTES.
  93. const int PLAINTEXT_BYTES = 5;
  94. const int BUFFER_BYTES = \
  95. PLAINTEXT_BYTES + AuthenticatedEncryption::OVERHEAD_BYTES;
  96. int msg_bytes = PLAINTEXT_BYTES;
  97. // Note that it makes room for message inflation
  98. const u8 message[CIPHERTEXT_BYTES] = {
  99. 'H', 'e', 'l', 'l', 'o'
  100. };
  101. // Note the second parameter is the size of the buffer, and
  102. // the third parameter will be adjusted to the size of the
  103. // encrypted message:
  104. if (client_e.Encrypt(message, BUFFER_BYTES, msg_bytes))
  105. {
  106. // msg_bytes is now adjusted to be the size of the ciphertext
  107. }
  108. ----------------------------------------------------------------
  109. client --> server : PROOF (32 random-looking bytes) + first encrypted packet can be appended here
  110. ----------------------------------------------------------------
  111. server_e.ValidateProof(proof, EasyHandshake::PROOF_BYTES);
  112. ----------------------------------------------------------------
  113. Decryption example:
  114. ----------------------------------------------------------------
  115. int buf_bytes = msg_bytes;
  116. // The second parameter is the number of bytes in the encrypted message
  117. if (server_e.Decrypt(message, buf_bytes))
  118. {
  119. // buf_bytes is now adjusted to be the size of the plaintext
  120. }
  121. ----------------------------------------------------------------
  122. During program termination, the client and server should clean up:
  123. ----------------------------------------------------------------
  124. EasyHandshake::Shutdown();
  125. ----------------------------------------------------------------
  126. NOTES:
  127. Once the authenticated encryption objects are created, if the messages received are always
  128. guaranteed to be in order, then the following flag can be set to make the object reject
  129. packets received out of order, which would indicate tampering:
  130. auth_enc.AllowOutOfOrder(false);
  131. By default the messages are assumed to arrive in any order up to 1024 messages out of order.
  132. The server similarly can encrypt messages the same way the client does in the examples.
  133. Encrypted messages are inflated by 11 random-looking bytes for a MAC and an IV.
  134. Modifications to the code can allow lower overhead if needed.
  135. The EasyHandshake classes are *NOT* THREAD-SAFE.
  136. The AuthenticatedEncryption class is *NOT* THREAD-SAFE. Simultaneously, only ONE thread
  137. can be encrypting messages. And only ONE thread can be decrypting messages. Encryption
  138. and decryption are separate and safe to perform simultaneously.
  139. */
  140. /*
  141. Common data needed for handshaking
  142. */
  143. class CAT_EXPORT EasyHandshake
  144. {
  145. protected:
  146. // Normally these would be created per-thread.
  147. // To free memory associated with these objects just delete them.
  148. BigTwistedEdwards *tls_math;
  149. FortunaOutput *tls_csprng;
  150. public:
  151. static const int BITS = 256;
  152. static const int BYTES = BITS / 8;
  153. static const int PUBLIC_KEY_BYTES = BYTES * 2;
  154. static const int PRIVATE_KEY_BYTES = BYTES;
  155. static const int CHALLENGE_BYTES = BYTES * 2; // Packet # 1 in handshake, sent to server
  156. static const int ANSWER_BYTES = BYTES * 4; // Packet # 2 in handshake, sent to client
  157. static const int PROOF_BYTES = BYTES; // Packet # 3 in handshake, sent to server
  158. static const int IDENTITY_BYTES = BYTES * 5; // [optional] Packet # 3 in handshake, sent to server, proves identity of client also
  159. public:
  160. // Demonstrates how to allocate and free the math and prng objects
  161. EasyHandshake();
  162. ~EasyHandshake();
  163. public:
  164. static bool Initialize();
  165. static void Shutdown();
  166. public:
  167. // Generate a server (public, private) key pair
  168. // Connecting clients will need to know the public key in order to connect
  169. bool GenerateServerKey(void *out_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */,
  170. void *out_private_key /* EasyHandshake::PRIVATE_KEY_BYTES */);
  171. // Fills the given buffer with a variable number of random bytes
  172. // Returns false on failure
  173. bool GenerateRandomNumber(void *out_num, int bytes);
  174. };
  175. /*
  176. Implements the simple case of a server that performs handshakes with clients
  177. from a single thread. Note that this implementation is not thread-safe.
  178. */
  179. class CAT_EXPORT ServerEasyHandshake : public EasyHandshake
  180. {
  181. KeyAgreementResponder tun_server;
  182. public:
  183. ServerEasyHandshake();
  184. ~ServerEasyHandshake();
  185. // Prepare a cookie jar for hungry consumers
  186. void FillCookieJar(CookieJar *jar);
  187. // Provide the public and private key for the server, previously generated offline
  188. bool Initialize(const void *in_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */,
  189. const void *in_private_key /* EasyHandshake::PRIVATE_KEY_BYTES */);
  190. // Process a client challenge and generate a server answer
  191. // Returns false if challenge was invalid
  192. bool ProcessChallenge(const void *in_challenge /* EasyHandshake::CHALLENGE_BYTES */,
  193. void *out_answer /* EasyHandshake::ANSWER_BYTES */,
  194. AuthenticatedEncryption *auth_enc);
  195. // Validate a client proof of identity
  196. // Returns false if proof was invalid
  197. bool VerifyInitiatorIdentity(const void *in_answer /* EasyHandshake::ANSWER_BYTES */,
  198. const void *in_proof /* EasyHandshake::IDENTITY_BYTES */,
  199. void *out_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */);
  200. };
  201. /*
  202. Implements the simple case of a client that performs handshakes with servers
  203. from a single thread. Note that this implementation is not thread-safe.
  204. */
  205. class CAT_EXPORT ClientEasyHandshake : public EasyHandshake
  206. {
  207. KeyAgreementInitiator tun_client;
  208. public:
  209. ClientEasyHandshake();
  210. ~ClientEasyHandshake();
  211. // Provide the public key for the server, acquired through some secure means
  212. bool Initialize(const void *in_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */);
  213. // (optional) Provide the identity for the client
  214. bool SetIdentity(const void *in_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */,
  215. const void *in_private_key /* EasyHandshake::PRIVATE_KEY_BYTES */);
  216. // Generate a challenge for the server to answer
  217. bool GenerateChallenge(void *out_challenge /* EasyHandshake::CHALLENGE_BYTES */);
  218. // Process a server answer to our challenge
  219. // Returns false if answer was invalid
  220. bool ProcessAnswer(const void *in_answer /* EasyHandshake::ANSWER_BYTES */,
  221. AuthenticatedEncryption *auth_enc);
  222. // Process a server answer to our challenge and provide a proof of client identity
  223. // Returns false if answer was invalid
  224. bool ProcessAnswerWithIdentity(const void *in_answer /* EasyHandshake::ANSWER_BYTES */,
  225. void *out_identity /* EasyHandshake::IDENTITY_BYTES */,
  226. AuthenticatedEncryption *auth_enc);
  227. };
  228. } // namespace cat
  229. #endif // CAT_EASY_HANDSHAKE_HPP
粤ICP备19079148号