"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.19/src/mx/cred-md5.c" (26 Apr 2020, 15264 Bytes) of package /linux/misc/s-nail-14.9.19.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cred-md5.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.18_vs_14.9.19.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Implementation of cred-md5.h.
    3  *
    4  * Copyright (c) 2014 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    5  * SPDX-License-Identifier: ISC
    6  *
    7  * Permission to use, copy, modify, and/or distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 /* MD5.c - header file for MD5C.C from RFC 1321 is */
   20 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
   21 rights reserved.
   22 
   23 License to copy and use this software is granted provided that it
   24 is identified as the "RSA Data Security, Inc. MD5 Message-Digest
   25 Algorithm" in all material mentioning or referencing this software
   26 or this function.
   27 
   28 License is also granted to make and use derivative works provided
   29 that such works are identified as "derived from the RSA Data
   30 Security, Inc. MD5 Message-Digest Algorithm" in all material
   31 mentioning or referencing the derived work.
   32 
   33 RSA Data Security, Inc. makes no representations concerning either
   34 the merchantability of this software or the suitability of this
   35 software for any particular purpose. It is provided "as is"
   36 without express or implied warranty of any kind.
   37 
   38 These notices must be retained in any copies of any part of this
   39 documentation and/or software.
   40  */
   41 #undef su_FILE
   42 #define su_FILE cred_md5
   43 #define mx_SOURCE
   44 #define mx_SOURCE_CRED_MD5
   45 
   46 #ifndef mx_HAVE_AMALGAMATION
   47 # include "mx/nail.h"
   48 #endif
   49 
   50 su_EMPTY_FILE()
   51 #ifdef mx_HAVE_MD5
   52 #include <su/cs.h>
   53 #include <su/mem.h>
   54 
   55 #include "mx/cred-md5.h"
   56 #include "su/code-in.h"
   57 
   58 #ifndef mx_XTLS_HAVE_MD5
   59 /* RFC 1321, MD5.C: */
   60 #define UINT4B_MAX  0xFFFFFFFFul
   61 
   62 /* Constants for MD5Transform routine.
   63  */
   64 #define S11 7
   65 #define S12 12
   66 #define S13 17
   67 #define S14 22
   68 #define S21 5
   69 #define S22 9
   70 #define S23 14
   71 #define S24 20
   72 #define S31 4
   73 #define S32 11
   74 #define S33 16
   75 #define S34 23
   76 #define S41 6
   77 #define S42 10
   78 #define S43 15
   79 #define S44 21
   80 
   81 static unsigned char PADDING[64] = {
   82   0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   83   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   84   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
   85 };
   86 
   87 /*
   88 #define F(x,y,z)    (((x) & (y))  |  ((~(x)) & (z)))
   89 #define G(x,y,z)    (((x) & (z))  |  ((y) & (~(z))))
   90 */
   91 
   92 /* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
   93  * simplified to the code below.  Wei attributes these optimizations
   94  * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel.
   95  */
   96 #define F(b,c,d)    ((((c) ^ (d)) & (b)) ^ (d))
   97 #define G(b,c,d)    ((((b) ^ (c)) & (d)) ^ (c))
   98 #define H(b,c,d)    ((b) ^ (c) ^ (d))
   99 #define I(b,c,d)    (((~(d) & UINT4B_MAX) | (b)) ^ (c))
  100 
  101 /* ROTATE_LEFT rotates x left n bits.
  102  */
  103 #define ROTATE_LEFT(x, n) ((((x) << (n)) & UINT4B_MAX) | ((x) >> (32 - (n))))
  104 
  105 /*
  106  * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
  107  * Rotation is separate from addition to prevent recomputation.
  108  */
  109 #define FF(a, b, c, d, x, s, ac) { \
  110     (a) = ((a) + F(b, c, d) + (x) + ((ac) & UINT4B_MAX)) & UINT4B_MAX; \
  111     (a) = ROTATE_LEFT((a), (s)); \
  112     (a) = ((a) + (b)) & UINT4B_MAX; \
  113 }
  114 
  115 #define GG(a, b, c, d, x, s, ac) { \
  116     (a) = ((a) + G(b, c, d) + (x) + ((ac) & UINT4B_MAX)) & UINT4B_MAX; \
  117     (a) = ROTATE_LEFT((a), (s)); \
  118     (a) = ((a) + (b)) & UINT4B_MAX; \
  119 }
  120 
  121 #define HH(a, b, c, d, x, s, ac) { \
  122     (a) = ((a) + H(b, c, d) + (x) + ((ac) & UINT4B_MAX)) & UINT4B_MAX; \
  123     (a) = ROTATE_LEFT((a), (s)); \
  124     (a) = ((a) + (b)) & UINT4B_MAX; \
  125 }
  126 
  127 #define II(a, b, c, d, x, s, ac) { \
  128     (a) = ((a) + I(b, c, d) + (x) + ((ac) & UINT4B_MAX)) & UINT4B_MAX; \
  129     (a) = ROTATE_LEFT((a), (s)); \
  130     (a) = ((a) + (b)) & UINT4B_MAX; \
  131 }
  132 
  133 static void Encode(unsigned char *outp, mx_md5_type *inp, unsigned int len);
  134 static void Decode(mx_md5_type *outp, unsigned char *inp, unsigned int len);
  135 static void MD5Transform(mx_md5_type state[], unsigned char block[]);
  136 
  137 /*
  138  * Encodes input (md5_type) into output (unsigned char). Assumes len is
  139  * a multiple of 4.
  140  */
  141 static void
  142 Encode(unsigned char *outp, mx_md5_type *inp, unsigned int len)
  143 {
  144     unsigned int i, j;
  145 
  146     for (i = 0, j = 0; j < len; i++, j += 4) {
  147         outp[j] = inp[i] & 0xff;
  148         outp[j+1] = (inp[i] >> 8) & 0xff;
  149         outp[j+2] = (inp[i] >> 16) & 0xff;
  150         outp[j+3] = (inp[i] >> 24) & 0xff;
  151     }
  152 }
  153 
  154 /*
  155  * Decodes input (unsigned char) into output (md5_type). Assumes len is
  156  * a multiple of 4.
  157  */
  158 static void
  159 Decode(mx_md5_type *outp, unsigned char *inp, unsigned int len)
  160 {
  161     unsigned int    i, j;
  162 
  163     for (i = 0, j = 0; j < len; i++, j += 4)
  164         outp[i] = ((mx_md5_type)inp[j] |
  165             (mx_md5_type)inp[j+1] << 8 |
  166             (mx_md5_type)inp[j+2] << 16 |
  167             (mx_md5_type)inp[j+3] << 24) & UINT4B_MAX;
  168 }
  169 
  170 /* MD5 basic transformation. Transforms state based on block. */
  171 static void
  172 MD5Transform(mx_md5_type state[4], unsigned char block[64])
  173 {
  174     mx_md5_type a = state[0], b = state[1], c = state[2], d = state[3],
  175         x[16];
  176 
  177     Decode(x, block, 64);
  178 
  179     /* Round 1 */
  180     FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
  181     FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
  182     FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
  183     FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
  184     FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
  185     FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
  186     FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
  187     FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
  188     FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
  189     FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
  190     FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
  191     FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
  192     FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
  193     FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
  194     FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
  195     FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
  196 
  197     /* Round 2 */
  198     GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
  199     GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
  200     GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
  201     GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
  202     GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
  203     GG(d, a, b, c, x[10], S22,  0x2441453); /* 22 */
  204     GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
  205     GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
  206     GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
  207     GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
  208     GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
  209     GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
  210     GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
  211     GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
  212     GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
  213     GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
  214 
  215     /* Round 3 */
  216     HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
  217     HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
  218     HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
  219     HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
  220     HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
  221     HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
  222     HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
  223     HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
  224     HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
  225     HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
  226     HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
  227     HH(b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
  228     HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
  229     HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
  230     HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
  231     HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
  232 
  233     /* Round 4 */
  234     II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
  235     II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
  236     II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
  237     II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
  238     II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
  239     II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
  240     II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
  241     II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
  242     II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
  243     II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
  244     II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
  245     II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
  246     II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
  247     II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
  248     II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
  249     II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
  250 
  251     state[0] = (state[0] + a) & UINT4B_MAX;
  252     state[1] = (state[1] + b) & UINT4B_MAX;
  253     state[2] = (state[2] + c) & UINT4B_MAX;
  254     state[3] = (state[3] + d) & UINT4B_MAX;
  255 
  256     /*
  257      * Zeroize sensitive information.
  258      */
  259     (*su_mem_set_volatile)(x, 0, sizeof x);
  260 }
  261 
  262 /*
  263  * MD5 initialization. Begins an MD5 operation, writing a new context.
  264  */
  265 void
  266 mx_md5_init(mx_md5_t *context)
  267 {
  268     context->count[0] = context->count[1] = 0;
  269     /*
  270      * Load magic initialization constants.
  271      */
  272     context->state[0] = 0x67452301;
  273     context->state[1] = 0xefcdab89;
  274     context->state[2] = 0x98badcfe;
  275     context->state[3] = 0x10325476;
  276 }
  277 
  278 /*
  279  * MD5 block update operation. Continues an MD5 message-digest
  280  * operation, processing another message block, and updating the
  281  * context.
  282  */
  283 void
  284 mx_md5_update(mx_md5_t *context, unsigned char *input,
  285    unsigned int inputLen)
  286 {
  287     unsigned int i, idx, partLen;
  288 
  289     /* Compute number of bytes mod 64 */
  290     idx = context->count[0]>>3 & 0x3F;
  291 
  292     /* Update number of bits */
  293     if ((context->count[0] = (context->count[0] + (inputLen<<3)) &
  294                     UINT4B_MAX)
  295             < ((inputLen << 3) & UINT4B_MAX))
  296     context->count[1] = (context->count[1] + 1) & UINT4B_MAX;
  297     context->count[1] = (context->count[1] + (inputLen >> 29)) & UINT4B_MAX;
  298 
  299     partLen = 64 - idx;
  300 
  301     /*
  302      * Transform as many times as possible.
  303      */
  304     if (inputLen >= partLen) {
  305         su_mem_copy(&context->buffer[idx], input, partLen);
  306         MD5Transform(context->state, context->buffer);
  307 
  308         for (i = partLen; i + 63 < inputLen; i += 64)
  309             MD5Transform(context->state, &input[i]);
  310 
  311         idx = 0;
  312     } else
  313         i = 0;
  314 
  315     /* Buffer remaining input */
  316     su_mem_copy(&context->buffer[idx], &input[i], inputLen-i);
  317 }
  318 
  319 /*
  320  * MD5 finalization. Ends an MD5 message-digest operation, writing the
  321  * the message digest and zeroizing the context.
  322  */
  323 void
  324 mx_md5_final(unsigned char digest[mx_MD5_DIGEST_SIZE], mx_md5_t *context)
  325 {
  326     unsigned char   bits[8];
  327     unsigned int    idx, padLen;
  328 
  329     /* Save number of bits */
  330     Encode(bits, context->count, 8);
  331 
  332     /*
  333      * Pad out to 56 mod 64.
  334      */
  335     idx = context->count[0]>>3 & 0x3f;
  336     padLen = idx < 56 ? 56 - idx : 120 - idx;
  337     mx_md5_update(context, PADDING, padLen);
  338 
  339     /* Append length (before padding) */
  340     mx_md5_update(context, bits, 8);
  341     /* Store state in digest */
  342     Encode(digest, context->state, 16);
  343 
  344     /*
  345      * Zeroize sensitive information.
  346      */
  347     (*su_mem_set_volatile)(context, 0, sizeof *context);
  348 }
  349 
  350 # undef UINT4B_MAX
  351 # undef S11
  352 # undef S12
  353 # undef S13
  354 # undef S14
  355 # undef S21
  356 # undef S22
  357 # undef S23
  358 # undef S24
  359 # undef S31
  360 # undef S32
  361 # undef S33
  362 # undef S34
  363 # undef S41
  364 # undef S42
  365 # undef S43
  366 # undef S44
  367 # undef F
  368 # undef G
  369 # undef H
  370 # undef I
  371 # undef ROTATE_LEFT
  372 # undef FF
  373 # undef GG
  374 # undef HH
  375 # undef II
  376 #endif /* mx_XTLS_HAVE_MD5 */
  377 
  378 char *
  379 mx_md5_tohex(char hex[mx_MD5_TOHEX_SIZE], void const *vp){
  380    uz i, j;
  381    char const *cp;
  382    NYD_IN;
  383 
  384    cp = vp;
  385 
  386    for(i = 0; i < mx_MD5_TOHEX_SIZE / 2; ++i){
  387       j = i << 1;
  388 #define a_HEX(n) ((n) > 9 ? (n) - 10 + 'a' : (n) + '0')
  389       hex[j] = a_HEX((cp[i] & 0xF0) >> 4);
  390       hex[++j] = a_HEX(cp[i] & 0x0F);
  391 #undef a_HEX
  392    }
  393 
  394    NYD_OU;
  395    return hex;
  396 }
  397 
  398 char *
  399 mx_md5_cram_string(struct str const *user, struct str const *pass,
  400       char const *b64){
  401    struct str in, out;
  402    char digest[16], *cp;
  403    NYD_IN;
  404 
  405    out.s = NIL;
  406    if(user->l >= UZ_MAX - 1 - mx_MD5_TOHEX_SIZE - 1)
  407       goto jleave;
  408    if(pass->l >= INT_MAX)
  409       goto jleave;
  410 
  411    in.s = UNCONST(char*,b64);
  412    in.l = su_cs_len(in.s);
  413    if(!b64_decode(&out, &in))
  414       goto jleave;
  415    if(out.l >= INT_MAX){
  416       n_free(out.s);
  417       out.s = NIL;
  418       goto jleave;
  419    }
  420 
  421    mx_md5_hmac(S(uc*,out.s), out.l, S(uc*,pass->s), pass->l, digest);
  422    n_free(out.s);
  423    cp = mx_md5_tohex(n_autorec_alloc(mx_MD5_TOHEX_SIZE +1), digest);
  424 
  425    in.l = user->l + mx_MD5_TOHEX_SIZE +1;
  426    in.s = n_lofi_alloc(user->l + 1 + mx_MD5_TOHEX_SIZE +1);
  427    su_mem_copy(in.s, user->s, user->l);
  428    in.s[user->l] = ' ';
  429    su_mem_copy(&in.s[user->l + 1], cp, mx_MD5_TOHEX_SIZE);
  430    if(b64_encode(&out, &in, B64_SALLOC | B64_CRLF) == NIL)
  431       out.s = NIL;
  432    n_lofi_free(in.s);
  433 
  434 jleave:
  435    NYD_OU;
  436    return out.s;
  437 }
  438 
  439 void
  440 mx_md5_hmac(unsigned char *text, int text_len, unsigned char *key,
  441       int key_len, void *digest){
  442    /*
  443     * This code is taken from
  444     *
  445     * Network Working Group                                       H. Krawczyk
  446     * Request for Comments: 2104                                          IBM
  447     * Category: Informational                                      M. Bellare
  448     *                                                                    UCSD
  449     *                                                              R. Canetti
  450     *                                                                     IBM
  451     *                                                           February 1997
  452     *
  453     *
  454     *             HMAC: Keyed-Hashing for Message Authentication
  455     */
  456    mx_md5_t context;
  457    unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */
  458    unsigned char k_opad[65]; /* outer padding - key XORd with opad */
  459    unsigned char tk[16];
  460    int i;
  461    NYD_IN;
  462 
  463    /* if key is longer than 64 bytes reset it to key=MD5(key) */
  464    if(key_len > 64){
  465       mx_md5_t tctx;
  466 
  467       mx_md5_init(&tctx);
  468       mx_md5_update(&tctx, key, key_len);
  469       mx_md5_final(tk, &tctx);
  470 
  471       key = tk;
  472       key_len = 16;
  473    }
  474 
  475    /* the HMAC_MD5 transform looks like:
  476     *
  477     * MD5(K XOR opad, MD5(K XOR ipad, text))
  478     *
  479     * where K is an n byte key
  480     * ipad is the byte 0x36 repeated 64 times
  481     * opad is the byte 0x5c repeated 64 times
  482     * and text is the data being protected */
  483 
  484    /* start out by storing key in pads */
  485    su_mem_set(k_ipad, 0, sizeof k_ipad);
  486    su_mem_set(k_opad, 0, sizeof k_opad);
  487    su_mem_copy(k_ipad, key, key_len);
  488    su_mem_copy(k_opad, key, key_len);
  489 
  490    /* XOR key with ipad and opad values */
  491    for(i=0; i<64; i++){
  492       k_ipad[i] ^= 0x36;
  493       k_opad[i] ^= 0x5c;
  494    }
  495 
  496    /* perform inner MD5 */
  497    mx_md5_init(&context); /* init context for 1st pass */
  498    mx_md5_update(&context, k_ipad, 64); /* start with inner pad */
  499    mx_md5_update(&context, text, text_len); /* then text of datagram */
  500    mx_md5_final(digest, &context); /* finish up 1st pass */
  501 
  502    /* perform outer MD5 */
  503    mx_md5_init(&context); /* init context for 2nd pass */
  504    mx_md5_update(&context, k_opad, 64); /* start with outer pad */
  505    mx_md5_update(&context, digest, 16); /* then results of 1st hash */
  506    mx_md5_final(digest, &context); /* finish up 2nd pass */
  507    NYD_OU;
  508 }
  509 
  510 #include "su/code-ou.h"
  511 #endif /* mx_HAVE_MD5 */
  512 /* s-it-mode */