diff -Naur pidgin-2.4.1/finch/gntblist.c pidgin-2.4.1.new/finch/gntblist.c
--- pidgin-2.4.1/finch/gntblist.c	2008-03-31 22:51:22.000000000 +0530
+++ pidgin-2.4.1.new/finch/gntblist.c	2008-04-11 00:58:19.000000000 +0530
@@ -27,6 +27,7 @@
 
 #include <account.h>
 #include <blist.h>
+#include <master-password.h>
 #include <log.h>
 #include <notify.h>
 #include <privacy.h>
@@ -2845,6 +2846,14 @@
 	gnt_menu_add_item(GNT_MENU(sub), item);
 	reconstruct_grouping_menu();
 
+	item = gnt_menuitem_new(_("Set master password"));
+	gnt_menu_add_item(GNT_MENU(sub), item);
+	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), (GntMenuItemCallback)request_set_master_password, NULL);
+
+	item = gnt_menuitem_new(_("Clear master password"));
+	gnt_menu_add_item(GNT_MENU(sub), item);
+	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), (GntMenuItemCallback)request_clear_master_password, NULL);
+
 	reconstruct_accounts_menu();
 	gnt_menu_add_item(GNT_MENU(menu), ggblist->accounts);
 
diff -Naur pidgin-2.4.1/libpurple/account.c pidgin-2.4.1.new/libpurple/account.c
--- pidgin-2.4.1/libpurple/account.c	2008-03-31 22:51:23.000000000 +0530
+++ pidgin-2.4.1.new/libpurple/account.c	2008-04-11 00:58:19.000000000 +0530
@@ -28,6 +28,7 @@
 #include "core.h"
 #include "dbus-maybe.h"
 #include "debug.h"
+#include "master-password.h"
 #include "network.h"
 #include "notify.h"
 #include "pounce.h"
@@ -83,6 +84,10 @@
 static guint    save_timer = 0;
 static gboolean accounts_loaded = FALSE;
 
