1 /* 2 * libjingle 3 * Copyright 2011, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/base/messagedigest.h" 29 30 #include <string.h> 31 32 #include "talk/base/sslconfig.h" 33 #if SSL_USE_OPENSSL 34 #include "talk/base/openssldigest.h" 35 #else 36 #include "talk/base/md5digest.h" 37 #include "talk/base/sha1digest.h" 38 #endif 39 #include "talk/base/scoped_ptr.h" 40 #include "talk/base/stringencode.h" 41 42 namespace talk_base { 43 44 // From RFC 4572. 45 const char DIGEST_MD5[] = "md5"; 46 const char DIGEST_SHA_1[] = "sha-1"; 47 const char DIGEST_SHA_224[] = "sha-224"; 48 const char DIGEST_SHA_256[] = "sha-256"; 49 const char DIGEST_SHA_384[] = "sha-384"; 50 const char DIGEST_SHA_512[] = "sha-512"; 51 52 static const size_t kBlockSize = 64; // valid for SHA-256 and down 53 54 MessageDigest* MessageDigestFactory::Create(const std::string& alg) { 55 #if SSL_USE_OPENSSL 56 MessageDigest* digest = new OpenSSLDigest(alg); 57 if (digest->Size() == 0) { // invalid algorithm 58 delete digest; 59 digest = NULL; 60 } 61 return digest; 62 #else 63 MessageDigest* digest = NULL; 64 if (alg == DIGEST_MD5) { 65 digest = new Md5Digest(); 66 } else if (alg == DIGEST_SHA_1) { 67 digest = new Sha1Digest(); 68 } 69 return digest; 70 #endif 71 } 72 73 size_t ComputeDigest(MessageDigest* digest, const void* input, size_t in_len, 74 void* output, size_t out_len) { 75 digest->Update(input, in_len); 76 return digest->Finish(output, out_len); 77 } 78 79 size_t ComputeDigest(const std::string& alg, const void* input, size_t in_len, 80 void* output, size_t out_len) { 81 scoped_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg)); 82 return (digest) ? 83 ComputeDigest(digest.get(), input, in_len, output, out_len) : 84 0; 85 } 86 87 std::string ComputeDigest(MessageDigest* digest, const std::string& input) { 88 scoped_ptr<char[]> output(new char[digest->Size()]); 89 ComputeDigest(digest, input.data(), input.size(), 90 output.get(), digest->Size()); 91 return hex_encode(output.get(), digest->Size()); 92 } 93 94 bool ComputeDigest(const std::string& alg, const std::string& input, 95 std::string* output) { 96 scoped_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg)); 97 if (!digest) { 98 return false; 99 } 100 *output = ComputeDigest(digest.get(), input); 101 return true; 102 } 103 104 std::string ComputeDigest(const std::string& alg, const std::string& input) { 105 std::string output; 106 ComputeDigest(alg, input, &output); 107 return output; 108 } 109 110 // Compute a RFC 2104 HMAC: H(K XOR opad, H(K XOR ipad, text)) 111 size_t ComputeHmac(MessageDigest* digest, 112 const void* key, size_t key_len, 113 const void* input, size_t in_len, 114 void* output, size_t out_len) { 115 // We only handle algorithms with a 64-byte blocksize. 116 // TODO: Add BlockSize() method to MessageDigest. 117 size_t block_len = kBlockSize; 118 if (digest->Size() > 32) { 119 return 0; 120 } 121 // Copy the key to a block-sized buffer to simplify padding. 122 // If the key is longer than a block, hash it and use the result instead. 123 scoped_ptr<uint8[]> new_key(new uint8[block_len]); 124 if (key_len > block_len) { 125 ComputeDigest(digest, key, key_len, new_key.get(), block_len); 126 memset(new_key.get() + digest->Size(), 0, block_len - digest->Size()); 127 } else { 128 memcpy(new_key.get(), key, key_len); 129 memset(new_key.get() + key_len, 0, block_len - key_len); 130 } 131 // Set up the padding from the key, salting appropriately for each padding. 132 scoped_ptr<uint8[]> o_pad(new uint8[block_len]), i_pad(new uint8[block_len]); 133 for (size_t i = 0; i < block_len; ++i) { 134 o_pad[i] = 0x5c ^ new_key[i]; 135 i_pad[i] = 0x36 ^ new_key[i]; 136 } 137 // Inner hash; hash the inner padding, and then the input buffer. 138 scoped_ptr<uint8[]> inner(new uint8[digest->Size()]); 139 digest->Update(i_pad.get(), block_len); 140 digest->Update(input, in_len); 141 digest->Finish(inner.get(), digest->Size()); 142 // Outer hash; hash the outer padding, and then the result of the inner hash. 143 digest->Update(o_pad.get(), block_len); 144 digest->Update(inner.get(), digest->Size()); 145 return digest->Finish(output, out_len); 146 } 147 148 size_t ComputeHmac(const std::string& alg, const void* key, size_t key_len, 149 const void* input, size_t in_len, 150 void* output, size_t out_len) { 151 scoped_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg)); 152 if (!digest) { 153 return 0; 154 } 155 return ComputeHmac(digest.get(), key, key_len, 156 input, in_len, output, out_len); 157 } 158 159 std::string ComputeHmac(MessageDigest* digest, const std::string& key, 160 const std::string& input) { 161 scoped_ptr<char[]> output(new char[digest->Size()]); 162 ComputeHmac(digest, key.data(), key.size(), 163 input.data(), input.size(), output.get(), digest->Size()); 164 return hex_encode(output.get(), digest->Size()); 165 } 166 167 bool ComputeHmac(const std::string& alg, const std::string& key, 168 const std::string& input, std::string* output) { 169 scoped_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg)); 170 if (!digest) { 171 return false; 172 } 173 *output = ComputeHmac(digest.get(), key, input); 174 return true; 175 } 176 177 std::string ComputeHmac(const std::string& alg, const std::string& key, 178 const std::string& input) { 179 std::string output; 180 ComputeHmac(alg, key, input, &output); 181 return output; 182 } 183 184 } // namespace talk_base 185