Annotation of embedaddon/libpdel/ppp/ppp_msoft.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (c) 2001-2002 Packet Design, LLC.
! 4: * All rights reserved.
! 5: *
! 6: * Subject to the following obligations and disclaimer of warranty,
! 7: * use and redistribution of this software, in source or object code
! 8: * forms, with or without modifications are expressly permitted by
! 9: * Packet Design; provided, however, that:
! 10: *
! 11: * (i) Any and all reproductions of the source or object code
! 12: * must include the copyright notice above and the following
! 13: * disclaimer of warranties; and
! 14: * (ii) No rights are granted, in any manner or form, to use
! 15: * Packet Design trademarks, including the mark "PACKET DESIGN"
! 16: * on advertising, endorsements, or otherwise except as such
! 17: * appears in the above copyright notice or in the software.
! 18: *
! 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
! 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
! 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
! 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
! 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
! 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
! 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
! 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
! 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
! 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
! 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
! 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
! 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
! 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
! 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
! 36: * THE POSSIBILITY OF SUCH DAMAGE.
! 37: *
! 38: * Author: Archie Cobbs <archie@freebsd.org>
! 39: */
! 40:
! 41: #include "ppp/ppp_defs.h"
! 42: #include "ppp/ppp_msoft.h"
! 43:
! 44: #include <openssl/md4.h>
! 45: #include <openssl/des.h>
! 46: #include <openssl/sha.h>
! 47:
! 48: /* Magic constants */
! 49: #define MS_MAGIC_1 "This is the MPPE Master Key"
! 50: #define MS_MAGIC_2 "On the client side, this is the send key;" \
! 51: " on the server side, it is the receive key."
! 52: #define MS_MAGIC_3 "On the client side, this is the receive key;" \
! 53: " on the server side, it is the send key."
! 54: #define MS_AR_MAGIC_1 "Magic server to client signing constant"
! 55: #define MS_AR_MAGIC_2 "Pad to make it do more than one iteration"
! 56:
! 57: /* Internal functions */
! 58: static void ppp_msoft_challenge_response(const u_char *chal,
! 59: const char *pwHash, u_char *hash);
! 60: static void ppp_msoft_des_encrypt(const u_char *clear,
! 61: u_char *key0, u_char *cypher);
! 62: static void ppp_msoft_challenge_hash(const u_char *peerchal,
! 63: const u_char *authchal, const char *username,
! 64: u_char *hash);
! 65:
! 66: /*
! 67: * ppp_msoft_lm_password_hash()
! 68: *
! 69: * password ASCII password
! 70: * hash 16 byte output LanManager hash
! 71: */
! 72: void
! 73: ppp_msoft_lm_password_hash(const char *password, u_char *hash)
! 74: {
! 75: const char *const clear = "KGS!@#$%%";
! 76: u_char up[14];
! 77: int k;
! 78:
! 79: memset(&up, 0, sizeof(up));
! 80: for (k = 0; k < sizeof(up) && password[k]; k++)
! 81: up[k] = toupper(password[k]);
! 82:
! 83: ppp_msoft_des_encrypt(clear, &up[0], &hash[0]);
! 84: ppp_msoft_des_encrypt(clear, &up[7], &hash[8]);
! 85: }
! 86:
! 87: /*
! 88: * ppp_msoft_nt_password_hash()
! 89: *
! 90: * password ASCII (NOT Unicode) password
! 91: * hash 16 byte output NT hash
! 92: */
! 93: void
! 94: ppp_msoft_nt_password_hash(const char *password, u_char *hash)
! 95: {
! 96: u_int16_t unipw[128];
! 97: const char *s;
! 98: int unipwLen;
! 99: MD4_CTX ctx;
! 100:
! 101: /* Convert password to Unicode */
! 102: for (unipwLen = 0, s = password;
! 103: unipwLen < sizeof(unipw) / 2 && *s; s++)
! 104: unipw[unipwLen++] = htons(*s << 8);
! 105:
! 106: /* Compute MD4 of Unicode password */
! 107: MD4_Init(&ctx);
! 108: MD4_Update(&ctx, (u_char *)unipw, unipwLen * sizeof(*unipw));
! 109: MD4_Final(hash, &ctx);
! 110: }
! 111:
! 112: /*
! 113: * ppp_msoft_nt_challenge_response()
! 114: *
! 115: * chal 8 byte challenge
! 116: * password ASCII (NOT Unicode) password
! 117: * hash 24 byte response
! 118: */
! 119: void
! 120: ppp_msoft_nt_challenge_response(const u_char *chal,
! 121: const char *password, u_char *hash)
! 122: {
! 123: u_char pwHash[16];
! 124:
! 125: ppp_msoft_nt_password_hash(password, pwHash);
! 126: ppp_msoft_challenge_response(chal, pwHash, hash);
! 127: }
! 128:
! 129: /*
! 130: * ppp_msoft_challenge_response()
! 131: *
! 132: * chal 8 byte challenge
! 133: * pwHash 16 byte password hash
! 134: * hash 24 byte response
! 135: */
! 136: static void
! 137: ppp_msoft_challenge_response(const u_char *chal,
! 138: const char *pwHash, u_char *hash)
! 139: {
! 140: u_char buf[21];
! 141: int i;
! 142:
! 143: /* Initialize buffer */
! 144: memset(&buf, 0, sizeof(buf));
! 145: memcpy(buf, pwHash, 16);
! 146:
! 147: /* Use DES to hash the hash */
! 148: for (i = 0; i < 3; i++) {
! 149: u_char *const key = &buf[i * 7];
! 150: u_char *const output = &hash[i * 8];
! 151:
! 152: ppp_msoft_des_encrypt(chal, key, output);
! 153: }
! 154: }
! 155:
! 156: /*
! 157: * ppp_msoft_des_encrypt()
! 158: *
! 159: * clear 8 byte cleartext
! 160: * key 7 byte key
! 161: * cypher 8 byte cyphertext
! 162: */
! 163: static void
! 164: ppp_msoft_des_encrypt(const u_char *clear, u_char *key0, u_char *cypher)
! 165: {
! 166: des_key_schedule ks;
! 167: u_char key[8];
! 168:
! 169: /*
! 170: * Create DES key
! 171: *
! 172: * Note: we don't bother setting the parity bit because
! 173: * the des_set_key() algorithm does that for us. A different
! 174: * algorithm may care though.
! 175: */
! 176: key[0] = key0[0] & 0xfe;
! 177: key[1] = (key0[0] << 7) | (key0[1] >> 1);
! 178: key[2] = (key0[1] << 6) | (key0[2] >> 2);
! 179: key[3] = (key0[2] << 5) | (key0[3] >> 3);
! 180: key[4] = (key0[3] << 4) | (key0[4] >> 4);
! 181: key[5] = (key0[4] << 3) | (key0[5] >> 5);
! 182: key[6] = (key0[5] << 2) | (key0[6] >> 6);
! 183: key[7] = key0[6] << 1;
! 184: des_set_key((des_cblock *)key, ks);
! 185:
! 186: /* Encrypt using key */
! 187: des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cypher, ks, 1);
! 188: }
! 189:
! 190: /*
! 191: * ppp_msoft_get_start_key()
! 192: */
! 193: void
! 194: ppp_msoft_get_start_key(const u_char *chal, u_char *hash)
! 195: {
! 196: u_char sha1[SHA_DIGEST_LENGTH];
! 197: SHA_CTX ctx;
! 198:
! 199: SHA1_Init(&ctx);
! 200: SHA1_Update(&ctx, hash, 16);
! 201: SHA1_Update(&ctx, hash, 16);
! 202: SHA1_Update(&ctx, chal, 8);
! 203: SHA1_Final(sha1, &ctx);
! 204: memcpy(hash, sha1, 16);
! 205: }
! 206:
! 207: /*
! 208: * ppp_msoft_generate_nt_response()
! 209: *
! 210: * authchal 16 byte authenticator challenge
! 211: * peerchal 16 byte peer challenge
! 212: * username ASCII username
! 213: * password ASCII (NOT Unicode) password
! 214: * hash 24 byte response
! 215: */
! 216: void
! 217: ppp_msoft_generate_nt_response(const u_char *authchal, const u_char *peerchal,
! 218: const char *username, const char *password, u_char *hash)
! 219: {
! 220: u_char chal[8];
! 221: u_char pwHash[16];
! 222:
! 223: ppp_msoft_challenge_hash(peerchal, authchal, username, chal);
! 224: ppp_msoft_nt_password_hash(password, pwHash);
! 225: ppp_msoft_challenge_response(chal, pwHash, hash);
! 226: }
! 227:
! 228: /*
! 229: * ppp_msoft_challenge_hash()
! 230: *
! 231: * peerchal 16 byte peer challenge
! 232: * authchal 16 byte authenticator challenge
! 233: * username ASCII username
! 234: * hash 8 byte response
! 235: */
! 236: static void
! 237: ppp_msoft_challenge_hash(const u_char *peerchal, const u_char *authchal,
! 238: const char *username, u_char *hash)
! 239: {
! 240: u_char sha1[SHA_DIGEST_LENGTH];
! 241: SHA_CTX ctx;
! 242: const char *slash;
! 243:
! 244: /* Strip off NT domain (if any) */
! 245: if ((slash = strrchr(username, '\\')) != NULL)
! 246: username = slash + 1;
! 247: SHA1_Init(&ctx);
! 248: SHA1_Update(&ctx, peerchal, 16);
! 249: SHA1_Update(&ctx, authchal, 16);
! 250: SHA1_Update(&ctx, username, strlen(username));
! 251: SHA1_Final(sha1, &ctx);
! 252: memcpy(hash, sha1, 8);
! 253: }
! 254:
! 255: /*
! 256: * Compute master key for MPPE
! 257: */
! 258: void
! 259: ppp_msoft_get_master_key(const u_char *resp, u_char *hash)
! 260: {
! 261: u_char sha1[SHA_DIGEST_LENGTH];
! 262: SHA_CTX ctx;
! 263:
! 264: SHA1_Init(&ctx);
! 265: SHA1_Update(&ctx, hash, 16);
! 266: SHA1_Update(&ctx, resp, 24);
! 267: SHA1_Update(&ctx, MS_MAGIC_1, 27);
! 268: SHA1_Final(sha1, &ctx);
! 269: memcpy(hash, sha1, 16);
! 270: }
! 271:
! 272: /*
! 273: * Compute asymmetric start key for MPPE (MS-CHAPv2 authentication)
! 274: *
! 275: * which Zero for server xmit/client recv, 1 for server recv/client xmit
! 276: */
! 277: void
! 278: ppp_msoft_get_asymetric_start_key(int which, const u_char *master, u_char *key)
! 279: {
! 280: u_char sha1[SHA_DIGEST_LENGTH];
! 281: u_char sha_pad[2][40];
! 282: SHA_CTX ctx;
! 283:
! 284: /* Generate start key */
! 285: memset(&sha_pad[0], 0x00, sizeof(sha_pad[0]));
! 286: memset(&sha_pad[1], 0xf2, sizeof(sha_pad[1]));
! 287: SHA1_Init(&ctx);
! 288: SHA1_Update(&ctx, master, 16);
! 289: SHA1_Update(&ctx, sha_pad[0], 40);
! 290: SHA1_Update(&ctx, which ? MS_MAGIC_2 : MS_MAGIC_3, 84);
! 291: SHA1_Update(&ctx, sha_pad[1], 40);
! 292: SHA1_Final(sha1, &ctx);
! 293: memcpy(key, sha1, 16);
! 294: }
! 295:
! 296: /*
! 297: * Initialize MPPE key based on MS-CHAPv1 credentials.
! 298: *
! 299: * e128 Non-zero for 128 bit key, zero for 64 bit key.
! 300: * pass Originating side's password
! 301: * chal Answering side's challenge
! 302: * key 16 byte output buffer
! 303: */
! 304: void
! 305: ppp_msoft_init_key_v1(int e128,
! 306: const char *pass, const u_char *chal, u_char *key)
! 307: {
! 308: if (e128) { /* 128 bit key */
! 309: u_char hash[16];
! 310: MD4_CTX ctx;
! 311:
! 312: ppp_msoft_nt_password_hash(pass, hash);
! 313: MD4_Init(&ctx);
! 314: MD4_Update(&ctx, hash, 16);
! 315: MD4_Final(hash, &ctx);
! 316: ppp_msoft_get_start_key(chal, hash);
! 317: memcpy(key, hash, 16);
! 318: } else /* 40 or 56 bit key */
! 319: ppp_msoft_lm_password_hash(pass, key);
! 320: }
! 321:
! 322: /*
! 323: * Initialize MPPE key based on MS-CHAPv2 credentials.
! 324: *
! 325: * which Zero for server xmit/client recv, 1 for server recv/client xmit
! 326: * pass Originating side's password
! 327: * resp Answering side's challenge response hash
! 328: * key 16 byte output buffer
! 329: */
! 330: void
! 331: ppp_msoft_init_key_v2(int which,
! 332: const char *pass, const u_char *resp, u_char *key)
! 333: {
! 334: u_char hash[16];
! 335: MD4_CTX ctx;
! 336:
! 337: ppp_msoft_nt_password_hash(pass, hash);
! 338: MD4_Init(&ctx);
! 339: MD4_Update(&ctx, hash, 16);
! 340: MD4_Final(hash, &ctx);
! 341: ppp_msoft_get_master_key(resp, hash);
! 342: ppp_msoft_get_asymetric_start_key(which, hash, key);
! 343: }
! 344:
! 345: /*
! 346: * Generate response to MS-CHAPv2 piggy-backed challenge.
! 347: *
! 348: * "authresp" must point to a 20 byte buffer.
! 349: */
! 350: void
! 351: ppp_msoft_generate_authenticator_response(const char *password,
! 352: const u_char *ntresp, const u_char *peerchal,
! 353: const u_char *authchal, const char *username, u_char *authresp)
! 354: {
! 355: u_char hash[16];
! 356: u_char digest[SHA_DIGEST_LENGTH];
! 357: u_char chal[8];
! 358: MD4_CTX md4ctx;
! 359: SHA_CTX shactx;
! 360:
! 361: ppp_msoft_nt_password_hash(password, hash);
! 362:
! 363: MD4_Init(&md4ctx);
! 364: MD4_Update(&md4ctx, hash, 16);
! 365: MD4_Final(hash, &md4ctx);
! 366:
! 367: SHA1_Init(&shactx);
! 368: SHA1_Update(&shactx, hash, 16);
! 369: SHA1_Update(&shactx, ntresp, 24);
! 370: SHA1_Update(&shactx, MS_AR_MAGIC_1, 39);
! 371: SHA1_Final(digest, &shactx);
! 372:
! 373: ppp_msoft_challenge_hash(peerchal, authchal, username, chal);
! 374:
! 375: SHA1_Init(&shactx);
! 376: SHA1_Update(&shactx, digest, sizeof(digest));
! 377: SHA1_Update(&shactx, chal, 8);
! 378: SHA1_Update(&shactx, MS_AR_MAGIC_2, 41);
! 379: SHA1_Final(authresp, &shactx);
! 380: }
! 381:
! 382: /*
! 383: * Verify server's piggy-backed response.
! 384: *
! 385: * Returns 1 if OK, otherwise zero.
! 386: */
! 387: int
! 388: ppp_msoft_check_authenticator_response(const char *password,
! 389: const u_char *ntresp, const u_char *peerchal, const u_char *authchal,
! 390: const char *username, const char *rechash)
! 391: {
! 392: char authresp[43];
! 393:
! 394: ppp_msoft_generate_authenticator_response(password, ntresp,
! 395: peerchal, authchal, username, authresp);
! 396: return (strcmp(rechash, authresp) == 0);
! 397: }
! 398:
! 399:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>