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 25namespace rtc { 26 27// From RFC 4572. 28const char DIGEST_MD5[] = "md5"; 29const char DIGEST_SHA_1[] = "sha-1"; 30const char DIGEST_SHA_224[] = "sha-224"; 31const char DIGEST_SHA_256[] = "sha-256"; 32const char DIGEST_SHA_384[] = "sha-384"; 33const char DIGEST_SHA_512[] = "sha-512"; 34 35static const size_t kBlockSize = 64; // valid for SHA-256 and down 36 37MessageDigest* 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 56bool 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 69size_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 75size_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 83std::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 90bool 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 100std::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)) 107size_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 144size_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 155std::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 163bool 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 173std::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