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