wave-crypto.cpp

Go to the documentation of this file.
00001 /*
00002  * wave-crypto.cpp
00003  *
00004  * Copyright (C) 2007-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  * Implementation of simple encryption helper functions.
00032  * See crypto.h
00033  */
00034 
00035 // includes --------------------------------------------------------------------
00036 #include "wave-crypto.h"        // always include our own header file first!
00037 
00038 #ifdef WIN32
00039 // for windows we have to provide our own pre-build OpenSSL binaries + headers
00040 #include "third-party/openssl/openssl/des.h"
00041 #include "third-party/openssl/openssl/rsa.h"
00042 #include "third-party/openssl/openssl/sha.h"
00043 #else   // WIN32
00044 // on Linux, use the current installed version of OpenSSL
00045 #include <openssl/des.h>
00046 #include <openssl/rsa.h>
00047 #include <openssl/sha.h>
00048 #endif  // WIN32
00049 
00050 #include "common/wave_ex.h"
00051 #include "perf/perf.h"
00052 
00053 
00054 namespace crypto {
00055 
00056 
00057 static const int s_keyNumber            = 1536;
00058 static const long s_keyExponent         = 65537;
00059 static const int s_padding              = RSA_PKCS1_OAEP_PADDING;
00060 
00061 static const int32_t s_maxEncodeLength  = 0x007FFFFFF;
00062 
00063 static const int s_bytesPerDESBlock     = 8;
00064 
00065 typedef std::vector<byte_t> byte_vec_t;
00066 
00067 
00068 // interface virtual destructor implementations
00069 RSAPublicKey::~RSAPublicKey(void) throw() { }
00070 RSAKey::~RSAKey(void) throw() { }
00071 DESKey::~DESKey(void) throw() { }
00072 
00073 
00074 static char s_base64encode[65] =
00075         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
00076 
00077 static int s_base64decode[128];
00078 
00079 
00080 ////////////////////////////////////////////////////////////////////////////////
00081 //
00082 //      static helper methods
00083 //
00084 ////////////////////////////////////////////////////////////////////////////////
00085 
00086 static void
00087 initializeDecoding
00088 (
00089 void
00090 )
00091 throw()
00092 {
00093         for (int i = 0; i < 128; ++i) {
00094                 s_base64decode[i] = -1;
00095         }
00096         for (int i = 0; i < 26; ++i) {
00097                 s_base64decode['A' + i] = i;
00098                 s_base64decode['a' + i] = i + 26;
00099         }
00100         for (int i = 0; i < 10; ++i) {
00101                 s_base64decode['0' + i] = i + 52;
00102         }
00103         s_base64decode['-' + 0] = 62;
00104         s_base64decode['_' + 0] = 63;
00105 }
00106 
00107 
00108 
00109 static void
00110 encodeInt32
00111 (
00112 IO std::string& out,
00113 IN int32_t l
00114 )
00115 {
00116         ASSERT(l >= 0 && l < s_maxEncodeLength, "bad l: %ld", (long) l);
00117 
00118         // base64 these 3 bytes into 4 characters
00119         char buff[4];
00120         for (int i = 0; i < 4; ++i) {
00121                 int val = l % 64;
00122                 l = l / 64;
00123                 buff[i] = s_base64encode[val];
00124         }
00125 
00126         for (int i = 3; i >= 0; --i) {
00127                 out += buff[i];
00128         }
00129 }
00130 
00131 
00132 
00133 static int32_t
00134 decodeInt32
00135 (
00136 IN const char * p
00137 )
00138 {
00139         int32_t l = 0;
00140         for (int i = 0; i < 4; ++i, ++p) {
00141                 l = 64 * l;
00142                 l += s_base64decode[(int) *p];
00143         }
00144         return l;
00145 }
00146 
00147 
00148 
00149 /*
00150 static void
00151 dumpDCB
00152 (
00153 IN const char * title,
00154 IN const_DES_cblock * pdcb
00155 )
00156 {
00157         ASSERT(title, "null");
00158         ASSERT(pdcb, "null");
00159 
00160         DPRINTF("DES cblock: %s", title);
00161         for (int i = 0; i < s_bytesPerDESBlock; ++i) {
00162                 byte_t b = (*pdcb)[i];
00163                 char c = '?';
00164                 if (b > 'A' && b < 'z')
00165                         c = b;
00166                 DPRINTF("  byte[%d] = %3d ('%c')", i, b, c);
00167         }
00168 }
00169 */
00170 
00171 
00172 
00173 static long
00174 symmetricEncrypt
00175 (
00176 IN const byte_t * input,
00177 IN long bytes,
00178 IN DES_key_schedule * ks,
00179 IN int flag,
00180 OUT byte_vec_t& output
00181 )
00182 {
00183         ASSERT(input, "null");
00184         ASSERT(bytes > 0, "bad bytes: %ld", bytes);
00185         ASSERT(ks, "null");
00186         output.clear();
00187 
00188         // loop through input in N-byte blocks
00189         int remainder = bytes % s_bytesPerDESBlock;
00190         int nBlocks = bytes / s_bytesPerDESBlock;
00191 
00192         long output_size = ((nBlocks + 1) * s_bytesPerDESBlock) + 1;
00193         output.resize(output_size);
00194 
00195         long output_bytes = 0;
00196         byte_t * b = &output[0];
00197         DES_cblock in_dcb;
00198         DES_cblock out_dcb;
00199         const byte_t * p = input;
00200         for (int i = 0; i < nBlocks; ++i, p += s_bytesPerDESBlock) {
00201                 // encrypt this block
00202                 DES_ecb_encrypt((const_DES_cblock *) p, &out_dcb, ks, flag);
00203                 //dumpDCB("output", &out_dcb);
00204 
00205                 // copy
00206                 memcpy(b, out_dcb, s_bytesPerDESBlock);
00207                 b += s_bytesPerDESBlock;
00208                 output_bytes += s_bytesPerDESBlock;
00209         }
00210 
00211         // final block
00212         if (remainder) {
00213                 byte_t * q = (byte_t *) in_dcb;
00214                 memcpy(q, p, remainder);
00215                 memset(q + remainder, 0, s_bytesPerDESBlock - remainder);
00216 //              dumpDCB("input", &in_dcb);
00217                 DES_ecb_encrypt(&in_dcb, &out_dcb, ks, flag);
00218                 memcpy(b, out_dcb, s_bytesPerDESBlock);
00219 //              dumpDCB("output", &out_dcb);
00220                 output_bytes += s_bytesPerDESBlock;
00221         }
00222 
00223         return output_bytes;
00224 }
00225 
00226 
00227 
00228 ////////////////////////////////////////////////////////////////////////////////
00229 //
00230 //      PublicKey -- class that implements the RSAPublicKey interface
00231 //
00232 ////////////////////////////////////////////////////////////////////////////////
00233 
00234 class PublicKey : public RSAPublicKey {
00235 public:
00236         PublicKey(void) throw();
00237         ~PublicKey(void) throw();
00238 
00239         // public class methods ------------------------------------------------
00240         void initialize(IN const char * serialized);
00241         void initialize(IN RSA * rsa);
00242 
00243         // crypto::PublicRSAKey class interface methods ------------------------
00244         std::string serialize(void);
00245         std::string encrypt(IN const char * plaintext);
00246 
00247 private:
00248         // private member data -------------------------------------------------
00249         RSA *           m_rsa;
00250 };
00251 
00252 
00253 
00254 PublicKey::PublicKey
00255 (
00256 void
00257 )
00258 throw()
00259 {
00260         m_rsa = NULL;
00261 }
00262 
00263 
00264 PublicKey::~PublicKey
00265 (
00266 void
00267 )
00268 throw()
00269 {
00270         if (m_rsa) {
00271                 RSA_free(m_rsa);
00272         }
00273 }
00274 
00275 
00276 
00277 void
00278 PublicKey::initialize
00279 (
00280 IN const char * serialized
00281 )
00282 {
00283         ASSERT(serialized, "null");
00284 
00285 //      DPRINTF("SERIALIZED: %s", serialized);
00286 
00287         // create empty key
00288         m_rsa = RSA_new();
00289         ASSERT(m_rsa, "failed to create empty RSA key");
00290         ASSERT(!m_rsa->n, "already have n?");
00291         ASSERT(!m_rsa->e, "already have e?");
00292 
00293         // attempt to extract N and E
00294         // (see PublicKey::serialize below for format, basically "n:e")
00295         const int buffsize = 1024;
00296         char buffer[buffsize];
00297         const char * s = strstr(serialized, ":");
00298         if (!s) {
00299                 WAVE_EX(wex);
00300                 wex << "Malformed serialized key";
00301         }
00302         int iN = s - serialized;
00303         if (iN < 1 || iN >= buffsize) {
00304                 WAVE_EX(wex);
00305                 wex << "Malformed serialized key";
00306         }
00307         strncpy(buffer, serialized, iN);
00308         buffer[iN] = 0;
00309 //      DPRINTF("N = %s", buffer);
00310         BN_hex2bn(&m_rsa->n, buffer);
00311 
00312         serialized += iN + 1;
00313         iN = strlen(serialized);
00314         if (iN < 1 || iN >= buffsize) {
00315                 WAVE_EX(wex);
00316                 wex << "Malformed serialized key";
00317         }
00318         strcpy(buffer, serialized);
00319 //      DPRINTF("e = %s", buffer);
00320         BN_hex2bn(&m_rsa->e, buffer);
00321 }
00322 
00323 
00324 
00325 void
00326 PublicKey::initialize
00327 (
00328 IN RSA * rsa
00329 )
00330 {
00331         ASSERT(rsa, "null");
00332         ASSERT(!m_rsa, "already have a key?");
00333         m_rsa = rsa;
00334 }
00335 
00336 
00337 
00338 std::string
00339 PublicKey::serialize
00340 (
00341 void
00342 )
00343 {
00344         std::string public_key;
00345 
00346         // WOW the RSA libraries SUCK
00347         // there is NO mechanism for getting/serializing the public key
00348         // of an RSA key.  Somehow they expect you to magically extract the
00349         // public bits of the key (!!??).  At the moment I don't have internet
00350         // access, so I'm basing this on the man documentation.  But it is
00351         // amazingly useless.
00352 
00353         // So I have rolled my OWN public key serialization.  Hopefully this
00354         // can be replaced by the real solution
00355         ASSERT(m_rsa, "null");
00356         ASSERT(m_rsa->n, "null");
00357         ASSERT(m_rsa->e, "null");
00358 
00359         char * n = BN_bn2hex(m_rsa->n);         // must be free()'d!
00360         char * e = BN_bn2hex(m_rsa->e);         // must be free()'d!
00361 
00362 //      DPRINTF("n = '%s'", n);
00363 //      DPRINTF("e = '%s'", e);
00364 
00365         public_key += n;
00366         public_key += ":";
00367         public_key += e;
00368 
00369         OPENSSL_free(n);
00370         OPENSSL_free(e);
00371 
00372         // that's it!
00373         return public_key;
00374 }
00375 
00376 
00377 
00378 std::string
00379 PublicKey::encrypt
00380 (
00381 IN const char * plaintext
00382 )
00383 {
00384         perf::Timer timer("crypto::RSAPublicKey::encrypt");
00385         ASSERT(m_rsa, "null");
00386         ASSERT(plaintext, "null");
00387 
00388         long bytes = strlen(plaintext);
00389 
00390         // construct array
00391         int rbytes = RSA_size(m_rsa);
00392 //      DPRINTF("encryption requires %d bytes", rbytes);
00393         ASSERT(bytes > 0, "bad byte count? %d", rbytes);
00394 
00395         std::vector<byte_t> out;
00396         out.resize(rbytes + 1);
00397 
00398         int ebytes = RSA_public_encrypt(bytes, (byte_t *) plaintext,
00399             &out[0], m_rsa, s_padding);
00400 
00401 //      DPRINTF("Encrypted %ld bytes, resulted in %d bytes",
00402 //          bytes, ebytes);
00403 
00404         if (ebytes < 1) {
00405                 WAVE_EX(wex);
00406                 wex << "Failed public key encryption";
00407         }
00408 
00409         return encodeBase64(&out[0], ebytes);
00410 }
00411 
00412 
00413 
00414 ////////////////////////////////////////////////////////////////////////////////
00415 //
00416 //      Key -- class that implements the RSAKey interface
00417 //
00418 ////////////////////////////////////////////////////////////////////////////////
00419 
00420 class Key : public RSAKey {
00421 public:
00422         Key(void) throw();
00423         ~Key(void) throw();
00424 
00425         // public class methods ------------------------------------------------
00426         void initialize(void);
00427 
00428         // crypto::RSAKey class interface methods ------------------------------
00429         smart_ptr<RSAPublicKey> getPublicKey(void);
00430         std::string decrypt(IN const char * encrypted);
00431 
00432 private:
00433         // private member data -------------------------------------------------
00434         RSA *           m_rsa;
00435 };
00436 
00437 
00438 
00439 Key::Key
00440 (
00441 void
00442 )
00443 throw()
00444 {
00445         m_rsa = NULL;
00446 }
00447 
00448 
00449 
00450 Key::~Key
00451 (
00452 void
00453 )
00454 throw()
00455 {
00456         if (m_rsa) {
00457                 RSA_free(m_rsa);
00458         }
00459 }
00460 
00461 
00462 
00463 void
00464 Key::initialize
00465 (
00466 void
00467 )
00468 {
00469         ASSERT(!m_rsa, "already have a key?");
00470         m_rsa = RSA_generate_key(s_keyNumber, s_keyExponent, NULL, NULL);
00471         ASSERT(m_rsa, "failed to generate RSA key");
00472 }
00473 
00474 
00475 
00476 smart_ptr<RSAPublicKey>
00477 Key::getPublicKey
00478 (
00479 void
00480 )
00481 {
00482         // See previous note.  Basically, RSA libraries suck.
00483         // There is no supported way to extract the public key (!?)
00484         // so I have rolled my own.  Sigh.
00485 
00486         RSA * rsa = RSA_new();
00487         ASSERT(rsa, "failed to create empty RSA key");
00488         ASSERT(!rsa->n, "already have n?");
00489         ASSERT(!rsa->e, "already have e?");
00490 
00491         // copy just the public parts (n and e)
00492         rsa->n = BN_dup(m_rsa->n);
00493         rsa->e = BN_dup(m_rsa->e);
00494         ASSERT(rsa->n, "null");
00495         ASSERT(rsa->e, "null");
00496 
00497         // okay, return public key from that
00498         smart_ptr<PublicKey> pkey = new PublicKey();
00499         ASSERT(pkey, "out of memory");
00500         pkey->initialize(rsa);          // public key takes ownership of rsa
00501         return pkey;
00502 }
00503 
00504 
00505 
00506 std::string
00507 Key::decrypt
00508 (
00509 IN const char * encrypted
00510 )
00511 {
00512         perf::Timer timer("crypto::RSAKey::decrypt");
00513         ASSERT(m_rsa, "null");
00514         ASSERT(encrypted, "null");
00515 
00516         byte_vec_t data;
00517         decodeBase64(encrypted, data);
00518 
00519         int ebytes = data.size();
00520 //      DPRINTF("Decoded string results in %d bytes of data", ebytes);
00521 
00522         byte_vec_t out;
00523         out.resize(RSA_size(m_rsa));
00524 
00525         int bytes = RSA_private_decrypt(ebytes, &data[0],
00526             &out[0], m_rsa, s_padding);
00527 //      DPRINTF("Decryption results in %d bytes", bytes);
00528         if (bytes < 1) {
00529                 WAVE_EX(wex);
00530                 wex << "Failed to decrypt data";
00531         }
00532 
00533         return (const char *) &out[0];
00534 }
00535 
00536 
00537 
00538 ////////////////////////////////////////////////////////////////////////////////
00539 //
00540 //      SymKey - class that implements the DESKey interface
00541 //
00542 ////////////////////////////////////////////////////////////////////////////////
00543 
00544 class SymKey : public DESKey {
00545 public:
00546         SymKey(void) throw();
00547         ~SymKey(void) throw();
00548 
00549         // public class methods ------------------------------------------------
00550         void initialize(void);
00551         void initialize(IN const char * serialized);
00552 
00553         // crypto::DESKey class interface methods -----------------------------
00554         std::string serialize(void);
00555         std::string encrypt(IN const char * plaintext, IN int minSize);
00556         std::string decrypt(IN const char * encrypted);
00557 
00558 private:
00559         // private member data -------------------------------------------------
00560         DES_cblock              m_dcb;
00561         DES_key_schedule        m_sched;
00562 };
00563 
00564 
00565 
00566 SymKey::SymKey
00567 (
00568 void
00569 )
00570 throw()
00571 {
00572 }
00573 
00574 
00575 
00576 SymKey::~SymKey
00577 (
00578 void
00579 )
00580 throw()
00581 {
00582 }
00583 
00584 
00585 
00586 void
00587 SymKey::initialize
00588 (
00589 void
00590 )
00591 {
00592         // see the des documentation ("man DES_random_key")
00593         // have to create a key, then a schedule
00594         DES_random_key(&m_dcb);
00595 
00596         // create schedule
00597         if (DES_set_key_checked(&m_dcb, &m_sched)) {
00598                 WAVE_EX(wex);
00599                 wex << "Failed to create symmetric key (schedule)";
00600         }
00601 
00602 //      dumpDCB("new", &m_dcb);
00603 }
00604 
00605 
00606 
00607 void
00608 SymKey::initialize
00609 (
00610 IN const char * serialized
00611 )
00612 {
00613         ASSERT(serialized, "null");
00614 
00615         byte_vec_t data;
00616         decodeBase64(serialized, data);
00617         if (s_bytesPerDESBlock != (int) data.size()) {
00618                 WAVE_EX(wex);
00619                 wex << "Improperly encoded DES key";
00620         }
00621 
00622         memcpy(m_dcb, &data[0], s_bytesPerDESBlock);
00623         if (DES_set_key_checked(&m_dcb, &m_sched)) {
00624                 WAVE_EX(wex);
00625                 wex << "Failed to create symmetric key (schedule)";
00626         }
00627 
00628 //      dumpDCB("remote", &m_dcb);
00629 }
00630 
00631 
00632 
00633 std::string
00634 SymKey::serialize
00635 (
00636 void
00637 )
00638 {
00639         const byte_t * b = (const byte_t *) m_dcb;
00640 
00641         return encodeBase64(b, s_bytesPerDESBlock);
00642 }
00643 
00644 
00645 
00646 std::string
00647 SymKey::encrypt
00648 (
00649 IN const char * plaintext,
00650 IN int minSize
00651 )
00652 {
00653         perf::Timer timer("crypto::DESKey::encrypt");
00654         ASSERT(plaintext, "null");
00655         long bytes = strlen(plaintext);
00656         ASSERT(bytes >= 0, "Bad bytes: %ld", bytes);
00657 
00658         //DPRINTF("Encrypting '%s'", plaintext);
00659 
00660         // pad if necessary
00661         std::string base;
00662         int nPad = minSize - bytes;
00663         if (minSize > 0 && nPad > 0) {
00664                 for (int i = 0; i < nPad; ++i) {
00665                         base += 'a' + (rand() % 26);
00666                 }
00667                 bytes += nPad;
00668         }
00669         base += ':';
00670         bytes += 1;             // account for colon
00671         base += plaintext;
00672 
00673         //DPRINTF("  '%s'", base.c_str());
00674         //DPRINTF("  %ld bytes", bytes);
00675 
00676         // encrypt
00677         byte_vec_t raw;
00678         long obytes = symmetricEncrypt((const byte_t *) base.c_str(), bytes,
00679             &m_sched, DES_ENCRYPT, raw);
00680         //DPRINTF("  %ld output bytes", obytes);
00681 
00682         // convert
00683         return encodeBase64(&raw[0], obytes);
00684 }
00685 
00686 
00687 
00688 std::string
00689 SymKey::decrypt
00690 (
00691 IN const char * encrypted
00692 )
00693 {
00694         perf::Timer timer("crypto::DESKey::decrypt");
00695         ASSERT(encrypted, "null");
00696 
00697         //DPRINTF("Decrypting '%s'", encrypted);
00698 
00699         // decode first
00700         byte_vec_t raw;
00701         decodeBase64(encrypted, raw);
00702 
00703         long bytes = raw.size();
00704         ASSERT(bytes > 0, "Bad bytes: %ld", bytes);
00705         //DPRINTF("  Found %ld bytes", bytes);
00706 
00707         // decrypt
00708         byte_vec_t output;
00709         symmetricEncrypt(&raw[0], bytes, &m_sched, DES_DECRYPT,
00710             output);
00711         output.push_back(0);    // null-terminate
00712 
00713         // skip padding
00714         const char * p = (const char *) &output[0];
00715         //DPRINTF("  '%s'", p);
00716         while (*p && *p != ':') { ++p; }
00717         if (!*p) {
00718                 WAVE_EX(wex);
00719                 wex << "Improperly encrypted string?";
00720         }
00721         ++p;    // skip colon
00722         //DPRINTF("  '%s'", p);
00723 
00724         // all done
00725         return p;
00726 }
00727 
00728 
00729 
00730 ////////////////////////////////////////////////////////////////////////////////
00731 //
00732 //      public API
00733 //
00734 ////////////////////////////////////////////////////////////////////////////////
00735 
00736 smart_ptr<RSAPublicKey>
00737 RSAPublicKey::create
00738 (
00739 IN const char * serialized
00740 )
00741 {
00742         perf::Timer timer("crypto::RSAPublicKey::create");
00743 
00744         smart_ptr<PublicKey> local = new PublicKey;
00745         ASSERT(local, "out of memory");
00746 
00747         local->initialize(serialized);
00748 
00749         return local;
00750 }
00751 
00752 
00753 
00754 smart_ptr<RSAKey>
00755 RSAKey::create
00756 (
00757 void
00758 )
00759 {
00760         perf::Timer timer("crypto::RSAKey::create");
00761 
00762         smart_ptr<Key> local = new Key;
00763         ASSERT(local, "out of memory");
00764 
00765         local->initialize();
00766 
00767         return local;
00768 }
00769 
00770 
00771 
00772 smart_ptr<DESKey>
00773 DESKey::create
00774 (
00775 void
00776 )
00777 {
00778         perf::Timer timer("crypto::DESKey::create");
00779 
00780         smart_ptr<SymKey> local = new SymKey;
00781         ASSERT(local, "out of memory");
00782 
00783         local->initialize();
00784 
00785         return local;
00786 }
00787 
00788 
00789 
00790 smart_ptr<DESKey>
00791 DESKey::create
00792 (
00793 IN const char * serialized
00794 )
00795 {
00796         smart_ptr<SymKey> local = new SymKey;
00797         ASSERT(local, "out of memory");
00798         local->initialize(serialized);
00799         return local;
00800 }
00801 
00802 
00803 
00804 std::string
00805 getSHA1
00806 (
00807 IN const char * data
00808 )
00809 {
00810         perf::Timer timer("crypto::getSHA1");
00811         ASSERT(data, "null");
00812 
00813         const int bufSize = SHA_DIGEST_LENGTH;
00814         byte_t buffer[bufSize];
00815         int length = strlen(data);
00816 
00817         SHA1((const unsigned char *) data, length, buffer);
00818         return encodeBase64(buffer, SHA_DIGEST_LENGTH, false);
00819 }
00820 
00821 
00822 
00823 std::string
00824 encodeBase64
00825 (
00826 IN const byte_t * data,
00827 IN long bytes,
00828 IN bool encodeLength
00829 )
00830 {
00831         perf::Timer timer("crypto::encodeBase64");
00832         ASSERT(data, "null");
00833         ASSERT(bytes > 0, "bad bytes: %ld", bytes);
00834         if (bytes >= s_maxEncodeLength) {
00835                 WAVE_EX(wex);
00836                 wex << "Cannot encode " << bytes << " bytes.";
00837                 wex << "  Max encode length is " << s_maxEncodeLength;
00838         }
00839 
00840         // uses a simple base64 encoding
00841         // uses "modified base64" so it is not necessary to URL encode
00842         // see http://en.wikipedia.org/wiki/Base64
00843 
00844         std::string out;
00845 
00846         // if you don't encode the length, it can't be decoded!
00847         if (encodeLength) {
00848                 // DPRINTF("Encoding %ld bytes", bytes);
00849                 encodeInt32(out, bytes);
00850         }
00851 
00852         char buf[4];
00853         buf[3] = 0;     // most significant byte is empty
00854         const byte_t * p = data;
00855         while (bytes > 0) {
00856                 // walk through data in chunks of 3 bytes
00857                 // pad with last valid byte if necessary
00858                 for (int i = 0; i < 3; ++i, --bytes) {
00859                         buf[i] = *p;
00860                         if (bytes > 1) {
00861                                 ++p;
00862                         }
00863                 }
00864 
00865                 int32_t * pl = (int32_t *) &buf;
00866                 int32_t l = *pl;
00867                 ASSERT(l >= 0, "Bad l: %ld", (long) l);
00868 //              DPRINTF("l = 0x%08lx", l);
00869                 encodeInt32(out, l);
00870         }
00871 //      DPRINTF("out: %s", out.c_str());
00872         return out;
00873 }
00874 
00875 
00876 
00877 void
00878 decodeBase64
00879 (
00880 IN const char * encoded,
00881 OUT byte_vec_t& data
00882 )
00883 {
00884         perf::Timer timer("crypto::decodeBase64");
00885         data.clear();
00886 
00887         int N = strlen(encoded);
00888         if (N % 4) {
00889                 WAVE_EX(wex);
00890                 wex << "Improperly encoded data (bad length)";
00891         }
00892 
00893         static bool s_init = false;
00894         if (!s_init) {
00895                 initializeDecoding();
00896                 s_init = true;
00897         }
00898 
00899         const char * p = encoded;
00900         int32_t bytes = decodeInt32(p);
00901         // DPRINTF("Decoding %ld bytes", bytes);
00902         p += 4;
00903 
00904         // decrypt 4 characters at a time, populate 3 bytes
00905         for (; N > 0; N -= 4) {
00906 
00907                 int32_t l = decodeInt32(p);
00908                 p += 4;
00909                 byte_t * pb = (byte_t *) &l;
00910                 for (int i = 0; i < 3; ++i ) {
00911                         if (bytes > 0) {
00912                                 data.push_back(pb[i]);
00913                                 bytes--;
00914                         }
00915                 }
00916         }
00917         // DPRINTF("  Decoded %d bytes", data.size());
00918 }
00919 
00920 
00921 
00922 };      // crypto namespace
00923