2 * Copyright (C) 2002 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2002 Wim Taymans <wim.taymans@chello.be>
5 * gstmd5sink.c: A sink computing an md5 checksum from a stream
7 * The md5 code was taken from glibc-2.2.3/crypt/md5.c and slightly
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
33 #include "gstmd5sink.h"
35 GST_DEBUG_CATEGORY_STATIC (gst_md5sink_debug);
36 #define GST_CAT_DEFAULT gst_md5sink_debug
38 GstElementDetails gst_md5sink_details = GST_ELEMENT_DETAILS ("MD5 Sink",
40 "compute MD5 for incoming data",
41 "Benjamin Otte <in7y118@public.uni-hamburg.de>");
43 /* MD5Sink signals and args */
57 GstStaticPadTemplate md5_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
62 #define _do_init(bla) \
63 GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
65 GST_BOILERPLATE_FULL (GstMD5Sink, gst_md5sink, GstElement, GST_TYPE_ELEMENT,
69 /*static void gst_md5sink_set_property (GObject *object, guint prop_id,
70 const GValue *value, GParamSpec *pspec);*/
71 static void gst_md5sink_get_property (GObject * object, guint prop_id,
72 GValue * value, GParamSpec * pspec);
74 static void gst_md5sink_chain (GstPad * pad, GstData * _data);
75 static GstElementStateReturn gst_md5sink_change_state (GstElement * element);
79 static void md5_init_ctx (GstMD5Sink * ctx);
80 static gpointer md5_read_ctx (GstMD5Sink * ctx, gpointer resbuf);
81 static gpointer md5_finish_ctx (GstMD5Sink * ctx, gpointer resbuf);
82 static void md5_process_bytes (const void *buffer, size_t len,
84 static void md5_process_block (const void *buffer, size_t len,
87 /* This array contains the bytes used to pad the buffer to the next
88 64-byte boundary. (RFC 1321, 3.1: Step 1) */
89 static const guchar fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
92 /* Initialize structure containing state of computation.
93 (RFC 1321, 3.3: Step 3) */
95 md5_init_ctx (GstMD5Sink * ctx)
102 ctx->total[0] = ctx->total[1] = 0;
106 /* Process the remaining bytes in the internal buffer and the usual
107 prolog according to the standard and write the result to RESBUF.
109 IMPORTANT: On some systems it is required that RESBUF is correctly
110 aligned for a 32 bits value. */
112 md5_finish_ctx (GstMD5Sink * ctx, gpointer resbuf)
114 /* Take yet unprocessed bytes into account. */
115 guint32 bytes = ctx->buflen;
118 /* Now count remaining bytes. */
119 ctx->total[0] += bytes;
120 if (ctx->total[0] < bytes)
123 pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
124 memcpy (&ctx->buffer[bytes], fillbuf, pad);
126 /* Put the 64-bit file length in *bits* at the end of the buffer. */
127 *(guint32 *) & ctx->buffer[bytes + pad] = GUINT32_TO_LE (ctx->total[0] << 3);
128 *(guint32 *) & ctx->buffer[bytes + pad + 4] =
129 GUINT32_TO_LE ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
131 /* Process last bytes. */
132 md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
134 return md5_read_ctx (ctx, resbuf);
137 /* Put result from CTX in first 16 bytes following RESBUF. The result
138 must be in little endian byte order.
140 IMPORTANT: On some systems it is required that RESBUF is correctly
141 aligned for a 32 bits value. */
143 md5_read_ctx (GstMD5Sink * ctx, gpointer resbuf)
145 ((guint32 *) resbuf)[0] = GUINT32_TO_LE (ctx->A);
146 ((guint32 *) resbuf)[1] = GUINT32_TO_LE (ctx->B);
147 ((guint32 *) resbuf)[2] = GUINT32_TO_LE (ctx->C);
148 ((guint32 *) resbuf)[3] = GUINT32_TO_LE (ctx->D);
154 md5_process_bytes (const void *buffer, size_t len, GstMD5Sink * ctx)
156 /*const void aligned_buffer = buffer; */
158 /* When we already have some bits in our internal buffer concatenate
159 both inputs first. */
160 if (ctx->buflen != 0) {
161 size_t left_over = ctx->buflen;
162 size_t add = 128 - left_over > len ? len : 128 - left_over;
164 /* Only put full words in the buffer. */
165 /* Forcing alignment here appears to be only an optimization.
166 * The glibc source uses __alignof__, which seems to be a
167 * gratuitous usage of a GCC extension, when sizeof() will
168 * work fine. (And don't question the sanity of using
169 * sizeof(guint32) instead of 4. */
170 /* add -= add % __alignof__ (guint32); */
171 add -= add % sizeof (guint32);
173 memcpy (&ctx->buffer[left_over], buffer, add);
176 if (ctx->buflen > 64) {
177 md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
180 /* The regions in the following copy operation cannot overlap. */
181 memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen);
184 buffer = (const char *) buffer + add;
188 /* Process available complete blocks. */
190 md5_process_block (buffer, len & ~63, ctx);
191 buffer = (const char *) buffer + (len & ~63);
195 /* Move remaining bytes in internal buffer. */
197 size_t left_over = ctx->buflen;
199 memcpy (&ctx->buffer[left_over], buffer, len);
201 if (left_over >= 64) {
202 md5_process_block (ctx->buffer, 64, ctx);
204 memcpy (ctx->buffer, &ctx->buffer[64], left_over);
206 ctx->buflen = left_over;
211 /* These are the four functions used in the four steps of the MD5 algorithm
212 and defined in the RFC 1321. The first function is a little bit optimized
213 (as found in Colin Plumbs public domain implementation). */
214 /* #define FF(b, c, d) ((b & c) | (~b & d)) */
215 #define FF(b, c, d) (d ^ (b & (c ^ d)))
216 #define FG(b, c, d) FF (d, b, c)
217 #define FH(b, c, d) (b ^ c ^ d)
218 #define FI(b, c, d) (c ^ (b | ~d))
220 /* Process LEN bytes of BUFFER, accumulating context into CTX.
221 It is assumed that LEN % 64 == 0. */
223 md5_process_block (const void *buffer, size_t len, GstMD5Sink * ctx)
225 guint32 correct_words[16];
226 const guint32 *words = buffer;
227 size_t nwords = len / sizeof (guint32);
228 const guint32 *endp = words + nwords;
234 /* First increment the byte count. RFC 1321 specifies the possible
235 length of the file up to 2^64 bits. Here we only compute the
236 number of bytes. Do a double word increment. */
237 ctx->total[0] += len;
238 if (ctx->total[0] < len)
241 /* Process all bytes in the buffer with 64 bytes in each round of
243 while (words < endp) {
244 guint32 *cwp = correct_words;
250 /* First round: using the given function, the context and a constant
251 the next context is computed. Because the algorithms processing
252 unit is a 32-bit word and it is determined to work on words in
253 little endian byte order we perhaps have to change the byte order
254 before the computation. To reduce the work for the next steps
255 we store the swapped words in the array CORRECT_WORDS. */
257 #define OP(a, b, c, d, s, T) \
260 a += FF (b, c, d) + (*cwp++ = GUINT32_TO_LE (*words)) + T; \
267 /* It is unfortunate that C does not provide an operator for
268 cyclic rotation. Hope the C compiler is smart enough. */
269 #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
271 /* Before we start, one word to the strange constants.
272 They are defined in RFC 1321 as
274 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
278 OP (A, B, C, D, 7, 0xd76aa478);
279 OP (D, A, B, C, 12, 0xe8c7b756);
280 OP (C, D, A, B, 17, 0x242070db);
281 OP (B, C, D, A, 22, 0xc1bdceee);
282 OP (A, B, C, D, 7, 0xf57c0faf);
283 OP (D, A, B, C, 12, 0x4787c62a);
284 OP (C, D, A, B, 17, 0xa8304613);
285 OP (B, C, D, A, 22, 0xfd469501);
286 OP (A, B, C, D, 7, 0x698098d8);
287 OP (D, A, B, C, 12, 0x8b44f7af);
288 OP (C, D, A, B, 17, 0xffff5bb1);
289 OP (B, C, D, A, 22, 0x895cd7be);
290 OP (A, B, C, D, 7, 0x6b901122);
291 OP (D, A, B, C, 12, 0xfd987193);
292 OP (C, D, A, B, 17, 0xa679438e);
293 OP (B, C, D, A, 22, 0x49b40821);
295 /* For the second to fourth round we have the possibly swapped words
296 in CORRECT_WORDS. Redefine the macro to take an additional first
297 argument specifying the function to use. */
299 #define OP(f, a, b, c, d, k, s, T) \
302 a += f (b, c, d) + correct_words[k] + T; \
309 OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
310 OP (FG, D, A, B, C, 6, 9, 0xc040b340);
311 OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
312 OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
313 OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
314 OP (FG, D, A, B, C, 10, 9, 0x02441453);
315 OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
316 OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
317 OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
318 OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
319 OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
320 OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
321 OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
322 OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
323 OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
324 OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
327 OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
328 OP (FH, D, A, B, C, 8, 11, 0x8771f681);
329 OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
330 OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
331 OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
332 OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
333 OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
334 OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
335 OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
336 OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
337 OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
338 OP (FH, B, C, D, A, 6, 23, 0x04881d05);
339 OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
340 OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
341 OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
342 OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
345 OP (FI, A, B, C, D, 0, 6, 0xf4292244);
346 OP (FI, D, A, B, C, 7, 10, 0x432aff97);
347 OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
348 OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
349 OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
350 OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
351 OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
352 OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
353 OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
354 OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
355 OP (FI, C, D, A, B, 6, 15, 0xa3014314);
356 OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
357 OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
358 OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
359 OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
360 OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
362 /* Add the starting values of the context. */
369 /* Put checksum in context given as argument. */
377 gst_md5sink_base_init (gpointer g_class)
379 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
381 gst_element_class_set_details (gstelement_class, &gst_md5sink_details);
382 gst_element_class_add_pad_template (gstelement_class,
383 gst_static_pad_template_get (&md5_sink_template));
387 gst_md5sink_class_init (GstMD5SinkClass * klass)
389 GObjectClass *gobject_class;
390 GstElementClass *gstelement_class;
392 gobject_class = (GObjectClass *) klass;
393 gstelement_class = (GstElementClass *) klass;
395 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_md5sink_get_property);
397 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MD5,
398 g_param_spec_string ("md5", "md5", "current value of the md5 sum",
399 "", G_PARAM_READABLE));
401 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_md5sink_change_state);
405 gst_md5sink_init (GstMD5Sink * md5sink)
410 gst_pad_new_from_template (gst_static_pad_template_get
411 (&md5_sink_template), "sink");
412 gst_element_add_pad (GST_ELEMENT (md5sink), pad);
413 gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_md5sink_chain));
415 md5_init_ctx (md5sink);
418 static GstElementStateReturn
419 gst_md5sink_change_state (GstElement * element)
424 sink = GST_MD5SINK (element);
426 g_return_val_if_fail (GST_IS_MD5SINK (sink), GST_STATE_FAILURE);
428 switch (GST_STATE_TRANSITION (element)) {
429 case GST_STATE_READY_TO_PAUSED:
431 g_object_notify (G_OBJECT (element), "md5");
433 case GST_STATE_PAUSED_TO_READY:
434 md5_finish_ctx (sink, sink->md5);
435 g_object_notify (G_OBJECT (element), "md5");
441 if ((GST_ELEMENT_CLASS (parent_class)->change_state))
442 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
444 return GST_STATE_SUCCESS;
448 gst_md5sink_get_property (GObject * object, guint prop_id, GValue * value,
453 g_return_if_fail (GST_IS_MD5SINK (object));
455 sink = GST_MD5SINK (object);
460 /* you could actually get a value for the current md5.
461 * This is currently disabled.
462 * md5_read_ctx (sink, sink->md5); */
463 /* md5 is a guchar[16] */
465 guchar *md5string = g_malloc0 (33);
467 for (i = 0; i < 16; ++i)
468 sprintf (md5string + i * 2, "%02x", sink->md5[i]);
469 g_value_set_string (value, md5string);
474 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
480 gst_md5sink_chain (GstPad * pad, GstData * _data)
482 GstBuffer *buf = GST_BUFFER (_data);
485 g_return_if_fail (pad != NULL);
486 g_return_if_fail (GST_IS_PAD (pad));
487 g_return_if_fail (buf != NULL);
489 md5sink = GST_MD5SINK (gst_pad_get_parent (pad));
491 if (GST_IS_BUFFER (buf)) {
492 md5_process_bytes (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), md5sink);
495 gst_buffer_unref (buf);