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

doxygen