| GCC Code Coverage Report | |||||||||||||||||||||
        
  | 
    |||||||||||||||||||||
| Line | Branch | Exec | Source | 
1  | 
    /**  | 
    ||
2  | 
    * This file is part of the CernVM File System.  | 
    ||
3  | 
    */  | 
    ||
4  | 
    |||
5  | 
    #include "cvmfs_config.h"  | 
    ||
6  | 
    #include "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 "duplex_ssl.h"  | 
    ||
21  | 
    #include "KeccakHash.h"  | 
    ||
22  | 
    |||
23  | 
    using namespace std; // NOLINT  | 
    ||
24  | 
    |||
25  | 
    #ifdef CVMFS_NAMESPACE_GUARD  | 
    ||
26  | 
    namespace CVMFS_NAMESPACE_GUARD { | 
    ||
27  | 
    #endif  | 
    ||
28  | 
    |||
29  | 
    namespace shash { | 
    ||
30  | 
    |||
31  | 
    const char *kAlgorithmIds[] =  | 
    ||
32  | 
      {"", "", "-rmd160", "-shake128", ""}; | 
    ||
33  | 
    |||
34  | 
    |||
35  | 
    22  | 
    bool HexPtr::IsValid() const { | 
    |
36  | 
    22  | 
    const unsigned l = str->length();  | 
    |
37  | 
    ✓✓ | 22  | 
    if (l == 0)  | 
    
38  | 
    1  | 
    return false;  | 
    |
39  | 
    21  | 
    const char *c = str->data(); // Walks through the string  | 
    |
40  | 
    21  | 
    unsigned i = 0; // String position of *c  | 
    |
41  | 
    |||
42  | 
    ✓✓ | 825  | 
      for ( ; i < l; ++i, ++c) { | 
    
43  | 
    ✓✓ | 820  | 
    if (*c == '-')  | 
    
44  | 
    14  | 
    break;  | 
    |
45  | 
    ✓✗✓✗ ✓✓✓✓  | 
    806  | 
    if ((*c < '0') || (*c > 'f') || ((*c > '9') && (*c < 'a')))  | 
    
46  | 
    2  | 
    return false;  | 
    |
47  | 
    }  | 
    ||
48  | 
    |||
49  | 
    // Walk through all algorithms  | 
    ||
50  | 
    ✓✓ | 85  | 
      for (unsigned j = 0; j < kAny; ++j) { | 
    
51  | 
    70  | 
    const unsigned hex_length = 2*kDigestSizes[j];  | 
    |
52  | 
    70  | 
    const unsigned algo_id_length = kAlgorithmIdSizes[j];  | 
    |
53  | 
    ✓✓ | 70  | 
        if (i == hex_length) { | 
    
54  | 
    // Right suffix?  | 
    ||
55  | 
    ✓✓✓✓ ✓✓  | 
    65  | 
          for ( ; (i < l) && (i-hex_length < algo_id_length); ++i, ++c) { | 
    
56  | 
    ✓✓ | 53  | 
    if (*c != kAlgorithmIds[j][i-hex_length])  | 
    
57  | 
    10  | 
    break;  | 
    |
58  | 
    }  | 
    ||
59  | 
    ✓✓✓✗ | 
    22  | 
    if ((i == l) && (l == hex_length + algo_id_length))  | 
    
60  | 
    4  | 
    return true;  | 
    |
61  | 
    18  | 
    i = hex_length;  | 
    |
62  | 
    18  | 
    c = str->data() + i;  | 
    |
63  | 
    }  | 
    ||
64  | 
    }  | 
    ||
65  | 
    |||
66  | 
    15  | 
    return false;  | 
    |
67  | 
    }  | 
    ||
68  | 
    |||
69  | 
    |||
70  | 
    Algorithms ParseHashAlgorithm(const string &algorithm_option) { | 
    ||
71  | 
    if (algorithm_option == "sha1")  | 
    ||
72  | 
    return kSha1;  | 
    ||
73  | 
    if (algorithm_option == "rmd160")  | 
    ||
74  | 
    return kRmd160;  | 
    ||
75  | 
    if (algorithm_option == "shake128")  | 
    ||
76  | 
    return kShake128;  | 
    ||
77  | 
    return kAny;  | 
    ||
78  | 
    }  | 
    ||
79  | 
    |||
80  | 
    |||
81  | 
    3734  | 
    Any MkFromHexPtr(const HexPtr hex, const char suffix) { | 
    |
82  | 
    3734  | 
    Any result;  | 
    |
83  | 
    |||
84  | 
    3734  | 
    const unsigned length = hex.str->length();  | 
    |
85  | 
    ✓✓ | 3734  | 
    if (length == 2*kDigestSizes[kMd5])  | 
    
86  | 
    ✗✓ | 1  | 
    result = Any(kMd5, hex);  | 
    
87  | 
    ✓✓ | 3734  | 
    if (length == 2*kDigestSizes[kSha1])  | 
    
88  | 
    ✗✓ | 3683  | 
    result = Any(kSha1, hex);  | 
    
89  | 
    // TODO(jblomer) compare -rmd160, -shake128  | 
    ||
90  | 
    ✓✓ | 3734  | 
    if ((length == 2*kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]))  | 
    
91  | 
    ✗✓ | 4  | 
    result = Any(kRmd160, hex);  | 
    
92  | 
    ✓✓ | 3734  | 
    if ((length == 2*kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]))  | 
    
93  | 
    ✗✓ | 1  | 
    result = Any(kShake128, hex);  | 
    
94  | 
    |||
95  | 
    3734  | 
    result.suffix = suffix;  | 
    |
96  | 
    3734  | 
    return result;  | 
    |
97  | 
    }  | 
    ||
