1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* MD5Encode filter */
18 #include "memory_.h"
19 #include "strimpl.h"
20 #include "stream.h"
21 #include "smd5.h"
22 
23 /* ------ MD5Encode ------ */
24 
25 private_st_MD5E_state();
26 
27 /* Initialize the state. */
28 static int
s_MD5E_init(stream_state * st)29 s_MD5E_init(stream_state * st)
30 {
31     stream_MD5E_state *const ss = (stream_MD5E_state *) st;
32 
33     gs_md5_init(&ss->md5);
34     return 0;
35 }
36 
37 /* Process a buffer. */
38 static int
s_MD5E_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)39 s_MD5E_process(stream_state * st, stream_cursor_read * pr,
40                stream_cursor_write * pw, bool last)
41 {
42     stream_MD5E_state *const ss = (stream_MD5E_state *) st;
43     int status = 0;
44 
45     if (pr->ptr < pr->limit) {
46         gs_md5_append(&ss->md5, pr->ptr + 1, pr->limit - pr->ptr);
47         pr->ptr = pr->limit;
48     }
49     if (last) {
50         if (pw->limit - pw->ptr >= 16) {
51             gs_md5_finish(&ss->md5, pw->ptr + 1);
52             pw->ptr += 16;
53             status = EOFC;
54         } else
55             status = 1;
56     }
57     return status;
58 }
59 
60 /* Stream template */
61 const stream_template s_MD5E_template = {
62     &st_MD5E_state, s_MD5E_init, s_MD5E_process, 1, 16
63 };
64 
65 stream *
s_MD5E_make_stream(gs_memory_t * mem,byte * digest,int digest_size)66 s_MD5E_make_stream(gs_memory_t *mem, byte *digest, int digest_size)
67 {
68     stream *s = s_alloc(mem, "s_MD5E_make_stream");
69     stream_state *ss = s_alloc_state(mem, s_MD5E_template.stype, "s_MD5E_make_stream");
70 
71     if (ss == NULL || s == NULL)
72         goto err;
73     ss->templat = &s_MD5E_template;
74     if (s_init_filter(s, ss, digest, digest_size, NULL) < 0)
75 goto err;
76     s->strm = s;
77     return s;
78 err:
79     gs_free_object(mem, ss, "s_MD5E_make_stream");
80     gs_free_object(mem, s, "s_MD5E_make_stream");
81     return NULL;
82 }
83 
84 /* Process a buffer. */
85 static int
s_MD5C_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)86 s_MD5C_process(stream_state * st, stream_cursor_read * pr,
87                stream_cursor_write * pw, bool last)
88 {
89     stream_MD5E_state *const ss = (stream_MD5E_state *) st;
90     int nr = pr->limit - pr->ptr;
91     int nw = pw->limit - pw->ptr;
92     int n = min(nr, nw);
93 
94     gs_md5_append(&ss->md5, pr->ptr + 1, n);
95     memcpy(pw->ptr + 1, pr->ptr + 1, n);
96     pr->ptr += n;
97     pw->ptr += n;
98     if (pw->limit == pw->ptr)
99         return 1;
100     return 0;
101 }
102 /* Stream template */
103 const stream_template s_MD5C_template = {
104     &st_MD5E_state, s_MD5E_init, s_MD5C_process, 1, 1024
105 };
106 
107 stream *
s_MD5C_make_stream(gs_memory_t * mem,stream * strm)108 s_MD5C_make_stream(gs_memory_t *mem, stream *strm)
109 {
110     stream *s = s_alloc(mem, "s_MD5E_make_stream");
111     stream_state *ss = s_alloc_state(mem, s_MD5E_template.stype, "s_MD5E_make_stream");
112     int buffer_size = 1024;
113     byte *buffer = gs_alloc_bytes(mem, buffer_size, "s_MD5E_make_stream(buffer)");
114 
115     if (ss == NULL || s == NULL || buffer == NULL)
116         goto err;
117     ss->templat = &s_MD5C_template;
118     if (s_init_filter(s, ss, buffer, buffer_size, NULL) < 0)
119         goto err;
120     s->strm = strm;
121     s->close_strm = true;
122     return s;
123 err:
124     gs_free_object(mem, ss, "s_MD5E_make_stream");
125     gs_free_object(mem, s, "s_MD5E_make_stream");
126     gs_free_object(mem, buffer, "s_MD5E_make_stream");
127     return NULL;
128 }
129 
130 /* Get a digest. Apply 'flush' before calling. */
131 int
s_MD5C_get_digest(stream * s,byte * buf,int buf_length)132 s_MD5C_get_digest(stream *s, byte *buf, int buf_length)
133 {
134     stream_MD5E_state *const ss = (stream_MD5E_state *)s->state;
135     gs_md5_state_t md5;
136     byte b[16], *p;
137     int l = min(16, buf_length), k;
138 
139     if (s->procs.process != s_MD5C_process)
140         return 0; /* Must not happen. */
141     md5 = ss->md5;
142     gs_md5_finish(&md5, b);
143     memcpy(buf, b, l);
144     for (p = b + l; p < b + sizeof(b); p += l) {
145         for (k = 0; k < l && p + k < b + sizeof(b); k++)
146             buf[k] ^= p[k];
147     }
148     return l;
149 }
150