1 /*******************************************************************************
2 
3     Wrapper to libgcrypt message digest and HMAC utility classes.
4 
5     Be aware that not all versions of libcgrypt support all hash algorithms; the
6     constructor will throw if the specified algorithm is not supported by the
7     run-time version of libgcrypt. However, if the constructor does not throw,
8     it is safe to assume it will never throw for the same set of parameters
9     (except for the fatal situation that libgcrypt failed allocating memory).
10 
11     Requires linking with libgcrypt:
12             -L-lgcrypt
13 
14     Copyright:
15         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
16         All rights reserved.
17 
18     License:
19         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
20         Alternatively, this file may be distributed under the terms of the Tango
21         3-Clause BSD License (see LICENSE_BSD.txt for details).
22 
23         Bear in mind this module provides bindings to an external library that
24         has its own license, which might be more restrictive. Please check the
25         external library license to see which conditions apply for linking.
26 
27 *******************************************************************************/
28 
29 module ocean.util.cipher.gcrypt.MessageDigest;
30 
31 import ocean.util.cipher.gcrypt.core.MessageDigestCore;
32 import ocean.transition;
33 import ocean.util.cipher.gcrypt.c.md;
34 
35 /*******************************************************************************
36 
37     Message digest/hash generator.
38 
39 *******************************************************************************/
40 
41 public class MessageDigest: MessageDigestCore
42 {
43     /***************************************************************************
44 
45         Constructor.
46 
47         Params:
48             algorithm = the hash algorithm to use
49             flags     = flags to `gcry_md_open()`
50 
51         Throws:
52             `GcryptException` on error. There are two possible error causes:
53               - The parameters are invalid or not supported by the libcrypt
54                 of the run-time enviromnent.
55               - libgcrypt failed allocating memory.
56 
57     ***************************************************************************/
58 
59     public this ( gcry_md_algos algorithm, gcry_md_flags flags = cast(gcry_md_flags)0,
60                      istring file = __FILE__, int line = __LINE__ )
61     {
62         super(algorithm, flags, file, line);
63     }
64 
65     /***************************************************************************
66 
67         Calculates the hash a.k.a. message digest from the input data.
68 
69         Discards the result of a previous hash calculation, invalidating and
70         overwriting a previously returned result.
71 
72         The length of the returned hash is the return value of
73         `gcry_md_get_algo_dlen(algorithm)` for the algorithm passed to the
74         constructor of this class.
75 
76         Params:
77             input_data = data to hash; the elements will be concatenated
78 
79         Returns:
80             the resuting hash.
81 
82     ***************************************************************************/
83 
84     public ubyte[] calculate ( Const!(ubyte)[][] input_data ... )
85     {
86         gcry_md_reset(this.md);
87         return this.calculate_(input_data);
88     }
89 }
90 
91 /******************************************************************************/
92 
93 version ( UnitTest )
94 {
95     import ocean.core.Test;
96 }
97 
98 unittest
99 {
100     // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA224.pdf
101     static Immut!(ubyte)[] sha224_hash = [
102         0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76,
103         0xCC, 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89,
104         0x01, 0x50, 0xB0, 0xC6, 0x45, 0x5C, 0xB4,
105         0xF5, 0x8B, 0x19, 0x52, 0x52, 0x25, 0x25
106     ];
107 
108     scope md = new MessageDigest(gcry_md_algos.GCRY_MD_SHA224);
109 
110     test!("==")(
111         md.calculate(
112             cast(Immut!(ubyte)[])"abcdbcdec",
113             cast(Immut!(ubyte)[])"defdefgefghfghig",
114             cast(Immut!(ubyte)[])"hi",
115             cast(Immut!(ubyte)[])"jhijkijkljklmklmnlmnomno",
116             cast(Immut!(ubyte)[])"pnopq"
117         ),
118         sha224_hash
119     );
120 
121     test!("==")(
122         md.calculate([
123             cast(Immut!(ubyte)[])"abcdbcdec",
124             cast(Immut!(ubyte)[])"defdefgefghfghig",
125             cast(Immut!(ubyte)[])"hi",
126             cast(Immut!(ubyte)[])"jhijkijkljklmklmnlmnomno",
127             cast(Immut!(ubyte)[])"pnopq"
128         ]),
129         sha224_hash
130     );
131 }