98  | 
    |||
99  | 
    |||
100  | 
    /**  | 
    ||
101  | 
    * Similar to MkFromHexPtr but the suffix is deducted from the HexPtr string.  | 
    ||
102  | 
    */  | 
    ||
103  | 
    6874  | 
    Any MkFromSuffixedHexPtr(const HexPtr hex) { | 
    |
104  | 
    6874  | 
    Any result;  | 
    |
105  | 
    |||
106  | 
    6874  | 
    const unsigned length = hex.str->length();  | 
    |
107  | 
    ✓✓✓✓ | 
    6874  | 
    if ((length == 2*kDigestSizes[kMd5]) || (length == 2*kDigestSizes[kMd5] + 1))  | 
    
108  | 
      { | 
    ||
109  | 
    6642  | 
    Suffix suffix = (length == 2*kDigestSizes[kMd5] + 1) ?  | 
    |
110  | 
    ✓✓ | 6642  | 
    *(hex.str->rbegin()) : kSuffixNone;  | 
    
111  | 
    ✗✓ | 6642  | 
    result = Any(kMd5, hex, suffix);  | 
    
112  | 
    }  | 
    ||
113  | 
    ✓✓✓✓ | 
    13614  | 
    if ((length == 2*kDigestSizes[kSha1]) ||  | 
    
114  | 
    6740  | 
    (length == 2*kDigestSizes[kSha1] + 1))  | 
    |
115  | 
      { | 
    ||
116  | 
    225  | 
    Suffix suffix = (length == 2*kDigestSizes[kSha1] + 1) ?  | 
    |
117  | 
    ✓✓ | 225  | 
    *(hex.str->rbegin()) : kSuffixNone;  | 
    
118  | 
    ✗✓ | 225  | 
    result = Any(kSha1, hex, suffix);  | 
    
119  | 
    }  | 
    ||
120  | 
    ✓✓✓✓ | 
    20620  | 
    if ((length == 2*kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160]) ||  | 
    
121  | 
    13746  | 
    (length == 2*kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1))  | 
    |
122  | 
      { | 
    ||
123  | 
    Suffix suffix =  | 
    ||
124  | 
    8  | 
    (length == 2*kDigestSizes[kRmd160] + kAlgorithmIdSizes[kRmd160] + 1)  | 
    |
125  | 
    ? *(hex.str->rbegin())  | 
    ||
126  | 
    ✓✓ | 8  | 
    : kSuffixNone;  | 
    
127  | 
    ✗✓ | 4  | 
    result = Any(kRmd160, hex, suffix);  | 
    
128  | 
    }  | 
    ||
