pidgin/pidgin

cbf9ccc715ab
Move everything in libpurple that was using the network-changed signal to use the gio one
/*
* A plugin to test the ciphers that ship with purple
*
* Copyright (C) 2004, Gary Kramlich <amc_grim@users.sf.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02111-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef PURPLE_PLUGINS
#define PURPLE_PLUGINS
#endif
#include "internal.h"
#include <glib.h>
#include <string.h>
#include "debug.h"
#include "plugins.h"
#include "version.h"
#include "util.h"
#include "ciphers/aescipher.h"
#include "ciphers/md5hash.h"
#include "ciphers/pbkdf2cipher.h"
#include "ciphers/sha1hash.h"
#include "ciphers/sha256hash.h"
struct test {
const gchar *question;
const gchar *answer;
};
/**************************************************************************
* MD5 Stuff
**************************************************************************/
struct test md5_tests[8] = {
{ "", "d41d8cd98f00b204e9800998ecf8427e"},
{ "a", "0cc175b9c0f1b6a831c399e269772661"},
{ "abc", "900150983cd24fb0d6963f7d28e17f72"},
{ "message digest", "f96b697d7cb7938d525a2f31aaf161d0"},
{ "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"},
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789", "d174ab98d277d9f5a5611c2c9f419d9f"},
{"123456789012345678901234567"
"890123456789012345678901234"
"56789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"},
{ NULL, NULL }
};
static void
cipher_test_md5(void) {
PurpleHash *hash;
gchar digest[33];
gboolean ret;
gint i = 0;
hash = purple_md5_hash_new();
if(!hash) {
purple_debug_info("cipher-test",
"could not find md5 cipher, not testing\n");
return;
}
purple_debug_info("cipher-test", "Running md5 tests\n");
while(md5_tests[i].answer) {
purple_debug_info("cipher-test", "Test %02d:\n", i);
purple_debug_info("cipher-test", "Testing '%s'\n", md5_tests[i].question);
purple_hash_append(hash, (guchar *)md5_tests[i].question,
strlen(md5_tests[i].question));
ret = purple_hash_digest_to_str(hash, digest, sizeof(digest));
if(!ret) {
purple_debug_info("cipher-test", "failed\n");
} else {
purple_debug_info("cipher-test", "\tGot: %s\n", digest);
purple_debug_info("cipher-test", "\tWanted: %s\n",
md5_tests[i].answer);
}
purple_hash_reset(hash);
i++;
}
g_object_unref(hash);
purple_debug_info("cipher-test", "md5 tests completed\n\n");
}
/**************************************************************************
* SHA-1 stuff
**************************************************************************/
struct test sha1_tests[5] = {
{"a", "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"},
{"abc", "a9993e364706816aba3e25717850c26c9cd0d89d"} ,
{"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1"} ,
{NULL, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"},
{NULL, NULL}
};
static void
cipher_test_sha1(void) {
PurpleHash *hash;
gchar digest[41];
gint i = 0;
gboolean ret;
hash = purple_sha1_hash_new();
if(!hash) {
purple_debug_info("cipher-test",
"could not find sha1 cipher, not testing\n");
return;
}
purple_debug_info("cipher-test", "Running sha1 tests\n");
while(sha1_tests[i].answer) {
purple_debug_info("cipher-test", "Test %02d:\n", i);
purple_debug_info("cipher-test", "Testing '%s'\n",
(sha1_tests[i].question != NULL) ?
sha1_tests[i].question : "'a'x1000, 1000 times");
if(sha1_tests[i].question) {
purple_hash_append(hash, (guchar *)sha1_tests[i].question,
strlen(sha1_tests[i].question));
} else {
gint j;
guchar buff[1000];
memset(buff, 'a', 1000);
for(j = 0; j < 1000; j++)
purple_hash_append(hash, buff, 1000);
}
ret = purple_hash_digest_to_str(hash, digest, sizeof(digest));
if(!ret) {
purple_debug_info("cipher-test", "failed\n");
} else {
purple_debug_info("cipher-test", "\tGot: %s\n", digest);
purple_debug_info("cipher-test", "\tWanted: %s\n",
sha1_tests[i].answer);
}
purple_hash_reset(hash);
i++;
}
g_object_unref(hash);
purple_debug_info("cipher-test", "sha1 tests completed\n\n");
}
static void
cipher_test_digest(void)
{
const gchar *nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093";
const gchar *client_nonce = "0a4f113b";
const gchar *username = "Mufasa";
const gchar *realm = "testrealm@host.com";
const gchar *password = "Circle Of Life";
const gchar *algorithm = "md5";
const gchar *nonce_count = "00000001";
const gchar *method = "GET";
const gchar *qop = "auth";
const gchar *digest_uri = "/dir/index.html";
const gchar *entity = NULL;
gchar *session_key;
purple_debug_info("cipher-test", "Running HTTP Digest tests\n");
session_key = purple_http_digest_calculate_session_key(
algorithm, username, realm, password,
nonce, client_nonce);
if (session_key == NULL)
{
purple_debug_info("cipher-test",
"purple_cipher_http_digest_calculate_session_key failed.\n");
}
else
{
gchar *response;
purple_debug_info("cipher-test", "\tsession_key: Got: %s\n", session_key);
purple_debug_info("cipher-test", "\tsession_key: Wanted: %s\n", "939e7578ed9e3c518a452acee763bce9");
response = purple_http_digest_calculate_response(
algorithm, method, digest_uri, qop, entity,
nonce, nonce_count, client_nonce, session_key);
g_free(session_key);
if (response == NULL)
{
purple_debug_info("cipher-test",
"purple_cipher_http_digest_calculate_session_key failed.\n");
}
else
{
purple_debug_info("cipher-test", "\tresponse: Got: %s\n", response);
purple_debug_info("cipher-test", "\tresponse: Wanted: %s\n", "6629fae49393a05397450978507c4ef1");
g_free(response);
}
}
purple_debug_info("cipher-test", "HTTP Digest tests completed\n\n");
}
/**************************************************************************
* PBKDF2 stuff
**************************************************************************/
#ifdef HAVE_NSS
# include <nss.h>
# include <secmod.h>
# include <pk11func.h>
# include <prerror.h>
# include <secerr.h>
#endif
typedef struct {
const gchar *hash;
const guint iter_count;
const gchar *passphrase;
const gchar *salt;
const guint out_len;
const gchar *answer;
} pbkdf2_test;
pbkdf2_test pbkdf2_tests[] = {
{ "sha256", 1, "password", "salt", 32, "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"},
{ "sha1", 1, "password", "salt", 32, "0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164"},
{ "sha1", 1000, "ala ma kota", "", 16, "924dba137b5bcf6d0de84998f3d8e1f9"},
{ "sha1", 1, "", "", 32, "1e437a1c79d75be61e91141dae20affc4892cc99abcc3fe753887bccc8920176"},
{ "sha256", 100, "some password", "and salt", 1, "c7"},
{ "sha1", 10000, "pretty long password W Szczebrzeszynie chrzaszcz brzmi w trzcinie i Szczebrzeszyn z tego slynie", "Grzegorz Brzeczyszczykiewicz", 32, "8cb0cb164f2554733ae02f5751b0e84a88fb385446e85a3991bdcdf1ea11795c"},
{ NULL, 0, NULL, NULL, 0, NULL}
};
#ifdef HAVE_NSS
static gchar*
cipher_pbkdf2_nss_sha1(const gchar *passphrase, const gchar *salt,
guint iter_count, guint out_len)
{
PK11SlotInfo *slot;
SECAlgorithmID *algorithm = NULL;
PK11SymKey *symkey = NULL;
const SECItem *symkey_data = NULL;
SECItem salt_item, passphrase_item;
guchar *passphrase_buff, *salt_buff;
gchar *ret;
g_return_val_if_fail(passphrase != NULL, NULL);
g_return_val_if_fail(iter_count > 0, NULL);
g_return_val_if_fail(out_len > 0, NULL);
NSS_NoDB_Init(NULL);
slot = PK11_GetBestSlot(PK11_AlgtagToMechanism(SEC_OID_PKCS5_PBKDF2),
NULL);
if (slot == NULL) {
purple_debug_error("cipher-test", "NSS: couldn't get slot: "
"%d\n", PR_GetError());
return NULL;
}
salt_buff = (guchar*)g_strdup(salt ? salt : "");
salt_item.type = siBuffer;
salt_item.data = salt_buff;
salt_item.len = salt ? strlen(salt) : 0;
algorithm = PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2,
SEC_OID_AES_256_CBC, SEC_OID_HMAC_SHA1, out_len, iter_count,
&salt_item);
if (algorithm == NULL) {
purple_debug_error("cipher-test", "NSS: couldn't create "
"algorithm ID: %d\n", PR_GetError());
PK11_FreeSlot(slot);
g_free(salt_buff);
return NULL;
}
passphrase_buff = (guchar*)g_strdup(passphrase);
passphrase_item.type = siBuffer;
passphrase_item.data = passphrase_buff;
passphrase_item.len = strlen(passphrase);
symkey = PK11_PBEKeyGen(slot, algorithm, &passphrase_item, PR_FALSE,
NULL);
if (symkey == NULL) {
purple_debug_error("cipher-test", "NSS: Couldn't generate key: "
"%d\n", PR_GetError());
SECOID_DestroyAlgorithmID(algorithm, PR_TRUE);
PK11_FreeSlot(slot);
g_free(passphrase_buff);
g_free(salt_buff);
return NULL;
}
if (PK11_ExtractKeyValue(symkey) == SECSuccess)
symkey_data = PK11_GetKeyData(symkey);
if (symkey_data == NULL || symkey_data->data == NULL) {
purple_debug_error("cipher-test", "NSS: Couldn't extract key "
"value: %d\n", PR_GetError());
PK11_FreeSymKey(symkey);
SECOID_DestroyAlgorithmID(algorithm, PR_TRUE);
PK11_FreeSlot(slot);
g_free(passphrase_buff);
g_free(salt_buff);
return NULL;
}
if (symkey_data->len != out_len) {
purple_debug_error("cipher-test", "NSS: Invalid key length: %d "
"(should be %d)\n", symkey_data->len, out_len);
PK11_FreeSymKey(symkey);
SECOID_DestroyAlgorithmID(algorithm, PR_TRUE);
PK11_FreeSlot(slot);
g_free(passphrase_buff);
g_free(salt_buff);
return NULL;
}
ret = purple_base16_encode(symkey_data->data, symkey_data->len);
PK11_FreeSymKey(symkey);
SECOID_DestroyAlgorithmID(algorithm, PR_TRUE);
PK11_FreeSlot(slot);
g_free(passphrase_buff);
g_free(salt_buff);
return ret;
}
#endif /* HAVE_NSS */
static void
cipher_test_pbkdf2(void)
{
PurpleCipher *cipher;
PurpleHash *hash;
int i = 0;
gboolean fail = FALSE;
purple_debug_info("cipher-test", "Running PBKDF2 tests\n");
while (!fail && pbkdf2_tests[i].answer) {
pbkdf2_test *test = &pbkdf2_tests[i];
gchar digest[2 * 32 + 1 + 10];
gchar *digest_nss = NULL;
gboolean ret, skip_nss = FALSE;
i++;
purple_debug_info("cipher-test", "Test %02d:\n", i);
purple_debug_info("cipher-test",
"\tTesting '%s' with salt:'%s' hash:%s iter_count:%d \n",
test->passphrase, test->salt, test->hash,
test->iter_count);
if (!strcmp(test->hash, "sha1"))
hash = purple_sha1_hash_new();
else if (!strcmp(test->hash, "sha256"))
hash = purple_sha256_hash_new();
else
hash = NULL;
cipher = purple_pbkdf2_cipher_new(hash);
g_object_set(G_OBJECT(cipher), "iter_count", GUINT_TO_POINTER(test->iter_count), NULL);
g_object_set(G_OBJECT(cipher), "out_len", GUINT_TO_POINTER(test->out_len), NULL);
purple_cipher_set_salt(cipher, (const guchar*)test->salt, test->salt ? strlen(test->salt): 0);
purple_cipher_set_key(cipher, (const guchar*)test->passphrase, strlen(test->passphrase));
ret = purple_cipher_digest_to_str(cipher, digest, sizeof(digest));
purple_cipher_reset(cipher);
if (!ret) {
purple_debug_info("cipher-test", "\tfailed\n");
fail = TRUE;
g_object_unref(cipher);
g_object_unref(hash);
continue;
}
if (g_strcmp0(test->hash, "sha1") != 0)
skip_nss = TRUE;
if (test->out_len != 16 && test->out_len != 32)
skip_nss = TRUE;
#ifdef HAVE_NSS
if (!skip_nss) {
digest_nss = cipher_pbkdf2_nss_sha1(test->passphrase,
test->salt, test->iter_count, test->out_len);
}
#else
skip_nss = TRUE;
#endif
purple_debug_info("cipher-test", "\tGot: %s\n", digest);
if (digest_nss)
purple_debug_info("cipher-test", "\tGot from NSS: %s\n", digest_nss);
purple_debug_info("cipher-test", "\tWanted: %s\n", test->answer);
if (g_strcmp0(digest, test->answer) == 0 &&
(skip_nss || g_strcmp0(digest, digest_nss) == 0)) {
purple_debug_info("cipher-test", "\tTest OK\n");
}
else {
purple_debug_info("cipher-test", "\twrong answer\n");
fail = TRUE;
}
g_object_unref(cipher);
g_object_unref(hash);
}
if (fail)
purple_debug_info("cipher-test", "PBKDF2 tests FAILED\n\n");
else
purple_debug_info("cipher-test", "PBKDF2 tests completed successfully\n\n");
}
/**************************************************************************
* AES stuff
**************************************************************************/
typedef struct {
const gchar *iv;
const gchar *key;
const gchar *plaintext;
const gchar *cipher;
} aes_test;
aes_test aes_tests[] = {
{ NULL, "000102030405060708090a0b0c0d0e0f", "plaintext", "152e5b950e5f28fafadee9e96fcc59c9" },
{ NULL, "000102030405060708090a0b0c0d0e0f", NULL, "954f64f2e4e86e9eee82d20216684899" },
{ "01010101010101010101010101010101", "000102030405060708090a0b0c0d0e0f", NULL, "35d14e6d3e3a279cf01e343e34e7ded3" },
{ "01010101010101010101010101010101", "000102030405060708090a0b0c0d0e0f", "plaintext", "19d1996e8c098cf3c94bba5dcf5bc57e" },
{ "01010101010101010101010101010101", "000102030405060708090a0b0c0d0e0f1011121314151617", "plaintext", "e8fba0deae94f63fe72ae9b8ef128aed" },
{ "01010101010101010101010101010101", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "plaintext", "e2dc50f6c60b33ac3b5953b6503cb684" },
{ "01010101010101010101010101010101", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "W Szczebrzeszynie chrzaszcz brzmi w trzcinie i Szczebrzeszyn z tego slynie", "8fcc068964e3505f0c2fac61c24592e5c8a9582d3a3264217cf605e9fd1cb056e679e159c4ac3110e8ce6c76c6630d42658c566ba3750c0e6da385b3a9baaa8b3a735b4c1ecaacf58037c8c281e523d2" },
{ NULL, NULL, NULL, NULL }
};
static void
cipher_test_aes(void)
{
PurpleCipher *cipher;
int i = 0;
gboolean fail = FALSE;
purple_debug_info("cipher-test", "Running AES tests\n");
cipher = purple_aes_cipher_new();
if (cipher == NULL) {
purple_debug_error("cipher-test", "AES cipher not found\n");
fail = TRUE;
}
while (!fail && aes_tests[i].cipher) {
aes_test *test = &aes_tests[i];
gsize key_size;
guchar *key;
guchar cipher_s[1024], decipher_s[1024];
ssize_t cipher_len, decipher_len;
gchar *cipher_b16, *deciphered;
purple_debug_info("cipher-test", "Test %02d:\n", i);
purple_debug_info("cipher-test", "\tTesting '%s' (%" G_GSIZE_FORMAT "bit) \n",
test->plaintext ? test->plaintext : "(null)",
strlen(test->key) * 8 / 2);
i++;
purple_cipher_reset(cipher);
if (test->iv) {
gsize iv_size;
guchar *iv = purple_base16_decode(test->iv, &iv_size);
g_assert(iv != NULL);
purple_cipher_set_iv(cipher, iv, iv_size);
g_free(iv);
}
key = purple_base16_decode(test->key, &key_size);
g_assert(key != NULL);
purple_cipher_set_key(cipher, key, key_size);
g_free(key);
if (purple_cipher_get_key_size(cipher) != key_size) {
purple_debug_info("cipher-test", "\tinvalid key size\n");
fail = TRUE;
continue;
}
cipher_len = purple_cipher_encrypt(cipher,
(const guchar*)(test->plaintext ? test->plaintext : ""),
test->plaintext ? (strlen(test->plaintext) + 1) : 0,
cipher_s, sizeof(cipher_s));
if (cipher_len < 0) {
purple_debug_info("cipher-test", "\tencryption failed\n");
fail = TRUE;
continue;
}
cipher_b16 = purple_base16_encode(cipher_s, cipher_len);
purple_debug_info("cipher-test", "\tGot: %s\n", cipher_b16);
purple_debug_info("cipher-test", "\tWanted: %s\n", test->cipher);
if (g_strcmp0(cipher_b16, test->cipher) != 0) {
purple_debug_info("cipher-test",
"\tencrypted data doesn't match\n");
g_free(cipher_b16);
fail = TRUE;
continue;
}
g_free(cipher_b16);
decipher_len = purple_cipher_decrypt(cipher,
cipher_s, cipher_len, decipher_s, sizeof(decipher_s));
if (decipher_len < 0) {
purple_debug_info("cipher-test", "\tdecryption failed\n");
fail = TRUE;
continue;
}
deciphered = (decipher_len > 0) ? (gchar*)decipher_s : NULL;
if (g_strcmp0(deciphered, test->plaintext) != 0) {
purple_debug_info("cipher-test",
"\tdecrypted data doesn't match\n");
fail = TRUE;
continue;
}
purple_debug_info("cipher-test", "\tTest OK\n");
}
if (cipher != NULL)
g_object_unref(cipher);
if (fail)
purple_debug_info("cipher-test", "AES tests FAILED\n\n");
else
purple_debug_info("cipher-test", "AES tests completed successfully\n\n");
}
/**************************************************************************
* Plugin stuff
**************************************************************************/
static PurplePluginInfo *
plugin_query(GError **error) {
const gchar * const authors[] = {
"Gary Kramlich <amc_grim@users.sf.net>",
NULL
};
return purple_plugin_info_new(
"id", "core-cipher-test",
"name", N_("Cipher Test"),
"version", DISPLAY_VERSION,
"category", N_("Testing"),
"summary", N_("Tests the ciphers that ship with libpurple."),
"description", N_("Tests the ciphers that ship with libpurple."),
"authors", authors,
"website", PURPLE_WEBSITE,
"abi-version", PURPLE_ABI_VERSION,
NULL
);
}
static gboolean
plugin_load(PurplePlugin *plugin, GError **error) {
cipher_test_md5();
cipher_test_sha1();
cipher_test_digest();
cipher_test_pbkdf2();
cipher_test_aes();
return TRUE;
}
static gboolean
plugin_unload(PurplePlugin *plugin, GError **error) {
return TRUE;
}
PURPLE_PLUGIN_INIT(cipher_test, plugin_query, plugin_load, plugin_unload);