Digest.cc
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00015 #include <cstdio>
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
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 }