+static void purple_account_set_only_password(PurpleAccount *account, const char *password);
+static const char *purple_account_get_encrypted_password(const PurpleAccount *account);
+static void purple_account_set_encrypted_password(PurpleAccount *account, const char *encrypted_password);
+
 static GList *handles = NULL;
 
 static void set_current_error(PurpleAccount *account,
@@ -371,11 +376,19 @@
 	child = xmlnode_new_child(node, "name");
 	xmlnode_insert_data(child, purple_account_get_username(account), -1);
 
-	if (purple_account_get_remember_password(account) &&
-		((tmp = purple_account_get_password(account)) != NULL))
+	if (purple_account_get_remember_password(account))
 	{
-		child = xmlnode_new_child(node, "password");
-		xmlnode_insert_data(child, tmp, -1);
+		/* if we have an encrypted password and are using encryption, just store the encrypted password */
+		if ((purple_get_encryption_type() != ENCRYPTION_NONE) &&
+		    ((tmp = purple_account_get_encrypted_password(account)) != NULL))
+		{
+			child = xmlnode_new_child(node, "encrypted_password");
+			xmlnode_insert_data(child, tmp, -1);
+		} else if ((tmp = purple_account_get_password(account)) != NULL)
+		{
+			child = xmlnode_new_child(node, "password");
+			xmlnode_insert_data(child, tmp, -1);
+		}
 	}
 
 	if ((tmp = purple_account_get_alias(account)) != NULL)
@@ -423,12 +436,29 @@
 static xmlnode *
 accounts_to_xmlnode(void)
 {
-	xmlnode *node, *child;
+	xmlnode *node, *subnode, *child;
 	GList *cur;
+	char buf[3];
+	const char *data;
 
 	node = xmlnode_new("account");
 	xmlnode_set_attrib(node, "version", "1.0");
 
+	subnode = xmlnode_new("encryption");
+
+	child = xmlnode_new_child(subnode, "encryption_type");
+	sprintf(buf, "%d", purple_get_encryption_type());
+	xmlnode_insert_data(child, buf, -1);
+	
+	if ((data = purple_get_encrypted_master_password()) != NULL)
+	{
+		child = xmlnode_new_child(subnode, "master_password");
+		xmlnode_insert_data(child, data, -1);
+	}
+
+	xmlnode_insert_child(node, subnode);
+
+
 	for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
 	{
 		child = account_to_xmlnode(cur->data);
@@ -763,9 +793,11 @@
 {
 	PurpleAccount *ret;
 	xmlnode *child;
+	const char *master_password;
 	char *protocol_id = NULL;
 	char *name = NULL;
 	char *data;
+	char *password;
 
 	child = xmlnode_get_child(node, "protocol");
 	if (child != NULL)
@@ -794,12 +826,36 @@
 	g_free(protocol_id);
 
 	/* Read the password */
-	child = xmlnode_get_child(node, "password");
+	/* if we have an encrypted password */
+	child = xmlnode_get_child(node, "encrypted_password");;
 	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
 	{
 		purple_account_set_remember_password(ret, TRUE);
-		purple_account_set_password(ret, data);
+		/* store the encrypted password */
+		purple_account_set_encrypted_password(ret, data);
+
+		/* if we have a master password */
+		if ((master_password = purple_get_master_password()) != NULL)
+		{
+			/* then decrypt the encrypted password */
+			password = decrypt_password(data, master_password);
+			if (password)
+			{
+				purple_account_set_only_password(ret, password);
+				g_free(password);
+			}
+		}
+    
 		g_free(data);
+	} else {
+		child = xmlnode_get_child(node, "password");
+		if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+		{
+			purple_account_set_remember_password(ret, TRUE);
+			purple_account_set_password(ret, data);
+			g_free(data);
+		}
+   
 	}
 
 	/* Read the alias */
@@ -877,10 +933,11 @@
 	return ret;
 }
 
-static void
+void
 load_accounts(void)
 {
-	xmlnode *node, *child;
+	xmlnode *node, *subnode, *child;
+	char *data;
 
 	accounts_loaded = TRUE;
 
@@ -889,6 +946,19 @@
 	if (node == NULL)
 		return;
 
+	subnode = xmlnode_get_child(node, "encryption");
+	if (subnode)
+	{
+		child = xmlnode_get_child(subnode, "encryption_type");
+		if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+			purple_set_encryption_type(atoi(data));
+
+		child = xmlnode_get_child(subnode, "master_password");
+		if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+			purple_set_encrypted_master_password(g_strdup(data));
+	}
+
+
 	for (child = xmlnode_get_child(node, "account"); child != NULL;
 			child = xmlnode_get_next_twin(child))
 	{
@@ -1126,7 +1196,7 @@
 {
 	PurplePlugin *prpl;
 	PurplePluginProtocolInfo *prpl_info;
-	const char *password;
+	const char *password, *encrypted_password, *master_password;
 
 	g_return_if_fail(account != NULL);
 
@@ -1150,6 +1220,21 @@
 
 	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 	password = purple_account_get_password(account);
+
+
+	/* if we don't know the plain text password and we do know the encrypted password */
+	if ((password == NULL) &&
+	    ((encrypted_password = purple_account_get_encrypted_password(account)) != NULL))
+	{
+		/* then if we also know the master password, we can decrypt the encrypted password */
+		if ((master_password = purple_get_master_password()) != NULL)
+			password = decrypt_password(encrypted_password, master_password);
+		/* otherwise we're still waiting for the user to enter the master password, so just wait */
+		else
+			return;
+	}
+
+
 	if ((password == NULL) &&
 		!(prpl_info->options & OPT_PROTO_NO_PASSWORD) &&
 		!(prpl_info->options & OPT_PROTO_PASSWORD_OPTIONAL))
@@ -1473,11 +1558,14 @@
 	purple_blist_schedule_save();
 }
 
-void
-purple_account_set_password(PurpleAccount *account, const char *password)
+static void
+purple_account_set_only_password(PurpleAccount *account, const char *password)
 {
 	g_return_if_fail(account != NULL);
 
+	/* don't do the free and strdup if the password hasn't changed */
+	if (account->password == password) return;  
+
 	g_free(account->password);
 	account->password = g_strdup(password);
 
@@ -1485,6 +1573,41 @@
 }
 
 void
+purple_account_set_password(PurpleAccount *account, const char *password)
+{
+	const char *master_password;
+
+	g_return_if_fail(account != NULL);
+
+	purple_account_set_only_password(account, password);
+	password = purple_account_get_password(account);
+
+	if (password == NULL || purple_get_encryption_type() == ENCRYPTION_NONE)
+		purple_account_set_encrypted_password(account, NULL);
+	else if ((master_password = purple_get_master_password()) != NULL)
+		purple_account_set_encrypted_password(account, encrypt_password(password, master_password));
+}
+
+static const char *
+purple_account_get_encrypted_password(const PurpleAccount *account)
+{
+	g_return_val_if_fail(account != NULL, NULL);
+
+	return account->encrypted_password;
+}
+
+static void
+purple_account_set_encrypted_password(PurpleAccount *account, const char *encrypted_password)
+{
+	g_return_if_fail(account != NULL);
+
+	g_free(account->encrypted_password);
+	account->encrypted_password = g_strdup(encrypted_password);
+
+	schedule_accounts_save();
+}
+
+void
 purple_account_set_alias(PurpleAccount *account, const char *alias)
 {
 	g_return_if_fail(account != NULL);
diff -Naur pidgin-2.4.1/libpurple/account.h pidgin-2.4.1.new/libpurple/account.h
--- pidgin-2.4.1/libpurple/account.h	2008-03-31 22:51:23.000000000 +0530
+++ pidgin-2.4.1.new/libpurple/account.h	2008-04-11 00:58:19.000000000 +0530
@@ -114,6 +114,7 @@
 	char *username;             /**< The username.                          */
 	char *alias;                /**< How you appear to yourself.            */
 	char *password;             /**< The account password.                  */
+	char *encrypted_password;   /**< The account encrypted password.        */ 
 	char *user_info;            /**< User information.                      */
 
 	char *buddy_icon_path;      /**< The buddy icon's non-cached path.      */
@@ -558,6 +559,13 @@
 const char *purple_account_get_password(const PurpleAccount *account);
 
 /**
+ * Load account information from accounts.xml
+ *
+ * @return void
+ */
+void load_accounts(void);
+
+/**
  * Returns the account's alias.
  *
  * @param account The account.
diff -Naur pidgin-2.4.1/libpurple/Makefile.am pidgin-2.4.1.new/libpurple/Makefile.am
--- pidgin-2.4.1/libpurple/Makefile.am	2008-03-31 22:51:23.000000000 +0530
+++ pidgin-2.4.1.new/libpurple/Makefile.am	2008-04-11 00:58:19.000000000 +0530
@@ -51,6 +51,7 @@
 	idle.c \
 	imgstore.c \
 	log.c \
+	master-password.c \
 	mime.c \
 	nat-pmp.c \
 	network.c \
@@ -103,6 +104,7 @@
 	idle.h \
 	imgstore.h \
 	log.h \
+	master-password.h \
 	mime.h \
 	nat-pmp.h \
 	network.h \
@@ -246,6 +248,7 @@
 	$(LIBXML_LIBS) \
 	$(LIBNM_LIBS) \
 	$(INTLLIBS) \
+	$(NSS_LIBS) \
 	-lm
 
 AM_CPPFLAGS = \
@@ -258,4 +261,5 @@
 	$(DEBUG_CFLAGS) \
 	$(DBUS_CFLAGS) \
 	$(LIBXML_CFLAGS) \
+	$(NSS_CFLAGS) \
 	$(LIBNM_CFLAGS)
diff -Naur pidgin-2.4.1/libpurple/Makefile.in pidgin-2.4.1.new/libpurple/Makefile.in
--- pidgin-2.4.1/libpurple/Makefile.in	2008-03-31 22:52:04.000000000 +0530
+++ pidgin-2.4.1.new/libpurple/Makefile.in	2008-04-11 00:58:19.000000000 +0530
@@ -82,7 +82,7 @@
 	savedstatuses.c server.c signals.c dnsquery.c dnssrv.c \
 	status.c stringref.c stun.c sound.c sslconn.c upnp.c util.c \
 	value.c version.c xmlnode.c whiteboard.c dbus-server.c \
-	dbus-useful.c
+	dbus-useful.c master-password.c
 am__objects_1 = account.lo accountopt.lo blist.lo buddyicon.lo \
 	certificate.lo cipher.lo circbuffer.lo cmds.lo connection.lo \
 	conversation.lo core.lo debug.lo desktopitem.lo eventloop.lo \
@@ -91,7 +91,7 @@
 	privacy.lo proxy.lo prpl.lo request.lo roomlist.lo \
 	savedstatuses.lo server.lo signals.lo dnsquery.lo dnssrv.lo \
 	status.lo stringref.lo stun.lo sound.lo sslconn.lo upnp.lo \
-	util.lo value.lo version.lo xmlnode.lo whiteboard.lo
+	util.lo value.lo version.lo xmlnode.lo whiteboard.lo master-password.lo
 @ENABLE_DBUS_TRUE@am__objects_2 = dbus-server.lo dbus-useful.lo
 am_libpurple_la_OBJECTS = $(am__objects_1) $(am__objects_2)
 libpurple_la_OBJECTS = $(am_libpurple_la_OBJECTS)
@@ -133,7 +133,7 @@
 pkgconfigDATA_INSTALL = $(INSTALL_DATA)
 DATA = $(pkgconfig_DATA)
 am__libpurpleinclude_HEADERS_DIST = account.h accountopt.h blist.h \
-	buddyicon.h certificate.h cipher.h circbuffer.h cmds.h \
+	master-password.h buddyicon.h certificate.h cipher.h circbuffer.h cmds.h \
 	connection.h conversation.h core.h dbus-maybe.h debug.h \
 	desktopitem.h eventloop.h ft.h gaim-compat.h idle.h imgstore.h \
 	log.h mime.h nat-pmp.h network.h notify.h ntlm.h plugin.h \
@@ -453,6 +453,7 @@
 	idle.c \
 	imgstore.c \
 	log.c \
+	master-password.c \
 	mime.c \
 	nat-pmp.c \
 	network.c \
@@ -505,6 +506,7 @@
 	idle.h \
 	imgstore.h \
 	log.h \
+	master-password.h \
 	mime.h \
 	nat-pmp.h \
 	network.h \
@@ -607,6 +609,7 @@
 	$(LIBXML_LIBS) \
 	$(LIBNM_LIBS) \
 	$(INTLLIBS) \
+	$(NSS_LIBS) \
 	-lm
 
 AM_CPPFLAGS = \
@@ -619,6 +622,7 @@
 	$(DEBUG_CFLAGS) \
 	$(DBUS_CFLAGS) \
 	$(LIBXML_CFLAGS) \
+	$(NSS_CFLAGS) \
 	$(LIBNM_CFLAGS)
 
 all: $(BUILT_SOURCES)
diff -Naur pidgin-2.4.1/libpurple/Makefile.mingw pidgin-2.4.1.new/libpurple/Makefile.mingw
--- pidgin-2.4.1/libpurple/Makefile.mingw	2008-03-31 22:51:23.000000000 +0530
+++ pidgin-2.4.1.new/libpurple/Makefile.mingw	2008-04-11 00:58:19.000000000 +0530
@@ -8,7 +8,9 @@
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
 TARGET = libpurple
-NEEDED_DLLS = $(LIBXML2_TOP)/bin/libxml2.dll
+NEEDED_DLLS = $(NSS_TOP)/lib/nss3.dll \
+			  $(NSPR_TOP)/lib/nspr4.dll \
+			  $(LIBXML2_TOP)/bin/libxml2.dll
 
 ##
 ## INCLUDE PATHS
@@ -20,9 +22,13 @@
 			-I$(GTK_TOP)/include \
 			-I$(GTK_TOP)/include/glib-2.0 \
 			-I$(GTK_TOP)/lib/glib-2.0/include \
+			-I$(NSS_TOP)/include \
+			-I$(NSPR_TOP)/include \
 			-I$(LIBXML2_TOP)/include
 
 LIB_PATHS +=		-L$(GTK_TOP)/lib \
+			-L$(NSS_TOP)/lib \
+			-L$(NSPR_TOP)/lib \
 			-L$(LIBXML2_TOP)/lib
 
 ##
@@ -48,6 +54,7 @@
 			idle.c \
 			imgstore.c \
 			log.c \
+			master-password.c \
 			mime.c \
 			nat-pmp.c \
 			network.c \
@@ -92,6 +99,8 @@
 		-lgthread-2.0 \
 		-lgobject-2.0 \
 		-lgmodule-2.0 \
+		-lnss3 \
+		-lnspr4 \
 		-lintl \
 		-lws2_32 \
 		-lxml2
diff -Naur pidgin-2.4.1/libpurple/master-password.c pidgin-2.4.1.new/libpurple/master-password.c
--- pidgin-2.4.1/libpurple/master-password.c	1970-01-01 05:30:00.000000000 +0530
+++ pidgin-2.4.1.new/libpurple/master-password.c	2008-04-11 00:58:19.000000000 +0530
@@ -0,0 +1,587 @@
+#include <nss.h>
+#include <nspr.h>
+#include <pk11func.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "internal.h"
+#include "account.h"
+#include "request.h"
+#include "master-password.h"
+
+/* saved encrypted passwords will be hex-encoded, which doubles their length
+ * they contain an IV block (16 bytes) + 10 bytes from their hash + an encrypted
+ * password (20 bytes or more), giving a total of 46 bytes
+ * rounded up to a multiple of 16 gives us 48 bytes, or 96 hex characters to save */
+
+/* for AES encryption, a fixed blocksize of 16 bytes is used */
+#define BLOCK_SIZE 16
+
+/* 256 bits */
+#define KEY_SIZE 32
+
+/* how many bytes of the password's hash to encrypt as a checksum */
+#define KEY_SIZE_TO_ENCRYPT 10
+
+/* pad passwords to this length before encrypting them, so it's
+   impossible to spot which passwords are short by looking at the
+   encrypted passwords */
+#define MIN_PASSWORD_LENGTH 20
+
+static const char *master_password = NULL;
+static const char *encrypted_master_password = NULL;
+static int master_password_prompt_pending = 0;
+encryption_type g_encryption_type = ENCRYPTION_NONE;
+
+static void
+purple_set_master_password(const char *new)
+{
+	if (master_password)
+		g_free((void *)master_password);
+
+	master_password = new;
+}
+
+static void
+purple_change_master_password(const char *mpass)
+{
+	GList *cur;
+
+	purple_set_master_password(mpass);
+
+	if (mpass)
+	{
+		purple_set_encryption_type(ENCRYPTION_ENC);
+		purple_set_encrypted_master_password(encrypt_password(mpass, mpass));
+	} else {
+		purple_set_encryption_type(ENCRYPTION_NONE);
+		purple_set_encrypted_master_password(NULL);
+	}
+
+	/* set each account's password - this will re-encrypt them all with the new master password */
+	for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
+		purple_account_set_password(cur->data, purple_account_get_password(cur->data));
+}
+
+static int
+validate_master_password(const char *mpass)
+{
+	const char *encrypted_master_password = purple_get_encrypted_master_password();
+	char *plain;
+
+	/* null master passwords never validate */
+	if (!mpass) return 0;
+
+	if (!encrypted_master_password)
+	{
+		printf("error - enc master password is NULL\n");
+		exit(1);
+	}
+
+	plain = decrypt_password(encrypted_master_password, mpass);
+	if (plain)
+	{
+		g_free(plain);
+
+		if (!master_password || strcmp(mpass, master_password))
+		{
+			purple_set_master_password(g_strdup(mpass));
+			load_accounts();
+			purple_accounts_restore_current_statuses();
+		}
+		return 1;
+	}
+	return 0;
+}
+
+static void
+purple_get_master_password_cb(char *notused, const char *master_password)
+{
+	master_password_prompt_pending = 0;
+
+	if (!validate_master_password(master_password))
+		/* didn't like the mp they entered - so prompt again */
+		purple_get_master_password();
+}
+
+static void
+purple_get_master_password_cancel_cb(char *encrypted, const char *value)
+{
+	master_password_prompt_pending = 0;
+}
+
+static void
+request_set_master_password_cb(char *data, PurpleRequestFields *fields)
+{
+	GList *groups, *flds;
+	const char *current = NULL, *password = NULL, *confirm = NULL;
+
+	for (groups = purple_request_fields_get_groups(fields); groups; groups = groups->next) {
+		for (flds = purple_request_field_group_get_fields(groups->data); flds; flds = flds->next) {
+			PurpleRequestField *field = flds->data;
+			const char *id = purple_request_field_get_id(field);
+			const char *value = purple_request_field_string_get_value(field);
+			if (!strcmp(id, "current")) current = value;
+			else if (!strcmp(id, "password")) password = value;
+			else if (!strcmp(id, "confirm")) confirm = value;
+		}
+	}
+
+	if (purple_get_encryption_type() == ENCRYPTION_ENC && validate_master_password(current) == 0)
+	{
+		purple_notify_error(NULL, _("Error"), _("The current password was typed incorrectly."), NULL);
+		request_set_master_password();
+		return;
+	}
+
+	if (password == NULL && confirm == NULL)
+	{
+		purple_change_master_password(NULL);
+		return;
+	}
+
+	if (password == NULL || confirm == NULL ||
+	    strcmp(password, confirm))
+	{
+		purple_notify_error(NULL, _("Error"), _("New passwords do not match."), NULL);
+		request_set_master_password();
+		return;
+	}
+
+	if (password[0] == '\0')
+	{
+		purple_change_master_password(NULL);
+		return;
+	}
+
+	purple_change_master_password(g_strdup(password));
+}
+
+static void
+request_clear_master_password_cb(char *notused, PurpleRequestFields *fields)
+{
+	GList *groups, *flds;
+	const char *current = NULL;
+
+	for(groups = purple_request_fields_get_groups(fields); groups; groups = groups->next) {
+		for(flds = purple_request_field_group_get_fields(groups->data); flds; flds = flds->next) {
+			PurpleRequestField *field = flds->data;
+			const char *id = purple_request_field_get_id(field);
+			const char *value = purple_request_field_string_get_value(field);
+			if (!strcmp(id, "current")) current = value;
+		}
+	}
+
+	if (current == NULL) {
+		purple_notify_error(NULL, _("Error"),
+				  _("You didn't fill in the current password field."),
+				  NULL);
+		request_clear_master_password();
+		return;
+	}
+
+	if (validate_master_password(current))
+	{
+		purple_change_master_password(NULL);
+		return;
+	}
+
+	if (!strcmp(current, "delete"))
+	{
+		if (master_password)
+		{
+			purple_notify_error(NULL, _("Error"),
+					  _("The master password has already been typed this"
+					    " session.  If you really want to delete all encrypted"
+					    " passwords, restart Pidgin and try again."),
+					  NULL);
+			return;
+		}
+
+		purple_change_master_password(NULL);
+		return;
+	}
+
+	purple_notify_error(NULL, _("Error"),
+			  _("Current password was typed incorrectly."),
+			  NULL);
+	request_clear_master_password();
+}
+
+void
+purple_set_encryption_type(encryption_type type)
+{
+	g_encryption_type = type;
+}
+
+encryption_type
+purple_get_encryption_type(void)
+{
+	return g_encryption_type;
+}
+
+const char *
+purple_get_master_password()
+{
+	if (purple_get_encryption_type() == ENCRYPTION_NONE) return NULL;
+
+	if (master_password) return master_password;
+
+	if (!master_password_prompt_pending &&
+		purple_request_input(NULL, _("Password Required"),
+						   NULL, _("Please enter the master password."),
+						   NULL, FALSE, TRUE, NULL,
+						   _("_OK"),     G_CALLBACK(purple_get_master_password_cb),
+						   _("_Cancel"), G_CALLBACK(purple_get_master_password_cancel_cb),
+						   NULL, NULL, NULL, NULL))
+		master_password_prompt_pending = 1;
+
+	return NULL;
+}
+
+const char *
+purple_get_encrypted_master_password(void)
+{
+	return encrypted_master_password;
+}
+
+void
+purple_set_encrypted_master_password(const char *encmpass)
+{
+	encrypted_master_password = encmpass;
+}
+
+static void
+purple_master_password_init(void)
+{
+	static int initialised = 0;
+	SECStatus rv;
+
+	if (initialised) return;
+
+	PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
+	rv = NSS_NoDB_Init(NULL);
+
+	if (rv != SECSuccess)
+	{
+		fprintf(stderr, "NSS initialization failed (err %d)\n",
+			PR_GetError());
+		exit(1);
+	}
+
+	initialised = 1;
+}
+
+/* Generate the key from the password */
+static unsigned char *
+hash_password(const char *password)
+{
+	static unsigned char key[KEY_SIZE];
+	PK11Context* DigestContext;
+	unsigned int len;
+
+	purple_master_password_init();
+
+	/* Create Digest context. Some of the digest algorithm identifiers
+	 * are (without the SEC_OID_ prefix) : MD2, MD5, SHA1, SHA256, SHA384, SHA512. */
+	if ((DigestContext = PK11_CreateDigestContext(SEC_OID_SHA256)) == NULL)
+	{
+		printf("hashing failed\n");
+		return NULL;
+	}
+
+	if (PK11_DigestBegin(DigestContext) != SECSuccess ||
+	    PK11_DigestOp(DigestContext, (unsigned char *)password, strlen(password)) != SECSuccess ||
+	    PK11_DigestFinal(DigestContext, key, &len, KEY_SIZE) != SECSuccess)
+	{
+		printf("hashing failed\n");
+		PK11_DestroyContext(DigestContext, PR_TRUE);
+		return NULL;
+	}
+
+	PK11_DestroyContext(DigestContext, PR_TRUE);
+
+	return key;
+}
+
+static void
+random_iv_block(unsigned char *buffer)
+{
+	int i;
+
+	srand(time(NULL) ^ rand());
+	for (i = 0; i < BLOCK_SIZE; i++)
+		buffer[i] = rand();
+}
+
+static void
+bin_to_hex(unsigned char *bin, int size, char *hex)
+{
+	char tmp[3];
+
+	hex[size*2] = '\0';
+	while (size--)
+	{
+		sprintf(tmp, "%02x", bin[size]);
+		hex[size*2 + 0] = tmp[0];
+		hex[size*2 + 1] = tmp[1];
+	}
+}
+
+static int
+hex_to_bin(const char *hex, int size, unsigned char *bin)
+{
+	int count = 0;
+
+	while ((size == 0 && *hex) || (count < size))
+	{
+		int tmp;
+		sscanf(hex, "%2x", &tmp);
+		*bin = tmp;
+		hex += 2;
+		bin++;
+		count++;
+	}
+
+	return count;
+}
+
+static int
+encrypt_or_decrypt_buffer(int direction, const char *password, SECItem ivItem,
+						  unsigned char *input, int input_len,
+						  unsigned char *output, int output_len)
+{
+	CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC_PAD;
+	PK11SlotInfo*     slot;
+	PK11SymKey*       SymKey = NULL;
+	SECItem*          SecParam = NULL;
+	PK11Context*      EncContext;
+	SECItem           keyItem;
+	int               write_len1, ret = 0;
+	unsigned int      write_len2;
+
+	purple_master_password_init();
+
+	if ((slot = PK11_GetBestSlot(cipherMech, NULL)) == NULL)
+	{
+		fprintf(stderr, "Unable to find security device (err %d)\n", PR_GetError());
+		goto out;
+	}
+
+	/* turn the raw key into a SECItem. */
+	keyItem.data = hash_password(password);
+	keyItem.len = KEY_SIZE;
+
+	/* turn the raw key into a key object */
+	if ((SymKey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL)) == NULL)
+	{
+		fprintf(stderr, "Failure to import key into NSS (err %d)\n", PR_GetError());
+		goto out;
+	}
+
+	/* set up the PKCS11 encryption paramters */
+	if ((SecParam = PK11_ParamFromIV(cipherMech, &ivItem)) == NULL)
+	{
+		fprintf(stderr, "Failure to set up PKCS11 param (err %d)\n", PR_GetError());
+		goto out;
+	}
+
+	/* create cipher context */
+	EncContext = PK11_CreateContextBySymKey(cipherMech, direction, SymKey, SecParam);
+
+	if (PK11_CipherOp(EncContext, output, &write_len1, output_len, input, input_len) != SECSuccess)
+	{
+		fprintf(stderr, "PK11_CipherOp failed (err %d)\n", PR_GetError());
+		goto out;
+	}
+
+	output += write_len1;
+	output_len -= write_len1;
+
+	if (PK11_DigestFinal(EncContext, output, &write_len2, output_len) != SECSuccess) goto out;
+
+	PK11_DestroyContext(EncContext, PR_TRUE);
+
+	ret = write_len1 + write_len2;
+
+out:
+	if (SymKey) PK11_FreeSymKey(SymKey);
+	if (SecParam) SECITEM_FreeItem(SecParam, PR_TRUE);
+
+	return ret;
+}
+
+char *
+encrypt_password(const char *password, const char *mpass)
+{
+	static char *plain = NULL, *encrypted = NULL;
+	static int allocated_plain_length = 0, allocated_encrypted_length = 0;
+	int pass_length, plain_length, encrypted_length, used_length, padding_length = 0;
+	char padding[MIN_PASSWORD_LENGTH + 1];
+	SECItem ivItem;
+	unsigned char ivData[BLOCK_SIZE];
+
+	if (!password || !mpass) return NULL;
+
+	if ((pass_length = strlen(password)) < MIN_PASSWORD_LENGTH)
+	{
+		int i;
+		padding_length = MIN_PASSWORD_LENGTH - pass_length;
+		for (i = 0; i < padding_length; i++)
+			padding[i] = rand();
+	}
+
+	/* the plain text we encrypt is the concatenation of the password's hash with the password */
+	plain_length = KEY_SIZE_TO_ENCRYPT + pass_length + 1 + padding_length;
+
+	/* the string we return is a hex representation of the concatenation of
+	 * the IV (BLOCK_SIZE bytes) and the encrypted string (plain_length + BLOCK_SIZE bytes) */
+	encrypted_length = (BLOCK_SIZE + plain_length + BLOCK_SIZE) * 2 + 1;
+
+	if (allocated_plain_length < plain_length)
+	{
+		plain = g_realloc(plain, plain_length);
+		allocated_plain_length = plain_length;
+	}
+  
+	if (allocated_encrypted_length < encrypted_length)
+	{
+		encrypted = g_realloc(encrypted, encrypted_length);
+		allocated_encrypted_length = encrypted_length;
+	}
+
+	/* set up a random IV block */
+	random_iv_block(ivData);
+	ivItem.data = ivData;
+	ivItem.len = BLOCK_SIZE;
+
+	/* copy the IV block to the output buffer */
+	memcpy(encrypted, ivData, BLOCK_SIZE);
+
+	/* the plaintext to encrypt is (some bytes from password's hash) + (password) + (optional padding) */
+	memcpy(plain, hash_password(password), KEY_SIZE_TO_ENCRYPT);
+	strcpy(plain + KEY_SIZE_TO_ENCRYPT, password);
+	memcpy(plain + KEY_SIZE_TO_ENCRYPT + pass_length + 1, padding, padding_length);
+
+	/* encrypt the plaintext into the output buffer */
+	used_length = encrypt_or_decrypt_buffer(CKA_ENCRYPT, mpass, ivItem,
+											(unsigned char *)plain, plain_length,
+											(unsigned char *)encrypted + BLOCK_SIZE, encrypted_length - BLOCK_SIZE);
+
+	bin_to_hex((unsigned char *)encrypted, used_length + BLOCK_SIZE, encrypted);
+	return g_strdup(encrypted);
+}
+
+char *
+decrypt_password(const char *hex_encrypted, const char *mpass)
+{
+	static char* plain = NULL;
+	static unsigned char *encrypted = NULL;
+	static int allocated_length = 0;
+	SECItem ivItem;
+	unsigned char ivData[BLOCK_SIZE];
+	int encrypted_length;
+
+	if (!hex_encrypted || !mpass) return NULL;
+
+	/* strip the IV from the start of the string */
+	hex_to_bin(hex_encrypted, BLOCK_SIZE, ivData);
+	hex_encrypted += BLOCK_SIZE*2;
+	ivItem.data = ivData;
+	ivItem.len = BLOCK_SIZE;
+
+	/* the remaining hex_encrypted string is a hex representation of the encrypted plaintext */
+	encrypted_length = strlen(hex_encrypted) / 2 + 1;
+
+	if (allocated_length < encrypted_length)
+	{
+		plain = g_realloc(plain, encrypted_length);
+		encrypted = g_realloc(encrypted, encrypted_length);
+		allocated_length = encrypted_length;
+	}
+  
+	/* extract the encrypted binary buffer */
+	encrypted_length = hex_to_bin(hex_encrypted, 0, encrypted);
+
+	/* decrypt it and check that the hash is correct */
+	if (!encrypt_or_decrypt_buffer(CKA_DECRYPT, mpass, ivItem,
+								   encrypted, encrypted_length,
+								   (unsigned char *)plain, allocated_length))
+	    return NULL;
+
+	if (memcmp(plain, hash_password(plain + KEY_SIZE_TO_ENCRYPT), KEY_SIZE_TO_ENCRYPT)) {
+		fprintf(stderr, "the password decrypted, but the hash didn't match\n");
+		return NULL;
+	}
+
+	return g_strdup(plain + KEY_SIZE_TO_ENCRYPT);
+}
+
+/* show a dialog allowing the user to request that the master password be changed */
+void
+request_set_master_password(void)
+{
+	PurpleRequestFields *fields;
+	PurpleRequestFieldGroup *group;
+	PurpleRequestField *field;
+
+	fields = purple_request_fields_new();
+	group = purple_request_field_group_new(NULL);
+	purple_request_fields_add_group(fields, group);
+
+	if (purple_get_encryption_type() == ENCRYPTION_ENC)
+	{
+		field = purple_request_field_string_new("current", _("Current Password"), NULL, FALSE);
+		purple_request_field_string_set_masked(field, TRUE);
+		purple_request_field_group_add_field(group, field);
+	}
+
+	field = purple_request_field_string_new("password", _("New Password"), NULL, FALSE);
+	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_group_add_field(group, field);
+
+	field = purple_request_field_string_new("confirm", _("Confirm New Password"), NULL, FALSE);
+	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_group_add_field(group, field);
+
+	purple_request_fields(NULL,
+						_("Set Master Password"),
+						_("Specify new master password"),
+						_("Leave the `New password' and `Confirm new password' fields blank"
+						  " to use plain text passwords."),
+						fields,
+						_("OK"), G_CALLBACK(request_set_master_password_cb),
+						_("Cancel"), NULL,
+						NULL, NULL, NULL, NULL);
+}
+
+/* show a dialog allowing the user to request that the master password be cleared */
+void
+request_clear_master_password(void)
+{
+	PurpleRequestFields *fields;
+	PurpleRequestFieldGroup *group;
+	PurpleRequestField *field;
+
+	fields = purple_request_fields_new();
+	group = purple_request_field_group_new(NULL);
+	purple_request_fields_add_group(fields, group);
+
+	field = purple_request_field_string_new("current", _("Current Password"), NULL, FALSE);
+	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_group_add_field(group, field);
+
+	purple_request_fields(NULL,
+			    _("Clear Master Password"),
+			    _("Specify current master password"),
+			    _("Specify the current master password and click OK to decrypt all"
+			      " stored passwords.  If you have forgotten the current master password,"
+			      " type 'delete' in the password field and all encrypted passwords will"
+			      " be deleted."),
+			    fields,
+			    _("OK"), G_CALLBACK(request_clear_master_password_cb),
+			    _("Cancel"), NULL,
+			    NULL, NULL, NULL, NULL);
+}
+
diff -Naur pidgin-2.4.1/libpurple/master-password.h pidgin-2.4.1.new/libpurple/master-password.h
--- pidgin-2.4.1/libpurple/master-password.h	1970-01-01 05:30:00.000000000 +0530
+++ pidgin-2.4.1.new/libpurple/master-password.h	2008-04-11 00:58:19.000000000 +0530
@@ -0,0 +1,93 @@
+/**
+ * @file master-password.h Master Password API
+ * @ingroup core
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+typedef enum {
+  ENCRYPTION_NONE,
+  ENCRYPTION_ENC
+} encryption_type;
+
+/**
+ * Sets the encrypted master password.
+ *
+ * @param encmpass The encrypted master password.
+ */
+void purple_set_encrypted_master_password(const char *encmpass);
+
+/**
+ * Returns the encrypted master password.
+ *
+ * @return The encypted master password.
+ */
+const char *purple_get_encrypted_master_password(void);
+
+/**
+ * Returns the master password.
+ *
+ * @return The master password.
+ */
+const char *purple_get_master_password(void);
+
+/**
+ * Encrypts a password using the master password.
+ *
+ * @param password The password to encrypt.
+ * @param master_password The master password to use as the encryption key.
+ *
+ * @return The encrypted password as a hex string.
+ */
+char *encrypt_password(const char *password, const char *master_password);
+
+/**
+ * @param encrypted The encrypted password as a hex string.
+ * @param master_password The master password to use as the decryption key.
+ *
+ * @return The decrypted password.
+ */
+char *decrypt_password(const char *encrypted, const char *master_password);
+
+/**
+ * Prompts the user to set the master password.
+ */
+void request_set_master_password(void);
+
+/**
+ * Prompts the user to clear the master password.
+ */
+void request_clear_master_password(void);
+
+/**
+ * Sets a flag saying whether passwords are encrypted or not.
+ *
+ * @paren type The value to set.  ENCRYPTION_NONE or ENCRYPTION_ENC.
+ */
+void purple_set_encryption_type(encryption_type type);
+
+/**
+ * Returns a flag saying whether passwords are encrypted or not.
+ *
+ * @return The flag.  ENCRYPTION_NONE or ENCRYPTION_ENC.
+ */
+encryption_type purple_get_encryption_type(void);
+
diff -Naur pidgin-2.4.1/pidgin/gtkprefs.c pidgin-2.4.1.new/pidgin/gtkprefs.c
--- pidgin-2.4.1/pidgin/gtkprefs.c	2008-03-31 22:51:25.000000000 +0530
+++ pidgin-2.4.1.new/pidgin/gtkprefs.c	2008-04-11 00:58:19.000000000 +0530
@@ -50,6 +50,7 @@
 #include "gtkthemes.h"
 #include "gtkutils.h"
 #include "pidginstock.h"
+#include "master-password.h"
 
 #define PROXYHOST 0
 #define PROXYPORT 1
@@ -1494,6 +1495,49 @@
 #endif /*_WIN32*/
 
 static GtkWidget *
+security_page()
+{
+	GtkWidget *ret;
+	GtkWidget *vbox, *label, *button;
+
+	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
+	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
+ 
+	vbox = pidgin_make_frame (ret, _("Master Password"));
+
+	label = gtk_label_new(_("A master password can be used to protect your account passwords.  If you create a master password you will be asked to enter it once per session."));
+
+	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+
+	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
+	// gtk_widget_show(label);
+
+	if (purple_get_encryption_type() == ENCRYPTION_NONE)
+		button = gtk_button_new_with_label(_("Set Master Password"));
+	else
+		button = gtk_button_new_with_label(_("Change Master Password"));
+	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(request_set_master_password), NULL);
+	gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
+
+	if (purple_get_encryption_type() != ENCRYPTION_NONE)
+	{
+		button = gtk_button_new_with_label(_("Clear Master Password"));
+		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(request_clear_master_password), NULL);
+		gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
+	}
+
+	// button = gtk_button_new_with_label(_("Load Accounts"));
+	// g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(mp_load_accounts), NULL);
+	// gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
+
+	gtk_widget_show_all(ret);
+
+	return ret;
+}
+
+static GtkWidget *
 logging_page(void)
 {
 	GtkWidget *ret;
@@ -2045,6 +2089,7 @@
 		prefs_notebook_add_page(_("Browser"), browser_page(), notebook_page++);
 	}
 #endif
+	prefs_notebook_add_page(_("Security"),security_page(), notebook_page++);
 	prefs_notebook_add_page(_("Logging"), logging_page(), notebook_page++);
 	prefs_notebook_add_page(_("Status / Idle"), away_page(), notebook_page++);
 }