129  | 
    ✓✓✓✓ | 
    20620  | 
    if ((length == 2*kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128]) ||  | 
    
130  | 
    13746  | 
    (length == 2*kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128] + 1))  | 
    |
131  | 
      { | 
    ||
132  | 
    Suffix suffix =  | 
    ||
133  | 
    4  | 
    (length == 2*kDigestSizes[kShake128] + kAlgorithmIdSizes[kShake128] + 1)  | 
    |
134  | 
    ? *(hex.str->rbegin())  | 
    ||
135  | 
    ✓✓ | 4  | 
    : kSuffixNone;  | 
    
136  | 
    ✗✓ | 2  | 
    result = Any(kShake128, hex, suffix);  | 
    
137  | 
    }  | 
    ||
138  | 
    |||
139  | 
    6874  | 
    return result;  | 
    |
140  | 
    }  | 
    ||
141  | 
    |||
142  | 
    |||
143  | 
    /**  | 
    ||
144  | 
    * Allows the caller to create the context on the stack.  | 
    ||
145  | 
    */  | 
    ||
146  | 
    240115  | 
    unsigned GetContextSize(const Algorithms algorithm) { | 
    |
147  | 
    ✓✓✓✓ ✗  | 
    240115  | 
      switch (algorithm) { | 
    
148  | 
    case kMd5:  | 
    ||
149  | 
    210410  | 
    return sizeof(MD5_CTX);  | 
    |
150  | 
    case kSha1:  | 
    ||
151  | 
    29536  | 
    return sizeof(SHA_CTX);  | 
    |
152  | 
    case kRmd160:  | 
    ||
153  | 
    13  | 
    return sizeof(RIPEMD160_CTX);  | 
    |
154  | 
    case kShake128:  | 
    ||
155  | 
    156  | 
    return sizeof(Keccak_HashInstance);  | 
    |
156  | 
    default:  | 
    ||
157  | 
    LogCvmfs(kLogHash, kLogDebug | kLogSyslogErr, "tried to generate hash "  | 
    ||
158  | 
    "context for unspecified hash. Aborting...");  | 
    ||
159  | 
    abort(); // Undefined hash  | 
    ||
160  | 
    }  | 
    ||
161  | 
    }  | 
    ||
162  | 
    |||
163  | 
    240123  | 
    void Init(ContextPtr context) { | 
    |
164  | 
    HashReturn keccak_result;  | 
    ||
165  | 
    ✓✓✓✓ ✗  | 
    240123  | 
      switch (context.algorithm) { | 
    
166  | 
    case kMd5:  | 
    ||
167  | 
    ✗✓ | 210411  | 
    assert(context.size == sizeof(MD5_CTX));  | 
    
168  | 
    210411  | 
    MD5_Init(reinterpret_cast<MD5_CTX *>(context.buffer));  | 
    |
169  | 
    210411  | 
    break;  | 
    |
170  | 
    case kSha1:  | 
    ||
171  | 
    ✗✓ | 29541  | 
    assert(context.size == sizeof(SHA_CTX));  | 
    
172  | 
    29541  | 
    SHA1_Init(reinterpret_cast<SHA_CTX *>(context.buffer));  | 
    |
173  | 
    29541  | 
    break;  | 
    |
174  | 
    case kRmd160:  | 
    ||
175  | 
    ✗✓ | 14  | 
    assert(context.size == sizeof(RIPEMD160_CTX));  | 
    
176  | 
    14  | 
    RIPEMD160_Init(reinterpret_cast<RIPEMD160_CTX *>(context.buffer));  | 
    |
177  | 
    14  | 
    break;  | 
    |
178  | 
    case kShake128:  | 
    ||
179  | 
    ✗✓ | 157  | 
    assert(context.size == sizeof(Keccak_HashInstance));  | 
    
180  | 
    keccak_result = Keccak_HashInitialize_SHAKE128(  | 
    ||
181  | 
    157  | 
    reinterpret_cast<Keccak_HashInstance *>(context.buffer));  | 
    |
182  | 
    ✗✓ | 157  | 
    assert(keccak_result == SUCCESS);  | 
    
183  | 
    157  | 
    break;  | 
    |
184  | 
    default:  | 
    ||
185  | 
    abort(); // Undefined hash  | 
    ||
186  | 
    }  | 
    ||
187  | 
    240123  | 
    }  | 
    |
