1 1.2 christos /* $NetBSD: apr1.c,v 1.2 2021/08/14 16:14:52 christos Exp $ */ 2 1.1 tron 3 1.2 christos /* $OpenLDAP$ */ 4 1.2 christos /* 5 1.2 christos * This file is derived from OpenLDAP Software. All of the modifications to 6 1.2 christos * OpenLDAP Software represented in the following file were developed by 7 1.2 christos * Devin J. Pohly <djpohly (at) gmail.com>. I have not assigned rights and/or 8 1.2 christos * interest in this work to any party. 9 1.2 christos * 10 1.2 christos * The extensions to OpenLDAP Software herein are subject to the following 11 1.2 christos * notice: 12 1.2 christos * 13 1.2 christos * Copyright 2011 Devin J. Pohly 14 1.2 christos * Portions Copyright 2011 Howard Chu 15 1.2 christos * Redistribution and use in source and binary forms, with or without 16 1.2 christos * modification, are permitted only as authorized by the OpenLDAP Public 17 1.2 christos * License. 18 1.2 christos * 19 1.2 christos * A portion of this code is used in accordance with the Beer-ware License, 20 1.2 christos * revision 42, as noted. 21 1.2 christos * 22 1.2 christos */ 23 1.2 christos 24 1.2 christos #include <sys/cdefs.h> 25 1.2 christos __RCSID("$NetBSD: apr1.c,v 1.2 2021/08/14 16:14:52 christos Exp $"); 26 1.2 christos 27 1.2 christos #include "portable.h" 28 1.2 christos 29 1.2 christos #include <lber.h> 30 1.2 christos #include <lber_pvt.h> 31 1.2 christos #include "lutil.h" 32 1.2 christos #include "lutil_md5.h" 33 1.2 christos #include <ac/string.h> 34 1.2 christos 35 1.2 christos #include <assert.h> 36 1.2 christos 37 1.2 christos /* the only difference between this and straight PHK is the magic */ 38 1.2 christos static LUTIL_PASSWD_CHK_FUNC chk_apr1; 39 1.2 christos static LUTIL_PASSWD_HASH_FUNC hash_apr1; 40 1.2 christos static const struct berval scheme_apr1 = BER_BVC("{APR1}"); 41 1.2 christos static const struct berval magic_apr1 = BER_BVC("$apr1$"); 42 1.2 christos 43 1.2 christos static LUTIL_PASSWD_CHK_FUNC chk_bsdmd5; 44 1.2 christos static LUTIL_PASSWD_HASH_FUNC hash_bsdmd5; 45 1.2 christos static const struct berval scheme_bsdmd5 = BER_BVC("{BSDMD5}"); 46 1.2 christos static const struct berval magic_bsdmd5 = BER_BVC("$1$"); 47 1.2 christos 48 1.2 christos static const unsigned char apr64[] = 49 1.2 christos "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 50 1.2 christos 51 1.2 christos #define APR_SALT_SIZE 8 52 1.2 christos 53 1.2 christos /* The algorithm implemented in this function was created by Poul-Henning 54 1.2 christos * Kamp and released under the following license: 55 1.2 christos * ---------------------------------------------------------------------------- 56 1.2 christos * "THE BEER-WARE LICENSE" (Revision 42): 57 1.2 christos * <phk (at) FreeBSD.ORG> wrote this file. As long as you retain this notice you 58 1.2 christos * can do whatever you want with this stuff. If we meet some day, and you think 59 1.2 christos * this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp 60 1.2 christos * ---------------------------------------------------------------------------- 61 1.2 christos */ 62 1.2 christos static void do_phk_hash( 63 1.2 christos const struct berval *passwd, 64 1.2 christos const struct berval *salt, 65 1.2 christos const struct berval *magic, 66 1.2 christos unsigned char *digest) 67 1.2 christos { 68 1.2 christos lutil_MD5_CTX ctx, ctx1; 69 1.2 christos int n; 70 1.2 christos 71 1.2 christos /* Start hashing */ 72 1.2 christos lutil_MD5Init(&ctx); 73 1.2 christos lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, passwd->bv_len); 74 1.2 christos lutil_MD5Update(&ctx, (const unsigned char *) magic->bv_val, magic->bv_len); 75 1.2 christos lutil_MD5Update(&ctx, (const unsigned char *) salt->bv_val, salt->bv_len); 76 1.2 christos /* Inner hash */ 77 1.2 christos lutil_MD5Init(&ctx1); 78 1.2 christos lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); 79 1.2 christos lutil_MD5Update(&ctx1, (const unsigned char *) salt->bv_val, salt->bv_len); 80 1.2 christos lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); 81 1.2 christos lutil_MD5Final(digest, &ctx1); 82 1.2 christos /* Nom start mixing things up */ 83 1.2 christos for (n = passwd->bv_len; n > 0; n -= LUTIL_MD5_BYTES) 84 1.2 christos lutil_MD5Update(&ctx, digest, 85 1.2 christos (n > LUTIL_MD5_BYTES ? LUTIL_MD5_BYTES : n)); 86 1.2 christos memset(digest, 0, LUTIL_MD5_BYTES); 87 1.2 christos /* Curiouser and curiouser... */ 88 1.2 christos for (n = passwd->bv_len; n; n >>= 1) 89 1.2 christos if (n & 1) 90 1.2 christos lutil_MD5Update(&ctx, digest, 1); 91 1.2 christos else 92 1.2 christos lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, 1); 93 1.2 christos lutil_MD5Final(digest, &ctx); 94 1.2 christos /* 95 1.2 christos * Repeatedly hash things into the final value. This was originally 96 1.2 christos * intended to slow the algorithm down. 97 1.2 christos */ 98 1.2 christos for (n = 0; n < 1000; n++) { 99 1.2 christos lutil_MD5Init(&ctx1); 100 1.2 christos if (n & 1) 101 1.2 christos lutil_MD5Update(&ctx1, 102 1.2 christos (const unsigned char *) passwd->bv_val, passwd->bv_len); 103 1.2 christos else 104 1.2 christos lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); 105 1.2 christos 106 1.2 christos if (n % 3) 107 1.2 christos lutil_MD5Update(&ctx1, 108 1.2 christos (const unsigned char *) salt->bv_val, salt->bv_len); 109 1.2 christos if (n % 7) 110 1.2 christos lutil_MD5Update(&ctx1, 111 1.2 christos (const unsigned char *) passwd->bv_val, passwd->bv_len); 112 1.2 christos 113 1.2 christos if (n & 1) 114 1.2 christos lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); 115 1.2 christos else 116 1.2 christos lutil_MD5Update(&ctx1, 117 1.2 christos (const unsigned char *) passwd->bv_val, passwd->bv_len); 118 1.2 christos lutil_MD5Final(digest, &ctx1); 119 1.2 christos } 120 1.2 christos } 121 1.2 christos 122 1.2 christos static int chk_phk( 123 1.2 christos const struct berval *magic, 124 1.2 christos const struct berval *passwd, 125 1.2 christos const struct berval *cred, 126 1.2 christos const char **text) 127 1.2 christos { 128 1.2 christos unsigned char digest[LUTIL_MD5_BYTES]; 129 1.2 christos unsigned char *orig_pass; 130 1.2 christos int rc; 131 1.2 christos struct berval salt; 132 1.2 christos size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); 133 1.2 christos 134 1.2 christos /* safety check */ 135 1.2 christos if (decode_len <= sizeof(digest)) 136 1.2 christos return LUTIL_PASSWD_ERR; 137 1.2 christos 138 1.2 christos /* base64 un-encode password hash */ 139 1.2 christos orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); 140 1.2 christos 141 1.2 christos if (orig_pass == NULL) 142 1.2 christos return LUTIL_PASSWD_ERR; 143 1.2 christos 144 1.2 christos rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); 145 1.2 christos 146 1.2 christos if (rc <= (int) sizeof(digest)) { 147 1.2 christos ber_memfree(orig_pass); 148 1.2 christos return LUTIL_PASSWD_ERR; 149 1.2 christos } 150 1.2 christos 151 1.2 christos salt.bv_val = (char *) &orig_pass[sizeof(digest)]; 152 1.2 christos salt.bv_len = rc - sizeof(digest); 153 1.2 christos 154 1.2 christos do_phk_hash(cred, &salt, magic, digest); 155 1.2 christos 156 1.2 christos if (text) 157 1.2 christos *text = NULL; 158 1.2 christos 159 1.2 christos /* compare */ 160 1.2 christos rc = memcmp((char *) orig_pass, (char *) digest, sizeof(digest)); 161 1.2 christos ber_memfree(orig_pass); 162 1.2 christos return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; 163 1.2 christos } 164 1.2 christos 165 1.2 christos static int chk_apr1( 166 1.2 christos const struct berval *scheme, 167 1.2 christos const struct berval *passwd, 168 1.2 christos const struct berval *cred, 169 1.2 christos const char **text) 170 1.2 christos { 171 1.2 christos return chk_phk(&magic_apr1, passwd, cred, text); 172 1.2 christos } 173 1.2 christos 174 1.2 christos static int chk_bsdmd5( 175 1.2 christos const struct berval *scheme, 176 1.2 christos const struct berval *passwd, 177 1.2 christos const struct berval *cred, 178 1.2 christos const char **text) 179 1.2 christos { 180 1.2 christos return chk_phk(&magic_bsdmd5, passwd, cred, text); 181 1.2 christos } 182 1.2 christos 183 1.2 christos static int hash_phk( 184 1.2 christos const struct berval *scheme, 185 1.2 christos const struct berval *magic, 186 1.2 christos const struct berval *passwd, 187 1.2 christos struct berval *hash, 188 1.2 christos const char **text) 189 1.2 christos { 190 1.2 christos unsigned char digest_buf[LUTIL_MD5_BYTES]; 191 1.2 christos char salt_buf[APR_SALT_SIZE]; 192 1.2 christos struct berval digest; 193 1.2 christos struct berval salt; 194 1.2 christos int n; 195 1.2 christos 196 1.2 christos digest.bv_val = (char *) digest_buf; 197 1.2 christos digest.bv_len = sizeof(digest_buf); 198 1.2 christos salt.bv_val = salt_buf; 199 1.2 christos salt.bv_len = APR_SALT_SIZE; 200 1.2 christos 201 1.2 christos /* generate random salt */ 202 1.2 christos if (lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0) 203 1.2 christos return LUTIL_PASSWD_ERR; 204 1.2 christos /* limit it to characters in the 64-char set */ 205 1.2 christos for (n = 0; n < salt.bv_len; n++) 206 1.2 christos salt.bv_val[n] = apr64[salt.bv_val[n] % (sizeof(apr64) - 1)]; 207 1.2 christos 208 1.2 christos do_phk_hash(passwd, &salt, magic, digest_buf); 209 1.2 christos 210 1.2 christos if (text) 211 1.2 christos *text = NULL; 212 1.2 christos 213 1.2 christos return lutil_passwd_string64(scheme, &digest, hash, &salt); 214 1.2 christos } 215 1.2 christos 216 1.2 christos static int hash_apr1( 217 1.2 christos const struct berval *scheme, 218 1.2 christos const struct berval *passwd, 219 1.2 christos struct berval *hash, 220 1.2 christos const char **text) 221 1.2 christos { 222 1.2 christos return hash_phk(scheme, &magic_apr1, passwd, hash, text); 223 1.2 christos } 224 1.2 christos 225 1.2 christos static int hash_bsdmd5( 226 1.2 christos const struct berval *scheme, 227 1.2 christos const struct berval *passwd, 228 1.2 christos struct berval *hash, 229 1.2 christos const char **text) 230 1.2 christos { 231 1.2 christos return hash_phk(scheme, &magic_bsdmd5, passwd, hash, text); 232 1.2 christos } 233 1.2 christos 234 1.2 christos int init_module(int argc, char *argv[]) { 235 1.2 christos int rc; 236 1.2 christos rc = lutil_passwd_add((struct berval *) &scheme_apr1, chk_apr1, hash_apr1); 237 1.2 christos if ( !rc ) 238 1.2 christos rc = lutil_passwd_add((struct berval *) &scheme_bsdmd5, 239 1.2 christos chk_bsdmd5, hash_bsdmd5); 240 1.2 christos return rc; 241 1.2 christos } 242