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;
396 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_md5sink_get_property);
398 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MD5,
399 g_param_spec_string ("md5", "md5", "current value of the md5 sum",
400 "", G_PARAM_READABLE));
402 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_md5sink_change_state);
406 gst_md5sink_init (GstMD5Sink * md5sink)
411 gst_pad_new_from_template (gst_static_pad_template_get
412 (&md5_sink_template), "sink");
413 gst_element_add_pad (GST_ELEMENT (md5sink), pad);
414 gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_md5sink_chain));
416 md5_init_ctx (md5sink);
419 static GstElementStateReturn
420 gst_md5sink_change_state (GstElement * element)
425 sink = GST_MD5SINK (element);
427 g_return_val_if_fail (GST_IS_MD5SINK (sink), GST_STATE_FAILURE);
429 switch (GST_STATE_TRANSITION (element)) {
430 case GST_STATE_READY_TO_PAUSED:
432 g_object_notify (G_OBJECT (element), "md5");
434 case GST_STATE_PAUSED_TO_READY:
435 md5_finish_ctx (sink, sink->md5);
436 g_object_notify (G_OBJECT (element), "md5");
442 if ((GST_ELEMENT_CLASS (parent_class)->change_state))
443 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
445 return GST_STATE_SUCCESS;
449 gst_md5sink_get_property (GObject * object, guint prop_id, GValue * value,
454 /* it's not null if we got it, but it might not be ours */
455 g_return_if_fail (GST_IS_MD5SINK (object));
457 sink = GST_MD5SINK (object);
462 /* you could actually get a value for the current md5.
463 * This is currently disabled.
464 * md5_read_ctx (sink, sink->md5); */
465 /* md5 is a guchar[16] */
467 guchar *md5string = g_malloc0 (33);
469 for (i = 0; i < 16; ++i)
470 sprintf (md5string + i * 2, "%02x", sink->md5[i]);
471 g_value_set_string (value, md5string);
476 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
482 gst_md5sink_chain (GstPad * pad, GstData * _data)
484 GstBuffer *buf = GST_BUFFER (_data);
487 g_return_if_fail (pad != NULL);
488 g_return_if_fail (GST_IS_PAD (pad));
489 g_return_if_fail (buf != NULL);
491 md5sink = GST_MD5SINK (gst_pad_get_parent (pad));
493 if (GST_IS_BUFFER (buf)) {
494 md5_process_bytes (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), md5sink);
497 gst_buffer_unref (buf);