Annotation of parser3/src/lib/md5/pa_md5c.c, revision 1.23

1.4       paf         1: /** @file
1.23    ! moko        2:        taken from libmd, added pa_ prefixes, Parser 3 includes,
1.22      moko        3:        Copyright (c) 2001-2024 Art. Lebedev Studio (http://www.artlebedev.com)
1.4       paf         4: */
                      5: 
1.23    ! moko        6: /*     $OpenBSD: md5.c,v 1.7 2004/05/28 15:10:27 millert Exp $ */
        !             7: 
1.1       paf         8: /*
1.23    ! moko        9:  * This code implements the MD5 message-digest algorithm.
        !            10:  * The algorithm is due to Ron Rivest. This code was
        !            11:  * written by Colin Plumb in 1993, no copyright is claimed.
        !            12:  * This code is in the public domain; do with it what you wish.
        !            13:  *
        !            14:  * Equivalent code is available from RSA Data Security, Inc.
        !            15:  * This code has been tested against that, and is equivalent,
        !            16:  * except that you don't need to include two pages of legalese
        !            17:  * with every copy.
        !            18:  *
        !            19:  * To compute the message digest of a chunk of bytes, declare an
        !            20:  * MD5Context structure, pass it to MD5Init, call MD5Update as
        !            21:  * needed on buffers full of bytes, and then call MD5Final, which
        !            22:  * will fill a supplied 16-byte array with the digest.
1.1       paf        23:  */
                     24: 
                     25: /*
1.10      paf        26:  * The pa_MD5Encode() routine uses much code obtained from the FreeBSD 3.0
1.1       paf        27:  * MD5 crypt() function, which is licenced as follows:
                     28:  * ----------------------------------------------------------------------------
                     29:  * "THE BEER-WARE LICENSE" (Revision 42):
                     30:  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
                     31:  * can do whatever you want with this stuff. If we meet some day, and you think
                     32:  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
                     33:  * ----------------------------------------------------------------------------
                     34:  */
1.4       paf        35: 
1.9       paf        36: #include "pa_md5.h"
1.1       paf        37: 
1.23    ! moko       38: volatile const char * IDENT_PA_MD5_C="$Id: pa_md5c.c,v 1.22 2024/11/04 03:53:25 moko Exp $" IDENT_PA_MD5_H;
1.1       paf        39: 
1.23    ! moko       40: #define PUT_64BIT_LE(cp, value) do {                                   \
        !            41:        (cp)[7] = (value) >> 56;                                        \
        !            42:        (cp)[6] = (value) >> 48;                                        \
        !            43:        (cp)[5] = (value) >> 40;                                        \
        !            44:        (cp)[4] = (value) >> 32;                                        \
        !            45:        (cp)[3] = (value) >> 24;                                        \
        !            46:        (cp)[2] = (value) >> 16;                                        \
        !            47:        (cp)[1] = (value) >> 8;                                         \
        !            48:        (cp)[0] = (value); } while (0)
        !            49: 
        !            50: #define PUT_32BIT_LE(cp, value) do {                                   \
        !            51:        (cp)[3] = (value) >> 24;                                        \
        !            52:        (cp)[2] = (value) >> 16;                                        \
        !            53:        (cp)[1] = (value) >> 8;                                         \
        !            54:        (cp)[0] = (value); } while (0)
        !            55: 
        !            56: static uint8_t PADDING[MD5_BLOCK_LENGTH] = {
        !            57:        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !            58:        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        !            59:        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1.1       paf        60: };
                     61: 
1.23    ! moko       62: /*
        !            63:  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
        !            64:  * initialization constants.
1.1       paf        65:  */
1.23    ! moko       66: void pa_MD5Init(PA_MD5_CTX *ctx)
1.1       paf        67: {
1.23    ! moko       68:        ctx->count = 0;
        !            69:        ctx->state[0] = 0x67452301;
        !            70:        ctx->state[1] = 0xefcdab89;
        !            71:        ctx->state[2] = 0x98badcfe;
        !            72:        ctx->state[3] = 0x10325476;
1.1       paf        73: }
                     74: 
