📄 rsa_nss.c
字号:
/* NSS keys for the Gaim encryption plugin *//* Copyright (C) 2001 William Tompkins *//* This plugin is free software, distributed under the GNU General Public *//* License. *//* Please see the file "COPYING" distributed with the Gaim source code *//* for more details *//* *//* *//* This software 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. *//* To compile and use: *//* See INSTALL file. */#include <gdk/gdk.h>#include <gtk/gtk.h>#include <gtk/gtkplug.h>#include <debug.h>#include <gaim.h>#include <gtkdialogs.h>#include "glib/gmain.h"#include <string.h>#include <assert.h>#ifdef _WIN32#include "win32dep.h"#endif#include "rsa_nss.h"#include <nspr.h>#include <nss.h>#include <ssl.h>#include <secmod.h>#include <pk11func.h>#include <keyhi.h>#include <nssb64.h>#include "nls.h"#include "nss_mgf1.h"#include "nss_oaep.h"#include "nss_pss.h"#include "cryptutil.h"#include "keys.h"#include "cryptproto.h"#include "state_ui.h"char* rsa_nss_proto_string="NSS 1.0";crypt_proto* rsa_nss_proto;/*Functions exported through crypt_proto structure */static int rsa_nss_encrypt(unsigned char**, unsigned char*, int, crypt_key*);static int rsa_nss_decrypt(unsigned char**, unsigned char*, int, crypt_key*);static int rsa_nss_sign(unsigned char**, unsigned char*, int, crypt_key*, crypt_key*);static int rsa_nss_auth(unsigned char**, unsigned char*, int, crypt_key*, const char* name);static crypt_key* rsa_nss_make_key_from_str(unsigned char *key_str);static GString* rsa_nss_key_to_gstr(crypt_key* inkey);static unsigned char* rsa_nss_parseable(unsigned char* key);static crypt_key* rsa_nss_parse_sent_key(unsigned char *key_str);static GString* rsa_nss_make_sendable_key(crypt_key* inkey, const char* name);static gchar* rsa_nss_make_key_id(crypt_key* inkey);void rsa_nss_gen_key_pair(crypt_key **, crypt_key **, const char* name, int keysize);static void rsa_nss_free(crypt_key*);static crypt_key* rsa_nss_make_pub_from_priv(crypt_key* priv);static int rsa_nss_calc_unencrypted_size(struct crypt_key*, int);static int rsa_nss_calc_unsigned_size(struct crypt_key*, int);/* internals */void rsa_nss_test(crypt_key *pub, crypt_key *priv);gboolean rsa_nss_init() { gboolean nss_loaded_ok = FALSE; GaimPlugin *plugin = gaim_plugins_find_with_name("NSS"); if (plugin != NULL) { nss_loaded_ok = gaim_plugin_is_loaded(plugin); if (!nss_loaded_ok) { nss_loaded_ok = gaim_plugin_load(plugin); } } if (!nss_loaded_ok) { gaim_debug(GAIM_DEBUG_ERROR, "gaim-encryption", "Initializing NSS without Gaim support\n"); /* Gaim doesn't seem to have NSS support: try to load it ourselves: */ PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); NSS_NoDB_Init(NULL); /* TODO: Fix this so autoconf does the work trying to find this lib. */ SECMOD_AddNewModule("Builtins",#ifndef _WIN32 LIBDIR "/libnssckbi.so",#else "nssckbi.dll",#endif 0, 0); NSS_SetDomesticPolicy(); /* gaim_debug(GAIM_DEBUG_ERROR, "gaim-encryption", _("Can't load the NSS plugin\n")); */ /* GE_error_window(_("Gaim was not compiled with the NSS plugin enabled. " */ /* "Gaim-Encryption requires the NSS plugin to function.")); */ /* return FALSE; */ } rsa_nss_proto = g_malloc(sizeof(crypt_proto)); crypt_proto_list = g_slist_prepend(crypt_proto_list, rsa_nss_proto); rsa_nss_proto->encrypt = rsa_nss_encrypt; rsa_nss_proto->decrypt = rsa_nss_decrypt; rsa_nss_proto->sign = rsa_nss_sign; rsa_nss_proto->auth = rsa_nss_auth; rsa_nss_proto->make_key_from_str = rsa_nss_make_key_from_str; rsa_nss_proto->key_to_gstr = rsa_nss_key_to_gstr; rsa_nss_proto->parseable = rsa_nss_parseable; rsa_nss_proto->parse_sent_key = rsa_nss_parse_sent_key; rsa_nss_proto->make_sendable_key = rsa_nss_make_sendable_key; rsa_nss_proto->make_key_id = rsa_nss_make_key_id; rsa_nss_proto->gen_key_pair = rsa_nss_gen_key_pair; rsa_nss_proto->free = rsa_nss_free; rsa_nss_proto->make_pub_from_priv = rsa_nss_make_pub_from_priv; rsa_nss_proto->calc_unencrypted_size = rsa_nss_calc_unencrypted_size; rsa_nss_proto->calc_unsigned_size = rsa_nss_calc_unsigned_size; rsa_nss_proto->name = rsa_nss_proto_string; return TRUE;}static void rsa_nss_free(crypt_key* key){ if (key->store.rsa_nss.pub) { SECKEY_DestroyPublicKey(key->store.rsa_nss.pub); key->store.rsa_nss.pub = 0; } if (key->store.rsa_nss.priv) { SECKEY_DestroyPrivateKey(key->store.rsa_nss.priv); key->store.rsa_nss.priv = 0; }}static SECItem*get_random_iv(CK_MECHANISM_TYPE mechType){ int iv_size = PK11_GetIVLength(mechType); SECItem *iv; SECStatus rv; iv = PORT_ZNew(SECItem); g_assert(iv != 0); g_assert(iv_size != 0); iv->data = PORT_NewArray(unsigned char, iv_size); g_assert(iv->data != 0); iv->len = iv_size; rv = PK11_GenerateRandom(iv->data, iv->len); g_assert(rv == SECSuccess); return iv;}static void generate_digest(char* digest, SECKEYPublicKey* key) { SECItem *hash = PK11_MakeIDFromPubKey(&key->u.rsa.modulus); int i = 0, digestPos = 0; while (i < hash->len && digestPos < KEY_DIGEST_LENGTH) { sprintf(digest + digestPos, "%02x", hash->data[i]); ++i; digestPos += 2; }}static void generate_fingerprint(char* print, SECKEYPublicKey* key) { SECItem *hash = PK11_MakeIDFromPubKey(&key->u.rsa.modulus); int i; for (i= 0; i < hash->len - 1; ++i) { sprintf(print + (3*i), "%02x:", hash->data[i]); } sprintf(print + 3 * (hash->len - 1), "%02x", hash->data[(hash->len - 1)]);}static SECKEYPublicKey *copy_public_rsa_key(SECKEYPublicKey *pubk) { SECKEYPublicKey *copyk; PRArenaPool *arena; SECStatus rv; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); g_assert(arena != NULL); copyk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey)); g_assert(copyk != NULL); copyk->arena = arena; copyk->keyType = pubk->keyType; copyk->pkcs11Slot = NULL; /* go get own reference */ copyk->pkcs11ID = CK_INVALID_HANDLE; rv = SECITEM_CopyItem(arena, ©k->u.rsa.modulus, &pubk->u.rsa.modulus); g_assert(rv == SECSuccess); rv = SECITEM_CopyItem (arena, ©k->u.rsa.publicExponent, &pubk->u.rsa.publicExponent); g_assert(rv == SECSuccess); return copyk;}void rsa_nss_gen_key_pair(crypt_key **pub_key, crypt_key **priv_key, const char* name, int keysize) { GtkWidget *status_window, *main_box, *label1, *label2; char labelText[1000]; PK11RSAGenParams rsaParams; PK11SlotInfo *slot; CK_MECHANISM_TYPE multiType[2] = {CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_DES_CBC_PAD}; /* Create the widgets */ GAIM_DIALOG(status_window); gtk_window_set_wmclass(GTK_WINDOW(status_window), "keygen", "Gaim"); gtk_widget_realize(status_window); gtk_container_set_border_width(GTK_CONTAINER(status_window), 10); gtk_widget_set_size_request(status_window, 350, 100); gtk_window_set_title(GTK_WINDOW(status_window), "Status"); main_box = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(status_window), main_box); gtk_widget_show(main_box); g_snprintf(labelText, sizeof(labelText), _("Generating RSA Key Pair for %s"), name); label1 = gtk_label_new (labelText); label2 = gtk_label_new (_("This may take a little bit...")); gtk_container_add (GTK_CONTAINER (main_box), label1); gtk_widget_show(label1); gtk_container_add (GTK_CONTAINER (main_box), label2); gtk_widget_show(label2); gtk_widget_show (status_window); // I don't understand: if I remove one of these // two loops, the contents of the status window don't // get drawn. Hmm... while (gtk_events_pending()) { gtk_main_iteration_do(FALSE); } gtk_main_iteration(); while (gtk_events_pending()) { gtk_main_iteration_do(FALSE); } *priv_key = g_malloc(sizeof(crypt_key)); rsaParams.keySizeInBits = keysize; rsaParams.pe = 65537L; slot = PK11_GetBestSlotMultiple(multiType, 2, 0); /* Generate "session" (first FALSE), "not sensitive" (next FALSE) key */ (*priv_key)->store.rsa_nss.priv = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, &(*priv_key)->store.rsa_nss.pub, PR_FALSE, PR_FALSE, 0); if (!(*priv_key)->store.rsa_nss.priv) { gaim_debug(GAIM_DEBUG_ERROR, "gaim-encryption", _("Could not generate key. NSS Error: %d\n"), PORT_GetError()); exit(0); } (*priv_key)->proto = rsa_nss_proto; g_snprintf((*priv_key)->length, sizeof((*priv_key)->length), "%d", keysize); generate_digest((*priv_key)->digest, (*priv_key)->store.rsa_nss.pub); generate_fingerprint((*priv_key)->fingerprint, (*priv_key)->store.rsa_nss.pub); (*pub_key) = rsa_nss_make_pub_from_priv(*priv_key); gtk_widget_hide(status_window); gtk_widget_destroy(status_window);}unsigned char* rsa_nss_parseable(unsigned char *key) { /* If the key is ours, return a pointer to the ':' after our token */ /* otherwise return 0 */ /* if we were more sophisticated, we could look for older versions */ /* of our protocol here, and accept them too. */ if (strncmp(rsa_nss_proto_string, key, strlen(rsa_nss_proto_string)) == 0) { return key + strlen(rsa_nss_proto_string); } else { return 0; }}static GString* append_priv_key_to_gstr(GString *str, SECKEYPrivateKey* priv) { /* for now, we hope that everyone can use DES3. This is for wrapping */ /* private keys, which isn't actually secure at this point anyways */ /* (security provided by the OS: no one else can read/write the keyfile */ const CK_MECHANISM_TYPE SymEncryptionType = CKM_DES3_CBC_PAD; PK11SlotInfo *symSlot; PK11SymKey *symKey; SECItem symKeyItem; /* storage space for binary key import */ unsigned char symKeyData[24] = {0}; SECItem *iv = NULL; /* IV for CBC encoding */ SECItem exportedKey; /* storage space for exported key */ unsigned char exportedKeyData[5000] = {0}; char* tmpstr; int errCode; if (priv == 0) return str; /* Wrap key using a null symmetric key. When/If we add password protection to keys, we can generate the symmetric key from a hashed password instead */ symSlot = PK11_GetBestSlot(SymEncryptionType, NULL); g_assert(symSlot != 0); symKeyItem.data = &symKeyData[0]; symKeyItem.len = sizeof(symKeyData); symKey = PK11_ImportSymKey(symSlot, PK11_GetKeyGen(SymEncryptionType), PK11_OriginUnwrap, CKA_WRAP, &symKeyItem, NULL); iv = get_random_iv(SymEncryptionType); exportedKey.len = sizeof(exportedKeyData); exportedKey.data = exportedKeyData; errCode = PK11_WrapPrivKey(symSlot, symKey, priv, SymEncryptionType, iv, &exportedKey, NULL); g_assert(errCode == SECSuccess); g_string_append(str, ","); tmpstr = NSSBase64_EncodeItem(0, 0, 0, iv); g_string_append(str, tmpstr); PORT_Free(tmpstr); g_string_append(str, ","); tmpstr = NSSBase64_EncodeItem(0, 0, 0, &exportedKey); g_string_append(str, tmpstr); PORT_Free(tmpstr); g_string_append(str, ","); PK11_FreeSymKey(symKey); PORT_Free(iv->data); PORT_Free(iv); /* The Base64 routine may have inserted lots of return chars into the string: */ /* take them out. */ GE_strip_returns(str); return str;}static GString* append_pub_key_to_gstr(GString *str, SECKEYPublicKey* pub) { char *tmpstr; SECItem *exportedKey; if (pub == 0) return str; exportedKey = SECKEY_EncodeDERSubjectPublicKeyInfo(pub); // exportedKey = PK11_DEREncodePublicKey(pub); tmpstr = NSSBase64_EncodeItem(0, 0, 0, exportedKey); g_string_append(str, tmpstr); PORT_Free(tmpstr); PORT_Free(exportedKey->data); PORT_Free(exportedKey); /* The Base64 routine may have inserted lots of return chars into the string: take them out. */ GE_strip_returns(str); return str;}GString* rsa_nss_make_sendable_key(crypt_key* inkey, const char* name) { GString *outString = g_string_new(""); gchar* nonce_str = GE_new_incoming_nonce(name); g_string_append(outString, nonce_str); gaim_debug(GAIM_DEBUG_INFO, "gaim-encryption", "Sending Nonce with key: %s\n", nonce_str); g_free(nonce_str); g_string_append(outString, ","); append_pub_key_to_gstr(outString, inkey->store.rsa_nss.pub); return outString;}gchar* rsa_nss_make_key_id(crypt_key* inkey) { return GE_nonce_to_str(&inkey->store.rsa_nss.nonce);}crypt_key* rsa_nss_parse_sent_key(unsigned char *key_str) { gchar** split_key = g_strsplit(key_str, ",", 2); crypt_key* key; if ((split_key[0] == 0) || (split_key[1] == 0)) { gaim_debug(GAIM_DEBUG_ERROR, "gaim-encryption", "Error parsing RSANSS nonce/key\n"); return 0; } key = rsa_nss_make_key_from_str(split_key[1]); if (key == 0) return 0; GE_str_to_nonce(&key->store.rsa_nss.nonce, split_key[0]); gaim_debug(GAIM_DEBUG_INFO, "gaim-encryption", "Received Nonce with key: %s\n", split_key[0]); g_strfreev(split_key); return key;}GString* rsa_nss_key_to_gstr(crypt_key* inkey) { GString *outString = g_string_new(""); append_pub_key_to_gstr(outString, inkey->store.rsa_nss.pub); append_priv_key_to_gstr(outString, inkey->store.rsa_nss.priv); return outString;}crypt_key* rsa_nss_make_key_from_str(unsigned char *key_str){ gchar **split_key;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -