00001 /* 00002 * wave-crypto.h 00003 * 00004 * Copyright (C) 2007,2009,2011 Thomas A. Vaughan 00005 * All rights reserved. 00006 * 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * * Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * * Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * * Neither the name of the <organization> nor the 00016 * names of its contributors may be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY 00020 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00022 * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY 00023 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00026 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 * 00030 * 00031 * Simple API for cryptography. These are helper functions layered on top of 00032 * the RSA APIs. 00033 */ 00034 00035 #ifndef WAVEPACKET_CRYPTO_H__ 00036 #define WAVEPACKET_CRYPTO_H__ 00037 00038 // includes -------------------------------------------------------------------- 00039 #include "common/common.h" 00040 #include "threadsafe/smart_ptr.h" 00041 00042 00043 namespace crypto { 00044 00045 /// \ingroup lib 00046 /*@{*/ 00047 00048 //////////////////////////////////////////////////////////////////////////////// 00049 /// 00050 /// \defgroup crypto Cryptography Libraries 00051 /// 00052 /// Provides basic encryption support. 00053 /// 00054 /// Simple objects to abstract: 00055 /// - RSA Keys (public/private pair) 00056 /// - RSA Public Key (just the public key from an RSA pair) 00057 /// - DES Key (used for fast symmetric encryption) 00058 /// 00059 /// These are optimized for usability (and correctness) over efficiency! 00060 /// If you are 00061 /// doing hardcore crypto you should use the RSA APIs directly. For 00062 /// instance, these APIs aren't clever about memory management, they 00063 /// allocate and de-allocate as needed. 00064 /// 00065 /// Encrypted strings have simple encoding applied so they are safe to 00066 /// pass around as strings (no null characters and should be MIME-friendly). 00067 /// Decryption routines assume the string is encoded and they will decode 00068 /// first. In theory these could be split out but in practice I expect 00069 /// most people to just treat the encrypted strings opaquely anyway. 00070 /// 00071 /// These APIs are best for applications that are using crypto tactically 00072 /// in just a few rarely-used places. 00073 /// 00074 /// Seed the randomizer before calling any crypto APIs 00075 /// 00076 /// Because the RSA libraries are confusing (or at least, I wasn't clever 00077 /// enough to determine if there was a standard way of serializing keys or 00078 /// not), 00079 /// I don't think the results 00080 /// of these can be mixed with other libraries. That is, you can't take 00081 /// the encrypted value from this API and decrypt it using another API. All 00082 /// encryption/decryption must happen using these APIs (although that can 00083 /// happen across processes and machines, etc.). 00084 /// 00085 /// These aren't designed for streaming. These are designed for 00086 /// encryption of small blocks of data (a couple of KB or so at most). 00087 /// These APIs are designed for user-readable null-terminated strings, not 00088 /// arbitrary binary data. 00089 /// 00090 /// Typical usage is to create a DESKey for use in encrypting data, 00091 /// and only use the public/private keys to safely exchange the DES key. 00092 /// 00093 /// Example: 00094 /// 00095 /// Generate RSAKey on host 1: 00096 /// \code 00097 /// smart_ptr<RSAKey> rsa = RSAKey::create(); // expensive! 00098 /// smart_ptr<RSAPublicKey> pubkey = rsa->getPublicKey(); 00099 /// std::string serialized = pubkey->serialize(); 00100 /// 00101 /// // great, now send serialized version of public key to host 2 00102 /// send_string_to("host2", serialized); 00103 /// \endcode 00104 /// 00105 /// Then, on host 2: 00106 /// \code 00107 /// // receive string from remote host 00108 /// std::string serialized = get_string_from("host1"); 00109 /// 00110 /// // deserialize into local version of their public key 00111 /// smart_ptr<RSAPublicKey> pubkey = 00112 /// RSAPublicKey::create(serialized.c_str()); 00113 /// 00114 /// // create a new secret symmetric encryption key 00115 /// smart_ptr<DESKey> secret = DESKey::create(); 00116 /// std::string des_serial = secret->serialize(); 00117 /// 00118 /// // encrypt DES key (secret) with host 1's public key 00119 /// std::string encrypted = pubkey->encrypt(des_serial.c_str()); 00120 /// 00121 /// // send secret to host 1 00122 /// send_string_to("host1", encrypted); 00123 /// \endcode 00124 /// 00125 /// Then, back on host 1: 00126 /// \code 00127 /// // receive encrypted secret from host 2 00128 /// std::string encrypted = get_string_from("host2"); 00129 /// 00130 /// // decrypt using our private key 00131 /// std::string serialized = rsa->decrypt(encrypted.c_str()); 00132 /// 00133 /// // deserialize DES key so we have a local copy 00134 /// smart_ptr<DESKey> secret = DESKey::create(serialized.c_str()); 00135 /// 00136 /// // now I can communicate with host 2 using shared secret key 00137 /// std::string password = secret->encrypt("This is my password!"); 00138 /// send_string_to("host2", password); 00139 /// \endcode 00140 /// 00141 /// Don't get too excited about these, because you are still vulnerable to 00142 /// attack/cracking during the initial handshake phase (how do you trust 00143 /// the machine you are handing your public key to?). But these are 00144 /// intended to make it harder to crack non-critical data, for instance 00145 /// game data where you want to make it more expensive but not necessarily 00146 /// impossible to crack other players' packets. 00147 /// 00148 /// Put another way, the code above is vulnerable to man-in-the-middle 00149 /// attacks but is good protection against passive listeners. 00150 /// 00151 /// Also, someday this library may beef up the handshake process, at which 00152 /// point the other code could be more generally useful and secure. 00153 //////////////////////////////////////////////////////////////////////////////// 00154 /*@{*/ 00155 00156 00157 /// public key suitable for encrypting 00158 /// 00159 /// Get these from a private/public RSAKey or by serializing 00160 /// and deserializing 00161 class RSAPublicKey { 00162 public: 00163 // virtual destructor -------------------------------------------------- 00164 virtual ~RSAPublicKey(void) throw(); 00165 00166 // crypto::RSAPublicKey class interface methods ------------------------ 00167 /// return a serialized (string) version of the public key 00168 virtual std::string serialize(void) = 0; 00169 00170 /// return the given text encrypted with the public key 00171 virtual std::string encrypt(IN const char * plaintext) = 0; 00172 00173 // static factory methods ---------------------------------------------- 00174 /// factory to create public key from serialized (string) version 00175 static smart_ptr<RSAPublicKey> create(IN const char * serialized); 00176 }; 00177 00178 00179 /// private/public key pair. 00180 class RSAKey { 00181 public: 00182 // virtual destructor -------------------------------------------------- 00183 virtual ~RSAKey(void) throw(); 00184 00185 // crypto::RSAKey class interface methods ------------------------------ 00186 /// return the public key for the public/private pair 00187 virtual smart_ptr<RSAPublicKey> getPublicKey(void) = 0; 00188 00189 /// decrypt a string encrypted with the public key, using the private key 00190 virtual std::string decrypt(IN const char * encrypted) = 0; 00191 00192 // static factory methods ---------------------------------------------- 00193 /// create new RSA public/private key pair (note: very expensive!) 00194 static smart_ptr<RSAKey> create(void); 00195 }; 00196 00197 00198 00199 /// fast symmetric encryption 00200 class DESKey { 00201 public: 00202 // virtual destructor -------------------------------------------------- 00203 virtual ~DESKey(void) throw(); 00204 00205 // crypto::DESKey class interface methods ----------------------------- 00206 /// return a serialized (string) version of the DES key 00207 virtual std::string serialize(void) = 0; 00208 00209 /// encrypt the given plaintext string using the DES key 00210 /// (pads if necessary to fill out to minSize) 00211 virtual std::string encrypt(IN const char * plaintext, 00212 IN int minSize) = 0; 00213 00214 /// decrypt the given string using the DES key (returns original plaintext) 00215 virtual std::string decrypt(IN const char * encrypted) = 0; 00216 00217 // static factory methods ---------------------------------------------- 00218 /// create new DES key 00219 static smart_ptr<DESKey> create(void); 00220 00221 /// factory to create DES key from serialized (string) version 00222 static smart_ptr<DESKey> create(IN const char * serialized); 00223 }; 00224 00225 00226 /// quick one-way encryption (SHA1 algorithm, see 00227 /// http://en.wikipedia.org/wiki/SHA-1) 00228 std::string getSHA1(IN const char * data); 00229 00230 00231 /// given binary data, encode into base64 ascii string 00232 std::string encodeBase64(IN const byte_t * data, IN long bytes, 00233 IN bool encodeLength = true); 00234 00235 00236 typedef std::vector<byte_t> vec_byte_t; 00237 00238 /// given base64 ascii string, decode into byte array 00239 void decodeBase64(IN const char * base64, 00240 OUT vec_byte_t& data); 00241 00242 00243 /*@}*/ // end of documentation group 00244 00245 00246 }; // crypto namespace 00247 00248 00249 #endif // WAVEPACKET_CRYPTO_H__ 00250