libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00015 #include <cstdio> // snprintf 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 // private data 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 } // namespace zypp