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 <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
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 }