1.23    ! moko       75: /*
        !            76:  * Update context to reflect the concatenation of another buffer full
        !            77:  * of bytes.
1.1       paf        78:  */
1.23    ! moko       79: void pa_MD5Update(PA_MD5_CTX *ctx, const unsigned char *input, size_t len)
1.1       paf        80: {
1.23    ! moko       81:        size_t have, need;
1.1       paf        82: 
1.23    ! moko       83:        /* Check how many bytes we already have and how many more we need. */
        !            84:        have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
        !            85:        need = MD5_BLOCK_LENGTH - have;
        !            86: 
        !            87:        /* Update bitcount */
        !            88:        ctx->count += (uint64_t)len << 3;
        !            89: 
        !            90:        if (len >= need) {
        !            91:                if (have != 0) {
        !            92:                        memcpy(ctx->buffer + have, input, need);
        !            93:                        pa_MD5Transform(ctx->state, ctx->buffer);
        !            94:                        input += need;
        !            95:                        len -= need;
        !            96:                        have = 0;
        !            97:                }
        !            98: 
        !            99:                /* Process data in MD5_BLOCK_LENGTH-byte chunks. */
        !           100:                while (len >= MD5_BLOCK_LENGTH) {
        !           101:                        pa_MD5Transform(ctx->state, input);
        !           102:                        input += MD5_BLOCK_LENGTH;
        !           103:                        len -= MD5_BLOCK_LENGTH;
        !           104:                }
1.1       paf       105:        }
                    106: 
1.23    ! moko      107:        /* Handle any remaining bytes of data. */
        !           108:        if (len != 0)
        !           109:                memcpy(ctx->buffer + have, input, len);
        !           110: }
1.1       paf       111: 
1.23    ! moko      112: /*
        !           113:  * Pad pad to 64-byte boundary with the bit pattern
        !           114:  * 1 0* (64-bit count of bits processed, MSB-first)
        !           115:  */
        !           116: void pa_MD5Pad(PA_MD5_CTX *ctx)
        !           117: {
        !           118:        uint8_t count[8];
        !           119:        size_t padlen;
1.1       paf       120: 
1.23    ! moko      121:        /* Convert count to 8 bytes in little endian order. */
        !           122:        PUT_64BIT_LE(count, ctx->count);
1.1       paf       123: 
1.23    ! moko      124:        /* Pad out to 56 mod 64. */
        !           125:        padlen = MD5_BLOCK_LENGTH -
        !           126:            ((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
        !           127:        if (padlen < 1 + 8)
        !           128:                padlen += MD5_BLOCK_LENGTH;
        !           129:        pa_MD5Update(ctx, PADDING, padlen - 8);         /* padlen - 8 <= 64 */
        !           130:        pa_MD5Update(ctx, count, 8);
1.1       paf       131: }
                    132: 
1.23    ! moko      133: /*
        !           134:  * Final wrapup--call MD5Pad, fill in digest and zero out ctx.
1.1       paf       135:  */
1.23    ! moko      136: void pa_MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], PA_MD5_CTX *ctx)
1.1       paf       137: {
1.23    ! moko      138:        int i;
1.1       paf       139: 
1.23    ! moko      140:        pa_MD5Pad(ctx);
        !           141:        if (digest != NULL) {
        !           142:                for (i = 0; i < 4; i++)
        !           143:                        PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
        !           144:                memset(ctx, 0, sizeof(*ctx));
        !           145:        }
1.1       paf       146: }
                    147: 
                    148: 
1.23    ! moko      149: /* The four core functions - F1 is optimized somewhat */
1.1       paf       150: 
1.23    ! moko      151: /* #define F1(x, y, z) (x & y | ~x & z) */
        !           152: #define F1(x, y, z) (z ^ (x & (y ^ z)))
        !           153: #define F2(x, y, z) F1(z, x, y)
        !           154: #define F3(x, y, z) (x ^ y ^ z)
        !           155: #define F4(x, y, z) (y ^ (x | ~z))
        !           156: 
        !           157: /* This is the central step in the MD5 algorithm. */
        !           158: #define MD5STEP(f, w, x, y, z, data, s) \
        !           159:        ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
1.1       paf       160: 
1.23    ! moko      161: /*
        !           162:  * The core of the MD5 algorithm, this alters an existing MD5 hash to
        !           163:  * reflect the addition of 16 longwords of new data.  MD5Update blocks
        !           164:  * the data and converts bytes into longwords for this routine.
1.1       paf       165:  */
1.23    ! moko      166: void pa_MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH])
1.1       paf       167: {
1.23    ! moko      168:        uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
1.1       paf       169: 
1.23    ! moko      170: #ifndef WORDS_BIGENDIAN
        !           171:        memcpy(in, block, sizeof(in));
        !           172: #else
        !           173:        for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
        !           174:                in[a] = (uint32_t)(
        !           175:                    (uint32_t)(block[a * 4 + 0]) |
        !           176:                    (uint32_t)(block[a * 4 + 1]) <<  8 |
        !           177:                    (uint32_t)(block[a * 4 + 2]) << 16 |
        !           178:                    (uint32_t)(block[a * 4 + 3]) << 24);
        !           179:        }
        !           180: #endif