188  | 
    |||
189  | 
    97308292  | 
    void Update(const unsigned char *buffer, const unsigned buffer_length,  | 
    |
190  | 
    ContextPtr context)  | 
    ||
191  | 
    { | 
    ||
192  | 
    HashReturn keccak_result;  | 
    ||
193  | 
    ✓✓✓✓ ✗  | 
    97308292  | 
      switch (context.algorithm) { | 
    
194  | 
    case kMd5:  | 
    ||
195  | 
    ✗✓ | 27468699  | 
    assert(context.size == sizeof(MD5_CTX));  | 
    
196  | 
    MD5_Update(reinterpret_cast<MD5_CTX *>(context.buffer),  | 
    ||
197  | 
    27468699  | 
    buffer, buffer_length);  | 
    |
198  | 
    27468699  | 
    break;  | 
    |
199  | 
    case kSha1:  | 
    ||
200  | 
    ✗✓ | 23702079  | 
    assert(context.size == sizeof(SHA_CTX));  | 
    
201  | 
    SHA1_Update(reinterpret_cast<SHA_CTX *>(context.buffer),  | 
    ||
202  | 
    23702079  | 
    buffer, buffer_length);  | 
    |
203  | 
    23702079  | 
    break;  | 
    |
204  | 
    case kRmd160:  | 
    ||
205  | 
    ✗✓ | 23068688  | 
    assert(context.size == sizeof(RIPEMD160_CTX));  | 
    
206  | 
    RIPEMD160_Update(reinterpret_cast<RIPEMD160_CTX *>(context.buffer),  | 
    ||
207  | 
    23068688  | 
    buffer, buffer_length);  | 
    |
208  | 
    23068688  | 
    break;  | 
    |
209  | 
    case kShake128:  | 
    ||
210  | 
    ✗✓ | 23068826  | 
    assert(context.size == sizeof(Keccak_HashInstance));  | 
    
211  | 
    keccak_result = Keccak_HashUpdate(reinterpret_cast<Keccak_HashInstance *>(  | 
    ||
212  | 
    23068826  | 
    context.buffer), buffer, buffer_length * 8);  | 
    |
213  | 
    ✗✓ | 23068826  | 
    assert(keccak_result == SUCCESS);  | 
    
214  | 
    23068826  | 
    break;  | 
    |
215  | 
    default:  | 
    ||
216  | 
    abort(); // Undefined hash  | 
    ||
217  | 
    }  | 
    ||
218  | 
    97308292  | 
    }  | 
    |
219  | 
    |||
220  | 
    235048  | 
    void Final(ContextPtr context, Any *any_digest) { | 
    |
221  | 
    HashReturn keccak_result;  | 
    ||
222  | 
    ✓✓✓✓ ✗  | 
    235048  | 
      switch (context.algorithm) { | 
    
223  | 
    case kMd5:  | 
    ||
224  | 
    ✗✓ | 210411  | 
    assert(context.size == sizeof(MD5_CTX));  | 
    
225  | 
    MD5_Final(any_digest->digest,  | 
    ||
226  | 
    210411  | 
    reinterpret_cast<MD5_CTX *>(context.buffer));  | 
    |
227  | 
    210411  | 
    break;  | 
    |
228  | 
    case kSha1:  | 
    ||
229  | 
    ✗✓ | 24466  | 
    assert(context.size == sizeof(SHA_CTX));  | 
    
230  | 
    SHA1_Final(any_digest->digest,  | 
    ||
231  | 
    24466  | 
    reinterpret_cast<SHA_CTX *>(context.buffer));  | 
    |
232  | 
    24466  | 
    break;  | 
    |
233  | 
    case kRmd160:  | 
    ||
234  | 
    ✗✓ | 14  | 
    assert(context.size == sizeof(RIPEMD160_CTX));  | 
    
235  | 
    RIPEMD160_Final(any_digest->digest,  | 
    ||
236  | 
    14  | 
    reinterpret_cast<RIPEMD160_CTX *>(context.buffer));  | 
    |
237  | 
    14  | 
    break;  | 
    |
238  | 
    case kShake128:  | 
    ||
239  | 
    ✗✓ | 157  | 
    assert(context.size == sizeof(Keccak_HashInstance));  | 
    
240  | 
    keccak_result = Keccak_HashFinal(reinterpret_cast<Keccak_HashInstance *>(  | 
    ||
241  | 
    157  | 
    context.buffer), NULL);  | 
    |
242  | 
    ✗✓ | 157  | 
    assert(keccak_result == SUCCESS);  | 
    
243  | 
    keccak_result =  | 
    ||
244  | 
    Keccak_HashSqueeze(reinterpret_cast<Keccak_HashInstance *>(  | 
    ||
245  | 
    157  | 
    context.buffer), any_digest->digest, kDigestSizes[kShake128] * 8);  | 
    |
246  | 
    157  | 
    break;  | 
    |
247  | 
    default:  | 
    ||
248  | 
    abort(); // Undefined hash  | 
    ||
249  | 
    }  | 
    ||
250  | 
    235048  | 
    any_digest->algorithm = context.algorithm;  | 
    |
251  | 
    235048  | 
    }  | 
    |
