And Richard Laager spoke on 07/01/2009 10:41 PM, saying:
> On Wed, 2009-07-01 at 01:29 -0700, Mark Doliner wrote:
>> Vijay from Meebo tells me that he seems to
>> remember the sha-1 implementation in glib 2.16 is much faster than the
>> one in our cipher.c.
>
> If this is true and it would be possible, it'd be nice if we just called
> that from our cipher API when libpurple is built against glib >= 2.16.
I've attached a patch that will conditionally use Glib for MD5, SHA1, and
SHA256 when available. `make check` passes with all three and it seems to
work fine.
In a very simplistic benchmark, I loaded the largest image in my
.purple/icons/ (32KiB) and calculated the SHA1sum 100,000 times (and stuck
a g_str_equal() in there just to make sure gcc didn't get cute with me). On
my AMD Athlon 64 4400+, the cipher.c implementation took about 41 seconds
and glib's implementation took about 14 seconds.
Anyone have any problems with my checking this in? The only thing left to
do is deal with the issue in adding data to the checksum, where GChecksum
uses a gssize and we use a gsize for the length, which will be bad when I
decide I want to use Pidgin to calculate the checksum for my 3GB file
(after I dig up a 32-bit system).
~Paul
#
# old_revision [5668e3b116ab205b1a3270d6aff7fca0332bccc6]
#
# patch "libpurple/cipher.c"
# from [2f4817fd21f86ce8ab710174ee2418da1591348a]
# to [3ddc29acfb4c36d387e1947a46b6e701cc96a33c]
#
# patch "libpurple/tests/test_cipher.c"
# from [eecb8040f3ea55a72301e71aded541240e22f0cf]
# to [c0799fa73cfe6b1361a634cb5d5f4e74398afc1f]
#
============================================================
--- libpurple/cipher.c 2f4817fd21f86ce8ab710174ee2418da1591348a
+++ libpurple/cipher.c 3ddc29acfb4c36d387e1947a46b6e701cc96a33c
@@ -61,11 +61,138 @@
#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);
+
+ /* FIXME: Handle len being more than a gssize can handle */
+ 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 +454,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 +475,8 @@ static PurpleCipherOps MD5Ops = {
NULL /* set key with len */
};
+#endif /* GLIB_CHECK_VERSION(2,16,0) */
+
/*******************************************************************************
* MD4
******************************************************************************/
@@ -1613,6 +1735,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 +2010,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 +2031,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 +2313,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 +2334,8 @@ static PurpleCipherOps SHA256Ops = {
NULL /* set key with len */
};
+#endif /* GLIB_CHECK_VERSION(2,16,0) */
+
/*******************************************************************************
* RC4
******************************************************************************/
============================================================
--- 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);
_______________________________________________
Devel mailing list
Devel@...
http://pidgin.im/cgi-bin/mailman/listinfo/devel