pidgin: cab8af47: Use glib's SHA1, SHA256, and MD5 impleme...

darkrain42 at pidgin.im darkrain42 at pidgin.im
Sat Jul 4 19:16:08 EDT 2009


-----------------------------------------------------------------
Revision: cab8af472a40309d0259ae5803861d9dd051ae1d
Ancestor: 832a8f3c3faf1fbbc69e803c6a1830896dd05e1f
Author: darkrain42 at pidgin.im
Date: 2009-07-04T23:13:23
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/cab8af472a40309d0259ae5803861d9dd051ae1d

Modified files:
        libpurple/cipher.c libpurple/internal.h
        libpurple/tests/test_cipher.c

ChangeLog: 

Use glib's SHA1, SHA256, and MD5 implementations when available (glib 2.16)

These SHA1 and SHA256 implementations do not expose any options, which
the built-in ones do (for getting/setting sizeHi, sizeLo, and lenW).
Nothing in Pidgin uses those (and I can't think of a decent use case),
so I think this is OK. Feel free to disagree.

As I mentioned on the mailing list, glib's SHA1 implementation was just
under 3x as fast on my system.

-------------- next part --------------
============================================================
--- libpurple/cipher.c	2f4817fd21f86ce8ab710174ee2418da1591348a
+++ libpurple/cipher.c	cd471d079160276a9b6998b35a1108299d08ee19
@@ -61,11 +61,152 @@
 #include "signals.h"
 #include "value.h"
 
+#if GLIB_CHECK_VERSION(2,16,0)
+static void
+purple_g_checksum_init(PurpleCipherContext *context, GChecksumType type)
+{
+	GChecksum *checksum;
+
+	checksum = g_checksum_new(type);
+	purple_cipher_context_set_data(context, checksum);
+}
+
+static void
+purple_g_checksum_reset(PurpleCipherContext *context, GChecksumType type)
+{
+	GChecksum *checksum;
+
+	checksum = purple_cipher_context_get_data(context);
+	g_return_if_fail(checksum != NULL);
+
+#if GLIB_CHECK_VERSION(2,18,0)
+	g_checksum_reset(checksum);
+#else
+	g_checksum_free(checksum);
+	checksum = g_checksum_new(type);
+	purple_cipher_context_set_data(context, checksum);
+#endif
+}
+
+static void
+purple_g_checksum_uninit(PurpleCipherContext *context)
+{
+	GChecksum *checksum;
+
+	checksum = purple_cipher_context_get_data(context);
+	g_return_if_fail(checksum != NULL);
+
+	g_checksum_free(checksum);
+}
+
+static void
+purple_g_checksum_append(PurpleCipherContext *context, const guchar *data,
+                         gsize len)
+{
+	GChecksum *checksum;
+
+	checksum = purple_cipher_context_get_data(context);
+	g_return_if_fail(checksum != NULL);
+
+	if (len > (gsize)G_MAXSSIZE) {
+		/*
+		 * g_checksum_update takes a gssize, whereas we handle gsizes. To
+		 * be pedantically correct, we need to handle this case. In real life,
+		 * I think this couldn't actually occur.
+		 */
+		const guchar *buf = data;
+		gssize chunk_size;
+		while (len > 0) {
+			chunk_size = MIN(G_MAXSSIZE, len);
+			g_checksum_update(checksum, buf, chunk_size);
+			len -= chunk_size;
+			buf += chunk_size;
+		}
+	} else
+		g_checksum_update(checksum, data, len);
+}
+
+static gboolean
+purple_g_checksum_digest(PurpleCipherContext *context, GChecksumType type,
+                         gsize len, guchar *digest, gsize *out_len)
+{
+	GChecksum *checksum;
+	const gssize required_length = g_checksum_type_get_length(type);
+
+	checksum = purple_cipher_context_get_data(context);
+
+	g_return_val_if_fail(len >= required_length, FALSE);
+	g_return_val_if_fail(checksum != NULL, FALSE);
+
+	g_checksum_get_digest(checksum, digest, &len);
+
+	purple_cipher_context_reset(context, NULL);
+
+	if (out_len)
+		*out_len = len;
+
+	return TRUE;
+}
+#endif
+
+
 /*******************************************************************************
  * MD5
  ******************************************************************************/
 #define MD5_HMAC_BLOCK_SIZE	64
 
+static size_t
+md5_get_block_size(PurpleCipherContext *context)
+{
+	/* This does not change (in this case) */
+	return MD5_HMAC_BLOCK_SIZE;
+}
+
+#if GLIB_CHECK_VERSION(2,16,0)
+
+static void
+md5_init(PurpleCipherContext *context, void *extra)
+{
+	purple_g_checksum_init(context, G_CHECKSUM_MD5);
+}
+
+static void
+md5_reset(PurpleCipherContext *context, void *extra)
+{
+	purple_g_checksum_reset(context, G_CHECKSUM_MD5);
+}
+
+static gboolean
+md5_digest(PurpleCipherContext *context, gsize in_len, guchar digest[16],
+           size_t *out_len)
+{
+	return purple_g_checksum_digest(context, G_CHECKSUM_MD5, in_len,
+	                                digest, out_len);
+}
+
+static PurpleCipherOps MD5Ops = {
+	NULL,			/* Set Option		*/
+	NULL,			/* Get Option		*/
+	md5_init,		/* init				*/
+	md5_reset,		/* reset			*/
+	purple_g_checksum_uninit,	/* uninit			*/
+	NULL,			/* set iv			*/
+	purple_g_checksum_append,	/* append			*/
+	md5_digest,		/* digest			*/
+	NULL,			/* encrypt			*/
+	NULL,			/* decrypt			*/
+	NULL,			/* set salt			*/
+	NULL,			/* get salt size	*/
+	NULL,			/* set key			*/
+	NULL,			/* get key size		*/
+	NULL,			/* set batch mode */
+	NULL,			/* get batch mode */
+	md5_get_block_size,	/* get block size */
+	NULL			/* set key with len */
+};
+
+#else /* GLIB_CHECK_VERSION(2,16,0) */
+
 struct MD5Context {
 	guint32 total[2];
 	guint32 state[4];
@@ -327,13 +468,6 @@ md5_digest(PurpleCipherContext *context,
 	return TRUE;
 }
 
-static size_t
-md5_get_block_size(PurpleCipherContext *context)
-{
-	/* This does not change (in this case) */
-	return MD5_HMAC_BLOCK_SIZE;
-}
-
 static PurpleCipherOps MD5Ops = {
 	NULL,			/* Set option */
 	NULL,			/* Get option */
@@ -355,6 +489,8 @@ static PurpleCipherOps MD5Ops = {
 	NULL			/* set key with len */
 };
 
+#endif /* GLIB_CHECK_VERSION(2,16,0) */
+
 /*******************************************************************************
  * MD4
  ******************************************************************************/
@@ -1613,6 +1749,61 @@ static PurpleCipherOps DES3Ops = {
  * SHA-1
  ******************************************************************************/
 #define SHA1_HMAC_BLOCK_SIZE	64
+
+static size_t
+sha1_get_block_size(PurpleCipherContext *context)
+{
+	/* This does not change (in this case) */
+	return SHA1_HMAC_BLOCK_SIZE;
+}
+
+
+#if GLIB_CHECK_VERSION(2,16,0)
+
+static void
+sha1_init(PurpleCipherContext *context, void *extra)
+{
+	purple_g_checksum_init(context, G_CHECKSUM_SHA1);
+}
+
+static void
+sha1_reset(PurpleCipherContext *context, void *extra)
+{
+	purple_g_checksum_reset(context, G_CHECKSUM_SHA1);
+}
+
+static gboolean
+sha1_digest(PurpleCipherContext *context, gsize in_len, guchar digest[20],
+            gsize *out_len)
+{
+	return purple_g_checksum_digest(context, G_CHECKSUM_SHA1, in_len,
+	                                digest, out_len);
+}
+
+static PurpleCipherOps SHA1Ops = {
+	NULL,			/* Set Option		*/
+	NULL,			/* Get Option		*/
+	sha1_init,		/* init				*/
+	sha1_reset,		/* reset			*/
+	purple_g_checksum_uninit,	/* uninit			*/
+	NULL,			/* set iv			*/
+	purple_g_checksum_append,	/* append			*/
+	sha1_digest,	/* digest			*/
+	NULL,			/* encrypt			*/
+	NULL,			/* decrypt			*/
+	NULL,			/* set salt			*/
+	NULL,			/* get salt size	*/
+	NULL,			/* set key			*/
+	NULL,			/* get key size		*/
+	NULL,			/* set batch mode */
+	NULL,			/* get batch mode */
+	sha1_get_block_size,	/* get block size */
+	NULL			/* set key with len */
+};
+
+#else /* GLIB_CHECK_VERSION(2,16,0) */
+
+#define SHA1_HMAC_BLOCK_SIZE	64
 #define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF)
 
 struct SHA1Context {
@@ -1833,13 +2024,6 @@ sha1_digest(PurpleCipherContext *context
 	return TRUE;
 }
 
-static size_t
-sha1_get_block_size(PurpleCipherContext *context)
-{
-	/* This does not change (in this case) */
-	return SHA1_HMAC_BLOCK_SIZE;
-}
-
 static PurpleCipherOps SHA1Ops = {
 	sha1_set_opt,	/* Set Option		*/
 	sha1_get_opt,	/* Get Option		*/
@@ -1861,10 +2045,65 @@ static PurpleCipherOps SHA1Ops = {
 	NULL			/* set key with len */
 };
 
+#endif /* GLIB_CHECK_VERSION(2,16,0) */
+
 /*******************************************************************************
  * SHA-256
  ******************************************************************************/
 #define SHA256_HMAC_BLOCK_SIZE	64
+
+static size_t
+sha256_get_block_size(PurpleCipherContext *context)
+{
+	/* This does not change (in this case) */
+	return SHA256_HMAC_BLOCK_SIZE;
+}
+
+#if GLIB_CHECK_VERSION(2,16,0)
+
+static void
+sha256_init(PurpleCipherContext *context, void *extra)
+{
+	purple_g_checksum_init(context, G_CHECKSUM_SHA256);
+}
+
+static void
+sha256_reset(PurpleCipherContext *context, void *extra)
+{
+	purple_g_checksum_reset(context, G_CHECKSUM_SHA256);
+}
+
+static gboolean
+sha256_digest(PurpleCipherContext *context, gsize in_len, guchar digest[20],
+            gsize *out_len)
+{
+	return purple_g_checksum_digest(context, G_CHECKSUM_SHA256, in_len,
+	                                digest, out_len);
+}
+
+static PurpleCipherOps SHA256Ops = {
+	NULL,			/* Set Option		*/
+	NULL,			/* Get Option		*/
+	sha256_init,	/* init				*/
+	sha256_reset,	/* reset			*/
+	purple_g_checksum_uninit,	/* uninit			*/
+	NULL,			/* set iv			*/
+	purple_g_checksum_append,	/* append			*/
+	sha256_digest,	/* digest			*/
+	NULL,			/* encrypt			*/
+	NULL,			/* decrypt			*/
+	NULL,			/* set salt			*/
+	NULL,			/* get salt size	*/
+	NULL,			/* set key			*/
+	NULL,			/* get key size		*/
+	NULL,			/* set batch mode */
+	NULL,			/* get batch mode */
+	sha256_get_block_size,	/* get block size */
+	NULL			/* set key with len */
+};
+
+#else /* GLIB_CHECK_VERSION(2,16,0) */
+
 #define SHA256_ROTR(X,n) ((((X) >> (n)) | ((X) << (32-(n)))) & 0xFFFFFFFF)
 
 static const guint32 sha256_K[64] =
@@ -2088,13 +2327,6 @@ sha256_digest(PurpleCipherContext *conte
 	return TRUE;
 }
 
-static size_t
-sha256_get_block_size(PurpleCipherContext *context)
-{
-	/* This does not change (in this case) */
-	return SHA256_HMAC_BLOCK_SIZE;
-}
-
 static PurpleCipherOps SHA256Ops = {
 	sha256_set_opt,	/* Set Option		*/
 	sha256_get_opt,	/* Get Option		*/
@@ -2116,6 +2348,8 @@ static PurpleCipherOps SHA256Ops = {
 	NULL			/* set key with len */
 };
 
+#endif /* GLIB_CHECK_VERSION(2,16,0) */
+
 /*******************************************************************************
  * RC4
  ******************************************************************************/
============================================================
--- libpurple/internal.h	dbc124585e288c7bdf107fd6594bc5518cda0ee7
+++ libpurple/internal.h	63b8d5809283f9fed738255d8a76511c755d178f
@@ -148,6 +148,14 @@
 #	endif
 #endif
 
+#ifndef G_MAXSSIZE
+#	if GLIB_SIZEOF_LONG == 8
+#		define G_MAXSSIZE ((gssize) 0x7fffffffffffffff)
+#	else
+#		define G_MAXSSIZE ((gssize) 0x7fffffff)
+#	endif
+#endif
+
 #if GLIB_CHECK_VERSION(2,6,0)
 #	include <glib/gstdio.h>
 #endif
============================================================
--- libpurple/tests/test_cipher.c	eecb8040f3ea55a72301e71aded541240e22f0cf
+++ libpurple/tests/test_cipher.c	c0799fa73cfe6b1361a634cb5d5f4e74398afc1f
@@ -168,6 +168,11 @@ END_TEST
 	purple_cipher_context_destroy(context); \
 }
 
+START_TEST(test_sha1_empty_string) {
+	SHA1_TEST("", "da39a3ee5e6b4b0d3255bfef95601890afd80709");
+}
+END_TEST
+
 START_TEST(test_sha1_a) {
 	SHA1_TEST("a", "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8");
 }
@@ -190,6 +195,66 @@ END_TEST
 END_TEST
 
 /******************************************************************************
+ * SHA-256 Tests
+ *****************************************************************************/
+#define SHA256_TEST(data, digest) { \
+	PurpleCipher *cipher = NULL; \
+	PurpleCipherContext *context = NULL; \
+	gchar cdigest[65]; \
+	gboolean ret = FALSE; \
+	\
+	cipher = purple_ciphers_find_cipher("sha256"); \
+	context = purple_cipher_context_new(cipher, NULL); \
+	\
+	if((data)) { \
+		purple_cipher_context_append(context, (guchar *)(data), strlen((data))); \
+	} else { \
+		gint j; \
+		guchar buff[1000]; \
+		\
+		memset(buff, 'a', 1000); \
+		\
+		for(j = 0; j < 1000; j++) \
+			purple_cipher_context_append(context, buff, 1000); \
+	} \
+	\
+	ret = purple_cipher_context_digest_to_str(context, sizeof(cdigest), cdigest, \
+	                                        NULL); \
+	\
+	fail_unless(ret == TRUE, NULL); \
+	\
+	fail_unless(strcmp((digest), cdigest) == 0, NULL); \
+	\
+	purple_cipher_context_destroy(context); \
+}
+
+START_TEST(test_sha256_empty_string) {
+	SHA256_TEST("", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+}
+END_TEST
+
+START_TEST(test_sha256_a) {
+	SHA256_TEST("a", "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb");
+}
+END_TEST
+
+START_TEST(test_sha256_abc) {
+	SHA256_TEST("abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
+}
+END_TEST
+
+START_TEST(test_sha256_abcd_gibberish) {
+	SHA256_TEST("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+			  "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
+}
+END_TEST
+
+START_TEST(test_sha256_1000_as_1000_times) {
+	SHA256_TEST(NULL, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
+}
+END_TEST
+
+/******************************************************************************
  * DES Tests
  *****************************************************************************/
 #define DES_TEST(in, keyz, out, len) { \
@@ -726,12 +791,22 @@ cipher_suite(void) {
 
 	/* sha1 tests */
 	tc = tcase_create("SHA1");
+	tcase_add_test(tc, test_sha1_empty_string);
 	tcase_add_test(tc, test_sha1_a);
 	tcase_add_test(tc, test_sha1_abc);
 	tcase_add_test(tc, test_sha1_abcd_gibberish);
 	tcase_add_test(tc, test_sha1_1000_as_1000_times);
 	suite_add_tcase(s, tc);
 
+	/* sha256 tests */
+	tc = tcase_create("SHA256");
+	tcase_add_test(tc, test_sha256_empty_string);
+	tcase_add_test(tc, test_sha256_a);
+	tcase_add_test(tc, test_sha256_abc);
+	tcase_add_test(tc, test_sha256_abcd_gibberish);
+	tcase_add_test(tc, test_sha256_1000_as_1000_times);
+	suite_add_tcase(s, tc);
+
 	/* des tests */
 	tc = tcase_create("DES");
 	tcase_add_test(tc, test_des_12345678);


More information about the Commits mailing list