252  | 
    |||
253  | 
    |||
254  | 
    11593  | 
    void HashMem(const unsigned char *buffer, const unsigned buffer_size,  | 
    |
255  | 
    Any *any_digest)  | 
    ||
256  | 
    { | 
    ||
257  | 
    11593  | 
    Algorithms algorithm = any_digest->algorithm;  | 
    |
258  | 
    11593  | 
    ContextPtr context(algorithm);  | 
    |
259  | 
    11593  | 
    context.buffer = alloca(context.size);  | 
    |
260  | 
    |||
261  | 
    11593  | 
    Init(context);  | 
    |
262  | 
    11593  | 
    Update(buffer, buffer_size, context);  | 
    |
263  | 
    11593  | 
    Final(context, any_digest);  | 
    |
264  | 
    11593  | 
    }  | 
    |
265  | 
    |||
266  | 
    |||
267  | 
    229  | 
    void HashString(const std::string &content, Any *any_digest) { | 
    |
268  | 
    HashMem(reinterpret_cast<const unsigned char *>(content.data()),  | 
    ||
269  | 
    229  | 
    content.length(), any_digest);  | 
    |
270  | 
    229  | 
    }  | 
    |
271  | 
    |||
272  | 
    |||
273  | 
    106073  | 
    void Hmac(  | 
    |
274  | 
    const string &key,  | 
    ||
275  | 
    const unsigned char *buffer,  | 
    ||
276  | 
    const unsigned buffer_size,  | 
    ||
277  | 
    Any *any_digest  | 
    ||
278  | 
    ) { | 
    ||
279  | 
    106073  | 
    Algorithms algorithm = any_digest->algorithm;  | 
    |
280  | 
    ✗✓ | 106073  | 
    assert(algorithm != kAny);  | 
    
281  | 
    |||
282  | 
    106073  | 
    const unsigned block_size = kBlockSizes[algorithm];  | 
    |
283  | 
    106073  | 
    unsigned char key_block[block_size];  | 
    |
284  | 
    106073  | 
    memset(key_block, 0, block_size);  | 
    |
285  | 
    ✓✓ | 106073  | 
      if (key.length() > block_size) { | 
    
286  | 
    6056  | 
    Any hash_key(algorithm);  | 
    |
287  | 
    HashMem(reinterpret_cast<const unsigned char *>(key.data()),  | 
    ||
288  | 
    6056  | 
    key.length(), &hash_key);  | 
    |
289  | 
    6056  | 
    memcpy(key_block, hash_key.digest, kDigestSizes[algorithm]);  | 
    |
290  | 
      } else { | 
    ||
291  | 
    ✓✓ | 100017  | 
    if (key.length() > 0)  | 
    
292  | 
    100014  | 
    memcpy(key_block, key.data(), key.length());  | 
    |
293  | 
    }  | 
    ||
294  | 
    |||
295  | 
    106073  | 
    unsigned char pad_block[block_size];  | 
    |
296  | 
    // Inner hash  | 
    ||
297  | 
    106073  | 
    Any hash_inner(algorithm);  | 
    |
298  | 
    106073  | 
    ContextPtr context_inner(algorithm);  | 
    |
299  | 
    106073  | 
    context_inner.buffer = alloca(context_inner.size);  | 
    |
300  | 
    106073  | 
    Init(context_inner);  | 
    |
301  | 
    ✓✓ | 6894745  | 
    for (unsigned i = 0; i < block_size; ++i)  | 
    
302  | 
    6788672  | 
    pad_block[i] = key_block[i] ^ 0x36;  | 
    |
303  | 
    106073  | 
    Update(pad_block, block_size, context_inner);  | 
    |
304  | 
    106073  | 
    Update(buffer, buffer_size, context_inner);  | 
    |
305  | 
    106073  | 
    Final(context_inner, &hash_inner);  | 
    |
306  | 
    |||
307  | 
    // Outer hash  | 
    ||
308  | 
    106073  | 
    ContextPtr context_outer(algorithm);  | 
    |
309  | 
    106073  | 
    context_outer.buffer = alloca(context_outer.size);  | 
    |
310  | 
    106073  | 
    Init(context_outer);  | 
    |
311  | 
    ✓✓ | 6894745  | 
    for (unsigned i = 0; i < block_size; ++i)  | 
    
312  | 
    6788672  | 
    pad_block[i] = key_block[i] ^ 0x5c;  | 
    |
313  | 
    106073  | 
    Update(pad_block, block_size, context_outer);  | 
    |
314  | 
    106073  | 
    Update(hash_inner.digest, kDigestSizes[algorithm], context_outer);  | 
    |
315  | 
    |||
316  | 
    106073  | 
    Final(context_outer, any_digest);  | 
    |
317  | 
    106073  | 
    }  | 
    |
