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