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