libzypp 8.13.6

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         finalized = false;
00125       }
00126     }
00127 
00128     Digest::Digest() : _dp(new P())
00129     {
00130     }
00131 
00132     Digest::~Digest()
00133     {
00134       delete _dp;
00135     }
00136 
00137     bool Digest::create(const std::string& name)
00138     {
00139       if(name.empty()) return false;
00140 
00141       if(_dp->initialized)
00142         _dp->cleanup();
00143 
00144       _dp->name = name;
00145 
00146       return _dp->maybeInit();
00147     }
00148 
00149     const std::string& Digest::name()
00150     {
00151       return _dp->name;
00152     }
00153 
00154     bool Digest::reset()
00155     {
00156       if (!_dp->initialized)
00157         return false;
00158       if(!_dp->finalized)
00159         {
00160           (void)EVP_DigestFinal_ex(&_dp->mdctx, _dp->md_value, &_dp->md_len);
00161           _dp->finalized = true;
00162         }
00163       if(!EVP_DigestInit_ex(&_dp->mdctx, _dp->md, NULL))
00164         return false;
00165       _dp->finalized = false;
00166       return true;
00167     }
00168 
00169     std::string Digest::digest()
00170     {
00171       if(!_dp->maybeInit())
00172         return std::string();
00173 
00174       if(!_dp->finalized)
00175       {
00176         if(!EVP_DigestFinal_ex(&_dp->mdctx, _dp->md_value, &_dp->md_len))
00177             return std::string();
00178 
00179         _dp->finalized = true;
00180       }
00181 
00182       char mdtxt[_dp->md_len*2 + 1];
00183       mdtxt[_dp->md_len*2] = '\0';
00184 
00185       for(unsigned i = 0; i < _dp->md_len; ++i)
00186       {
00187         ::snprintf(mdtxt + i*2, 3, "%02hhx", _dp->md_value[i]);
00188       }
00189 
00190       return std::string(mdtxt);
00191     }
00192 
00193     std::vector<unsigned char> Digest::digestVector()
00194     {
00195       std::vector<unsigned char> r;
00196       if(!_dp->maybeInit())
00197         return r;
00198 
00199       if(!_dp->finalized)
00200       {
00201         if(!EVP_DigestFinal_ex(&_dp->mdctx, _dp->md_value, &_dp->md_len))
00202             return r;
00203         _dp->finalized = true;
00204       }
00205       r.reserve(_dp->md_len);
00206       for(unsigned i = 0; i < _dp->md_len; ++i)
00207         r.push_back(_dp->md_value[i]);
00208       return r;
00209     }
00210 
00211     bool Digest::update(const char* bytes, size_t len)
00212     {
00213       if(!bytes)
00214       {
00215         return false;
00216       }
00217 
00218       if(!_dp->maybeInit())
00219         return false;
00220 
00221       if(_dp->finalized)
00222       {
00223         _dp->cleanup();
00224         if(!_dp->maybeInit())
00225             return false;
00226 
00227       }
00228       if(!EVP_DigestUpdate(&_dp->mdctx, reinterpret_cast<const unsigned char*>(bytes), len))
00229         return false;
00230 
00231       return true;
00232     }
00233 
00234     std::string Digest::digest(const std::string& name, std::istream& is, size_t bufsize)
00235     {
00236       if(name.empty() || !is)
00237         return string();
00238 
00239       char buf[bufsize];
00240 
00241       Digest digest;
00242       if(!digest.create(name))
00243         return string();
00244 
00245 
00246       while(is.good())
00247       {
00248         int readed;
00249         is.read(buf, bufsize);
00250         readed = is.gcount();
00251         if(readed && !digest.update(buf, readed))
00252             return string();
00253       }
00254 
00255       return digest.digest();
00256     }
00257 
00258     std::string Digest::digest( const std::string & name, const std::string & input, size_t bufsize )
00259     {
00260       istringstream is( input );
00261       return digest( name, is, bufsize );
00262     }
00263 
00264 #ifdef DIGEST_TESTSUITE
00265     int main(int argc, char *argv[])
00266     {
00267       bool openssl = false;
00268       unsigned argpos = 1;
00269 
00270       if(argc > 1 && string(argv[argpos]) == "--openssl")
00271       {
00272         openssl = true;
00273         ++argpos;
00274       }
00275 
00276       if(argc - argpos < 2)
00277       {
00278         cerr << "Usage: " << argv[0] << " <DIGESTNAME> <FILE>" << endl;
00279         return 1;
00280       }
00281 
00282       const char* digestname = argv[argpos++];
00283       const char* fn = argv[argpos++];
00284 
00285       ifstream file(fn);
00286 
00287       string digest = Digest::digest(digestname, file);
00288 
00289       if(openssl)
00290         cout << digestname << "(" << fn << ")= " << digest << endl;
00291       else
00292         cout << digest << "  " << fn << endl;
00293 
00294       return 0;
00295     }
00296 #endif
00297 
00298 } // namespace zypp