1 /*             Nonces for the Pidgin encryption plugin                      */
2 /*            Copyright (C) 2001-2003 William Tompkins                    */
3 
4 /* This plugin is free software, distributed under the GNU General Public */
5 /* License.                                                               */
6 /* Please see the file "COPYING" distributed with this source code        */
7 /* for more details                                                       */
8 /*                                                                        */
9 /*                                                                        */
10 /*    This software is distributed in the hope that it will be useful,    */
11 /*   but WITHOUT ANY WARRANTY; without even the implied warranty of       */
12 /*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    */
13 /*   General Public License for more details.                             */
14 
15 /*   To compile and use:                                                  */
16 /*     See INSTALL file.                                                  */
17 
18 #include "internal.h"
19 
20 #include <glib.h>
21 
22 #include "debug.h"
23 
24 #include "base64.h"
25 #include "pk11func.h"
26 
27 #include "nonce.h"
28 
29 
30 static GHashTable *incoming_nonces;
31 
32 static const int MaxNonceIncr = 20;
33 
PE_nonce_map_init()34 void PE_nonce_map_init() {
35    incoming_nonces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
36 }
37 
PE_nonce_str_len()38 int PE_nonce_str_len() {
39    return (sizeof(Nonce) * 4 / 3);
40 }
41 
PE_incr_nonce(Nonce * nonce)42 void PE_incr_nonce(Nonce* nonce) {
43    int i = sizeof(Nonce);
44    unsigned char carry = 1;
45 
46    while (carry && i > 0) {
47       ++((*nonce)[--i]);
48       carry = (nonce[i] == 0);
49    }
50 }
51 
PE_nonce_to_str(Nonce * nonce)52 gchar* PE_nonce_to_str(Nonce* nonce) {
53    char * tmp = BTOA_DataToAscii(*nonce, sizeof(Nonce));
54    gchar* out = g_strdup(tmp);
55 
56    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Built Nonce:%u:%s\n", (unsigned)sizeof(Nonce), tmp);
57 
58    PORT_Free(tmp);
59    return out;
60 }
61 
62 /* Intentionally un-optimized compare: should take constant time no matter */
63 /* where nonces may differ.                                                */
64 
nonce_cmp(Nonce * n1,Nonce * n2)65 static int nonce_cmp(Nonce* n1, Nonce* n2) {
66    int retval = 0;
67    int i;
68    for (i = 0; i < sizeof(Nonce); ++i) {
69       if ((*n1)[i] != (*n2)[i]) retval = 1;
70    }
71 
72    return retval;
73 }
74 
75 
PE_str_to_nonce(Nonce * nonce,char * nonce_str)76 void PE_str_to_nonce(Nonce* nonce, char* nonce_str) {
77    unsigned int tmp_len;
78    unsigned char* tmp_bin;
79 
80    tmp_bin = ATOB_AsciiToData(nonce_str, &tmp_len);
81    if (tmp_len != sizeof(Nonce)) {
82       PORT_Free(tmp_bin);
83       memset(nonce, 0, sizeof(Nonce));
84       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "Error parsing RSANSS nonce\n");
85       return;
86    }
87    memcpy(nonce, tmp_bin, sizeof(Nonce));
88 
89    PORT_Free(tmp_bin);
90 }
91 
PE_new_incoming_nonce(const char * name)92 gchar* PE_new_incoming_nonce(const char* name) {
93    Nonce *nonce = g_malloc(sizeof(Nonce));
94 
95    SECStatus rv = PK11_GenerateRandom(*nonce, sizeof(Nonce));
96    g_assert(rv == SECSuccess);
97 
98    g_hash_table_replace(incoming_nonces, g_strdup(name), nonce);
99 
100    return PE_nonce_to_str(nonce);
101 }
102 
PE_check_incoming_nonce(const char * name,char * nonce_str)103 int PE_check_incoming_nonce(const char* name, char* nonce_str) {
104    Nonce new_nonce;
105    Nonce* orig_nonce = g_hash_table_lookup(incoming_nonces, name);
106    Nonce try_nonce;
107    int i;
108 
109    /* purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Nonce Check start\n"); */
110 
111    if (orig_nonce == 0) return 0;
112 
113    memcpy(&try_nonce, orig_nonce, sizeof(Nonce));
114 
115    PE_str_to_nonce(&new_nonce, nonce_str);
116 
117    for (i = 0; i < MaxNonceIncr; ++i) {
118       if (nonce_cmp(&new_nonce, &try_nonce) == 0) {
119          memcpy(orig_nonce, &try_nonce, sizeof(Nonce));
120          PE_incr_nonce(orig_nonce);
121          return 1;
122       }
123       PE_incr_nonce(&try_nonce);
124    }
125 
126    return 0;
127 }
128 
129