Digest.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00015 #include <cstdio> // snprintf
00016 #include <openssl/evp.h>
00017 #include <string>
00018 
00019 #include <iostream>
00020 
00021 #ifdef DIGEST_TESTSUITE
00022 #include <fstream>
00023 #endif
00024 
00025 #include "zypp/Digest.h"
00026 
00027 namespace zypp {
00028 
00029     bool DigestReport::askUserToAcceptNoDigest( const zypp::Pathname &file )
00030     { return true; }
00031 
00032     bool DigestReport::askUserToAccepUnknownDigest( const Pathname &file, const std::string &name ) 
00033     { return true; }
00034 
00035     bool DigestReport::askUserToAcceptWrongDigest( const Pathname &file, const std::string &requested, const std::string &found ) 
00036     { return true; }
00037 
00038 
00039     // private data
00040     class Digest::P
00041     {
00042         P(const P& p);
00043         const P& operator=(const P& p);
00044       public:
00045         P();
00046         ~P();
00047     
00048         EVP_MD_CTX mdctx;
00049     
00050         const EVP_MD *md;
00051         unsigned char md_value[EVP_MAX_MD_SIZE];
00052         unsigned md_len;
00053     
00054         bool initialized : 1;
00055         bool finalized : 1;
00056         static bool openssl_digests_added;
00057     
00058         std::string name;
00059     
00060         inline bool maybeInit();
00061         inline void cleanup();
00062     };
00063     
00064     
00065     using namespace std;
00066     
00067     bool Digest::P::openssl_digests_added = false;
00068     
00069     Digest::P::P() :
00070       md(NULL),
00071       initialized(false),
00072       finalized(false)
00073     {
00074     }
00075     
00076     Digest::P::~P()
00077     {
00078       cleanup();
00079     }
00080     
00081     bool Digest::P::maybeInit()
00082     {
00083       if(!openssl_digests_added)
00084       {
00085         OpenSSL_add_all_digests();
00086         openssl_digests_added = true;
00087       }
00088     
00089       if(!initialized)
00090       {
00091         md = EVP_get_digestbyname(name.c_str());
00092         if(!md)
00093             return false;
00094     
00095         EVP_MD_CTX_init(&mdctx);
00096     
00097         if(!EVP_DigestInit_ex(&mdctx, md, NULL))
00098             return false;
00099     
00100         md_len = 0;
00101         ::memset(md_value, 0, sizeof(md_value));
00102         initialized = true;
00103       }
00104     
00105       return true;
00106     }
00107     
00108     void Digest::P::cleanup()
00109     {
00110       if(initialized)
00111       {
00112         EVP_MD_CTX_cleanup(&mdctx);
00113         initialized = false;
00114       }
00115     }
00116     
00117     Digest::Digest() : _dp(new P())
00118     {
00119     }
00120     
00121     Digest::~Digest()
00122     {
00123       delete _dp;
00124     }
00125     
00126     bool Digest::create(const std::string& name)
00127     {
00128       if(name.empty()) return false;
00129     
00130       if(_dp->initialized)
00131         _dp->cleanup();
00132     
00133       _dp->name = name;
00134     
00135       return _dp->maybeInit();
00136     }
00137     
00138     const std::string& Digest::name()
00139     {
00140       return _dp->name;
00141     }
00142     
00143     std::string Digest::digest()
00144     {
00145       if(!_dp->maybeInit())
00146         return false;
00147     
00148       if(!_dp->finalized)
00149       {
00150         if(!EVP_DigestFinal_ex(&_dp->mdctx, _dp->md_value, &_dp->md_len))
00151             return false;
00152     
00153         _dp->finalized = true;
00154       }
00155     
00156       char mdtxt[_dp->md_len*2 + 1];
00157       mdtxt[_dp->md_len*2] = '\0';
00158     
00159       for(unsigned i = 0; i < _dp->md_len; ++i)
00160       {
00161         ::snprintf(mdtxt + i*2, 3, "%02hhx", _dp->md_value[i]);
00162       }
00163     
00164       return std::string(mdtxt);
00165     }
00166     
00167     bool Digest::update(const char* bytes, size_t len)
00168     {
00169       if(!bytes)
00170       {
00171         return false;
00172       }
00173     
00174       if(!_dp->maybeInit())
00175         return false;
00176     
00177       if(_dp->finalized)
00178       {
00179         _dp->cleanup();
00180         if(!_dp->maybeInit())
00181             return false;
00182     
00183       }
00184       if(!EVP_DigestUpdate(&_dp->mdctx, reinterpret_cast<const unsigned char*>(bytes), len))
00185         return false;
00186     
00187       return true;
00188     }
00189     
00190     std::string Digest::digest(const std::string& name, std::istream& is, size_t bufsize)
00191     {
00192       if(name.empty() || !is)
00193         return string();
00194     
00195       char buf[bufsize];
00196       size_t num;
00197     
00198       Digest digest;
00199       if(!digest.create(name))
00200         return string();
00201     
00202       while(is.good())
00203       {
00204         for(num = 0; num < bufsize && is.get(buf[num]).good(); ++num);
00205     
00206         if(num && !digest.update(buf, num))
00207             return string();
00208       }
00209     
00210       return digest.digest();
00211     }
00212     
00213 #ifdef DIGEST_TESTSUITE
00214     int main(int argc, char *argv[])
00215     {
00216       bool openssl = false;
00217       unsigned argpos = 1;
00218     
00219       if(argc > 1 && string(argv[argpos]) == "--openssl")
00220       {
00221         openssl = true;
00222         ++argpos;
00223       }
00224     
00225       if(argc - argpos < 2)
00226       {
00227         cerr << "Usage: " << argv[0] << " <DIGESTNAME> <FILE>" << endl;
00228         return 1;
00229       }
00230     
00231       const char* digestname = argv[argpos++];
00232       const char* fn = argv[argpos++];
00233     
00234       ifstream file(fn);
00235     
00236       string digest = Digest::digest(digestname, file);
00237     
00238       if(openssl)
00239         cout << digestname << "(" << fn << ")= " << digest << endl;
00240       else
00241         cout << digest << "  " << fn << endl;
00242     
00243       return 0;
00244     }
00245 #endif
00246     
00247 } // namespace zypp

Generated on Thu Jul 6 00:07:20 2006 for zypp by  doxygen 1.4.6