1*7effb097Schristos /* $NetBSD: crypto.c,v 1.6 2018/02/06 04:21:24 christos Exp $ */
2231558cbSagc
3231558cbSagc /*
4231558cbSagc * Copyright (c) 2010 The NetBSD Foundation, Inc.
5231558cbSagc * All rights reserved.
6231558cbSagc *
7231558cbSagc * This code is derived from software contributed to The NetBSD Foundation
8231558cbSagc * by Mateusz Kocielski.
9231558cbSagc *
10231558cbSagc * Redistribution and use in source and binary forms, with or without
11231558cbSagc * modification, are permitted provided that the following conditions
12231558cbSagc * are met:
13231558cbSagc * 1. Redistributions of source code must retain the above copyright
14231558cbSagc * notice, this list of conditions and the following disclaimer.
15231558cbSagc * 2. Redistributions in binary form must reproduce the above copyright
16231558cbSagc * notice, this list of conditions and the following disclaimer in the
17231558cbSagc * documentation and/or other materials provided with the distribution.
18231558cbSagc * 3. All advertising materials mentioning features or use of this software
19231558cbSagc * must display the following acknowledgement:
20231558cbSagc * This product includes software developed by the NetBSD
21231558cbSagc * Foundation, Inc. and its contributors.
22231558cbSagc * 4. Neither the name of The NetBSD Foundation nor the names of its
23231558cbSagc * contributors may be used to endorse or promote products derived
24231558cbSagc * from this software without specific prior written permission.
25231558cbSagc *
26231558cbSagc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27231558cbSagc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28231558cbSagc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29231558cbSagc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30231558cbSagc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31231558cbSagc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32231558cbSagc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33231558cbSagc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34231558cbSagc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35231558cbSagc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36231558cbSagc * POSSIBILITY OF SUCH DAMAGE.
37231558cbSagc */
3819c14409Schristos #include <sys/cdefs.h>
39*7effb097Schristos __RCSID("$NetBSD: crypto.c,v 1.6 2018/02/06 04:21:24 christos Exp $");
40231558cbSagc
4119c14409Schristos #include <assert.h>
42231558cbSagc #include <stdio.h>
43231558cbSagc #include <stdlib.h>
44231558cbSagc #include <string.h>
45beea8b97Schristos
4619c14409Schristos #include <openssl/bio.h>
4719c14409Schristos #include <openssl/buffer.h>
4819c14409Schristos #include <openssl/evp.h>
49beea8b97Schristos #include <openssl/hmac.h>
50231558cbSagc #include <openssl/md5.h>
51231558cbSagc #include <openssl/rand.h>
5219c14409Schristos
53231558cbSagc #include "crypto.h"
54231558cbSagc
5519c14409Schristos /**
5619c14409Schristos * @brief base64 encode data.
5719c14409Schristos * @param in input data
5819c14409Schristos * @param inlen input data length (in bytes)
5919c14409Schristos * @param out output data
6019c14409Schristos * @param outlen output data length (in bytes)
6119c14409Schristos * @return 0 on success, -1 on failure
6219c14409Schristos */
6319c14409Schristos int
saslc__crypto_encode_base64(const void * in,size_t inlen,char ** out,size_t * outlen)6419c14409Schristos saslc__crypto_encode_base64(const void *in, size_t inlen,
6519c14409Schristos char **out, size_t *outlen)
6619c14409Schristos {
6719c14409Schristos BIO *bio;
6819c14409Schristos BIO *b64;
6919c14409Schristos size_t enclen;
7019c14409Schristos char *r;
7119c14409Schristos int n;
726b638291Sagc
7319c14409Schristos enclen = (((inlen + 2) / 3)) * 4;
7419c14409Schristos r = calloc(enclen + 1, sizeof(*r));
7519c14409Schristos if (r == NULL)
7619c14409Schristos return -1;
77231558cbSagc
7819c14409Schristos if ((bio = BIO_new(BIO_s_mem())) == NULL)
7919c14409Schristos goto err;
80231558cbSagc
8119c14409Schristos if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
8219c14409Schristos BIO_free(bio);
8319c14409Schristos goto err;
8419c14409Schristos }
8519c14409Schristos BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
8619c14409Schristos b64 = BIO_push(b64, bio);
8719c14409Schristos if (BIO_write(b64, in, (int)inlen) != (int)inlen) {
8819c14409Schristos BIO_free_all(b64);
8919c14409Schristos goto err;
9019c14409Schristos }
9119c14409Schristos /*LINTED: no effect*/
9219c14409Schristos (void)BIO_flush(b64);
9319c14409Schristos n = BIO_read(bio, r, (int)enclen);
9419c14409Schristos BIO_free_all(b64);
9519c14409Schristos if (n < 0)
9619c14409Schristos goto err;
9719c14409Schristos if (out)
9819c14409Schristos *out = r;
9919c14409Schristos if (outlen)
10019c14409Schristos *outlen = n;
10119c14409Schristos return 0;
10219c14409Schristos err:
10319c14409Schristos free(r);
10419c14409Schristos return -1;
10519c14409Schristos }
106231558cbSagc
107231558cbSagc /**
10819c14409Schristos * @brief decode base64 data.
10919c14409Schristos * @param in input data
11019c14409Schristos * @param inlen input data length (in bytes)
11119c14409Schristos * @param out output data
11219c14409Schristos * @param outlen output data length (in bytes)
11319c14409Schristos * @return 0 on success, -1 on failure
114231558cbSagc */
11519c14409Schristos int
saslc__crypto_decode_base64(const char * in,size_t inlen,void ** out,size_t * outlen)11619c14409Schristos saslc__crypto_decode_base64(const char *in, size_t inlen,
11719c14409Schristos void **out, size_t *outlen)
118231558cbSagc {
11919c14409Schristos BIO *bio;
12019c14409Schristos BIO *b64;
12119c14409Schristos void *r;
12219c14409Schristos size_t declen;
12319c14409Schristos int n;
12419c14409Schristos
12519c14409Schristos declen = ((inlen + 3) / 4) * 3;
12619c14409Schristos r = malloc(declen + 1);
12719c14409Schristos if (r == NULL)
12819c14409Schristos return -1;
12919c14409Schristos
13019c14409Schristos if ((bio = BIO_new(BIO_s_mem())) == NULL)
13119c14409Schristos goto err;
13219c14409Schristos
13319c14409Schristos if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
13419c14409Schristos BIO_free(bio);
13519c14409Schristos goto err;
13619c14409Schristos }
13719c14409Schristos BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
13819c14409Schristos b64 = BIO_push(b64, bio);
13919c14409Schristos if (BIO_write(bio, in, (int)inlen) != (int)inlen) {
14019c14409Schristos BIO_free_all(b64);
14119c14409Schristos goto err;
14219c14409Schristos }
14319c14409Schristos n = BIO_read(b64, r, (int)declen);
14419c14409Schristos BIO_free_all(b64);
14519c14409Schristos if (n < 0)
14619c14409Schristos goto err;
14719c14409Schristos ((char *)r)[n] = '\0';
14819c14409Schristos if (out)
14919c14409Schristos *out = r;
15019c14409Schristos if (outlen)
15119c14409Schristos *outlen = n;
15219c14409Schristos return 0;
15319c14409Schristos err:
15419c14409Schristos free(r);
15519c14409Schristos return -1;
15619c14409Schristos }
15719c14409Schristos
15819c14409Schristos /**
15919c14409Schristos * @brief generates safe nonce basing on OpenSSL
16019c14409Schristos * RAND_pseudo_bytes, which should be enough for our purposes.
16119c14409Schristos * @param len nonce length in bytes
16219c14409Schristos * @return nonce, user is responsible for freeing nonce.
16319c14409Schristos */
16419c14409Schristos char *
saslc__crypto_nonce(size_t len)16519c14409Schristos saslc__crypto_nonce(size_t len)
16619c14409Schristos {
16719c14409Schristos char *n;
16819c14409Schristos
16919c14409Schristos if ((n = malloc(len)) == NULL)
17019c14409Schristos return NULL;
17119c14409Schristos
172*7effb097Schristos if (RAND_bytes((unsigned char *)n, (int)len) != 1) {
17319c14409Schristos free(n);
17419c14409Schristos return NULL;
17519c14409Schristos }
17619c14409Schristos return n;
17719c14409Schristos }
17819c14409Schristos
17919c14409Schristos /**
18019c14409Schristos * @brief converts MD5 binary digest into text representation.
18119c14409Schristos * @param hash MD5 digest (16 bytes) to convert
18219c14409Schristos * @return the '\0' terminated text representation of the hash. Note
18319c14409Schristos * that user is responsible for freeing allocated memory.
18419c14409Schristos */
18519c14409Schristos char *
saslc__crypto_hash_to_hex(const uint8_t * hash)18619c14409Schristos saslc__crypto_hash_to_hex(const uint8_t *hash)
18719c14409Schristos {
18819c14409Schristos static const char hex[] = "0123456789abcdef";
18919c14409Schristos char *r;
1906b638291Sagc size_t i, j;
191231558cbSagc
19219c14409Schristos if ((r = malloc(MD5_DIGEST_LENGTH * 2 + 1)) == NULL)
193231558cbSagc return NULL;
194231558cbSagc
195231558cbSagc for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
19619c14409Schristos j = i * 2;
19719c14409Schristos r[j] = hex[(unsigned)hash[i] >> 4];
19819c14409Schristos r[j + 1] = hex[hash[i] & 0x0F];
199231558cbSagc }
20019c14409Schristos r[MD5_DIGEST_LENGTH * 2] = '\0';
201231558cbSagc return r;
202231558cbSagc }
203231558cbSagc
204231558cbSagc /**
20519c14409Schristos * @brief computes md5(D)
20619c14409Schristos * @param buf input data buffer
20719c14409Schristos * @param buflen number of bytes in input data buffer
20819c14409Schristos * @param digest buffer for hash (must not be NULL)
20919c14409Schristos * @return the md5 digest, note that user is responsible for freeing
21019c14409Schristos * allocated memory if digest is not NULL.
211231558cbSagc */
21219c14409Schristos void
saslc__crypto_md5_hash(const char * buf,size_t buflen,unsigned char * digest)21319c14409Schristos saslc__crypto_md5_hash(const char *buf, size_t buflen, unsigned char *digest)
214231558cbSagc {
215231558cbSagc
21619c14409Schristos assert(digest != NULL);
21719c14409Schristos if (digest != NULL)
21816e81cb9Schristos (void)MD5((const unsigned char *)buf, buflen, digest);
219231558cbSagc }
220231558cbSagc
221231558cbSagc /**
222231558cbSagc * @brief computes md5(D)
22319c14409Schristos * @param buf input data buffer
22419c14409Schristos * @param buflen number of bytes in input data buffer
22519c14409Schristos * @return the text representation of the computed digest, note that
22619c14409Schristos * user is responsible for freeing allocated memory.
227231558cbSagc */
228231558cbSagc char *
saslc__crypto_md5_hex(const char * buf,size_t buflen)22919c14409Schristos saslc__crypto_md5_hex(const char *buf, size_t buflen)
230231558cbSagc {
231231558cbSagc unsigned char digest[MD5_DIGEST_LENGTH];
232231558cbSagc
23316e81cb9Schristos (void)MD5((const unsigned char *)buf, buflen, digest);
23419c14409Schristos return saslc__crypto_hash_to_hex(digest);
235231558cbSagc }
236231558cbSagc
237231558cbSagc /**
238231558cbSagc * @brief computes hmac_md5(K, I)
239231558cbSagc * @param key hmac_md5 key
240231558cbSagc * @param keylen hmac_md5 key length
24119c14409Schristos * @param in input data to compute hash for
24219c14409Schristos * @param inlen input data length in bytes
24319c14409Schristos * @param hmac space for output (MD5_DIGEST_LENGTH bytes)
24419c14409Schristos * @return 0 on success, -1 on error
245231558cbSagc */
24619c14409Schristos int
saslc__crypto_hmac_md5_hash(const unsigned char * key,size_t keylen,const unsigned char * in,size_t inlen,unsigned char * hmac)24719c14409Schristos saslc__crypto_hmac_md5_hash(const unsigned char *key, size_t keylen,
24819c14409Schristos const unsigned char *in, size_t inlen, unsigned char *hmac)
249231558cbSagc {
25019c14409Schristos unsigned int hmac_len;
251231558cbSagc
25219c14409Schristos assert(hmac != NULL);
25316e81cb9Schristos if (hmac == NULL || HMAC(EVP_md5(), key, (int)keylen, in,
25416e81cb9Schristos inlen, hmac, &hmac_len) == NULL)
25519c14409Schristos return -1;
256231558cbSagc
25719c14409Schristos assert(hmac_len == MD5_DIGEST_LENGTH);
25819c14409Schristos return 0;
259231558cbSagc }
260231558cbSagc
26119c14409Schristos /**
26219c14409Schristos * @brief computes hmac_md5(K, I)
26319c14409Schristos * @param key hmac_md5 key
26419c14409Schristos * @param keylen hmac_md5 key length
26519c14409Schristos * @param in input data to compute hash for
26619c14409Schristos * @param inlen input data length in bytes
26719c14409Schristos * @return the text representation of the computed digest, note that user is
26819c14409Schristos * responsible for freeing allocated memory.
26919c14409Schristos */
27019c14409Schristos char *
saslc__crypto_hmac_md5_hex(const unsigned char * key,size_t keylen,const unsigned char * in,size_t inlen)27119c14409Schristos saslc__crypto_hmac_md5_hex(const unsigned char *key, size_t keylen,
27219c14409Schristos const unsigned char *in, size_t inlen)
27319c14409Schristos {
27419c14409Schristos unsigned char digest[MD5_DIGEST_LENGTH];
275231558cbSagc
27619c14409Schristos if (saslc__crypto_hmac_md5_hash(key, keylen, in, inlen, digest) == -1)
27719c14409Schristos return NULL;
27819c14409Schristos
27919c14409Schristos return saslc__crypto_hash_to_hex(digest);
280231558cbSagc }
281