xref: /minix3/crypto/external/bsd/libsaslc/dist/src/crypto.c (revision ebfedea0ce5bbe81e252ddf32d732e40fb633fae)
1*ebfedea0SLionel Sambuc /* $NetBSD: crypto.c,v 1.5 2011/02/12 23:21:32 christos Exp $ */
2*ebfedea0SLionel Sambuc 
3*ebfedea0SLionel Sambuc /*
4*ebfedea0SLionel Sambuc  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5*ebfedea0SLionel Sambuc  * All rights reserved.
6*ebfedea0SLionel Sambuc  *
7*ebfedea0SLionel Sambuc  * This code is derived from software contributed to The NetBSD Foundation
8*ebfedea0SLionel Sambuc  * by Mateusz Kocielski.
9*ebfedea0SLionel Sambuc  *
10*ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11*ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
12*ebfedea0SLionel Sambuc  * are met:
13*ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
14*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
15*ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17*ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18*ebfedea0SLionel Sambuc  * 3. All advertising materials mentioning features or use of this software
19*ebfedea0SLionel Sambuc  *    must display the following acknowledgement:
20*ebfedea0SLionel Sambuc  *        This product includes software developed by the NetBSD
21*ebfedea0SLionel Sambuc  *        Foundation, Inc. and its contributors.
22*ebfedea0SLionel Sambuc  * 4. Neither the name of The NetBSD Foundation nor the names of its
23*ebfedea0SLionel Sambuc  *    contributors may be used to endorse or promote products derived
24*ebfedea0SLionel Sambuc  *    from this software without specific prior written permission.
25*ebfedea0SLionel Sambuc  *
26*ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27*ebfedea0SLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28*ebfedea0SLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29*ebfedea0SLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30*ebfedea0SLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31*ebfedea0SLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32*ebfedea0SLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33*ebfedea0SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34*ebfedea0SLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35*ebfedea0SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36*ebfedea0SLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
37*ebfedea0SLionel Sambuc  */
38*ebfedea0SLionel Sambuc #include <sys/cdefs.h>
39*ebfedea0SLionel Sambuc __RCSID("$NetBSD: crypto.c,v 1.5 2011/02/12 23:21:32 christos Exp $");
40*ebfedea0SLionel Sambuc 
41*ebfedea0SLionel Sambuc #include <assert.h>
42*ebfedea0SLionel Sambuc #include <stdio.h>
43*ebfedea0SLionel Sambuc #include <stdlib.h>
44*ebfedea0SLionel Sambuc #include <string.h>
45*ebfedea0SLionel Sambuc 
46*ebfedea0SLionel Sambuc #include <openssl/bio.h>
47*ebfedea0SLionel Sambuc #include <openssl/buffer.h>
48*ebfedea0SLionel Sambuc #include <openssl/evp.h>
49*ebfedea0SLionel Sambuc #include <openssl/hmac.h>
50*ebfedea0SLionel Sambuc #include <openssl/md5.h>
51*ebfedea0SLionel Sambuc #include <openssl/rand.h>
52*ebfedea0SLionel Sambuc 
53*ebfedea0SLionel Sambuc #include "crypto.h"
54*ebfedea0SLionel Sambuc 
55*ebfedea0SLionel Sambuc /**
56*ebfedea0SLionel Sambuc  * @brief base64 encode data.
57*ebfedea0SLionel Sambuc  * @param in input data
58*ebfedea0SLionel Sambuc  * @param inlen input data length (in bytes)
59*ebfedea0SLionel Sambuc  * @param out output data
60*ebfedea0SLionel Sambuc  * @param outlen output data length (in bytes)
61*ebfedea0SLionel Sambuc  * @return 0 on success, -1 on failure
62*ebfedea0SLionel Sambuc  */
63*ebfedea0SLionel Sambuc int
saslc__crypto_encode_base64(const void * in,size_t inlen,char ** out,size_t * outlen)64*ebfedea0SLionel Sambuc saslc__crypto_encode_base64(const void *in, size_t inlen,
65*ebfedea0SLionel Sambuc     char **out, size_t *outlen)
66*ebfedea0SLionel Sambuc {
67*ebfedea0SLionel Sambuc 	BIO *bio;
68*ebfedea0SLionel Sambuc 	BIO *b64;
69*ebfedea0SLionel Sambuc 	size_t enclen;
70*ebfedea0SLionel Sambuc 	char *r;
71*ebfedea0SLionel Sambuc 	int n;
72*ebfedea0SLionel Sambuc 
73*ebfedea0SLionel Sambuc 	enclen = (((inlen + 2) / 3)) * 4;
74*ebfedea0SLionel Sambuc 	r = calloc(enclen + 1, sizeof(*r));
75*ebfedea0SLionel Sambuc 	if (r == NULL)
76*ebfedea0SLionel Sambuc 		return -1;
77*ebfedea0SLionel Sambuc 
78*ebfedea0SLionel Sambuc 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
79*ebfedea0SLionel Sambuc 		goto err;
80*ebfedea0SLionel Sambuc 
81*ebfedea0SLionel Sambuc 	if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
82*ebfedea0SLionel Sambuc 		BIO_free(bio);
83*ebfedea0SLionel Sambuc 		goto err;
84*ebfedea0SLionel Sambuc 	}
85*ebfedea0SLionel Sambuc 	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
86*ebfedea0SLionel Sambuc 	b64 = BIO_push(b64, bio);
87*ebfedea0SLionel Sambuc 	if (BIO_write(b64, in, (int)inlen) != (int)inlen) {
88*ebfedea0SLionel Sambuc 		BIO_free_all(b64);
89*ebfedea0SLionel Sambuc 		goto err;
90*ebfedea0SLionel Sambuc 	}
91*ebfedea0SLionel Sambuc 	/*LINTED: no effect*/
92*ebfedea0SLionel Sambuc 	(void)BIO_flush(b64);
93*ebfedea0SLionel Sambuc 	n = BIO_read(bio, r, (int)enclen);
94*ebfedea0SLionel Sambuc 	BIO_free_all(b64);
95*ebfedea0SLionel Sambuc 	if (n < 0)
96*ebfedea0SLionel Sambuc 		goto err;
97*ebfedea0SLionel Sambuc 	if (out)
98*ebfedea0SLionel Sambuc 		*out = r;
99*ebfedea0SLionel Sambuc 	if (outlen)
100*ebfedea0SLionel Sambuc 		*outlen = n;
101*ebfedea0SLionel Sambuc 	return 0;
102*ebfedea0SLionel Sambuc  err:
103*ebfedea0SLionel Sambuc 	free(r);
104*ebfedea0SLionel Sambuc 	return -1;
105*ebfedea0SLionel Sambuc }
106*ebfedea0SLionel Sambuc 
107*ebfedea0SLionel Sambuc /**
108*ebfedea0SLionel Sambuc  * @brief decode base64 data.
109*ebfedea0SLionel Sambuc  * @param in input data
110*ebfedea0SLionel Sambuc  * @param inlen input data length (in bytes)
111*ebfedea0SLionel Sambuc  * @param out output data
112*ebfedea0SLionel Sambuc  * @param outlen output data length (in bytes)
113*ebfedea0SLionel Sambuc  * @return 0 on success, -1 on failure
114*ebfedea0SLionel Sambuc  */
115*ebfedea0SLionel Sambuc int
saslc__crypto_decode_base64(const char * in,size_t inlen,void ** out,size_t * outlen)116*ebfedea0SLionel Sambuc saslc__crypto_decode_base64(const char *in, size_t inlen,
117*ebfedea0SLionel Sambuc     void **out, size_t *outlen)
118*ebfedea0SLionel Sambuc {
119*ebfedea0SLionel Sambuc 	BIO *bio;
120*ebfedea0SLionel Sambuc 	BIO *b64;
121*ebfedea0SLionel Sambuc 	void *r;
122*ebfedea0SLionel Sambuc 	size_t declen;
123*ebfedea0SLionel Sambuc 	int n;
124*ebfedea0SLionel Sambuc 
125*ebfedea0SLionel Sambuc 	declen = ((inlen + 3) / 4) * 3;
126*ebfedea0SLionel Sambuc 	r = malloc(declen + 1);
127*ebfedea0SLionel Sambuc 	if (r == NULL)
128*ebfedea0SLionel Sambuc 		return -1;
129*ebfedea0SLionel Sambuc 
130*ebfedea0SLionel Sambuc 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
131*ebfedea0SLionel Sambuc 		goto err;
132*ebfedea0SLionel Sambuc 
133*ebfedea0SLionel Sambuc 	if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
134*ebfedea0SLionel Sambuc 		BIO_free(bio);
135*ebfedea0SLionel Sambuc 		goto err;
136*ebfedea0SLionel Sambuc 	}
137*ebfedea0SLionel Sambuc 	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
138*ebfedea0SLionel Sambuc 	b64 = BIO_push(b64, bio);
139*ebfedea0SLionel Sambuc 	if (BIO_write(bio, in, (int)inlen) != (int)inlen) {
140*ebfedea0SLionel Sambuc 		BIO_free_all(b64);
141*ebfedea0SLionel Sambuc 		goto err;
142*ebfedea0SLionel Sambuc 	}
143*ebfedea0SLionel Sambuc 	n = BIO_read(b64, r, (int)declen);
144*ebfedea0SLionel Sambuc 	BIO_free_all(b64);
145*ebfedea0SLionel Sambuc 	if (n < 0)
146*ebfedea0SLionel Sambuc 		goto err;
147*ebfedea0SLionel Sambuc 	((char *)r)[n] = '\0';
148*ebfedea0SLionel Sambuc 	if (out)
149*ebfedea0SLionel Sambuc 		*out = r;
150*ebfedea0SLionel Sambuc 	if (outlen)
151*ebfedea0SLionel Sambuc 		*outlen = n;
152*ebfedea0SLionel Sambuc 	return 0;
153*ebfedea0SLionel Sambuc  err:
154*ebfedea0SLionel Sambuc 	free(r);
155*ebfedea0SLionel Sambuc 	return -1;
156*ebfedea0SLionel Sambuc }
157*ebfedea0SLionel Sambuc 
158*ebfedea0SLionel Sambuc /**
159*ebfedea0SLionel Sambuc  * @brief generates safe nonce basing on OpenSSL
160*ebfedea0SLionel Sambuc  * RAND_pseudo_bytes, which should be enough for our purposes.
161*ebfedea0SLionel Sambuc  * @param len nonce length in bytes
162*ebfedea0SLionel Sambuc  * @return nonce, user is responsible for freeing nonce.
163*ebfedea0SLionel Sambuc  */
164*ebfedea0SLionel Sambuc char *
saslc__crypto_nonce(size_t len)165*ebfedea0SLionel Sambuc saslc__crypto_nonce(size_t len)
166*ebfedea0SLionel Sambuc {
167*ebfedea0SLionel Sambuc 	char *n;
168*ebfedea0SLionel Sambuc 
169*ebfedea0SLionel Sambuc 	if ((n = malloc(len)) == NULL)
170*ebfedea0SLionel Sambuc 		return NULL;
171*ebfedea0SLionel Sambuc 
172*ebfedea0SLionel Sambuc 	if (RAND_pseudo_bytes((unsigned char *)n, (int)len) != 1) {
173*ebfedea0SLionel Sambuc 		free(n);
174*ebfedea0SLionel Sambuc 		return NULL;
175*ebfedea0SLionel Sambuc 	}
176*ebfedea0SLionel Sambuc 	return n;
177*ebfedea0SLionel Sambuc }
178*ebfedea0SLionel Sambuc 
179*ebfedea0SLionel Sambuc /**
180*ebfedea0SLionel Sambuc  * @brief converts MD5 binary digest into text representation.
181*ebfedea0SLionel Sambuc  * @param hash MD5 digest (16 bytes) to convert
182*ebfedea0SLionel Sambuc  * @return the '\0' terminated text representation of the hash.  Note
183*ebfedea0SLionel Sambuc  * that user is responsible for freeing allocated memory.
184*ebfedea0SLionel Sambuc  */
185*ebfedea0SLionel Sambuc char *
saslc__crypto_hash_to_hex(const uint8_t * hash)186*ebfedea0SLionel Sambuc saslc__crypto_hash_to_hex(const uint8_t *hash)
187*ebfedea0SLionel Sambuc {
188*ebfedea0SLionel Sambuc 	static const char hex[] = "0123456789abcdef";
189*ebfedea0SLionel Sambuc 	char *r;
190*ebfedea0SLionel Sambuc 	size_t i, j;
191*ebfedea0SLionel Sambuc 
192*ebfedea0SLionel Sambuc 	if ((r = malloc(MD5_DIGEST_LENGTH * 2 + 1)) == NULL)
193*ebfedea0SLionel Sambuc 		return NULL;
194*ebfedea0SLionel Sambuc 
195*ebfedea0SLionel Sambuc 	for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
196*ebfedea0SLionel Sambuc 		j = i * 2;
197*ebfedea0SLionel Sambuc 		r[j] = hex[(unsigned)hash[i] >> 4];
198*ebfedea0SLionel Sambuc 		r[j + 1] = hex[hash[i] & 0x0F];
199*ebfedea0SLionel Sambuc 	}
200*ebfedea0SLionel Sambuc 	r[MD5_DIGEST_LENGTH * 2] = '\0';
201*ebfedea0SLionel Sambuc 	return r;
202*ebfedea0SLionel Sambuc }
203*ebfedea0SLionel Sambuc 
204*ebfedea0SLionel Sambuc /**
205*ebfedea0SLionel Sambuc  * @brief computes md5(D)
206*ebfedea0SLionel Sambuc  * @param buf input data buffer
207*ebfedea0SLionel Sambuc  * @param buflen number of bytes in input data buffer
208*ebfedea0SLionel Sambuc  * @param digest buffer for hash (must not be NULL)
209*ebfedea0SLionel Sambuc  * @return the md5 digest, note that user is responsible for freeing
210*ebfedea0SLionel Sambuc  * allocated memory if digest is not NULL.
211*ebfedea0SLionel Sambuc  */
212*ebfedea0SLionel Sambuc void
saslc__crypto_md5_hash(const char * buf,size_t buflen,unsigned char * digest)213*ebfedea0SLionel Sambuc saslc__crypto_md5_hash(const char *buf, size_t buflen, unsigned char *digest)
214*ebfedea0SLionel Sambuc {
215*ebfedea0SLionel Sambuc 
216*ebfedea0SLionel Sambuc 	assert(digest != NULL);
217*ebfedea0SLionel Sambuc 	if (digest != NULL)
218*ebfedea0SLionel Sambuc 		(void)MD5((const unsigned char *)buf, buflen, digest);
219*ebfedea0SLionel Sambuc }
220*ebfedea0SLionel Sambuc 
221*ebfedea0SLionel Sambuc /**
222*ebfedea0SLionel Sambuc  * @brief computes md5(D)
223*ebfedea0SLionel Sambuc  * @param buf input data buffer
224*ebfedea0SLionel Sambuc  * @param buflen number of bytes in input data buffer
225*ebfedea0SLionel Sambuc  * @return the text representation of the computed digest, note that
226*ebfedea0SLionel Sambuc  * user is responsible for freeing allocated memory.
227*ebfedea0SLionel Sambuc  */
228*ebfedea0SLionel Sambuc char *
saslc__crypto_md5_hex(const char * buf,size_t buflen)229*ebfedea0SLionel Sambuc saslc__crypto_md5_hex(const char *buf, size_t buflen)
230*ebfedea0SLionel Sambuc {
231*ebfedea0SLionel Sambuc 	unsigned char digest[MD5_DIGEST_LENGTH];
232*ebfedea0SLionel Sambuc 
233*ebfedea0SLionel Sambuc 	(void)MD5((const unsigned char *)buf, buflen, digest);
234*ebfedea0SLionel Sambuc 	return saslc__crypto_hash_to_hex(digest);
235*ebfedea0SLionel Sambuc }
236*ebfedea0SLionel Sambuc 
237*ebfedea0SLionel Sambuc /**
238*ebfedea0SLionel Sambuc  * @brief computes hmac_md5(K, I)
239*ebfedea0SLionel Sambuc  * @param key hmac_md5 key
240*ebfedea0SLionel Sambuc  * @param keylen hmac_md5 key length
241*ebfedea0SLionel Sambuc  * @param in input data to compute hash for
242*ebfedea0SLionel Sambuc  * @param inlen input data length in bytes
243*ebfedea0SLionel Sambuc  * @param hmac space for output (MD5_DIGEST_LENGTH bytes)
244*ebfedea0SLionel Sambuc  * @return 0 on success, -1 on error
245*ebfedea0SLionel Sambuc  */
246*ebfedea0SLionel Sambuc int
saslc__crypto_hmac_md5_hash(const unsigned char * key,size_t keylen,const unsigned char * in,size_t inlen,unsigned char * hmac)247*ebfedea0SLionel Sambuc saslc__crypto_hmac_md5_hash(const unsigned char *key, size_t keylen,
248*ebfedea0SLionel Sambuc     const unsigned char *in, size_t inlen, unsigned char *hmac)
249*ebfedea0SLionel Sambuc {
250*ebfedea0SLionel Sambuc 	unsigned int hmac_len;
251*ebfedea0SLionel Sambuc 
252*ebfedea0SLionel Sambuc 	assert(hmac != NULL);
253*ebfedea0SLionel Sambuc 	if (hmac == NULL || HMAC(EVP_md5(), key, (int)keylen, in,
254*ebfedea0SLionel Sambuc 	    inlen, hmac, &hmac_len) == NULL)
255*ebfedea0SLionel Sambuc 		return -1;
256*ebfedea0SLionel Sambuc 
257*ebfedea0SLionel Sambuc 	assert(hmac_len == MD5_DIGEST_LENGTH);
258*ebfedea0SLionel Sambuc 	return 0;
259*ebfedea0SLionel Sambuc }
260*ebfedea0SLionel Sambuc 
261*ebfedea0SLionel Sambuc /**
262*ebfedea0SLionel Sambuc  * @brief computes hmac_md5(K, I)
263*ebfedea0SLionel Sambuc  * @param key hmac_md5 key
264*ebfedea0SLionel Sambuc  * @param keylen hmac_md5 key length
265*ebfedea0SLionel Sambuc  * @param in input data to compute hash for
266*ebfedea0SLionel Sambuc  * @param inlen input data length in bytes
267*ebfedea0SLionel Sambuc  * @return the text representation of the computed digest, note that user is
268*ebfedea0SLionel Sambuc  * responsible for freeing allocated memory.
269*ebfedea0SLionel Sambuc  */
270*ebfedea0SLionel Sambuc char *
saslc__crypto_hmac_md5_hex(const unsigned char * key,size_t keylen,const unsigned char * in,size_t inlen)271*ebfedea0SLionel Sambuc saslc__crypto_hmac_md5_hex(const unsigned char *key, size_t keylen,
272*ebfedea0SLionel Sambuc     const unsigned char *in, size_t inlen)
273*ebfedea0SLionel Sambuc {
274*ebfedea0SLionel Sambuc 	unsigned char digest[MD5_DIGEST_LENGTH];
275*ebfedea0SLionel Sambuc 
276*ebfedea0SLionel Sambuc 	if (saslc__crypto_hmac_md5_hash(key, keylen, in, inlen, digest) == -1)
277*ebfedea0SLionel Sambuc 		return NULL;
278*ebfedea0SLionel Sambuc 
279*ebfedea0SLionel Sambuc 	return saslc__crypto_hash_to_hex(digest);
280*ebfedea0SLionel Sambuc }
281