| /* | 
 |  * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. | 
 |  * | 
 |  * Licensed under the OpenSSL license (the "License").  You may not use | 
 |  * this file except in compliance with the License.  You can obtain a copy | 
 |  * in the file LICENSE in the source distribution or at | 
 |  * https://www.openssl.org/source/license.html | 
 |  */ | 
 |  | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <openssl/crypto.h> | 
 | #include <openssl/des.h> | 
 | #include <openssl/mdc2.h> | 
 |  | 
 | #undef c2l | 
 | #define c2l(c,l)        (l =((DES_LONG)(*((c)++)))    , \ | 
 |                          l|=((DES_LONG)(*((c)++)))<< 8L, \ | 
 |                          l|=((DES_LONG)(*((c)++)))<<16L, \ | 
 |                          l|=((DES_LONG)(*((c)++)))<<24L) | 
 |  | 
 | #undef l2c | 
 | #define l2c(l,c)        (*((c)++)=(unsigned char)(((l)     )&0xff), \ | 
 |                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ | 
 |                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ | 
 |                         *((c)++)=(unsigned char)(((l)>>24L)&0xff)) | 
 |  | 
 | static void mdc2_body(MDC2_CTX *c, const unsigned char *in, size_t len); | 
 | int MDC2_Init(MDC2_CTX *c) | 
 | { | 
 |     c->num = 0; | 
 |     c->pad_type = 1; | 
 |     memset(&(c->h[0]), 0x52, MDC2_BLOCK); | 
 |     memset(&(c->hh[0]), 0x25, MDC2_BLOCK); | 
 |     return 1; | 
 | } | 
 |  | 
 | int MDC2_Update(MDC2_CTX *c, const unsigned char *in, size_t len) | 
 | { | 
 |     size_t i, j; | 
 |  | 
 |     i = c->num; | 
 |     if (i != 0) { | 
 |         if (len < MDC2_BLOCK - i) { | 
 |             /* partial block */ | 
 |             memcpy(&(c->data[i]), in, len); | 
 |             c->num += (int)len; | 
 |             return 1; | 
 |         } else { | 
 |             /* filled one */ | 
 |             j = MDC2_BLOCK - i; | 
 |             memcpy(&(c->data[i]), in, j); | 
 |             len -= j; | 
 |             in += j; | 
 |             c->num = 0; | 
 |             mdc2_body(c, &(c->data[0]), MDC2_BLOCK); | 
 |         } | 
 |     } | 
 |     i = len & ~((size_t)MDC2_BLOCK - 1); | 
 |     if (i > 0) | 
 |         mdc2_body(c, in, i); | 
 |     j = len - i; | 
 |     if (j > 0) { | 
 |         memcpy(&(c->data[0]), &(in[i]), j); | 
 |         c->num = (int)j; | 
 |     } | 
 |     return 1; | 
 | } | 
 |  | 
 | static void mdc2_body(MDC2_CTX *c, const unsigned char *in, size_t len) | 
 | { | 
 |     register DES_LONG tin0, tin1; | 
 |     register DES_LONG ttin0, ttin1; | 
 |     DES_LONG d[2], dd[2]; | 
 |     DES_key_schedule k; | 
 |     unsigned char *p; | 
 |     size_t i; | 
 |  | 
 |     for (i = 0; i < len; i += 8) { | 
 |         c2l(in, tin0); | 
 |         d[0] = dd[0] = tin0; | 
 |         c2l(in, tin1); | 
 |         d[1] = dd[1] = tin1; | 
 |         c->h[0] = (c->h[0] & 0x9f) | 0x40; | 
 |         c->hh[0] = (c->hh[0] & 0x9f) | 0x20; | 
 |  | 
 |         DES_set_odd_parity(&c->h); | 
 |         DES_set_key_unchecked(&c->h, &k); | 
 |         DES_encrypt1(d, &k, 1); | 
 |  | 
 |         DES_set_odd_parity(&c->hh); | 
 |         DES_set_key_unchecked(&c->hh, &k); | 
 |         DES_encrypt1(dd, &k, 1); | 
 |  | 
 |         ttin0 = tin0 ^ dd[0]; | 
 |         ttin1 = tin1 ^ dd[1]; | 
 |         tin0 ^= d[0]; | 
 |         tin1 ^= d[1]; | 
 |  | 
 |         p = c->h; | 
 |         l2c(tin0, p); | 
 |         l2c(ttin1, p); | 
 |         p = c->hh; | 
 |         l2c(ttin0, p); | 
 |         l2c(tin1, p); | 
 |     } | 
 | } | 
 |  | 
 | int MDC2_Final(unsigned char *md, MDC2_CTX *c) | 
 | { | 
 |     unsigned int i; | 
 |     int j; | 
 |  | 
 |     i = c->num; | 
 |     j = c->pad_type; | 
 |     if ((i > 0) || (j == 2)) { | 
 |         if (j == 2) | 
 |             c->data[i++] = 0x80; | 
 |         memset(&(c->data[i]), 0, MDC2_BLOCK - i); | 
 |         mdc2_body(c, c->data, MDC2_BLOCK); | 
 |     } | 
 |     memcpy(md, (char *)c->h, MDC2_BLOCK); | 
 |     memcpy(&(md[MDC2_BLOCK]), (char *)c->hh, MDC2_BLOCK); | 
 |     return 1; | 
 | } |