1.1       paf       181: 
1.23    ! moko      182:        a = state[0];
        !           183:        b = state[1];
        !           184:        c = state[2];
        !           185:        d = state[3];
        !           186: 
        !           187:        MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478,  7);
        !           188:        MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
        !           189:        MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
        !           190:        MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
        !           191:        MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf,  7);
        !           192:        MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
        !           193:        MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
        !           194:        MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
        !           195:        MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8,  7);
        !           196:        MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
        !           197:        MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
        !           198:        MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
        !           199:        MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122,  7);
        !           200:        MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
        !           201:        MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
        !           202:        MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
        !           203: 
        !           204:        MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562,  5);
        !           205:        MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340,  9);
        !           206:        MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
        !           207:        MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
        !           208:        MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d,  5);
        !           209:        MD5STEP(F2, d, a, b, c, in[10] + 0x02441453,  9);
        !           210:        MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
        !           211:        MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
        !           212:        MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6,  5);
        !           213:        MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6,  9);
        !           214:        MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
        !           215:        MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
        !           216:        MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905,  5);
        !           217:        MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8,  9);
        !           218:        MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
        !           219:        MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
        !           220: 
        !           221:        MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942,  4);
        !           222:        MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
        !           223:        MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
        !           224:        MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
        !           225:        MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44,  4);
        !           226:        MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
        !           227:        MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
        !           228:        MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
        !           229:        MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6,  4);
        !           230:        MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
        !           231:        MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
        !           232:        MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
        !           233:        MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039,  4);
        !           234:        MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
        !           235:        MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
        !           236:        MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
        !           237: 
        !           238:        MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244,  6);
        !           239:        MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
        !           240:        MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
        !           241:        MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
        !           242:        MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3,  6);
        !           243:        MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
        !           244:        MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
        !           245:        MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
        !           246:        MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f,  6);
        !           247:        MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
        !           248:        MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
        !           249:        MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
        !           250:        MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82,  6);
        !           251:        MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
        !           252:        MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
        !           253:        MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
        !           254: 
        !           255:        state[0] += a;
        !           256:        state[1] += b;
        !           257:        state[2] += c;
        !           258:        state[3] += d;
1.1       paf       259: }
                    260: 
                    261: /*
                    262:  * The following MD5 password encryption code was largely borrowed from
                    263:  * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
                    264:  * licenced as stated at the top of this file.
                    265:  */
1.23    ! moko      266: 
1.15      moko      267: void pa_to64(char *s, unsigned long v, int n)
1.1       paf       268: {
                    269:     static unsigned char itoa64[] =         /* 0 ... 63 => ASCII - 64 */
                    270:        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
                    271: 
                    272:     while (--n >= 0) {
                    273:        *s++ = itoa64[v&0x3f];
                    274:        v >>= 6;
                    275:     }
                    276: }
                    277: 
1.23    ! moko      278: void pa_MD5Encode(const unsigned char *pw, const unsigned char *salt, char *result, size_t nbytes)
1.1       paf       279: {
                    280:     /*
                    281:      * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
                    282:      * plus 4 for the '$' separators, plus the password hash itself.
                    283:      * Let's leave a goodly amount of leeway.
                    284:      */
                    285: 
                    286:     char passwd[120], *p;
                    287:     const unsigned char *sp, *ep;
                    288:     unsigned char final[16];
                    289:     int i;
                    290:     unsigned int sl;
                    291:     int pl;
                    292:     unsigned int pwlen;
                    293:     PA_MD5_CTX ctx, ctx1;
                    294:     unsigned long l;
                    295: 
                    296:     /* 
                    297:      * Refine the salt first.  It's possible we were given an already-hashed
                    298:      * string as the salt argument, so extract the actual salt value from it
                    299:      * if so.  Otherwise just use the string up to the first '$' as the salt.
                    300:      */
                    301:     sp = salt;
                    302: 
                    303:     /*
                    304:      * If it starts with the magic string, then skip that.
                    305:      */
                    306:     if (strncmp((char *)sp, PA_MD5PW_ID, PA_MD5PW_IDLEN) == 0) {
                    307:        sp += PA_MD5PW_IDLEN;
                    308:     }
                    309: 
                    310:     /*
                    311:      * It stops at the first '$' or 8 chars, whichever comes first
                    312:      */
                    313:     for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) {
                    314:        continue;
                    315:     }
                    316: 
                    317:     /*
                    318:      * Get the length of the true salt
                    319:      */
                    320:     sl = ep - sp;
                    321: 
                    322:     /*
                    323:      * 'Time to make the doughnuts..'
                    324:      */
1.10      paf       325:     pa_MD5Init(&ctx);
1.1       paf       326: 
                    327:     pwlen = strlen((char *)pw);
                    328:     /*
                    329:      * The password first, since that is what is most unknown
                    330:      */
