| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/crypto/hash.cc |
| Date: | 2026-08-09 02:40:25 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 276 | 307 | 89.9% |
| Branches: | 158 | 246 | 64.2% |
| 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 <nettle/md5.h> | ||
| 12 | #include <nettle/ripemd160.h> | ||
| 13 | #include <nettle/sha1.h> | ||
| 14 | #include <nettle/sha2.h> | ||
| 15 | #include <nettle/sha3.h> | ||
| 16 | #include <nettle/version.h> | ||
| 17 | #include <unistd.h> | ||
| 18 | |||
| 19 | #include <cstdio> | ||
| 20 | #include <cstring> | ||
| 21 | |||
| 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 | namespace { | ||
| 34 | |||
| 35 | // nettle 4 dropped the digest_size parameter from the *_digest() functions. | ||
| 36 | #if defined(NETTLE_VERSION_MAJOR) && (NETTLE_VERSION_MAJOR >= 4) | ||
| 37 | void Md5Digest(md5_ctx *ctx, uint8_t *digest) { | ||
| 38 | nettle_md5_digest(ctx, digest); | ||
| 39 | } | ||
| 40 | |||
| 41 | void Sha1Digest(sha1_ctx *ctx, uint8_t *digest) { | ||
| 42 | nettle_sha1_digest(ctx, digest); | ||
| 43 | } | ||
| 44 | |||
| 45 | void Sha256Digest(sha256_ctx *ctx, uint8_t *digest) { | ||
| 46 | nettle_sha256_digest(ctx, digest); | ||
| 47 | } | ||
| 48 | |||
| 49 | void Ripemd160Digest(ripemd160_ctx *ctx, uint8_t *digest) { | ||
| 50 | nettle_ripemd160_digest(ctx, digest); | ||
| 51 | } | ||
| 52 | |||
| 53 | #else // nettle 3.x takes digest size as 2nd arg | ||
| 54 | 5097806 | void Md5Digest(md5_ctx *ctx, uint8_t *digest) { | |
| 55 | 5097806 | nettle_md5_digest(ctx, MD5_DIGEST_SIZE, digest); | |
| 56 | 5097806 | } | |
| 57 | |||
| 58 | 767962 | void Sha1Digest(sha1_ctx *ctx, uint8_t *digest) { | |
| 59 | 767962 | nettle_sha1_digest(ctx, SHA1_DIGEST_SIZE, digest); | |
| 60 | 767989 | } | |
| 61 | |||
| 62 | 54 | void Sha256Digest(sha256_ctx *ctx, uint8_t *digest) { | |
| 63 | 54 | nettle_sha256_digest(ctx, SHA256_DIGEST_SIZE, digest); | |
| 64 | 54 | } | |
| 65 | |||
| 66 | 38 | void Ripemd160Digest(ripemd160_ctx *ctx, uint8_t *digest) { | |
| 67 | 38 | nettle_ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, digest); | |
| 68 | 38 | } | |
| 69 | |||
| 70 | #endif | ||
| 71 | |||
| 72 | 968 | void Shake128Digest(sha3_128_ctx *ctx, uint8_t *digest) { | |
| 73 | 968 | nettle_sha3_128_shake(ctx, kDigestSizes[kShake128], digest); | |
| 74 | 968 | } | |
| 75 | |||
| 76 | static_assert(sizeof(sha3_128_ctx) <= kMaxContextSize, | ||
| 77 | "SHAKE128 context exceeds allocated buffers"); | ||
| 78 | |||
| 79 | } // namespace | ||
| 80 | |||
| 81 | const char *kAlgorithmIds[] = {"", "", "-rmd160", "-shake128", ""}; | ||
| 82 | |||
| 83 | |||
| 84 | 66 | bool HexPtr::IsValid() const { | |
| 85 | 66 | const unsigned l = str->length(); | |
| 86 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 63 times.
|
66 | if (l == 0) |
| 87 | 3 | return false; | |
| 88 | 63 | const char *c = str->data(); // Walks through the string | |
| 89 | 63 | unsigned i = 0; // String position of *c | |
| 90 | |||
| 91 |
2/2✓ Branch 0 taken 2460 times.
✓ Branch 1 taken 15 times.
|
2475 | for (; i < l; ++i, ++c) { |
| 92 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 2418 times.
|
2460 | if (*c == '-') |
| 93 | 42 | break; | |
| 94 |
6/8✓ Branch 0 taken 2418 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2418 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 981 times.
✓ Branch 5 taken 1437 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 975 times.
|
2418 | if ((*c < '0') || (*c > 'f') || ((*c > '9') && (*c < 'a'))) |
| 95 | 6 | return false; | |
| 96 | } | ||
| 97 | |||
| 98 | // Walk through all algorithms | ||
| 99 |
2/2✓ Branch 0 taken 210 times.
✓ Branch 1 taken 45 times.
|
255 | for (unsigned j = 0; j < kAny; ++j) { |
| 100 | 210 | const unsigned hex_length = 2 * kDigestSizes[j]; | |
| 101 | 210 | const unsigned algo_id_length = kAlgorithmIdSizes[j]; | |
| 102 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 144 times.
|
210 | if (i == hex_length) { |
| 103 | // Right suffix? | ||
| 104 |
4/4✓ Branch 0 taken 183 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 159 times.
✓ Branch 3 taken 24 times.
|
195 | for (; (i < l) && (i - hex_length < algo_id_length); ++i, ++c) { |
| 105 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 129 times.
|
159 | if (*c != kAlgorithmIds[j][i - hex_length]) |
| 106 | 30 | break; | |
| 107 | } | ||
| 108 |
3/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
66 | if ((i == l) && (l == hex_length + algo_id_length)) |
| 109 | 12 | return true; | |
| 110 | 54 | i = hex_length; | |
| 111 | 54 | c = str->data() + i; | |
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | 45 | return false; | |
| 116 | } | ||
| 117 | |||
| 118 | |||
| 119 | ✗ | Algorithms ParseHashAlgorithm(const string &algorithm_option) { | |
| 120 | ✗ | if (algorithm_option == "sha1") | |
| 121 | ✗ | return kSha1; | |
| 122 | ✗ | if (algorithm_option == "rmd160") | |
| 123 | ✗ | return kRmd160; | |
| 124 | ✗ | if (algorithm_option == "shake128") | |
| 125 | ✗ | return kShake128; | |
| 126 | ✗ | return kAny; | |
| 127 | } | ||
| 128 | |||
| 129 | |||
| 130 | 73409 | Any MkFromHexPtr(const HexPtr hex, const char suffix) { | |
| 131 | 73409 | Any result; | |
| 132 | |||
| 133 | 73409 | const unsigned length = hex.str->length(); | |
| 134 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 73406 times.
|
73409 | if (length == 2 * kDigestSizes[kMd5]) |
| 135 | 3 | result = Any(kMd5, hex); | |
| 136 |
2/2✓ Branch 0 taken 73250 times.
✓ Branch 1 taken 159 times.
|
73409 | if (length == 2 * kDigestSizes[kSha1]) |
| 137 | 73250 | result = Any(kSha1, hex); | |
| 138 | // TODO(jblomer) compare -rmd160, -shake128 | ||
| 139 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 73388 times.
|
73409 | if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160])) |
| 140 | 21 | result = Any(kRmd160, hex); | |
| 141 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 73382 times.
|
73409 | if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128])) |
| 142 | 27 | result = Any(kShake128, hex); | |
| 143 | |||
| 144 | 73409 | result.suffix = suffix; | |
| 145 | 73409 | return result; | |
| 146 | } | ||
| 147 | |||
| 148 | |||
| 149 | /** | ||
| 150 | * Similar to MkFromHexPtr but the suffix is deducted from the HexPtr string. | ||
| 151 | */ | ||
| 152 | 44263 | Any MkFromSuffixedHexPtr(const HexPtr hex) { | |
| 153 | 44263 | Any result; | |
| 154 | |||
| 155 | 44263 | const unsigned length = hex.str->length(); | |
| 156 |
2/2✓ Branch 0 taken 1174 times.
✓ Branch 1 taken 43089 times.
|
44263 | if ((length == 2 * kDigestSizes[kMd5]) |
| 157 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1171 times.
|
1174 | || (length == 2 * kDigestSizes[kMd5] + 1)) { |
| 158 | 43092 | const Suffix suffix = (length == 2 * kDigestSizes[kMd5] + 1) | |
| 159 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 43089 times.
|
43092 | ? *(hex.str->rbegin()) |
| 160 | 43092 | : kSuffixNone; | |
| 161 | 43092 | result = Any(kMd5, hex, suffix); | |
| 162 | } | ||
| 163 |
2/2✓ Branch 0 taken 43626 times.
✓ Branch 1 taken 637 times.
|
44263 | if ((length == 2 * kDigestSizes[kSha1]) |
| 164 |
2/2✓ Branch 0 taken 507 times.
✓ Branch 1 taken 43119 times.
|
43626 | || (length == 2 * kDigestSizes[kSha1] + 1)) { |
| 165 | 1144 | const Suffix suffix = (length == 2 * kDigestSizes[kSha1] + 1) | |
| 166 |
2/2✓ Branch 0 taken 507 times.
✓ Branch 1 taken 637 times.
|
1144 | ? *(hex.str->rbegin()) |
| 167 | 1144 | : kSuffixNone; | |
| 168 | 1144 | result = Any(kSha1, hex, suffix); | |
| 169 | } | ||
| 170 |
2/2✓ Branch 0 taken 44260 times.
✓ Branch 1 taken 3 times.
|
44263 | if ((length == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]) |
| 171 | 44260 | || (length | |
| 172 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 44245 times.
|
44260 | == 2 * kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1)) { |
| 173 | const Suffix suffix = (length | ||
| 174 | 18 | == 2 * kDigestSizes[kRmd160] | |
| 175 | 18 | + kAlgorithmIdSizes[kRmd160] + 1) | |
| 176 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
|
18 | ? *(hex.str->rbegin()) |
| 177 | 18 | : kSuffixNone; | |
| 178 | 18 | result = Any(kRmd160, hex, suffix); | |
| 179 | } | ||
| 180 |
2/2✓ Branch 0 taken 44260 times.
✓ Branch 1 taken 3 times.
|
44263 | if ((length == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]) |
| 181 | 44260 | || (length | |
| 182 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 44257 times.
|
44260 | == 2 * kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128] + 1)) { |
| 183 | const Suffix suffix = (length | ||
| 184 | 6 | == 2 * kDigestSizes[kShake128] | |
| 185 | 6 | + kAlgorithmIdSizes[kShake128] + 1) | |
| 186 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | ? *(hex.str->rbegin()) |
| 187 | 6 | : kSuffixNone; | |
| 188 | 6 | result = Any(kShake128, hex, suffix); | |
| 189 | } | ||
| 190 | |||
| 191 | 44263 | return result; | |
| 192 | } | ||
| 193 | |||
| 194 | |||
| 195 | /** | ||
| 196 | * Allows the caller to create the context on the stack. | ||
| 197 | */ | ||
| 198 | 1402012 | unsigned GetContextSize(const Algorithms algorithm) { | |
| 199 |
4/5✓ Branch 0 taken 608559 times.
✓ Branch 1 taken 792459 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 968 times.
✗ Branch 4 not taken.
|
1402012 | switch (algorithm) { |
| 200 | 608559 | case kMd5: | |
| 201 | 608559 | return sizeof(md5_ctx); | |
| 202 | 792459 | case kSha1: | |
| 203 | 792459 | return sizeof(sha1_ctx); | |
| 204 | 38 | case kRmd160: | |
| 205 | 38 | return sizeof(ripemd160_ctx); | |
| 206 | 968 | case kShake128: | |
| 207 | 968 | return sizeof(sha3_128_ctx); | |
| 208 | ✗ | default: | |
| 209 | ✗ | PANIC(kLogDebug | kLogSyslogErr, | |
| 210 | "tried to generate hash context for unspecified hash. Aborting..."); | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | 1402368 | void Init(ContextPtr context) { | |
| 215 |
4/5✓ Branch 0 taken 608577 times.
✓ Branch 1 taken 792791 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 968 times.
✗ Branch 4 not taken.
|
1402368 | switch (context.algorithm) { |
| 216 | 608577 | case kMd5: | |
| 217 | 608577 | md5_init(reinterpret_cast<md5_ctx *>(context.buffer)); | |
| 218 | 608577 | break; | |
| 219 | 792791 | case kSha1: | |
| 220 | 792791 | sha1_init(reinterpret_cast<sha1_ctx *>(context.buffer)); | |
| 221 | 792779 | break; | |
| 222 | 38 | case kRmd160: | |
| 223 | 38 | ripemd160_init(reinterpret_cast<ripemd160_ctx *>(context.buffer)); | |
| 224 | 38 | break; | |
| 225 | 968 | case kShake128: | |
| 226 | 968 | sha3_128_init(reinterpret_cast<sha3_128_ctx *>(context.buffer)); | |
| 227 | 968 | break; | |
| 228 | ✗ | default: | |
| 229 | ✗ | PANIC(NULL); // Undefined hash | |
| 230 | } | ||
| 231 | 1402362 | } | |
| 232 | |||
| 233 | 281331878 | void Update(const unsigned char *buffer, const unsigned buffer_length, | |
| 234 | ContextPtr context) { | ||
| 235 |
4/5✓ Branch 0 taken 72210084 times.
✓ Branch 1 taken 70708767 times.
✓ Branch 2 taken 69206060 times.
✓ Branch 3 taken 69206973 times.
✗ Branch 4 not taken.
|
281331878 | switch (context.algorithm) { |
| 236 | 72210084 | case kMd5: | |
| 237 | 72210084 | md5_update(reinterpret_cast<md5_ctx *>(context.buffer), | |
| 238 | buffer_length, buffer); | ||
| 239 | 72210084 | break; | |
| 240 | 70708767 | case kSha1: | |
| 241 | 70708767 | sha1_update(reinterpret_cast<sha1_ctx *>(context.buffer), | |
| 242 | buffer_length, buffer); | ||
| 243 | 70709187 | break; | |
| 244 | 69206060 | case kRmd160: | |
| 245 | 69206060 | ripemd160_update(reinterpret_cast<ripemd160_ctx *>(context.buffer), | |
| 246 | buffer_length, buffer); | ||
| 247 | 69206060 | break; | |
| 248 | 69206973 | case kShake128: | |
| 249 | 69206973 | sha3_128_update(reinterpret_cast<sha3_128_ctx *>(context.buffer), | |
| 250 | buffer_length, buffer); | ||
| 251 | 69206973 | break; | |
| 252 | ✗ | default: | |
| 253 | ✗ | PANIC(NULL); // Undefined hash | |
| 254 | } | ||
| 255 | 281332304 | } | |
| 256 | |||
| 257 | 1377515 | void Final(ContextPtr context, Any *any_digest) { | |
| 258 |
4/5✓ Branch 0 taken 608553 times.
✓ Branch 1 taken 767956 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 968 times.
✗ Branch 4 not taken.
|
1377515 | switch (context.algorithm) { |
| 259 | 608553 | case kMd5: | |
| 260 | 608553 | Md5Digest(reinterpret_cast<md5_ctx *>(context.buffer), any_digest->digest); | |
| 261 | 608553 | break; | |
| 262 | 767956 | case kSha1: | |
| 263 | 767956 | Sha1Digest(reinterpret_cast<sha1_ctx *>(context.buffer), | |
| 264 | 767956 | any_digest->digest); | |
| 265 | 767977 | break; | |
| 266 | 38 | case kRmd160: | |
| 267 | 38 | Ripemd160Digest(reinterpret_cast<ripemd160_ctx *>(context.buffer), | |
| 268 | 38 | any_digest->digest); | |
| 269 | 38 | break; | |
| 270 | 968 | case kShake128: | |
| 271 | 968 | Shake128Digest(reinterpret_cast<sha3_128_ctx *>(context.buffer), | |
| 272 | 968 | any_digest->digest); | |
| 273 | 968 | break; | |
| 274 | ✗ | default: | |
| 275 | ✗ | PANIC(NULL); // Undefined hash | |
| 276 | } | ||
| 277 | 1377536 | any_digest->algorithm = context.algorithm; | |
| 278 | 1377536 | } | |
| 279 | |||
| 280 | |||
| 281 | 12610 | void HashMem(const unsigned char *buffer, const unsigned buffer_size, | |
| 282 | Any *any_digest) { | ||
| 283 | 12610 | const Algorithms algorithm = any_digest->algorithm; | |
| 284 |
1/2✓ Branch 1 taken 12610 times.
✗ Branch 2 not taken.
|
12610 | ContextPtr context(algorithm); |
| 285 | 12610 | context.buffer = alloca(context.size); | |
| 286 | |||
| 287 |
1/2✓ Branch 1 taken 12610 times.
✗ Branch 2 not taken.
|
12610 | Init(context); |
| 288 |
1/2✓ Branch 1 taken 12610 times.
✗ Branch 2 not taken.
|
12610 | Update(buffer, buffer_size, context); |
| 289 |
1/2✓ Branch 1 taken 12610 times.
✗ Branch 2 not taken.
|
12610 | Final(context, any_digest); |
| 290 | 12610 | } | |
| 291 | |||
| 292 | |||
| 293 | 1114 | void HashString(const std::string &content, Any *any_digest) { | |
| 294 | 1114 | HashMem(reinterpret_cast<const unsigned char *>(content.data()), | |
| 295 | 1114 | content.length(), any_digest); | |
| 296 | 1114 | } | |
| 297 | |||
| 298 | |||
| 299 | 303744 | void Hmac(const string &key, | |
| 300 | const unsigned char *buffer, | ||
| 301 | const unsigned buffer_size, | ||
| 302 | Any *any_digest) { | ||
| 303 | 303744 | const Algorithms algorithm = any_digest->algorithm; | |
| 304 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 303744 times.
|
303744 | assert(algorithm != kAny); |
| 305 | |||
| 306 | 303744 | const unsigned block_size = kBlockSizes[algorithm]; | |
| 307 | 303744 | unsigned char key_block[block_size]; | |
| 308 | 303744 | memset(key_block, 0, block_size); | |
| 309 |
2/2✓ Branch 1 taken 3684 times.
✓ Branch 2 taken 300060 times.
|
303744 | if (key.length() > block_size) { |
| 310 |
1/2✓ Branch 1 taken 3684 times.
✗ Branch 2 not taken.
|
3684 | Any hash_key(algorithm); |
| 311 |
1/2✓ Branch 3 taken 3684 times.
✗ Branch 4 not taken.
|
3684 | HashMem(reinterpret_cast<const unsigned char *>(key.data()), key.length(), |
| 312 | &hash_key); | ||
| 313 | 3684 | memcpy(key_block, hash_key.digest, kDigestSizes[algorithm]); | |
| 314 | } else { | ||
| 315 |
2/2✓ Branch 1 taken 300051 times.
✓ Branch 2 taken 9 times.
|
300060 | if (key.length() > 0) |
| 316 | 300051 | memcpy(key_block, key.data(), key.length()); | |
| 317 | } | ||
| 318 | |||
| 319 | 303744 | unsigned char pad_block[block_size]; | |
| 320 | // Inner hash | ||
| 321 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | Any hash_inner(algorithm); |
| 322 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | ContextPtr context_inner(algorithm); |
| 323 | 303744 | context_inner.buffer = alloca(context_inner.size); | |
| 324 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | Init(context_inner); |
| 325 |
2/2✓ Branch 0 taken 19439616 times.
✓ Branch 1 taken 303744 times.
|
19743360 | for (unsigned i = 0; i < block_size; ++i) |
| 326 | 19439616 | pad_block[i] = key_block[i] ^ 0x36; | |
| 327 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | Update(pad_block, block_size, context_inner); |
| 328 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | Update(buffer, buffer_size, context_inner); |
| 329 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | Final(context_inner, &hash_inner); |
| 330 | |||
| 331 | // Outer hash | ||
| 332 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | ContextPtr context_outer(algorithm); |
| 333 | 303744 | context_outer.buffer = alloca(context_outer.size); | |
| 334 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | Init(context_outer); |
| 335 |
2/2✓ Branch 0 taken 19439616 times.
✓ Branch 1 taken 303744 times.
|
19743360 | for (unsigned i = 0; i < block_size; ++i) |
| 336 | 19439616 | pad_block[i] = key_block[i] ^ 0x5c; | |
| 337 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | Update(pad_block, block_size, context_outer); |
| 338 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | Update(hash_inner.digest, kDigestSizes[algorithm], context_outer); |
| 339 | |||
| 340 |
1/2✓ Branch 1 taken 303744 times.
✗ Branch 2 not taken.
|
303744 | Final(context_outer, any_digest); |
| 341 | 303744 | } | |
| 342 | |||
| 343 | |||
| 344 | 4602 | bool HashFd(int fd, Any *any_digest) { | |
| 345 | 4602 | const Algorithms algorithm = any_digest->algorithm; | |
| 346 |
1/2✓ Branch 1 taken 4602 times.
✗ Branch 2 not taken.
|
4602 | ContextPtr context(algorithm); |
| 347 | 4602 | context.buffer = alloca(context.size); | |
| 348 | |||
| 349 |
1/2✓ Branch 1 taken 4602 times.
✗ Branch 2 not taken.
|
4602 | Init(context); |
| 350 | unsigned char io_buffer[4096]; | ||
| 351 | int actual_bytes; | ||
| 352 |
3/4✓ Branch 1 taken 2122550 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2117948 times.
✓ Branch 4 taken 4602 times.
|
2122550 | while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) { |
| 353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2117948 times.
|
2117948 | if (actual_bytes == -1) { |
| 354 | ✗ | if (errno == EINTR) | |
| 355 | ✗ | continue; | |
| 356 | ✗ | return false; | |
| 357 | } | ||
| 358 |
1/2✓ Branch 1 taken 2117948 times.
✗ Branch 2 not taken.
|
2117948 | Update(io_buffer, actual_bytes, context); |
| 359 | } | ||
| 360 |
1/2✓ Branch 1 taken 4602 times.
✗ Branch 2 not taken.
|
4602 | Final(context, any_digest); |
| 361 | 4602 | return true; | |
| 362 | } | ||
| 363 | |||
| 364 | |||
| 365 | 4602 | bool HashFile(const std::string &filename, Any *any_digest) { | |
| 366 | 4602 | const int fd = open(filename.c_str(), O_RDONLY); | |
| 367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4602 times.
|
4602 | if (fd == -1) |
| 368 | ✗ | return false; | |
| 369 | |||
| 370 | 4602 | const bool result = HashFd(fd, any_digest); | |
| 371 | 4602 | close(fd); | |
| 372 | 4602 | return result; | |
| 373 | } | ||
| 374 | |||
| 375 | |||
| 376 | /** | ||
| 377 | * Fast constructor for hashing path names. | ||
| 378 | */ | ||
| 379 | 6503 | Md5::Md5(const AsciiPtr ascii) { | |
| 380 | 6503 | algorithm = kMd5; | |
| 381 | 6503 | const string *str = ascii.str; | |
| 382 | |||
| 383 | md5_ctx md5_state; | ||
| 384 |
1/2✓ Branch 1 taken 6503 times.
✗ Branch 2 not taken.
|
6503 | md5_init(&md5_state); |
| 385 |
1/2✓ Branch 2 taken 6503 times.
✗ Branch 3 not taken.
|
6503 | md5_update(&md5_state, str->length(), |
| 386 | 6503 | reinterpret_cast<const uint8_t *>(&(*str)[0])); | |
| 387 |
1/2✓ Branch 1 taken 6503 times.
✗ Branch 2 not taken.
|
6503 | Md5Digest(&md5_state, digest); |
| 388 | 6503 | } | |
| 389 | |||
| 390 | |||
| 391 | 4482750 | Md5::Md5(const char *chars, const unsigned length) { | |
| 392 | 4482750 | algorithm = kMd5; | |
| 393 | |||
| 394 | md5_ctx md5_state; | ||
| 395 |
1/2✓ Branch 1 taken 4482750 times.
✗ Branch 2 not taken.
|
4482750 | md5_init(&md5_state); |
| 396 |
1/2✓ Branch 1 taken 4482750 times.
✗ Branch 2 not taken.
|
4482750 | md5_update(&md5_state, length, reinterpret_cast<const uint8_t *>(chars)); |
| 397 |
1/2✓ Branch 1 taken 4482750 times.
✗ Branch 2 not taken.
|
4482750 | Md5Digest(&md5_state, digest); |
| 398 | 4482750 | } | |
| 399 | |||
| 400 | |||
| 401 | ✗ | Md5::Md5(const uint64_t lo, const uint64_t hi) { | |
| 402 | ✗ | algorithm = kMd5; | |
| 403 | ✗ | memcpy(digest, &lo, 8); | |
| 404 | ✗ | memcpy(digest + 8, &hi, 8); | |
| 405 | } | ||
| 406 | |||
| 407 | 8383 | void Md5::ToIntPair(uint64_t *lo, uint64_t *hi) const { | |
| 408 | 8383 | memcpy(lo, digest, 8); | |
| 409 | 8383 | memcpy(hi, digest + 8, 8); | |
| 410 | 8383 | } | |
| 411 | |||
| 412 | |||
| 413 | 300067 | Md5 Any::CastToMd5() { | |
| 414 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 300067 times.
|
300067 | assert(algorithm == kMd5); |
| 415 | 300067 | Md5 result; | |
| 416 | 300067 | memcpy(result.digest, digest, kDigestSizes[kMd5]); | |
| 417 | 300067 | return result; | |
| 418 | } | ||
| 419 | |||
| 420 | 18 | static string HexFromSha256(unsigned char digest[SHA256_DIGEST_SIZE]) { | |
| 421 | 18 | string result; | |
| 422 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | result.reserve(2 * SHA256_DIGEST_SIZE); |
| 423 |
2/2✓ Branch 0 taken 576 times.
✓ Branch 1 taken 18 times.
|
594 | for (unsigned i = 0; i < SHA256_DIGEST_SIZE; ++i) { |
| 424 | 576 | const char d1 = digest[i] / 16; | |
| 425 | 576 | const char d2 = digest[i] % 16; | |
| 426 |
3/4✓ Branch 0 taken 333 times.
✓ Branch 1 taken 243 times.
✓ Branch 3 taken 576 times.
✗ Branch 4 not taken.
|
576 | result.push_back(d1 + ((d1 <= 9) ? '0' : 'a' - 10)); |
| 427 |
3/4✓ Branch 0 taken 399 times.
✓ Branch 1 taken 177 times.
✓ Branch 3 taken 576 times.
✗ Branch 4 not taken.
|
576 | result.push_back(d2 + ((d2 <= 9) ? '0' : 'a' - 10)); |
| 428 | } | ||
| 429 | 18 | return result; | |
| 430 | } | ||
| 431 | |||
| 432 | 3 | string Sha256File(const string &filename) { | |
| 433 |
1/2✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | const int fd = open(filename.c_str(), O_RDONLY); |
| 434 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (fd < 0) |
| 435 | ✗ | return ""; | |
| 436 | |||
| 437 | sha256_ctx ctx; | ||
| 438 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | sha256_init(&ctx); |
| 439 | |||
| 440 | unsigned char io_buffer[4096]; | ||
| 441 | int actual_bytes; | ||
| 442 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
|
3 | while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) { |
| 443 | ✗ | if (actual_bytes == -1) { | |
| 444 | ✗ | if (errno == EINTR) | |
| 445 | ✗ | continue; | |
| 446 | ✗ | close(fd); | |
| 447 | ✗ | return ""; | |
| 448 | } | ||
| 449 | ✗ | sha256_update(&ctx, actual_bytes, io_buffer); | |
| 450 | } | ||
| 451 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | close(fd); |
| 452 | |||
| 453 | unsigned char digest[SHA256_DIGEST_SIZE]; | ||
| 454 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | Sha256Digest(&ctx, digest); |
| 455 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | return HexFromSha256(digest); |
| 456 | } | ||
| 457 | |||
| 458 | 6 | string Sha256Mem(const unsigned char *buffer, const unsigned buffer_size) { | |
| 459 | unsigned char digest[SHA256_DIGEST_SIZE]; | ||
| 460 | sha256_ctx ctx; | ||
| 461 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | sha256_init(&ctx); |
| 462 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | sha256_update(&ctx, buffer_size, buffer); |
| 463 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | Sha256Digest(&ctx, digest); |
| 464 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | return HexFromSha256(digest); |
| 465 | } | ||
| 466 | |||
| 467 | 3 | string Sha256String(const string &content) { | |
| 468 | 3 | return Sha256Mem(reinterpret_cast<const unsigned char *>(content.data()), | |
| 469 | 3 | content.length()); | |
| 470 | } | ||
| 471 | |||
| 472 | |||
| 473 | 21 | std::string Hmac256(const std::string &key, | |
| 474 | const std::string &content, | ||
| 475 | bool raw_output) { | ||
| 476 | sha256_ctx ctx; | ||
| 477 | unsigned char digest[SHA256_DIGEST_SIZE]; | ||
| 478 | 21 | const unsigned block_size = 64; | |
| 479 | 21 | const unsigned key_length = key.length(); | |
| 480 | unsigned char key_block[block_size]; | ||
| 481 | 21 | memset(key_block, 0, block_size); | |
| 482 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 18 times.
|
21 | if (key_length > block_size) { |
| 483 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | sha256_init(&ctx); |
| 484 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | sha256_update(&ctx, key_length, |
| 485 | 3 | reinterpret_cast<const unsigned char *>(key.data())); | |
| 486 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | Sha256Digest(&ctx, key_block); |
| 487 | } else { | ||
| 488 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | if (key.length() > 0) |
| 489 | 18 | memcpy(key_block, key.data(), key_length); | |
| 490 | } | ||
| 491 | |||
| 492 | unsigned char pad_block[block_size]; | ||
| 493 | // Inner hash | ||
| 494 | unsigned char digest_inner[SHA256_DIGEST_SIZE]; | ||
| 495 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | sha256_init(&ctx); |
| 496 |
2/2✓ Branch 0 taken 1344 times.
✓ Branch 1 taken 21 times.
|
1365 | for (unsigned i = 0; i < block_size; ++i) |
| 497 | 1344 | pad_block[i] = key_block[i] ^ 0x36; | |
| 498 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | sha256_update(&ctx, block_size, pad_block); |
| 499 |
1/2✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
|
21 | sha256_update(&ctx, content.length(), |
| 500 | 21 | reinterpret_cast<const unsigned char *>(content.data())); | |
| 501 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | Sha256Digest(&ctx, digest_inner); |
| 502 | |||
| 503 | // Outer hash | ||
| 504 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | sha256_init(&ctx); |
| 505 |
2/2✓ Branch 0 taken 1344 times.
✓ Branch 1 taken 21 times.
|
1365 | for (unsigned i = 0; i < block_size; ++i) |
| 506 | 1344 | pad_block[i] = key_block[i] ^ 0x5c; | |
| 507 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | sha256_update(&ctx, block_size, pad_block); |
| 508 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | sha256_update(&ctx, SHA256_DIGEST_SIZE, digest_inner); |
| 509 | |||
| 510 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | Sha256Digest(&ctx, digest); |
| 511 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9 times.
|
21 | if (raw_output) |
| 512 |
1/2✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | return string(reinterpret_cast<const char *>(digest), SHA256_DIGEST_SIZE); |
| 513 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | return HexFromSha256(digest); |
| 514 | } | ||
| 515 | |||
| 516 | } // namespace shash | ||
| 517 | |||
| 518 | #ifdef CVMFS_NAMESPACE_GUARD | ||
| 519 | } // namespace CVMFS_NAMESPACE_GUARD | ||
| 520 | #endif | ||
| 521 |