1 /* $Id: crypto.c,v 1.2 2011/01/29 23:35:31 agc Exp $ */ 2 3 /* 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Mateusz Kocielski. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <openssl/md5.h> 43 #include <openssl/rand.h> 44 #include <openssl/bio.h> 45 #include <openssl/evp.h> 46 #include <openssl/buffer.h> 47 #include "crypto.h" 48 49 /* local headers */ 50 51 #define HMAC_MD5_KEYSIZE 64 52 #define HMAC_MD5_IPAD 0x36 53 #define HMAC_MD5_OPAD 0x5C 54 55 static const char saslc__hex[] = "0123456789abcdef"; 56 57 static char *saslc__digest_to_ascii(const unsigned char *); 58 59 /** 60 * @brief converts MD5 binary digest into its text representation. 61 * @param d MD5 digest in binary form 62 * @return the text representation, note that user is responsible for freeing 63 * allocated memory. 64 */ 65 66 static char * 67 saslc__digest_to_ascii(const unsigned char *digest) 68 { 69 char *result; 70 size_t i,j; 71 72 result = calloc((2 * MD5_DIGEST_LENGTH) + 1, sizeof(*result)); 73 if (result == NULL) 74 return NULL; 75 76 for (i = 0; i < MD5_DIGEST_LENGTH; i++) { 77 j = 2*i; 78 result[j] = saslc__hex[(unsigned char)digest[i] >> 4]; 79 result[j + 1] = saslc__hex[digest[i] & 0x0F]; 80 } 81 82 return result; 83 } 84 85 /** 86 * @brief encode data to base64. 87 * @param in input data 88 * @param len input data length 89 * @return in encoded using base64. User is responsible for freeing string. 90 */ 91 92 char * 93 saslc__crypto_base64(const unsigned char *in, size_t len) 94 { 95 BIO *m; 96 BIO *base64; 97 BUF_MEM *c; 98 char *r; 99 100 m = BIO_new(BIO_s_mem()); 101 base64 = BIO_new(BIO_f_base64()); 102 103 /* base64 -> mem */ 104 base64 = BIO_push(base64, m); 105 /*LINTED len should be size_t in api*/ 106 BIO_write(base64, in, (int)len); 107 /*LINTED wrong argument, null effect*/ 108 (void)BIO_flush(base64); 109 /*LINTED wrong argument, non-portable cast*/ 110 (void)BIO_get_mem_ptr(base64, &c); 111 /*LINTED length should be size_t in api*/ 112 r = calloc(c->length, sizeof(*r)); 113 if (r == NULL) 114 goto end; 115 if (c->length != 0) { 116 /*LINTED length should be size_t in api*/ 117 memcpy(r, c->data, (size_t)(c->length - 1)); 118 } 119 end: 120 BIO_free_all(base64); 121 122 return r; 123 } 124 125 /** 126 * @brief generates safe nonce basing on the OpenSSL 127 * RAND_pseudo_bytes, which should be good enough for our purposes. 128 * @param b nonce length 129 * @return nonce, user is responsible for freeing nonce. 130 */ 131 132 unsigned char * 133 saslc__crypto_nonce(size_t len) 134 { 135 unsigned char *nonce; 136 137 nonce = calloc(len, sizeof(*nonce)); 138 if (nonce == NULL) 139 return NULL; 140 141 /*LINTED b should be size_t in api*/ 142 if (RAND_pseudo_bytes(nonce, (int)len) != 1) { 143 free(nonce); 144 return NULL; 145 } 146 147 return nonce; 148 } 149 150 /** 151 * @brief computes md5(D) 152 * @param str data 153 * @param len data length 154 * @return text representation of the computed digest, note that user is 155 * responsible for freeing allocated memory. 156 */ 157 158 char * 159 saslc__crypto_md5(const char *str, size_t len) 160 { 161 unsigned char digest[MD5_DIGEST_LENGTH]; 162 MD5_CTX md5c; 163 164 MD5_Init(&md5c); 165 MD5_Update(&md5c, str, len); 166 MD5_Final(digest, &md5c); 167 168 return saslc__digest_to_ascii(digest); 169 } 170 171 /** 172 * @brief computes hmac_md5(K, I) 173 * @param key hmac_md5 key 174 * @param keylen hmac_md5 key length 175 * @param in hmac_md5 input 176 * @param inlen hmac_md5 input length 177 * @returntext representation of the computed digest, note that user is 178 * responsible for freeing allocated memory. 179 */ 180 181 char * 182 saslc__crypto_hmac_md5(const unsigned char *key, size_t keylen, 183 const unsigned char *in, size_t inlen) 184 { 185 unsigned char ipad_key[HMAC_MD5_KEYSIZE], 186 opad_key[HMAC_MD5_KEYSIZE], digest[MD5_DIGEST_LENGTH]; 187 const unsigned char *hmac_key; 188 size_t i; 189 MD5_CTX md5c; 190 191 /* HMAC_MD5(K, T) = MD5(K XOR OPAD, MD5(K XOR IPAD, T)) */ 192 193 memset(ipad_key, 0, sizeof(ipad_key)); 194 memset(opad_key, 0, sizeof(opad_key)); 195 196 if (keylen > 64) { 197 hmac_key = MD5(key, keylen, NULL); 198 keylen = MD5_DIGEST_LENGTH; 199 } else 200 hmac_key = (const unsigned char *)key; 201 202 for (i = 0; i < HMAC_MD5_KEYSIZE ; i++) { 203 unsigned char k = i < keylen ? hmac_key[i] : 0; 204 ipad_key[i] = k ^ HMAC_MD5_IPAD; 205 opad_key[i] = k ^ HMAC_MD5_OPAD; 206 } 207 208 /* d = MD5(K XOR IPAD, T) */ 209 MD5_Init(&md5c); 210 MD5_Update(&md5c, ipad_key, HMAC_MD5_KEYSIZE); 211 MD5_Update(&md5c, in, inlen); 212 MD5_Final(digest, &md5c); 213 /* MD5(K XOR OPAD, d) */ 214 MD5_Init(&md5c); 215 MD5_Update(&md5c, opad_key, HMAC_MD5_KEYSIZE); 216 MD5_Update(&md5c, digest, MD5_DIGEST_LENGTH); 217 MD5_Final(digest, &md5c); 218 219 return saslc__digest_to_ascii(digest); 220 } 221