318  | 
    |||
319  | 
    |||
320  | 
    8225  | 
    bool HashFd(int fd, Any *any_digest) { | 
    |
321  | 
    8225  | 
    Algorithms algorithm = any_digest->algorithm;  | 
    |
322  | 
    8225  | 
    ContextPtr context(algorithm);  | 
    |
323  | 
    8225  | 
    context.buffer = alloca(context.size);  | 
    |
324  | 
    |||
325  | 
    8225  | 
    Init(context);  | 
    |
326  | 
    unsigned char io_buffer[4096];  | 
    ||
327  | 
    int actual_bytes;  | 
    ||
328  | 
    ✓✓ | 4061603  | 
      while ((actual_bytes = read(fd, io_buffer, 4096)) != 0) { | 
    
329  | 
    ✗✓ | 4045153  | 
        if (actual_bytes == -1) { | 
    
330  | 
    if (errno == EINTR)  | 
    ||
331  | 
    continue;  | 
    ||
332  | 
    return false;  | 
    ||
333  | 
    }  | 
    ||
334  | 
    4045153  | 
    Update(io_buffer, actual_bytes, context);  | 
    |
335  | 
    }  | 
    ||
336  | 
    8225  | 
    Final(context, any_digest);  | 
    |
337  | 
    8225  | 
    return true;  | 
    |
338  | 
    }  | 
    ||
339  | 
    |||
340  | 
    |||
341  | 
    8225  | 
    bool HashFile(const std::string &filename, Any *any_digest) { | 
    |
342  | 
    8225  | 
    int fd = open(filename.c_str(), O_RDONLY);  | 
    |
343  | 
    ✗✓ | 8225  | 
    if (fd == -1)  | 
    
344  | 
    return false;  | 
    ||
345  | 
    |||
346  | 
    8225  | 
    bool result = HashFd(fd, any_digest);  | 
    |
347  | 
    8225  | 
    close(fd);  | 
    |
348  | 
    8225  | 
    return result;  | 
    |
349  | 
    }  | 
    ||
350  | 
    |||
351  | 
    |||
352  | 
    /**  | 
    ||
353  | 
    * Fast constructor for hashing path names.  | 
    ||
354  | 
    */  | 
    ||
