Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2011 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 "webrtc/base/messagedigest.h"
     12 
     13 #include <string.h>
     14 
     15 #include "webrtc/base/basictypes.h"
     16 #include "webrtc/base/sslconfig.h"
     17 #if SSL_USE_OPENSSL
     18 #include "webrtc/base/openssldigest.h"
     19 #else
     20 #include "webrtc/base/md5digest.h"
     21 #include "webrtc/base/sha1digest.h"
     22 #endif
     23 #include "webrtc/base/scoped_ptr.h"
     24 #include "webrtc/base/stringencode.h"
     25 
     26 namespace rtc {
     27 
     28 // From RFC 4572.
     29 const char DIGEST_MD5[]     = "md5";
     30 const char DIGEST_SHA_1[]   = "sha-1";
     31 const char DIGEST_SHA_224[] = "sha-224";
     32 const char DIGEST_SHA_256[] = "sha-256";
     33 const char DIGEST_SHA_384[] = "sha-384";
     34 const char DIGEST_SHA_512[] = "sha-512";
     35 
     36 static const size_t kBlockSize = 64;  // valid for SHA-256 and down
     37 
     38 MessageDigest* MessageDigestFactory::Create(const std::string& alg) {
     39 #if SSL_USE_OPENSSL
     40   MessageDigest* digest = new OpenSSLDigest(alg);
     41   if (digest->Size() == 0) {  // invalid algorithm
     42     delete digest;
     43     digest = NULL;
     44   }
     45   return digest;
     46 #else
     47   MessageDigest* digest = NULL;
     48   if (alg == DIGEST_MD5) {
     49     digest = new Md5Digest();
     50   } else if (alg == DIGEST_SHA_1) {
     51     digest = new Sha1Digest();
     52   }
     53   return digest;
     54 #endif
     55 }
     56 
     57 bool IsFips180DigestAlgorithm(const std::string& alg) {
     58   // These are the FIPS 180 algorithms.  According to RFC 4572 Section 5,
     59   // "Self-signed certificates (for which legacy certificates are not a
     60   // consideration) MUST use one of the FIPS 180 algorithms (SHA-1,
     61   // SHA-224, SHA-256, SHA-384, or SHA-512) as their signature algorithm,
     62   // and thus also MUST use it to calculate certificate fingerprints."
     63   return alg == DIGEST_SHA_1 ||
     64          alg == DIGEST_SHA_224 ||
     65          alg == DIGEST_SHA_256 ||
     66          alg == DIGEST_SHA_384 ||
     67          alg == DIGEST_SHA_512;
     68 }
     69 
     70 size_t ComputeDigest(MessageDigest* digest, const void* input, size_t in_len,
     71                      void* output, size_t out_len) {
     72   digest->Update(input, in_len);
     73   return digest->Finish(output, out_len);
     74 }
     75 
     76 size_t ComputeDigest(const std::string& alg, const void* input, size_t in_len,
     77                      void* output, size_t out_len) {
     78   scoped_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg));
     79   return (digest) ?
     80       ComputeDigest(digest.get(), input, in_len, output, out_len) :
     81       0;
     82 }
     83 
     84 std::string ComputeDigest(MessageDigest* digest, const std::string& input) {
     85   scoped_ptr<char[]> output(new char[digest->Size()]);
     86   ComputeDigest(digest, input.data(), input.size(),
     87                 output.get(), digest->Size());
     88   return hex_encode(output.get(), digest->Size());
     89 }
     90 
     91 bool ComputeDigest(const std::string& alg, const std::string& input,
     92                    std::string* output) {
     93   scoped_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg));
     94   if (!digest) {
     95     return false;
     96   }
     97   *output = ComputeDigest(digest.get(), input);
     98   return true;
     99 }
    100 
    101 std::string ComputeDigest(const std::string& alg, const std::string& input) {
    102   std::string output;
    103   ComputeDigest(alg, input, &output);
    104   return output;
    105 }
    106 
    107 // Compute a RFC 2104 HMAC: H(K XOR opad, H(K XOR ipad, text))
    108 size_t ComputeHmac(MessageDigest* digest,
    109                    const void* key, size_t key_len,
    110                    const void* input, size_t in_len,
    111                    void* output, size_t out_len) {
    112   // We only handle algorithms with a 64-byte blocksize.
    113   // TODO: Add BlockSize() method to MessageDigest.
    114   size_t block_len = kBlockSize;
    115   if (digest->Size() > 32) {
    116     return 0;
    117   }
    118   // Copy the key to a block-sized buffer to simplify padding.
    119   // If the key is longer than a block, hash it and use the result instead.
    120   scoped_ptr<uint8_t[]> new_key(new uint8_t[block_len]);
    121   if (key_len > block_len) {
    122     ComputeDigest(digest, key, key_len, new_key.get(), block_len);
    123     memset(new_key.get() + digest->Size(), 0, block_len - digest->Size());
    124   } else {
    125     memcpy(new_key.get(), key, key_len);
    126     memset(new_key.get() + key_len, 0, block_len - key_len);
    127   }
    128   // Set up the padding from the key, salting appropriately for each padding.
    129   scoped_ptr<uint8_t[]> o_pad(new uint8_t[block_len]);
    130   scoped_ptr<uint8_t[]> i_pad(new uint8_t[block_len]);
    131   for (size_t i = 0; i < block_len; ++i) {
    132     o_pad[i] = 0x5c ^ new_key[i];
    133     i_pad[i] = 0x36 ^ new_key[i];
    134   }
    135   // Inner hash; hash the inner padding, and then the input buffer.
    136   scoped_ptr<uint8_t[]> inner(new uint8_t[digest->Size()]);
    137   digest->Update(i_pad.get(), block_len);
    138   digest->Update(input, in_len);
    139   digest->Finish(inner.get(), digest->Size());
    140   // Outer hash; hash the outer padding, and then the result of the inner hash.
    141   digest->Update(o_pad.get(), block_len);
    142   digest->Update(inner.get(), digest->Size());
    143   return digest->Finish(output, out_len);
    144 }
    145 
    146 size_t ComputeHmac(const std::string& alg, const void* key, size_t key_len,
    147                    const void* input, size_t in_len,
    148                    void* output, size_t out_len) {
    149   scoped_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg));
    150   if (!digest) {
    151     return 0;
    152   }
    153   return ComputeHmac(digest.get(), key, key_len,
    154                      input, in_len, output, out_len);
    155 }
    156 
    157 std::string ComputeHmac(MessageDigest* digest, const std::string& key,
    158                         const std::string& input) {
    159   scoped_ptr<char[]> output(new char[digest->Size()]);
    160   ComputeHmac(digest, key.data(), key.size(),
    161               input.data(), input.size(), output.get(), digest->Size());
    162   return hex_encode(output.get(), digest->Size());
    163 }
    164 
    165 bool ComputeHmac(const std::string& alg, const std::string& key,
    166                  const std::string& input, std::string* output) {
    167   scoped_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg));
    168   if (!digest) {
    169     return false;
    170   }
    171   *output = ComputeHmac(digest.get(), key, input);
    172   return true;
    173 }
    174 
    175 std::string ComputeHmac(const std::string& alg, const std::string& key,
    176                         const std::string& input) {
    177   std::string output;
    178   ComputeHmac(alg, key, input, &output);
    179   return output;
    180 }
    181 
    182 }  // namespace rtc
    183