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 }
00125 }
00126
00127 Digest::Digest() : _dp(new P())
00128 {
00129 }
00130
00131 Digest::~Digest()
00132 {
00133 delete _dp;
00134 }
00135
00136 bool Digest::create(const std::string& name)
00137 {
00138 if(name.empty()) return false;
00139
00140 if(_dp->initialized)
00141 _dp->cleanup();
00142
00143 _dp->name = name;
00144
00145 return _dp->maybeInit();
00146 }
00147
00148 const std::string& Digest::name()
00149 {
00150 return _dp->name;
00151 }
00152
00153 std::string Digest::digest()
00154 {
00155 if(!_dp->maybeInit())
00156 return std::string();
00157
00158 if(!_dp->finalized)
00159 {
00160 if(!EVP_DigestFinal_ex(&_dp->mdctx, _dp->md_value, &_dp->md_len))
00161 return std::string();
00162
00163 _dp->finalized = true;
00164 }
00165
00166 char mdtxt[_dp->md_len*2 + 1];
00167 mdtxt[_dp->md_len*2] = '\0';
00168
00169 for(unsigned i = 0; i < _dp->md_len; ++i)
00170 {
00171 ::snprintf(mdtxt + i*2, 3, "%02hhx", _dp->md_value[i]);
00172 }
00173
00174 return std::string(mdtxt);
00175 }
00176
00177 bool Digest::update(const char* bytes, size_t len)
00178 {
00179 if(!bytes)
00180 {
00181 return false;
00182 }
00183
00184 if(!_dp->maybeInit())
00185 return false;
00186
00187 if(_dp->finalized)
00188 {
00189 _dp->cleanup();
00190 if(!_dp->maybeInit())
00191 return false;
00192
00193 }
00194 if(!EVP_DigestUpdate(&_dp->mdctx, reinterpret_cast<const unsigned char*>(bytes), len))
00195 return false;
00196
00197 return true;
00198 }
00199
00200 std::string Digest::digest(const std::string& name, std::istream& is, size_t bufsize)
00201 {
00202 if(name.empty() || !is)
00203 return string();
00204
00205 char buf[bufsize];
00206
00207 Digest digest;
00208 if(!digest.create(name))
00209 return string();
00210
00211
00212 while(is.good())
00213 {
00214 int readed;
00215 is.read(buf, bufsize);
00216 readed = is.gcount();
00217 if(readed && !digest.update(buf, readed))
00218 return string();
00219 }
00220
00221 return digest.digest();
00222 }
00223
00224 std::string Digest::digest( const std::string & name, const std::string & input, size_t bufsize )
00225 {
00226 istringstream is( input );
00227 return digest( name, is, bufsize );
00228 }
00229
00230 #ifdef DIGEST_TESTSUITE
00231 int main(int argc, char *argv[])
00232 {
00233 bool openssl = false;
00234 unsigned argpos = 1;
00235
00236 if(argc > 1 && string(argv[argpos]) == "--openssl")
00237 {
00238 openssl = true;
00239 ++argpos;
00240 }
00241
00242 if(argc - argpos < 2)
00243 {
00244 cerr << "Usage: " << argv[0] << " <DIGESTNAME> <FILE>" << endl;
00245 return 1;
00246 }
00247
00248 const char* digestname = argv[argpos++];
00249 const char* fn = argv[argpos++];
00250
00251 ifstream file(fn);
00252
00253 string digest = Digest::digest(digestname, file);
00254
00255 if(openssl)
00256 cout << digestname << "(" << fn << ")= " << digest << endl;
00257 else
00258 cout << digest << " " << fn << endl;
00259
00260 return 0;
00261 }
00262 #endif
00263
00264 }