355  | 
    923  | 
    Md5::Md5(const AsciiPtr ascii) { | 
    |
356  | 
    923  | 
    algorithm = kMd5;  | 
    |
357  | 
    923  | 
    const string *str = ascii.str;  | 
    |
358  | 
    |||
359  | 
    MD5_CTX md5_state;  | 
    ||
360  | 
    923  | 
    MD5_Init(&md5_state);  | 
    |
361  | 
    MD5_Update(&md5_state, reinterpret_cast<const unsigned char *>(&(*str)[0]),  | 
    ||
362  | 
    923  | 
    str->length());  | 
    |
363  | 
    923  | 
    MD5_Final(digest, &md5_state);  | 
    |
364  | 
    923  | 
    }  | 
    |
365  | 
    |||
366  | 
    |||
367  | 
    27674  | 
    Md5::Md5(const char *chars, const unsigned length) { | 
    |
368  | 
    27674  | 
    algorithm = kMd5;  | 
    |
369  | 
    |||
370  | 
    MD5_CTX md5_state;  | 
    ||
371  | 
    27674  | 
    MD5_Init(&md5_state);  | 
    |
372  | 
    MD5_Update(&md5_state, reinterpret_cast<const unsigned char *>(chars),  | 
    ||
373  | 
    27674  | 
    length);  | 
    |
374  | 
    27674  | 
    MD5_Final(digest, &md5_state);  | 
    |
375  | 
    27674  | 
    }  | 
    |
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  | 
    722  | 
    void Md5::ToIntPair(uint64_t *lo, uint64_t *hi) const { | 
    |
385  | 
    722  | 
    memcpy(lo, digest, 8);  | 
    |
386  | 
    722  | 
    memcpy(hi, digest+8, 8);  | 
    |
387  | 
    722  | 
    }  | 
    |
388  | 
    |||
389  | 
    |||
390  | 
    100014  | 
    Md5 Any::CastToMd5() { | 
    |
391  | 
    ✗✓ | 100014  | 
    assert(algorithm == kMd5);  | 
    
392  | 
    100014  | 
    Md5 result;  | 
    |
393  | 
    100014  | 
    memcpy(result.digest, digest, kDigestSizes[kMd5]);  | 
    |
394  | 
    100014  | 
    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  | 
    6  | 
    result.reserve(2 * SHA256_DIGEST_LENGTH);  | 
    |
401  | 
    ✓✓ | 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  | 
    ✓✓ | 192  | 
    result.push_back(d1 + ((d1 <= 9) ? '0' : 'a' - 10));  | 
    
405  | 
    ✓✓ | 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  | 
    abort();  | 
    ||
414  | 
    #else  | 
    ||
415  | 
    1  | 
    int fd = open(filename.c_str(), O_RDONLY);  | 
    |
416  | 
    ✗✓ | 1  | 
    if (fd < 0)  | 
    
417  | 
    return "";  | 
    ||
418  | 
    |||
419  | 
    SHA256_CTX ctx;  | 
    ||
420  | 
    1  | 
    SHA256_Init(&ctx);  | 
    |
421  | 
    |||
422  | 
    unsigned char io_buffer[4096];  | 
    ||
423  | 
    int actual_bytes;  | 
    ||
424  | 
    ✗✓ | 2  | 
      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  | 
    close(fd);  | 
    |
434  | 
    |||
435  | 
    unsigned char digest[SHA256_DIGEST_LENGTH];  | 
    ||
436  | 
    1  | 
    SHA256_Final(digest, &ctx);  | 
    |
437  | 
    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  | 
    abort();  | 
    ||
444  | 
    #else  | 
    ||
445  | 
    unsigned char digest[SHA256_DIGEST_LENGTH];  | 
    ||
446  | 
    2  | 
    SHA256(buffer, buffer_size, digest);  | 
    |
447  | 
    2  | 
    return HexFromSha256(digest);  | 
    |
448  | 
    #endif  | 
    ||
449  | 
    }  | 
    ||
450  | 
    |||
