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