libdigidocpp
Digest.cpp
Go to the documentation of this file.
1 /*
2  * libdigidocpp
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  */
19 
20 #include <openssl/err.h>
21 #include <openssl/objects.h>
22 #include <openssl/sha.h>
23 
24 #include "../log.h"
25 #include "../Conf.h"
26 #include "Digest.h"
27 
28 namespace digidoc
29 {
31 {
32 public:
34 
35  union {
36  SHA_CTX sha1;
37  SHA256_CTX sha256;
38  SHA512_CTX sha512;
39  };
40  int method;
41  std::vector<unsigned char> digest;
42 };
43 }
44 
51  : d( new DigestPrivate )
52 {
53  d->method = toMethod(Conf::getInstance()->getDigestUri());
54  reset();
55 }
56 
64  : d( new DigestPrivate )
65 {
66  switch(method)
67  {
68  case NID_sha1:
69  case NID_sha224:
70  case NID_sha256:
71  case NID_sha384:
72  case NID_sha512:
73  d->method = method;
74  reset();
75  break;
76  default:
77  THROW_IOEXCEPTION("Digest method '%s' is not supported.", OBJ_nid2sn(method));
78  }
79 }
80 
87 digidoc::Digest::Digest(const std::string &methodUri) throw(IOException)
88  : d( new DigestPrivate )
89 {
90  d->method = toMethod(methodUri);
91  reset();
92 }
93 
98 {
99  delete d;
100 }
101 
102 
110 void digidoc::Digest::update(const std::vector<unsigned char> &data) throw(IOException)
111 {
112  update(&data[0], (unsigned int)data.size());
113 }
114 
119 {
120  return d->method;
121 }
122 
126 std::string digidoc::Digest::getName() const
127 {
128  return OBJ_nid2sn(d->method);
129 }
130 
134 unsigned int digidoc::Digest::getSize() const
135 {
136  switch(d->method)
137  {
138  case NID_sha1: return SHA_DIGEST_LENGTH;
139  case NID_sha224: return SHA224_DIGEST_LENGTH;
140  case NID_sha256: return SHA256_DIGEST_LENGTH;
141  case NID_sha384: return SHA384_DIGEST_LENGTH;
142  case NID_sha512: return SHA512_DIGEST_LENGTH;
143  default: return 0;
144  }
145 }
146 
151 std::string digidoc::Digest::getUri() const
152 {
153  switch(d->method)
154  {
155  case NID_sha1: return URI_SHA1;
156  case NID_sha224: return URI_SHA224;
157  case NID_sha256: return URI_SHA256;
158  case NID_sha384: return URI_SHA384;
159  case NID_sha512: return URI_SHA512;
160  default: return "";
161  }
162 }
163 
168 {
169  int result = 1;
170  switch(d->method)
171  {
172  case NID_sha1: result = SHA1_Init(&d->sha1); break;
173  case NID_sha224: result = SHA224_Init(&d->sha256); break;
174  case NID_sha256: result = SHA256_Init(&d->sha256); break;
175  case NID_sha384: result = SHA384_Init(&d->sha512); break;
176  case NID_sha512: result = SHA512_Init(&d->sha512); break;
177  default: break;
178  }
179  d->digest.clear();
180  if(result != 1)
181  THROW_IOEXCEPTION("Failed to initialize %s digest calculator: %s", getName().c_str(), ERR_reason_error_string(ERR_get_error()));
182 }
183 
197 int digidoc::Digest::toMethod(const std::string &methodUri) throw(IOException)
198 {
199  if ( methodUri == URI_SHA1 || methodUri == URI_RSA_SHA1 ) return NID_sha1;
200  if ( methodUri == URI_SHA224 || methodUri == URI_RSA_SHA224 ) return NID_sha224;
201  if ( methodUri == URI_SHA256 || methodUri == URI_RSA_SHA256 ) return NID_sha256;
202  if ( methodUri == URI_SHA384 || methodUri == URI_RSA_SHA384 ) return NID_sha384;
203  if ( methodUri == URI_SHA512 || methodUri == URI_RSA_SHA512 ) return NID_sha512;
204  THROW_IOEXCEPTION( "Digest method URI '%s' is not supported.", methodUri.c_str() );
205  return 0;
206 }
207 
218 bool digidoc::Digest::isSupported(const std::string &methodUri)
219 {
220  try
221  {
222  toMethod(methodUri);
223  return true;
224  }
225  catch (IOException& )
226  {
227  return false;
228  }
229 }
230 
240 void digidoc::Digest::update(const unsigned char *data, unsigned long length) throw(IOException)
241 {
242  if(data == NULL)
243  THROW_IOEXCEPTION("Can not update digest value from NULL pointer.");
244 
245  if(!d->digest.empty())
246  THROW_IOEXCEPTION("Digest is already finalized, can not update it.");
247 
248  int result = 1;
249  switch(d->method)
250  {
251  case NID_sha1: result = SHA1_Update(&d->sha1, data, length); break;
252  case NID_sha224: result = SHA224_Update(&d->sha256, data, length); break;
253  case NID_sha256: result = SHA256_Update(&d->sha256, data, length); break;
254  case NID_sha384: result = SHA384_Update(&d->sha512, data, length); break;
255  case NID_sha512: result = SHA512_Update(&d->sha512, data, length); break;
256  default: break;
257  }
258  if(result != 1)
259  THROW_IOEXCEPTION("Failed to update %s digest value: %s", getName().c_str(), ERR_reason_error_string(ERR_get_error()));
260 }
261 
269 std::vector<unsigned char> digidoc::Digest::getDigest() throw(IOException)
270 {
271  // If digest is already calculated return it.
272  if(!d->digest.empty())
273  return d->digest;
274 
275  int result = 1;
276  unsigned char *buf = new unsigned char[getSize()];
277  switch(d->method)
278  {
279  case NID_sha1: result = SHA1_Final(buf, &d->sha1); break;
280  case NID_sha224: result = SHA224_Final(buf, &d->sha256); break;
281  case NID_sha256: result = SHA256_Final(buf, &d->sha256); break;
282  case NID_sha384: result = SHA384_Final(buf, &d->sha512); break;
283  case NID_sha512: result = SHA512_Final(buf, &d->sha512); break;
284  default:
285  break;
286  }
287  if(result != 1)
288  {
289  delete[] buf;
290  THROW_IOEXCEPTION("Failed to create %s digest: %s", getName().c_str(), ERR_reason_error_string(ERR_get_error()));
291  }
292 
293  for(unsigned int i = 0; i < getSize(); i++)
294  d->digest.push_back(buf[i]);
295  delete[] buf;
296  return d->digest;
297 }