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