451  | 
    1  | 
    string Sha256String(const string &content) { | 
    |
452  | 
    return Sha256Mem(reinterpret_cast<const unsigned char *>(content.data()),  | 
    ||
453  | 
    1  | 
    content.length());  | 
    |
454  | 
    }  | 
    ||
455  | 
    |||
456  | 
    |||
457  | 
    7  | 
    std::string Hmac256(  | 
    |
458  | 
    const std::string &key,  | 
    ||
459  | 
    const std::string &content,  | 
    ||
460  | 
    bool raw_output)  | 
    ||
461  | 
    { | 
    ||
462  | 
    #ifdef OPENSSL_API_INTERFACE_V09  | 
    ||
463  | 
    abort();  | 
    ||
464  | 
    #else  | 
    ||
465  | 
    unsigned char digest[SHA256_DIGEST_LENGTH];  | 
    ||
466  | 
    7  | 
    const unsigned block_size = 64;  | 
    |
467  | 
    7  | 
    const unsigned key_length = key.length();  | 
    |
468  | 
    unsigned char key_block[block_size];  | 
    ||
469  | 
    7  | 
    memset(key_block, 0, block_size);  | 
    |
470  | 
    ✓✓ | 7  | 
      if (key_length > block_size) { | 
    
471  | 
    SHA256(reinterpret_cast<const unsigned char *>(key.data()), key_length,  | 
    ||
472  | 
    1  | 
    key_block);  | 
    |
473  | 
      } else { | 
    ||
474  | 
    ✓✗ | 6  | 
    if (key.length() > 0)  | 
    
475  | 
    6  | 
    memcpy(key_block, key.data(), key_length);  | 
    |
476  | 
    }  | 
    ||
477  | 
    |||
478  | 
    unsigned char pad_block[block_size];  | 
    ||
479  | 
    // Inner hash  | 
    ||
480  | 
    SHA256_CTX ctx_inner;  | 
    ||
481  | 
    unsigned char digest_inner[SHA256_DIGEST_LENGTH];  | 
    ||
482  | 
    7  | 
    SHA256_Init(&ctx_inner);  | 
    |
483  | 
    ✓✓ | 455  | 
    for (unsigned i = 0; i < block_size; ++i)  | 
    
484  | 
    448  | 
    pad_block[i] = key_block[i] ^ 0x36;  | 
    |
485  | 
    7  | 
    SHA256_Update(&ctx_inner, pad_block, block_size);  | 
    |
486  | 
    7  | 
    SHA256_Update(&ctx_inner, content.data(), content.length());  | 
    |
487  | 
    7  | 
    SHA256_Final(digest_inner, &ctx_inner);  | 
    |
488  | 
    |||
489  | 
    // Outer hash  | 
    ||
490  | 
    SHA256_CTX ctx_outer;  | 
    ||
491  | 
    7  | 
    SHA256_Init(&ctx_outer);  | 
    |
492  | 
    ✓✓ | 455  | 
    for (unsigned i = 0; i < block_size; ++i)  | 
    
493  | 
    448  | 
    pad_block[i] = key_block[i] ^ 0x5c;  | 
    |
494  | 
    7  | 
    SHA256_Update(&ctx_outer, pad_block, block_size);  | 
    |
495  | 
    7  | 
    SHA256_Update(&ctx_outer, digest_inner, SHA256_DIGEST_LENGTH);  | 
    |
496  | 
    |||
497  | 
    7  | 
    SHA256_Final(digest, &ctx_outer);  | 
    |
498  | 
    ✓✓ | 7  | 
    if (raw_output)  | 
    
499  | 
    4  | 
    return string(reinterpret_cast<const char *>(digest), SHA256_DIGEST_LENGTH);  | 
    |
500  | 
    3  | 
    return HexFromSha256(digest);  | 
    |
501  | 
    #endif  | 
    ||
502  | 
    }  | 
    ||
503  | 
    |||
504  | 
    } // namespace shash  | 
    ||
505  | 
    |||
506  | 
    #ifdef CVMFS_NAMESPACE_GUARD  | 
    ||
507  | 
    } // namespace CVMFS_NAMESPACE_GUARD  | 
    ||
508  | 
    #endif  | 
    
| Generated by: GCOVR (Version 4.1) |