/*
 * Copyright 1998-2021 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (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
 */

/*
 * DES low level APIs are deprecated for public use, but still ok for internal
 * use.
 */
#include "internal/deprecated.h"

/* NOCW */
#include <stdio.h>
#ifdef _OSD_POSIX
#ifndef CHARSET_EBCDIC
#define CHARSET_EBCDIC 1
#endif
#endif
#ifdef CHARSET_EBCDIC
#include <openssl/ebcdic.h>
#endif

#include <openssl/crypto.h>
#include "des_local.h"

/*
 * Added more values to handle illegal salt values the way normal crypt()
 * implementations do.
 */
static const unsigned char con_salt[128] = {
    0xD2,
    0xD3,
    0xD4,
    0xD5,
    0xD6,
    0xD7,
    0xD8,
    0xD9,
    0xDA,
    0xDB,
    0xDC,
    0xDD,
    0xDE,
    0xDF,
    0xE0,
    0xE1,
    0xE2,
    0xE3,
    0xE4,
    0xE5,
    0xE6,
    0xE7,
    0xE8,
    0xE9,
    0xEA,
    0xEB,
    0xEC,
    0xED,
    0xEE,
    0xEF,
    0xF0,
    0xF1,
    0xF2,
    0xF3,
    0xF4,
    0xF5,
    0xF6,
    0xF7,
    0xF8,
    0xF9,
    0xFA,
    0xFB,
    0xFC,
    0xFD,
    0xFE,
    0xFF,
    0x00,
    0x01,
    0x02,
    0x03,
    0x04,
    0x05,
    0x06,
    0x07,
    0x08,
    0x09,
    0x0A,
    0x0B,
    0x05,
    0x06,
    0x07,
    0x08,
    0x09,
    0x0A,
    0x0B,
    0x0C,
    0x0D,
    0x0E,
    0x0F,
    0x10,
    0x11,
    0x12,
    0x13,
    0x14,
    0x15,
    0x16,
    0x17,
    0x18,
    0x19,
    0x1A,
    0x1B,
    0x1C,
    0x1D,
    0x1E,
    0x1F,
    0x20,
    0x21,
    0x22,
    0x23,
    0x24,
    0x25,
    0x20,
    0x21,
    0x22,
    0x23,
    0x24,
    0x25,
    0x26,
    0x27,
    0x28,
    0x29,
    0x2A,
    0x2B,
    0x2C,
    0x2D,
    0x2E,
    0x2F,
    0x30,
    0x31,
    0x32,
    0x33,
    0x34,
    0x35,
    0x36,
    0x37,
    0x38,
    0x39,
    0x3A,
    0x3B,
    0x3C,
    0x3D,
    0x3E,
    0x3F,
    0x40,
    0x41,
    0x42,
    0x43,
    0x44,
};

static const unsigned char cov_2char[64] = {
    0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
    0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44,
    0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C,
    0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
    0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62,
    0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
    0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
    0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
};

char *DES_crypt(const char *buf, const char *salt)
{
    static char buff[14];

#ifndef CHARSET_EBCDIC
    return DES_fcrypt(buf, salt, buff);
#else
    char e_salt[2 + 1];
    char e_buf[32 + 1]; /* replace 32 by 8 ? */
    char *ret;

    if (salt[0] == '\0' || salt[1] == '\0')
        return NULL;

    /* Copy salt, convert to ASCII. */
    e_salt[0] = salt[0];
    e_salt[1] = salt[1];
    e_salt[2] = '\0';
    ebcdic2ascii(e_salt, e_salt, sizeof(e_salt));

    /* Convert password to ASCII. */
    OPENSSL_strlcpy(e_buf, buf, sizeof(e_buf));
    ebcdic2ascii(e_buf, e_buf, sizeof(e_buf));

    /* Encrypt it (from/to ASCII); if it worked, convert back. */
    ret = DES_fcrypt(e_buf, e_salt, buff);
    if (ret != NULL)
        ascii2ebcdic(ret, ret, strlen(ret));

    return ret;
#endif
}

char *DES_fcrypt(const char *buf, const char *salt, char *ret)
{
    unsigned int i, j, x, y;
    DES_LONG Eswap0, Eswap1;
    DES_LONG out[2], ll;
    DES_cblock key;
    DES_key_schedule ks;
    unsigned char bb[9];
    unsigned char *b = bb;
    unsigned char c, u;

    x = ret[0] = salt[0];
    if (x == 0 || x >= sizeof(con_salt))
        return NULL;
    Eswap0 = con_salt[x] << 2;
    x = ret[1] = salt[1];
    if (x == 0 || x >= sizeof(con_salt))
        return NULL;
    Eswap1 = con_salt[x] << 6;

    /*
     * EAY r=strlen(buf); r=(r+7)/8;
     */
    for (i = 0; i < 8; i++) {
        c = *(buf++);
        if (!c)
            break;
        key[i] = (c << 1);
    }
    for (; i < 8; i++)
        key[i] = 0;

    DES_set_key_unchecked(&key, &ks);
    fcrypt_body(&(out[0]), &ks, Eswap0, Eswap1);

    ll = out[0];
    l2c(ll, b);
    ll = out[1];
    l2c(ll, b);
    y = 0;
    u = 0x80;
    bb[8] = 0;
    for (i = 2; i < 13; i++) {
        c = 0;
        for (j = 0; j < 6; j++) {
            c <<= 1;
            if (bb[y] & u)
                c |= 1;
            u >>= 1;
            if (!u) {
                y++;
                u = 0x80;
            }
        }
        ret[i] = cov_2char[c];
    }
    ret[13] = '\0';
    return ret;
}
