libzypp 8.13.6
|
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