1 /******************************************************************************
2 
3         copyright:      Copyright (c) 2006 Tango. All rights reserved
4 
5         license:        BSD style: see doc/license.txt for details
6 
7         version:        Initial release: Feb 2006
8 
9         author:         Regan Heath, Oskar Linde
10 
11         This module defines the Digest interface. 
12 
13 ******************************************************************************/
14 
15 module tango.util.digest.Digest;
16 
17 private import tango.stdc.stdlib : alloca;
18 
19 /*******************************************************************************
20 
21         The DigestTransform interface defines the interface of message
22         digest algorithms, such as MD5 and SHA. Message digests are
23         secure hash functions that take a message of arbitrary length
24         and produce a fix length digest as output.
25 
26         A object implementing the DigestTransform should start out initialized.
27         The data is processed though calls to the update method. Once all data
28         has been sent to the algorithm, the digest is finalized and computed
29         with the digest method.
30 
31         The digest method may only be called once. After the digest
32         method has been called, the algorithm is reset to its initial
33         state.
34 
35         Using the update method, data may be processed piece by piece, 
36         which is useful for cases involving streams of data.
37 
38         For example:
39         ---
40         // create an MD5 hash algorithm
41         Md5 hash = new Md5();
42 
43         // process some data
44         hash.update("The quick brown fox");
45 
46         // process some more data
47         hash.update(" jumps over the lazy dog");
48 
49         // conclude algorithm and produce digest
50         ubyte[] digest = hash.binaryDigest();
51         ---
52 
53 ******************************************************************************/
54 
55 abstract class Digest 
56 {
57         /*********************************************************************
58      
59                Processes data
60                
61                Remarks:
62                      Updates the hash algorithm state with new data
63                  
64         *********************************************************************/
65     
66         abstract Digest update (const(void[]) data);
67     
68         /********************************************************************
69 
70                Computes the digest and resets the state
71 
72                Params:
73                    buffer = a buffer can be supplied for the digest to be
74                             written to
75 
76                Remarks:
77                    If the buffer is not large enough to hold the
78                    digest, a new buffer is allocated and returned.
79                    The algorithm state is always reset after a call to
80                    binaryDigest. Use the digestSize method to find out how
81                    large the buffer has to be.
82                    
83         *********************************************************************/
84     
85         abstract ubyte[] binaryDigest(ubyte[] buffer = null);
86     
87         /********************************************************************
88      
89                Returns the size in bytes of the digest
90                
91                Returns:
92                  the size of the digest in bytes
93 
94                Remarks:
95                  Returns the size of the digest.
96                  
97         *********************************************************************/
98     
99         abstract uint digestSize();
100         
101         /*********************************************************************
102                
103                Computes the digest as a hex string and resets the state
104                
105                Params:
106                    buffer = a buffer can be supplied in which the digest
107                             will be written. It needs to be able to hold
108                             2 * digestSize chars
109             
110                Remarks:
111                     If the buffer is not large enough to hold the hex digest,
112                     a new buffer is allocated and returned. The algorithm
113                     state is always reset after a call to hexDigest.
114                     
115         *********************************************************************/
116         
117         char[] hexDigest (char[] buffer = null) 
118         {
119                 uint ds = digestSize();
120             
121                 if (buffer.length < ds * 2)
122                     buffer.length = ds * 2;
123                 
124                 version(OSX){
125                     ubyte[] buf = new ubyte[ds]; // the whole alloca mess needs to be adressed better
126                 } else {
127                     ubyte[] buf = (cast(ubyte *) alloca(ds))[0..ds];
128                 }
129                 ubyte[] ret = binaryDigest(buf);
130                 assert(ret.ptr == buf.ptr);
131             
132                 __gshared immutable immutable(char)[] hexdigits = "0123456789abcdef";
133                 int i = 0;
134             
135                 foreach (b; buf) 
136                         {
137                         buffer[i++] = hexdigits[b >> 4];
138                         buffer[i++] = hexdigits[b & 0xf];
139                         }
140             
141                 return buffer;
142         }
143 }
144