1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "rtc_base/openssl_digest.h"
12 
13 #include "rtc_base/checks.h"  // RTC_DCHECK, RTC_CHECK
14 #include "rtc_base/openssl.h"
15 
16 namespace rtc {
17 
OpenSSLDigest(const std::string & algorithm)18 OpenSSLDigest::OpenSSLDigest(const std::string& algorithm) {
19   ctx_ = EVP_MD_CTX_new();
20   RTC_CHECK(ctx_ != nullptr);
21   EVP_MD_CTX_init(ctx_);
22   if (GetDigestEVP(algorithm, &md_)) {
23     EVP_DigestInit_ex(ctx_, md_, nullptr);
24   } else {
25     md_ = nullptr;
26   }
27 }
28 
~OpenSSLDigest()29 OpenSSLDigest::~OpenSSLDigest() {
30   EVP_MD_CTX_destroy(ctx_);
31 }
32 
Size() const33 size_t OpenSSLDigest::Size() const {
34   if (!md_) {
35     return 0;
36   }
37   return EVP_MD_size(md_);
38 }
39 
Update(const void * buf,size_t len)40 void OpenSSLDigest::Update(const void* buf, size_t len) {
41   if (!md_) {
42     return;
43   }
44   EVP_DigestUpdate(ctx_, buf, len);
45 }
46 
Finish(void * buf,size_t len)47 size_t OpenSSLDigest::Finish(void* buf, size_t len) {
48   if (!md_ || len < Size()) {
49     return 0;
50   }
51   unsigned int md_len;
52   EVP_DigestFinal_ex(ctx_, static_cast<unsigned char*>(buf), &md_len);
53   EVP_DigestInit_ex(ctx_, md_, nullptr);  // prepare for future Update()s
54   RTC_DCHECK(md_len == Size());
55   return md_len;
56 }
57 
GetDigestEVP(const std::string & algorithm,const EVP_MD ** mdp)58 bool OpenSSLDigest::GetDigestEVP(const std::string& algorithm,
59                                  const EVP_MD** mdp) {
60   const EVP_MD* md;
61   if (algorithm == DIGEST_MD5) {
62     md = EVP_md5();
63   } else if (algorithm == DIGEST_SHA_1) {
64     md = EVP_sha1();
65   } else if (algorithm == DIGEST_SHA_224) {
66     md = EVP_sha224();
67   } else if (algorithm == DIGEST_SHA_256) {
68     md = EVP_sha256();
69   } else if (algorithm == DIGEST_SHA_384) {
70     md = EVP_sha384();
71   } else if (algorithm == DIGEST_SHA_512) {
72     md = EVP_sha512();
73   } else {
74     return false;
75   }
76 
77   // Can't happen
78   RTC_DCHECK(EVP_MD_size(md) >= 16);
79   *mdp = md;
80   return true;
81 }
82 
GetDigestName(const EVP_MD * md,std::string * algorithm)83 bool OpenSSLDigest::GetDigestName(const EVP_MD* md, std::string* algorithm) {
84   RTC_DCHECK(md != nullptr);
85   RTC_DCHECK(algorithm != nullptr);
86 
87   int md_type = EVP_MD_type(md);
88   if (md_type == NID_md5) {
89     *algorithm = DIGEST_MD5;
90   } else if (md_type == NID_sha1) {
91     *algorithm = DIGEST_SHA_1;
92   } else if (md_type == NID_sha224) {
93     *algorithm = DIGEST_SHA_224;
94   } else if (md_type == NID_sha256) {
95     *algorithm = DIGEST_SHA_256;
96   } else if (md_type == NID_sha384) {
97     *algorithm = DIGEST_SHA_384;
98   } else if (md_type == NID_sha512) {
99     *algorithm = DIGEST_SHA_512;
100   } else {
101     algorithm->clear();
102     return false;
103   }
104 
105   return true;
106 }
107 
GetDigestSize(const std::string & algorithm,size_t * length)108 bool OpenSSLDigest::GetDigestSize(const std::string& algorithm,
109                                   size_t* length) {
110   const EVP_MD* md;
111   if (!GetDigestEVP(algorithm, &md))
112     return false;
113 
114   *length = EVP_MD_size(md);
115   return true;
116 }
117 
118 }  // namespace rtc
119