1.10      paf       331:     pa_MD5Update(&ctx, pw, pwlen);
1.1       paf       332: 
1.10      paf       333:     /*
                    334:      * Then our magic string
                    335:      */
                    336:     pa_MD5Update(&ctx, (const unsigned char *) PA_MD5PW_ID, PA_MD5PW_IDLEN);
1.1       paf       337: 
                    338:     /*
                    339:      * Then the raw salt
                    340:      */
1.10      paf       341:     pa_MD5Update(&ctx, sp, sl);
1.1       paf       342: 
                    343:     /*
                    344:      * Then just as many characters of the MD5(pw, salt, pw)
                    345:      */
1.10      paf       346:     pa_MD5Init(&ctx1);
                    347:     pa_MD5Update(&ctx1, pw, pwlen);
                    348:     pa_MD5Update(&ctx1, sp, sl);
                    349:     pa_MD5Update(&ctx1, pw, pwlen);
                    350:     pa_MD5Final(final, &ctx1);
1.1       paf       351:     for(pl = pwlen; pl > 0; pl -= 16) {
1.10      paf       352:        pa_MD5Update(&ctx, final, (pl > 16) ? 16 : (unsigned int) pl);
1.1       paf       353:     }
                    354: 
                    355:     /*
                    356:      * Don't leave anything around in vm they could use.
                    357:      */
                    358:     memset(final, 0, sizeof(final));
                    359: 
                    360:     /*
                    361:      * Then something really weird...
                    362:      */
                    363:     for (i = pwlen; i != 0; i >>= 1) {
                    364:        if (i & 1) {
1.10      paf       365:            pa_MD5Update(&ctx, final, 1);
1.1       paf       366:        }
                    367:        else {
1.10      paf       368:            pa_MD5Update(&ctx, pw, 1);
1.1       paf       369:        }
                    370:     }
                    371: 
                    372:     /*
                    373:      * Now make the output string.  We know our limitations, so we
                    374:      * can use the string routines without bounds checking.
                    375:      */
1.17      moko      376:     strncpy(passwd, PA_MD5PW_ID, PA_MD5PW_IDLEN + 1);
                    377:     strncpy(passwd + PA_MD5PW_IDLEN, (char *)sp, sl + 1);
1.1       paf       378:     passwd[PA_MD5PW_IDLEN + sl]     = '$';
                    379:     passwd[PA_MD5PW_IDLEN + sl + 1] = '\0';
                    380: 
1.10      paf       381:     pa_MD5Final(final, &ctx);
1.1       paf       382: 
                    383:     /*
                    384:      * And now, just to make sure things don't run too fast..
                    385:      * On a 60 Mhz Pentium this takes 34 msec, so you would
                    386:      * need 30 seconds to build a 1000 entry dictionary...
                    387:      */
                    388:     for (i = 0; i < 1000; i++) {
1.10      paf       389:        pa_MD5Init(&ctx1);
1.1       paf       390:        if (i & 1) {
1.10      paf       391:            pa_MD5Update(&ctx1, pw, pwlen);
1.1       paf       392:        }
                    393:        else {
1.10      paf       394:            pa_MD5Update(&ctx1, final, 16);
1.1       paf       395:        }
                    396:        if (i % 3) {
1.10      paf       397:            pa_MD5Update(&ctx1, sp, sl);
1.1       paf       398:        }
                    399: 
                    400:        if (i % 7) {
1.10      paf       401:            pa_MD5Update(&ctx1, pw, pwlen);
1.1       paf       402:        }
                    403: 
                    404:        if (i & 1) {
1.10      paf       405:            pa_MD5Update(&ctx1, final, 16);
1.1       paf       406:        }
                    407:        else {
1.10      paf       408:            pa_MD5Update(&ctx1, pw, pwlen);
1.1       paf       409:        }
1.10      paf       410:        pa_MD5Final(final,&ctx1);
1.1       paf       411:     }
                    412: 
                    413:     p = passwd + strlen(passwd);
                    414: 
1.10      paf       415:     l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; pa_to64(p, l, 4); p += 4;
                    416:     l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; pa_to64(p, l, 4); p += 4;
                    417:     l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; pa_to64(p, l, 4); p += 4;
                    418:     l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; pa_to64(p, l, 4); p += 4;
                    419:     l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; pa_to64(p, l, 4); p += 4;
                    420:     l =                    final[11]                ; pa_to64(p, l, 2); p += 2;
1.1       paf       421:     *p = '\0';
                    422: 
                    423:     /*
                    424:      * Don't leave anything around in vm they could use.
                    425:      */
                    426:     memset(final, 0, sizeof(final));
1.8       paf       427: 
1.17      moko      428:     strncpy(result, passwd, nbytes - 1);
1.1       paf       429: }

E-mail: