2 * @file sipe-crypt-nss.c
6 * Copyright (C) 2011-2015 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2010 pier11 <pier11@operamail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * Cypher routines implementation based on NSS.
33 * Work around a compiler error in NSS 3.13.x. Let's hope they fix it for
34 * 3.14.x. See also: https://bugzilla.mozilla.org/show_bug.cgi?id=702090
36 #if (NSS_VMAJOR == 3) && (NSS_VMINOR == 13)
37 #define __GNUC_MINOR __GNUC_MINOR__
41 #include "sipe-common.h"
42 #include "sipe-backend.h"
43 #include "sipe-crypt.h"
45 /* NSS specific initialization/shutdown */
46 void sipe_crypto_init(SIPE_UNUSED_PARAMETER gboolean production_mode
)
48 if (!NSS_IsInitialized()) {
50 * I have a bad feeling about this: according to the NSS
51 * documentation, NSS can only be initialized once.
52 * Unfortunately there seems to be no way to initialize a
53 * "NSS context" that could then be used by the SIPE code
54 * to avoid colliding with other NSS users.
56 * This seems to work, so it'll have to do for now.
58 * It might also be required to move this to the backend
59 * so that the backend code can decide when it is OK to
63 SIPE_DEBUG_INFO_NOFORMAT("NSS initialised");
67 void sipe_crypto_shutdown(void)
69 /* do nothing for NSS.
70 * We don't want accedently switch off NSS possibly used by other plugin -
71 * ssl-nss in Pidgin for example.
78 sipe_crypt_ctx_create(CK_MECHANISM_TYPE cipherMech
,
79 const guchar
*key
, gsize key_length
,
80 const guchar
*iv
, gsize iv_length
)
87 PK11Context
* EncContext
;
90 slot
= PK11_GetBestSlot(cipherMech
, NULL
);
92 keyItem
.type
= siBuffer
;
93 keyItem
.data
= (unsigned char *)key
;
94 keyItem
.len
= key_length
;
96 SymKey
= PK11_ImportSymKey(slot
, cipherMech
, PK11_OriginUnwrap
, CKA_ENCRYPT
, &keyItem
, NULL
);
98 /* Parameter for crypto context */
99 ivItem
.type
= siBuffer
;
100 ivItem
.data
= (unsigned char *)iv
;
101 ivItem
.len
= iv_length
;
102 SecParam
= PK11_ParamFromIV(cipherMech
, &ivItem
);
104 EncContext
= PK11_CreateContextBySymKey(cipherMech
, CKA_ENCRYPT
, SymKey
, SecParam
);
106 PK11_FreeSymKey(SymKey
);
107 SECITEM_FreeItem(SecParam
, PR_TRUE
);
114 sipe_crypt_ctx_encrypt(PK11Context
* EncContext
, const guchar
*in
, gsize length
, guchar
*out
)
118 PK11_CipherOp(EncContext
, out
, &tmp1_outlen
, length
, (unsigned char *)in
, length
);
122 sipe_crypt_ctx_destroy(PK11Context
* EncContext
)
124 PK11_DestroyContext(EncContext
, PR_TRUE
);
128 sipe_crypt(CK_MECHANISM_TYPE cipherMech
,
129 const guchar
*key
, gsize key_length
,
130 const guchar
*plaintext
, gsize plaintext_length
,
131 guchar
*encrypted_text
)
135 EncContext
= sipe_crypt_ctx_create(cipherMech
, key
, key_length
, NULL
, 0);
136 sipe_crypt_ctx_encrypt(EncContext
, plaintext
, plaintext_length
, encrypted_text
);
137 sipe_crypt_ctx_destroy(EncContext
);
144 sipe_crypt_des(const guchar
*key
,
145 const guchar
*plaintext
, gsize plaintext_length
,
146 guchar
*encrypted_text
)
148 sipe_crypt(CKM_DES_ECB
, key
, 8, plaintext
, plaintext_length
, encrypted_text
);
152 sipe_crypt_rc4(const guchar
*key
, gsize key_length
,
153 const guchar
*plaintext
, gsize plaintext_length
,
154 guchar
*encrypted_text
)
156 sipe_crypt(CKM_RC4
, key
, key_length
, plaintext
, plaintext_length
, encrypted_text
);
160 sipe_crypt_rsa_encrypt(gpointer
public, gsize modulus_length
,
161 const guchar
*plaintext
,
162 guchar
*encrypted_text
)
164 SECStatus result
= PK11_PubEncryptRaw(public,
165 encrypted_text
, (guchar
*) plaintext
,
166 modulus_length
, NULL
);
167 return(result
== SECSuccess
);
171 sipe_crypt_rsa_decrypt(gpointer
private, gsize modulus_length
,
172 const guchar
*encrypted_text
,
176 SECStatus result
= PK11_PubDecryptRaw(private,
177 (guchar
*) encrypted_text
, &length
, modulus_length
,
178 plaintext
, modulus_length
);
179 return((result
== SECSuccess
) && (length
== modulus_length
));
182 guchar
*sipe_crypt_rsa_sign(gpointer
private,
183 const guchar
*digest
, gsize digest_length
,
184 gsize
*signature_length
)
190 length
= PK11_SignatureLen(private);
191 if (length
< 0) return(NULL
);
193 /* digest to sign (= encrypt) with private key */
194 digItem
.data
= (guchar
*) digest
;
195 digItem
.len
= digest_length
;
198 sigItem
.data
= g_malloc(length
);
199 sigItem
.len
= length
;
201 length
= PK11_Sign(private, &sigItem
, &digItem
);
202 if (length
!= SECSuccess
) {
203 g_free(sigItem
.data
);
207 *signature_length
= sigItem
.len
;
208 return(sigItem
.data
);
211 gboolean
sipe_crypt_verify_rsa(gpointer
public,
212 const guchar
*digest
, gsize digest_length
,
213 const guchar
*signature
, gsize signature_length
)
218 /* digest to verify against */
219 digItem
.data
= (guchar
*) digest
;
220 digItem
.len
= digest_length
;
222 /* signature to decrypt with public key -> digest to compare */
223 sigItem
.data
= (guchar
*) signature
;
224 sigItem
.len
= signature_length
;
226 return(PK11_Verify(public, &sigItem
, &digItem
, NULL
) == SECSuccess
);
230 /* Stream RC4 cipher for file transfer */
232 sipe_crypt_ft_start(const guchar
*key
)
234 return sipe_crypt_ctx_create(CKM_RC4
, key
, 16, NULL
, 0);
238 sipe_crypt_ft_stream(gpointer context
,
239 const guchar
*in
, gsize length
,
242 sipe_crypt_ctx_encrypt(context
, in
, length
, out
);
246 sipe_crypt_ft_destroy(gpointer context
)
248 sipe_crypt_ctx_destroy(context
);
252 * Stream RC4 cipher for TLS
254 * basically the same as for FT, but with variable key length
256 gpointer
sipe_crypt_tls_start(const guchar
*key
, gsize key_length
)
258 return sipe_crypt_ctx_create(CKM_RC4
, key
, key_length
, NULL
, 0);
261 void sipe_crypt_tls_stream(gpointer context
,
262 const guchar
*in
, gsize length
,
265 sipe_crypt_ctx_encrypt(context
, in
, length
, out
);
268 void sipe_crypt_tls_destroy(gpointer context
)
270 sipe_crypt_ctx_destroy(context
);
273 /* Block AES-CBC cipher for TLS */
274 void sipe_crypt_tls_block(const guchar
*key
, gsize key_length
,
275 const guchar
*iv
, gsize iv_length
,
276 const guchar
*in
, gsize length
,
279 PK11Context
* context
= sipe_crypt_ctx_create(CKM_AES_CBC
,
283 sipe_crypt_ctx_encrypt(context
, in
, length
, out
);
284 sipe_crypt_ctx_destroy(context
);