| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/crypto/hash.cc |
| Date: | 2025-11-09 02:35:23 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 275 | 306 | 89.9% |
| Branches: | 169 | 268 | 63.1% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * This file is part of the CernVM File System. | ||
| 3 | */ | ||
| 4 | |||
| 5 | |||
| 6 | #include "crypto/hash.h" | ||
| 7 | |||
| 8 | #include <alloca.h> | ||
| 9 | #include <errno.h> | ||
| 10 | #include <fcntl.h> | ||
| 11 | #include <openssl/hmac.h> | ||
| 12 | #include <openssl/md5.h> | ||
| 13 | #include <openssl/ripemd.h> | ||
| 14 | #include <openssl/sha.h> | ||
| 15 | #include <unistd.h> | ||
| 16 | |||
| 17 | #include <cstdio> | ||
| 18 | #include <cstring> | ||
| 19 | |||
| 20 | #include "KeccakHash.h" | ||
| 21 | #include "crypto/openssl_version.h" | ||
| 22 | #include "util/exception.h" | ||
| 23 | |||
| 24 | |||
| 25 | using namespace std; // NOLINT | ||
| 26 | |||
| 27 | #ifdef CVMFS_NAMESPACE_GUARD | ||
| 28 | namespace CVMFS_NAMESPACE_GUARD { | ||
| 29 | #endif | ||
| 30 | |||
| 31 | namespace shash { | ||
| 32 | |||
| 33 | const char *kAlgorithmIds[] = {"", "", "-rmd160", "-shake128", ""}; | ||
| 34 | |||
| 35 | |||
| 36 | 22 | bool HexPtr::IsValid() const { | |
| 37 | 22 | const unsigned l = str->length(); | |
| 38 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 21 times.
|
22 | if (l == 0) |
| 39 | 1 | return false; | |
| 40 | 21 | const char *c = str->data(); // Walks through the string | |
| 41 | 21 | unsigned i = 0; // String position of *c | |
| 42 | |||
| 43 |
2/2✓ Branch 0 taken 820 times.
✓ Branch 1 taken 5 times.
|
825 | for (; i < l; ++i, ++c) { |
| 44 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 806 times.
|
820 | if (*c == '-') |
| 45 | 14 | break; | |
| 46 |
6/8✓ Branch 0 taken 806 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 806 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 327 times.
✓ Branch 5 taken 479 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 325 times.
|
806 | if ((*c < '0') || (*c > 'f') || ((*c > '9') && (*c < 'a'))) |
| 47 | 2 | return false; | |
| 48 | } | ||
| 49 | |||
| 50 | // Walk through all algorithms | ||
| 51 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 15 times.
|
85 | for (unsigned j = 0; j < kAny; ++j) { |
| 52 | 70 | const unsigned hex_length = 2 * kDigestSizes[j]; | |
| 53 | 70 | const unsigned algo_id_length = kAlgorithmIdSizes[j]; | |
| 54 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 48 times.
|
70 | if (i == hex_length) { |
| 55 | // Right suffix? | ||
| 56 |
4/4✓ Branch 0 taken 61 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 8 times.
|
65 | for (; (i < l) && (i - hex_length < algo_id_length); ++i, ++c) { |
| 57 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 43 times.
|
53 | if (*c != kAlgorithmIds[j][i - hex_length]) |
| 58 | 10 | break; | |
| 59 | } | ||
| 60 |
3/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
22 | if ((i == l) && (l == hex_length + algo_id_length)) |
| 61 | 4 | return true; | |
| 62 | 18 | i = hex_length; | |
| 63 | 18 | c = str->data() + i; | |
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | 15 | return false; | |
| 68 | } | ||
| 69 | |||
| 70 | |||
| 71 | ✗ | Algorithms ParseHashAlgorithm(const string &algorithm_option) { | |
| 72 | ✗ | if (algorithm_option == "sha1") | |
| 73 | ✗ | return kSha1; | |
| 74 | ✗ | if (algorithm_option == "rmd160") | |
| 75 | ✗ | return kRmd160; | |
| 76 | ✗ | if (algorithm_option == "shake128") | |
| 77 | ✗ | return kShake128; | |
| 78 | ✗ | return kAny; | |
| 79 | } | ||
| 80 | |||
| 81 | |||
| 82 | 74143 | Any MkFromHexPtr(const HexPtr hex, const char suffix) { | |
| 83 | 74143 | Any result; | |
| 84 | |||
| 85 | 74143 | const unsigned length = hex.str->length(); | |
| 86 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 74142 times.
|
74143 | if (length == 2 * kDigestSizes[kMd5]) |
| 87 | 1 | result = Any(kMd5, hex); | |
| 88 |
2/2✓ Branch 0 taken 74026 times.
✓ Branch 1 taken 117 times.
|
74143 | if (length == 2 * kDigestSizes[kSha1]) |
| 89 | 74026 | result = Any(kSha1, hex); | |
| 90 | // TODO(jblomer) compare -rmd160, -shake128 | ||
| 91 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 74124 times.
|
74143 | if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160])) |
| 92 | 19 | result = Any(kRmd160, hex); | |
| 93 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 74138 times.
|
74143 | if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128])) |
| 94 | 5 | result = Any(kShake128, hex); | |
| 95 | |||
| 96 | 74143 | result.suffix = suffix; | |
| 97 | 74143 | return result; | |
| 98 | } | ||
| 99 | |||
| 100 | |||
| 101 | /** | ||
| 102 | * Similar to MkFromHexPtr but the suffix is deducted from the HexPtr string. | ||
| 103 | */ | ||
| 104 | 14927 | Any MkFromSuffixedHexPtr(const HexPtr hex) { | |
| 105 | 14927 | Any result; | |
| 106 | |||
| 107 | 14927 | const unsigned length = hex.str->length(); | |
| 108 |
2/2✓ Branch 0 taken 2210 times.
✓ Branch 1 taken 12717 times.
|
14927 | if ((length == 2 * kDigestSizes[kMd5]) |
| 109 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2209 times.
|
2210 | || (length == 2 * kDigestSizes[kMd5] + 1)) { |
| 110 | 12718 | const Suffix suffix = (length == 2 * kDigestSizes[kMd5] + 1) | |
| 111 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12717 times.
|
12718 | ? *(hex.str->rbegin()) |
| 112 | 12718 | : kSuffixNone; | |
| 113 | 12718 | result = Any(kMd5, hex, suffix); | |
| 114 | } | ||
| 115 |
2/2✓ Branch 0 taken 13736 times.
✓ Branch 1 taken 1191 times.
|
14927 | if ((length == 2 * kDigestSizes[kSha1]) |
| 116 |
2/2✓ Branch 0 taken 1009 times.
✓ Branch 1 taken 12727 times.
|
13736 | || (length == 2 * kDigestSizes[kSha1] + 1)) { |
| 117 | 2200 | const Suffix suffix = (length == 2 * kDigestSizes[kSha1] + 1) | |
| 118 |
2/2✓ Branch 0 taken 1009 times.
✓ Branch 1 taken 1191 times.
|
2200 | ? *(hex.str->rbegin()) |
| 119 | 2200 | : kSuffixNone; | |
| 120 | 2200 | result = Any(kSha1, hex, suffix); | |
| 121 | } | ||
| 122 |
2/2✓ Branch 0 taken 14926 times.
✓ Branch 1 taken 1 times.
|
14927 | if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]) |
| 123 | 14926 | || (length | |
| 124 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 14921 times.
|
14926 | == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1)) { |
| 125 | const Suffix suffix = (length | ||
| 126 | 6 | == 2 * kDigestSizes[kRmd160] | |
| 127 | 6 | + kAlgorithmIdSizes[kRmd160] + 1) | |
| 128 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
|
6 | ? *(hex.str->rbegin()) |
| 129 | 6 | : kSuffixNone; | |
| 130 | 6 | result = Any(kRmd160, hex, suffix); | |
| 131 | } | ||
| 132 |
2/2✓ Branch 0 taken 14926 times.
✓ Branch 1 taken 1 times.
|
14927 | if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]) |
| 133 | 14926 | || (length | |
| 134 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14925 times.
|
14926 | == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128] + 1)) { |
| 135 | const Suffix suffix = (length | ||
| 136 | 2 | == 2 * kDigestSizes[kShake128] | |
| 137 | 2 | + kAlgorithmIdSizes[kShake128] + 1) | |
| 138 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | ? *(hex.str->rbegin()) |
| 139 | 2 | : kSuffixNone; | |
| 140 | 2 | result = Any(kShake128, hex, suffix); | |
| 141 | } | ||
| 142 | |||
| 143 | 14927 | return result; | |
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | /** | ||
| 148 | * Allows the caller to create the context on the stack. | ||
| 149 | */ | ||
| 150 | 2778552 | unsigned GetContextSize(const Algorithms algorithm) { | |
| 151 |
4/5✓ Branch 0 taken 1218948 times.
✓ Branch 1 taken 1559261 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 359 times.
✗ Branch 4 not taken.
|
2778552 | switch (algorithm) { |
| 152 | 1218948 | case kMd5: | |
| 153 | 1218948 | return sizeof(MD5_CTX); | |
| 154 | 1559261 | case kSha1: | |
| 155 | 1559261 | return sizeof(SHA_CTX); | |
| 156 | 14 | case kRmd160: | |
| 157 | 14 | return sizeof(RIPEMD160_CTX); | |
| 158 | 359 | case kShake128: | |
| 159 | 359 | return sizeof(Keccak_HashInstance); | |
| 160 | ✗ | default: | |
| 161 | ✗ | PANIC(kLogDebug | kLogSyslogErr, | |
| 162 | "tried to generate hash context for unspecified hash. Aborting..."); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | 2779494 | void Init(ContextPtr context) { | |
| 167 | HashReturn keccak_result; | ||
| 168 |
4/5✓ Branch 0 taken 1218966 times.
✓ Branch 1 taken 1560167 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 359 times.
✗ Branch 4 not taken.
|
2779494 | switch (context.algorithm) { |
| 169 | 1218966 | case kMd5: | |
| 170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1218966 times.
|
1218966 | assert(context.size == sizeof(MD5_CTX)); |
| 171 | 1218966 | MD5_Init(reinterpret_cast<MD5_CTX *>(context.buffer)); | |
| 172 | 1218966 | break; | |
| 173 | 1560167 | case kSha1: | |
| 174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1560167 times.
|
1560167 | assert(context.size == sizeof(SHA_CTX)); |
| 175 | 1560167 | SHA1_Init(reinterpret_cast<SHA_CTX *>(context.buffer)); | |
| 176 | 1559681 | break; | |
| 177 | 14 | case kRmd160: | |
| 178 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | assert(context.size == sizeof(RIPEMD160_CTX)); |
| 179 | 14 | RIPEMD160_Init(reinterpret_cast<RIPEMD160_CTX *>(context.buffer)); | |
| 180 | 14 | break; | |
| 181 | 359 | case kShake128: | |
| 182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 359 times.
|
359 | assert(context.size == sizeof(Keccak_HashInstance)); |
| 183 | 359 | keccak_result = Keccak_HashInitialize_SHAKE128( | |
| 184 | reinterpret_cast<Keccak_HashInstance *>(context.buffer)); | ||
| 185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 359 times.
|
359 | assert(keccak_result == SUCCESS); |
| 186 | 359 | break; | |
| 187 | ✗ | default: | |
| 188 | ✗ | PANIC(NULL); // Undefined hash | |
| 189 | } | ||
| 190 | 2779020 | } | |
| 191 | |||
| 192 | 102559187 | void Update(const unsigned char *buffer, const unsigned buffer_length, | |
| 193 | ContextPtr context) { | ||
| 194 | HashReturn keccak_result; | ||
| 195 |
4/5✓ Branch 0 taken 30886210 times.
✓ Branch 1 taken 25535344 times.
✓ Branch 2 taken 23068688 times.
✓ Branch 3 taken 23069023 times.
✗ Branch 4 not taken.
|
102559187 | switch (context.algorithm) { |
| 196 | 30886210 | case kMd5: | |
| 197 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30886210 times.
|
30886210 | assert(context.size == sizeof(MD5_CTX)); |
| 198 | 30886210 | MD5_Update(reinterpret_cast<MD5_CTX *>(context.buffer), buffer, | |
| 199 | buffer_length); | ||
| 200 | 30886210 | break; | |
| 201 | 25535344 | case kSha1: | |
| 202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25535344 times.
|
25535344 | assert(context.size == sizeof(SHA_CTX)); |
| 203 | 25535344 | SHA1_Update(reinterpret_cast<SHA_CTX *>(context.buffer), buffer, | |
| 204 | buffer_length); | ||
| 205 | 25541230 | break; | |
| 206 | 23068688 | case kRmd160: | |
| 207 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23068688 times.
|
23068688 | assert(context.size == sizeof(RIPEMD160_CTX)); |
| 208 | 23068688 | RIPEMD160_Update(reinterpret_cast<RIPEMD160_CTX *>(context.buffer), | |
| 209 | buffer, buffer_length); | ||
| 210 | 23068688 | break; | |
| 211 | 23069023 | case kShake128: | |
| 212 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23069023 times.
|
23069023 | assert(context.size == sizeof(Keccak_HashInstance)); |
| 213 | 46138046 | keccak_result = Keccak_HashUpdate( | |
| 214 | 23069023 | reinterpret_cast<Keccak_HashInstance *>(context.buffer), buffer, | |
| 215 | 23069023 | buffer_length * 8); | |
| 216 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23069023 times.
|
23069023 | assert(keccak_result == SUCCESS); |
| 217 | 23069023 | break; | |
| 218 | ✗ | default: | |
| 219 | ✗ | PANIC(NULL); // Undefined hash | |
| 220 | } | ||
| 221 | 102565151 | } | |
| 222 | |||
| 223 | 2740551 | void Final(ContextPtr context, Any *any_digest) { | |
| 224 | HashReturn keccak_result; | ||
| 225 |
4/5✓ Branch 0 taken 1218942 times.
✓ Branch 1 taken 1521458 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 359 times.
✗ Branch 4 not taken.
|
2740551 | switch (context.algorithm) { |
| 226 | 1218942 | case kMd5: | |
| 227 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1218942 times.
|
1218942 | assert(context.size == sizeof(MD5_CTX)); |
| 228 | 1218942 | MD5_Final(any_digest->digest, | |
| 229 | 1218942 | reinterpret_cast<MD5_CTX *>(context.buffer)); | |
| 230 | 1218942 | break; | |
| 231 | 1521458 | case kSha1: | |
| 232 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1521458 times.
|
1521458 | assert(context.size == sizeof(SHA_CTX)); |
| 233 | 1521458 | SHA1_Final(any_digest->digest, | |
| 234 | 1521458 | reinterpret_cast<SHA_CTX *>(context.buffer)); | |
| 235 | 1532024 | break; | |
| 236 | 14 | case kRmd160: | |
| 237 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | assert(context.size == sizeof(RIPEMD160_CTX)); |
| 238 | 14 | RIPEMD160_Final(any_digest->digest, | |
| 239 | 14 | reinterpret_cast<RIPEMD160_CTX *>(context.buffer)); | |
| 240 | 14 | break; | |
| 241 | 359 | case kShake128: | |
| 242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 359 times.
|
359 | assert(context.size == sizeof(Keccak_HashInstance)); |
| 243 | 718 | keccak_result = Keccak_HashFinal( | |
| 244 | 359 | reinterpret_cast<Keccak_HashInstance *>(context.buffer), NULL); | |
| 245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 359 times.
|
359 | assert(keccak_result == SUCCESS); |
| 246 | 718 | keccak_result = Keccak_HashSqueeze( | |
| 247 | 359 | reinterpret_cast<Keccak_HashInstance *>(context.buffer), | |
| 248 | 359 | any_digest->digest, kDigestSizes[kShake128] * 8); | |
| 249 | 359 | break; | |
| 250 | ✗ | default: | |
| 251 | ✗ | PANIC(NULL); // Undefined hash | |
| 252 | } | ||
| 253 | 2751339 | any_digest->algorithm = context.algorithm; | |
| 254 | 2751339 | } | |
| 255 | |||
| 256 | |||
| 257 | 18007 | void HashMem(const unsigned char *buffer, const unsigned buffer_size, | |
| 258 | Any *any_digest) { | ||
| 259 | 18007 | const Algorithms algorithm = any_digest->algorithm; | |
| 260 |
1/2✓ Branch 1 taken 18007 times.
✗ Branch 2 not taken.
|
18007 | ContextPtr context(algorithm); |
| 261 | 18007 | context.buffer = alloca(context.size); | |
| 262 | |||
| 263 |
1/2✓ Branch 1 taken 18007 times.
✗ Branch 2 not taken.
|
18007 | Init(context); |
| 264 |
1/2✓ Branch 1 taken 18007 times.
✗ Branch 2 not taken.
|
18007 | Update(buffer, buffer_size, context); |
| 265 |
1/2✓ Branch 1 taken 18007 times.
✗ Branch 2 not taken.
|
18007 | Final(context, any_digest); |
| 266 | 18007 | } | |
| 267 | |||
| 268 | |||
| 269 | 585 | void HashString(const std::string &content, Any *any_digest) { | |
| 270 | 585 | HashMem(reinterpret_cast<const unsigned char *>(content.data()), | |
| 271 | 585 | content.length(), any_digest); | |
| 272 | 585 | } | |
| 273 | |||
| 274 | |||
| 275 | 607399 | void Hmac(const string &key, | |
| 276 | const unsigned char *buffer, | ||
| 277 | const unsigned buffer_size, | ||
| 278 | Any *any_digest) { | ||
| 279 | 607399 | const Algorithms algorithm = any_digest->algorithm; | |
| 280 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 607399 times.
|
607399 | assert(algorithm != kAny); |
| 281 | |||
| 282 | 607399 | const unsigned block_size = kBlockSizes[algorithm]; | |
| 283 | 607399 | unsigned char key_block[block_size]; | |
| 284 | 607399 | memset(key_block, 0, block_size); | |
| 285 |
2/2✓ Branch 1 taken 7332 times.
✓ Branch 2 taken 600067 times.
|
607399 | if (key.length() > block_size) { |
| 286 |
1/2✓ Branch 1 taken 7332 times.
✗ Branch 2 not taken.
|
7332 | Any hash_key(algorithm); |
| 287 |
1/2✓ Branch 3 taken 7332 times.
✗ Branch 4 not taken.
|
7332 | HashMem(reinterpret_cast<const unsigned char *>(key.data()), key.length(), |
| 288 | &hash_key); | ||
| 289 | 7332 | memcpy(key_block, hash_key.digest, kDigestSizes[algorithm]); | |
| 290 | } else { | ||
| 291 |
2/2✓ Branch 1 taken 600064 times.
✓ Branch 2 taken 3 times.
|
600067 | if (key.length() > 0) |
| 292 | 600064 | memcpy(key_block, key.data(), key.length()); | |
| 293 | } | ||
| 294 | |||
| 295 | 607399 | unsigned char pad_block[block_size]; | |
| 296 | // Inner hash | ||
| 297 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | Any hash_inner(algorithm); |
| 298 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | ContextPtr context_inner(algorithm); |
| 299 | 607399 | context_inner.buffer = alloca(context_inner.size); | |
| 300 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | Init(context_inner); |
| 301 |
2/2✓ Branch 0 taken 38873536 times.
✓ Branch 1 taken 607399 times.
|
39480935 | for (unsigned i = 0; i < block_size; ++i) |
| 302 | 38873536 | pad_block[i] = key_block[i] ^ 0x36; | |
| 303 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | Update(pad_block, block_size, context_inner); |
| 304 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | Update(buffer, buffer_size, context_inner); |
| 305 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | Final(context_inner, &hash_inner); |
| 306 | |||
| 307 | // Outer hash | ||
| 308 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | ContextPtr context_outer(algorithm); |
| 309 | 607399 | context_outer.buffer = alloca(context_outer.size); | |
| 310 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | Init(context_outer); |
| 311 |
2/2✓ Branch 0 taken 38873536 times.
✓ Branch 1 taken 607399 times.
|
39480935 | for (unsigned i = 0; i < block_size; ++i) |
| 312 | 38873536 | pad_block[i] = key_block[i] ^ 0x5c; | |
| 313 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | Update(pad_block, block_size, context_outer); |
| 314 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | Update(hash_inner.digest, kDigestSizes[algorithm], context_outer); |
| 315 | |||
| 316 |
1/2✓ Branch 1 taken 607399 times.
✗ Branch 2 not taken.
|
607399 | Final(context_outer, any_digest); |
| 317 | 607399 | } | |
| 318 | |||
| 319 | |||
| 320 | 13576 | bool HashFd(int fd, Any *any_digest) { | |
| 321 | 13576 | const Algorithms algorithm = any_digest->algorithm; | |
| 322 |
1/2✓ Branch 1 taken 13576 times.
✗ Branch 2 not taken.
|
13576 | ContextPtr context(algorithm); |
| 323 | 13576 | context.buffer = alloca(context.size); | |
| 324 | |||
| 325 |
1/2✓ Branch 1 taken 13576 times.
✗ Branch 2 not taken.
|
13576 | Init(context); |
| 326 | unsigned char io_buffer[4096]; | ||
| 327 | int actual_bytes; | ||
| 328 |
3/4✓ Branch 1 taken 5529980 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5516404 times.
✓ Branch 4 taken 13576 times.
|
5529980 | while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) { |
| 329 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5516404 times.
|
5516404 | if (actual_bytes == -1) { |
| 330 | ✗ | if (errno == EINTR) | |
| 331 | ✗ | continue; | |
| 332 | ✗ | return false; | |
| 333 | } | ||
| 334 |
1/2✓ Branch 1 taken 5516404 times.
✗ Branch 2 not taken.
|
5516404 | Update(io_buffer, actual_bytes, context); |
| 335 | } | ||
| 336 |
1/2✓ Branch 1 taken 13576 times.
✗ Branch 2 not taken.
|
13576 | Final(context, any_digest); |
| 337 | 13576 | return true; | |
| 338 | } | ||
| 339 | |||
| 340 | |||
| 341 | 13576 | bool HashFile(const std::string &filename, Any *any_digest) { | |
| 342 | 13576 | const int fd = open(filename.c_str(), O_RDONLY); | |
| 343 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13576 times.
|
13576 | if (fd == -1) |
| 344 | ✗ | return false; | |
| 345 | |||
| 346 | 13576 | const bool result = HashFd(fd, any_digest); | |
| 347 | 13576 | close(fd); | |
| 348 | 13576 | return result; | |
| 349 | } | ||
| 350 | |||
| 351 | |||
| 352 | /** | ||
| 353 | * Fast constructor for hashing path names. | ||
| 354 | */ | ||
| 355 | 9229 | Md5::Md5(const AsciiPtr ascii) { | |
| 356 | 9229 | algorithm = kMd5; | |
| 357 | 9229 | const string *str = ascii.str; | |
| 358 | |||
| 359 | MD5_CTX md5_state; | ||
| 360 |
1/2✓ Branch 1 taken 9229 times.
✗ Branch 2 not taken.
|
9229 | MD5_Init(&md5_state); |
| 361 |
1/2✓ Branch 3 taken 9229 times.
✗ Branch 4 not taken.
|
9229 | MD5_Update(&md5_state, reinterpret_cast<const unsigned char *>(&(*str)[0]), |
| 362 | str->length()); | ||
| 363 |
1/2✓ Branch 1 taken 9229 times.
✗ Branch 2 not taken.
|
9229 | MD5_Final(digest, &md5_state); |
| 364 | 9229 | } | |
| 365 | |||
| 366 | |||
| 367 | 1545047 | Md5::Md5(const char *chars, const unsigned length) { | |
| 368 | 1545047 | algorithm = kMd5; | |
| 369 | |||
| 370 | MD5_CTX md5_state; | ||
| 371 |
1/2✓ Branch 1 taken 1545047 times.
✗ Branch 2 not taken.
|
1545047 | MD5_Init(&md5_state); |
| 372 |
1/2✓ Branch 1 taken 1545047 times.
✗ Branch 2 not taken.
|
1545047 | MD5_Update(&md5_state, reinterpret_cast<const unsigned char *>(chars), |
| 373 | length); | ||
| 374 |
1/2✓ Branch 1 taken 1545047 times.
✗ Branch 2 not taken.
|
1545047 | MD5_Final(digest, &md5_state); |
| 375 | 1545047 | } | |
| 376 | |||
| 377 | |||
| 378 | ✗ | Md5::Md5(const uint64_t lo, const uint64_t hi) { | |
| 379 | ✗ | algorithm = kMd5; | |
| 380 | ✗ | memcpy(digest, &lo, 8); | |
| 381 | ✗ | memcpy(digest + 8, &hi, 8); | |
| 382 | } | ||
| 383 | |||
| 384 | 12138 | void Md5::ToIntPair(uint64_t *lo, uint64_t *hi) const { | |
| 385 | 12138 | memcpy(lo, digest, 8); | |
| 386 | 12138 | memcpy(hi, digest + 8, 8); | |
| 387 | 12138 | } | |
| 388 | |||
| 389 | |||
| 390 | 600088 | Md5 Any::CastToMd5() { | |
| 391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 600088 times.
|
600088 | assert(algorithm == kMd5); |
| 392 | 600088 | Md5 result; | |
| 393 | 600088 | memcpy(result.digest, digest, kDigestSizes[kMd5]); | |
| 394 | 600088 | return result; | |
| 395 | } | ||
| 396 | |||
| 397 | #ifndef OPENSSL_API_INTERFACE_V09 | ||
| 398 | 6 | static string HexFromSha256(unsigned char digest[SHA256_DIGEST_LENGTH]) { | |
| 399 | 6 | string result; | |
| 400 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | result.reserve(2 * SHA256_DIGEST_LENGTH); |
| 401 |
2/2✓ Branch 0 taken 192 times.
✓ Branch 1 taken 6 times.
|
198 | for (unsigned i = 0; i < SHA256_DIGEST_LENGTH; ++i) { |
| 402 | 192 | const char d1 = digest[i] / 16; | |
| 403 | 192 | const char d2 = digest[i] % 16; | |
| 404 |
3/4✓ Branch 0 taken 111 times.
✓ Branch 1 taken 81 times.
✓ Branch 3 taken 192 times.
✗ Branch 4 not taken.
|
192 | result.push_back(d1 + ((d1 <= 9) ? '0' : 'a' - 10)); |
| 405 |
3/4✓ Branch 0 taken 133 times.
✓ Branch 1 taken 59 times.
✓ Branch 3 taken 192 times.
✗ Branch 4 not taken.
|
192 | result.push_back(d2 + ((d2 <= 9) ? '0' : 'a' - 10)); |
| 406 | } | ||
| 407 | 6 | return result; | |
| 408 | } | ||
| 409 | #endif | ||
| 410 | |||
| 411 | 1 | string Sha256File(const string &filename) { | |
| 412 | #ifdef OPENSSL_API_INTERFACE_V09 | ||
| 413 | PANIC(NULL); | ||
| 414 | #else | ||
| 415 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | const int fd = open(filename.c_str(), O_RDONLY); |
| 416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (fd < 0) |
| 417 | ✗ | return ""; | |
| 418 | |||
| 419 | SHA256_CTX ctx; | ||
| 420 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | SHA256_Init(&ctx); |
| 421 | |||
| 422 | unsigned char io_buffer[4096]; | ||
| 423 | int actual_bytes; | ||
| 424 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1 | while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) { |
| 425 | ✗ | if (actual_bytes == -1) { | |
| 426 | ✗ | if (errno == EINTR) | |
| 427 | ✗ | continue; | |
| 428 | ✗ | close(fd); | |
| 429 | ✗ | return ""; | |
| 430 | } | ||
| 431 | ✗ | SHA256_Update(&ctx, io_buffer, actual_bytes); | |
| 432 | } | ||
| 433 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | close(fd); |
| 434 | |||
| 435 | unsigned char digest[SHA256_DIGEST_LENGTH]; | ||
| 436 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | SHA256_Final(digest, &ctx); |
| 437 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | return HexFromSha256(digest); |
| 438 | #endif | ||
| 439 | } | ||
| 440 | |||
| 441 | 2 | string Sha256Mem(const unsigned char *buffer, const unsigned buffer_size) { | |
| 442 | #ifdef OPENSSL_API_INTERFACE_V09 | ||
| 443 | PANIC(NULL); | ||
| 444 | #else | ||
| 445 | unsigned char digest[SHA256_DIGEST_LENGTH]; | ||
| 446 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | SHA256(buffer, buffer_size, digest); |
| 447 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | return HexFromSha256(digest); |
| 448 | #endif | ||
| 449 | } | ||
| 450 | |||
| 451 | 1 | string Sha256String(const string &content) { | |
| 452 | 1 | return Sha256Mem(reinterpret_cast<const unsigned char *>(content.data()), | |
| 453 | 1 | content.length()); | |
| 454 | } | ||
| 455 | |||
| 456 | |||
| 457 | 7 | std::string Hmac256(const std::string &key, | |
| 458 | const std::string &content, | ||
| 459 | bool raw_output) { | ||
| 460 | #ifdef OPENSSL_API_INTERFACE_V09 | ||
| 461 | PANIC(NULL); | ||
| 462 | #else | ||
| 463 | unsigned char digest[SHA256_DIGEST_LENGTH]; | ||
| 464 | 7 | const unsigned block_size = 64; | |
| 465 | 7 | const unsigned key_length = key.length(); | |
| 466 | unsigned char key_block[block_size]; | ||
| 467 | 7 | memset(key_block, 0, block_size); | |
| 468 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
|
7 | if (key_length > block_size) { |
| 469 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | SHA256(reinterpret_cast<const unsigned char *>(key.data()), key_length, |
| 470 | key_block); | ||
| 471 | } else { | ||
| 472 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | if (key.length() > 0) |
| 473 | 6 | memcpy(key_block, key.data(), key_length); | |
| 474 | } | ||
| 475 | |||
| 476 | unsigned char pad_block[block_size]; | ||
| 477 | // Inner hash | ||
| 478 | SHA256_CTX ctx_inner; | ||
| 479 | unsigned char digest_inner[SHA256_DIGEST_LENGTH]; | ||
| 480 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | SHA256_Init(&ctx_inner); |
| 481 |
2/2✓ Branch 0 taken 448 times.
✓ Branch 1 taken 7 times.
|
455 | for (unsigned i = 0; i < block_size; ++i) |
| 482 | 448 | pad_block[i] = key_block[i] ^ 0x36; | |
| 483 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | SHA256_Update(&ctx_inner, pad_block, block_size); |
| 484 |
1/2✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
|
7 | SHA256_Update(&ctx_inner, content.data(), content.length()); |
| 485 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | SHA256_Final(digest_inner, &ctx_inner); |
| 486 | |||
| 487 | // Outer hash | ||
| 488 | SHA256_CTX ctx_outer; | ||
| 489 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | SHA256_Init(&ctx_outer); |
| 490 |
2/2✓ Branch 0 taken 448 times.
✓ Branch 1 taken 7 times.
|
455 | for (unsigned i = 0; i < block_size; ++i) |
| 491 | 448 | pad_block[i] = key_block[i] ^ 0x5c; | |
| 492 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | SHA256_Update(&ctx_outer, pad_block, block_size); |
| 493 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | SHA256_Update(&ctx_outer, digest_inner, SHA256_DIGEST_LENGTH); |
| 494 | |||
| 495 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | SHA256_Final(digest, &ctx_outer); |
| 496 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
|
7 | if (raw_output) |
| 497 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | return string(reinterpret_cast<const char *>(digest), SHA256_DIGEST_LENGTH); |
| 498 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | return HexFromSha256(digest); |
| 499 | #endif | ||
| 500 | } | ||
| 501 | |||
| 502 | } // namespace shash | ||
| 503 | |||
| 504 | #ifdef CVMFS_NAMESPACE_GUARD | ||
| 505 | } // namespace CVMFS_NAMESPACE_GUARD | ||
| 506 | #endif | ||
| 507 |