// ==========================================================================
// Author:  Yee Hsu
// Date:    6/8/2006
//
// Desc:    File Encryptor/Decryptor. This library uses DES encryption
//          to encode/decode files. It can be used to obfuscate file for
//          storage or transfer through a medium for security.
// ==========================================================================

//#include <mem.h>
#include "stdafx.h"
#include "Des.h"

typedef unsigned long DWORD;

const int KEY_SHIFT[DES_ROUNDS] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};

const unsigned char COMPRESSION_PERMUTATION[DES_SBUFFER_SIZE] =
{
    14,17,11,24, 1, 5, 3,28,15, 6,21,10,
        23,19,12, 4,26, 8,16, 7,27,20,13, 2,
        41,52,31,37,47,55,30,40,51,45,33,48,
        44,49,39,56,34,53,46,42,50,36,29,32
};

const unsigned char EXPANSION_PERMUTATION[DES_SBUFFER_SIZE] =
{
    32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
        8, 9,10,11,12,13,12,13,14,15,16,17,
        16,17,18,19,20,21,20,21,22,23,24,25,
        24,25,26,27,28,29,28,29,30,31,32, 1
};

/*
S-Boxes:

14  4 13  1  2 15 11  8  3 10  6 12  5  9  0  7 
0 15  7  4 14  2 13  1 10  6 12 11  9  5  3  8 
4  1 14  8 13  6  2 11 15 12  9  7  3 10  5  0 
15 12  8  2  4  9  1  7  5 11  3 14 10  0  6 13

15  1  8 14  6 11  3  4  9  7  2 13 12  0  5 10 
3 13  4  7 15  2  8 14 12  0  1 10  6  9 11  5 
0 14  7 11 10  4 13  1  5  8 12  6  9  3  2 15 
13  8 10  1  3 15  4  2 11  6  7 12  0  5 14  9 

10  0  9 14  6  3 15  5  1 13 12  7 11  4  2  8 
13  7  0  9  3  4  6 10  2  8  5 14 12 11 15  1 
13  6  4  9  8 15  3  0 11  1  2 12  5 10 14  7 
1 10 13  0  6  9  8  7  4 15 14  3 11  5  2 12 

7 13 14  3  0  6  9 10  1  2  8  5 11 12  4 15
13  8 11  5  6 15  0  3  4  7  2 12  1 10 14  9
10  6  9  0 12 11  7 13 15  1  3 14  5  2  8  4
3 15  0  6 10  1 13  8  9  4  5 11 12  7  2 14

2 12  4  1  7 10 11  6  8  5  3 15 13  0 14  9
14 11  2 12  4  7 13  1  5  0 15 10  3  9  8  6
4  2  1 11 10 13  7  8 15  9 12  5  6  3  0 14
11  8 12  7  1 14  2 13  6 15  0  9 10  4  5  3

12  1 10 15  9  2  6  8  0 13  3  4 14  7  5 11
10 15  4  2  7 12  9  5  6  1 13 14  0 11  3  8
9 14 15  5  2  8 12  3  7  0  4 10  1 13 11  6
4  3  2 12  9  5 15 10 11 14  1  7  6  0  8 13

4 11  2 14 15  0  8 13  3 12  9  7  5 10  6  1
13  0 11  7  4  9  1 10 14  3  5 12  2 15  8  6
1  4 11 13 12  3  7 14 10 15  6  8  0  5  9  2
6 11 13  8  1  4 10  7  9  5  0 15 14  2  3 12

13  2  8  4  6 15 11  1 10  9  3 14  5  0 12  7
1 15 13  8 10  3  7  4 12  5  6 11  0 14  9  2 
7 11  4  1  9 12 14  2  0  6 10 13 15  3  5  8 
2  1 14  7  4 10  8 13 15 12  9  0  3  5  6 11 

*/

// The following are the above S-boxes, packed one bit per byte:

const unsigned char MODIFIED_SBOX_1[4*64] =
{
    1,1,1,0,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,1,1,1,1,1,0,1,1,1,0,0,0,
        0,0,1,1,1,0,1,0,0,1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,0,0,0,0,0,1,1,1,
        0,0,0,0,1,1,1,1,0,1,1,1,0,1,0,0,1,1,1,0,0,0,1,0,1,1,0,1,0,0,0,1,
        1,0,1,0,0,1,1,0,1,1,0,0,1,0,1,1,1,0,0,1,0,1,0,1,0,0,1,1,1,0,0,0,
        0,1,0,0,0,0,0,1,1,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1,0,1,0,1,1,
        1,1,1,1,1,1,0,0,1,0,0,1,0,1,1,1,0,0,1,1,1,0,1,0,0,1,0,1,0,0,0,0,
        1,1,1,1,1,1,0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,1,1,1,
        0,1,0,1,1,0,1,1,0,0,1,1,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,1,0,1
};

const unsigned char MODIFIED_SBOX_2[4*64] =
{
    1,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,1,0,1,0,0,
        1,0,0,1,0,1,1,1,0,0,1,0,1,1,0,1,1,1,0,0,0,0,0,0,0,1,0,1,1,0,1,0,
        0,0,1,1,1,1,0,1,0,1,0,0,0,1,1,1,1,1,1,1,0,0,1,0,1,0,0,0,1,1,1,0,
        1,1,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,0,1,1,0,1,0,1,
        0,0,0,0,1,1,1,0,0,1,1,1,1,0,1,1,1,0,1,0,0,1,0,0,1,1,0,1,0,0,0,1,
        0,1,0,1,1,0,0,0,1,1,0,0,0,1,1,0,1,0,0,1,0,0,1,1,0,0,1,0,1,1,1,1,
        1,1,0,1,1,0,0,0,1,0,1,0,0,0,0,1,0,0,1,1,1,1,1,1,0,1,0,0,0,0,1,0,
        1,0,1,1,0,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,1,1,1,1,0,1,0,0,1
};

const unsigned char MODIFIED_SBOX_3[4*64] =
{
    1,0,1,0,0,0,0,0,1,0,0,1,1,1,1,0,0,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,
        0,0,0,1,1,1,0,1,1,1,0,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,0,0,
        1,1,0,1,0,1,1,1,0,0,0,0,1,0,0,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,1,0,
        0,0,1,0,1,0,0,0,0,1,0,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,1,1,0,0,0,1,
        1,1,0,1,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,
        1,0,1,1,0,0,0,1,0,0,1,0,1,1,0,0,0,1,0,1,1,0,1,0,1,1,1,0,0,1,1,1,
        0,0,0,1,1,0,1,0,1,1,0,1,0,0,0,0,0,1,1,0,1,0,0,1,1,0,0,0,0,1,1,1,
        0,1,0,0,1,1,1,1,1,1,1,0,0,0,1,1,1,0,1,1,0,1,0,1,0,0,1,0,1,1,0,0
};

const unsigned char MODIFIED_SBOX_4[4*64] =
{
    0,1,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,1,1,0,1,0,
        0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,1,1,1,1,
        1,1,0,1,1,0,0,0,1,0,1,1,0,1,0,1,0,1,1,0,1,1,1,1,0,0,0,0,0,0,1,1,
        0,1,0,0,0,1,1,1,0,0,1,0,1,1,0,0,0,0,0,1,1,0,1,0,1,1,1,0,1,0,0,1,
        1,0,1,0,0,1,1,0,1,0,0,1,0,0,0,0,1,1,0,0,1,0,1,1,0,1,1,1,1,1,0,1,
        1,1,1,1,0,0,0,1,0,0,1,1,1,1,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,
        0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,1,0,1,1,0,0,0,
        1,0,0,1,0,1,0,0,0,1,0,1,1,0,1,1,1,1,0,0,0,1,1,1,0,0,1,0,1,1,1,0
};

const unsigned char MODIFIED_SBOX_5[4*64] =
{
    0,0,1,0,1,1,0,0,0,1,0,0,0,0,0,1,0,1,1,1,1,0,1,0,1,0,1,1,0,1,1,0,
        1,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,1,
        1,1,1,0,1,0,1,1,0,0,1,0,1,1,0,0,0,1,0,0,0,1,1,1,1,1,0,1,0,0,0,1,
        0,1,0,1,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,1,0,0,1,1,0,0,0,0,1,1,0,
        0,1,0,0,0,0,1,0,0,0,0,1,1,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,0,0,
        1,1,1,1,1,0,0,1,1,1,0,0,0,1,0,1,0,1,1,0,0,0,1,1,0,0,0,0,1,1,1,0,
        1,0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,1,1,0,0,0,1,0,1,1,0,1,
        0,1,1,0,1,1,1,1,0,0,0,0,1,0,0,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,1,1
};

const unsigned char MODIFIED_SBOX_6[4*64] =
{
    1,1,0,0,0,0,0,1,1,0,1,0,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,0,0,0,
        0,0,0,0,1,1,0,1,0,0,1,1,0,1,0,0,1,1,1,0,0,1,1,1,0,1,0,1,1,0,1,1,
        1,0,1,0,1,1,1,1,0,1,0,0,0,0,1,0,0,1,1,1,1,1,0,0,1,0,0,1,0,1,0,1,
        0,1,1,0,0,0,0,1,1,1,0,1,1,1,1,0,0,0,0,0,1,0,1,1,0,0,1,1,1,0,0,0,
        1,0,0,1,1,1,1,0,1,1,1,1,0,1,0,1,0,0,1,0,1,0,0,0,1,1,0,0,0,0,1,1,
        0,1,1,1,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,1,1,1,0,1,1,0,1,1,0,1,1,0,
        0,1,0,0,0,0,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,1,0,1,1,1,1,1,1,0,1,0,
        1,0,1,1,1,1,1,0,0,0,0,1,0,1,1,1,0,1,1,0,0,0,0,0,1,0,0,0,1,1,0,1
};

const unsigned char MODIFIED_SBOX_7[4*64] =
{
    0,1,0,0,1,0,1,1,0,0,1,0,1,1,1,0,1,1,1,1,0,0,0,0,1,0,0,0,1,1,0,1,
        0,0,1,1,1,1,0,0,1,0,0,1,0,1,1,1,0,1,0,1,1,0,1,0,0,1,1,0,0,0,0,1,
        1,1,0,1,0,0,0,0,1,0,1,1,0,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1,1,0,1,0,
        1,1,1,0,0,0,1,1,0,1,0,1,1,1,0,0,0,0,1,0,1,1,1,1,1,0,0,0,0,1,1,0,
        0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,1,1,0,0,0,0,1,1,0,1,1,1,1,1,1,0,
        1,0,1,0,1,1,1,1,0,1,1,0,1,0,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,1,0,
        0,1,1,0,1,0,1,1,1,1,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,1,1,
        1,0,0,1,0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,0,0,1,1,1,1,0,0
};

const unsigned char MODIFIED_SBOX_8[4*64] =
{
    1,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,1,1,0,1,1,1,1,1,0,1,1,0,0,0,1,
        1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,0,0,1,0,1,0,0,0,0,1,1,0,0,0,1,1,1,
        0,0,0,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,1,0,0,
        1,1,0,0,0,1,0,1,0,1,1,0,1,0,1,1,0,0,0,0,1,1,1,0,1,0,0,1,0,0,1,0,
        0,1,1,1,1,0,1,1,0,1,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,1,0,0,0,1,0,
        0,0,0,0,0,1,1,0,1,0,1,0,1,1,0,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,0,0,
        0,0,1,0,0,0,0,1,1,1,1,0,0,1,1,1,0,1,0,0,1,0,1,0,1,0,0,0,1,1,0,1,
        1,1,1,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,0,1,0,1,1
};

const unsigned char PBOX_PERMUTATION[32] =
{
    16, 7,20,21,29,12,28,17, 1,15,23,26, 5,18,31,10,
        2, 8,24,14,32,27, 3, 9,19,13,30, 6,22,11, 4,25
};

static void shift_half_key_left(unsigned char *k)
{
    unsigned char x = *k;
    unsigned char *kmax = k + (DES_KEY_SIZE/2-1);
    do k[0] = k[1]; while (++k < kmax);
    *k = x;
}

/*-----------------------------------------------------------------------------
This function performs the required shifts and precomputes the 16 shifted
and compressed keys.
-----------------------------------------------------------------------------*/

void des::initialize(const unsigned char key[DES_KEY_SIZE])
{
    unsigned char shifted_key[DES_KEY_SIZE];
    memcpy(shifted_key, key, DES_KEY_SIZE);
    for (int round = 0; round < DES_ROUNDS; round++)
    {
        shift_half_key_left(shifted_key);
        shift_half_key_left(shifted_key+DES_KEY_SIZE/2);
        if (KEY_SHIFT[round] == 2)
        {
            shift_half_key_left(shifted_key);
            shift_half_key_left(shifted_key+DES_KEY_SIZE/2);
        }
        for (int i = 0; i < DES_SBUFFER_SIZE; i++)
        {
            compressed_shifted_key[round][i] =
                shifted_key[COMPRESSION_PERMUTATION[i]-1];
        }
    }
}

/*-----------------------------------------------------------------------------
This function performs a DES encryption or decryption on a single 64-bit block
of data, using the specified 56-bit key. The data and key are packed one bit
per byte. Every element of data[] must be either 0 or 1. The results
will be highly anomalous if this is not the case.

The encrypted or decrypted data is returned to the data[] buffer.
-----------------------------------------------------------------------------*/

void des::encrypt_decrypt(unsigned char data[DES_DATA_SIZE],
                          int /* boolean */ encrypt)
{
    unsigned char sbuffer[DES_SBUFFER_SIZE];
    union pbuffer_tag
    {
        unsigned char byte[DES_DATA_SIZE/2];
        DWORD dword[DES_DATA_SIZE/8];
    } pbuffer;
    for (int round = 0; round < DES_ROUNDS; round++)
    {
        /* XOR compressed key with expanded right half of data */
        {
            int i;
            for (i = 0; i < DES_SBUFFER_SIZE; i++)
            {
                sbuffer[i] = data[DES_DATA_SIZE/2 + EXPANSION_PERMUTATION[i]-1] ^
                    compressed_shifted_key[encrypt ? round : 15-round][i];
            }
        }
        /* S-Box substitutions */
        {
#define index(n) (sbuffer[n]<<5+2 | sbuffer[n+5]<<4+2 | \
    sbuffer[n+1]<<3+2 | sbuffer[n+2]<<2+2 | sbuffer[n+3]<<1+2 | \
    sbuffer[n+4]<<0+2)
            pbuffer.dword[0] = * (DWORD *) (MODIFIED_SBOX_1 + index(0));
            pbuffer.dword[1] = * (DWORD *) (MODIFIED_SBOX_2 + index(6));
            pbuffer.dword[2] = * (DWORD *) (MODIFIED_SBOX_3 + index(12));
            pbuffer.dword[3] = * (DWORD *) (MODIFIED_SBOX_4 + index(18));
            pbuffer.dword[4] = * (DWORD *) (MODIFIED_SBOX_5 + index(24));
            pbuffer.dword[5] = * (DWORD *) (MODIFIED_SBOX_6 + index(30));
            pbuffer.dword[6] = * (DWORD *) (MODIFIED_SBOX_7 + index(36));
            pbuffer.dword[7] = * (DWORD *) (MODIFIED_SBOX_8 + index(42));
        }

        /* XOR and swap */
        if (round < 15)
        {
            int i;
            for (i = 0; i < DES_DATA_SIZE/2; i++)
            {
                unsigned char x = data[DES_DATA_SIZE/2 + i];
                data[DES_DATA_SIZE/2 + i] = data[i] ^ pbuffer.byte[PBOX_PERMUTATION[i]-1];
                data[i] = x;
            }
        }
        else
        {
            int i;
            for (i = 0; i < DES_DATA_SIZE/2; i++)
                data[i] = data[i] ^ pbuffer.byte[PBOX_PERMUTATION[i]-1];
        }
    }
}

/*----------------------------------------------------------------------------
This function takes 64 bits (8 bytes) of a password, XOR's it into a buffer,
and DES encrypts the buffer contents with the specified key. It then returns a
pointer to the next character of the password.
----------------------------------------------------------------------------*/

const char *des::xmix(const char *password,
                      unsigned char buffer[DES_DATA_SIZE], const unsigned char key[DES_KEY_SIZE])
{
    int i;
    for (i = 0; i < 64; i+=8)
    {
        int c = *password;
        if (c != 0) password++;
        buffer[i] ^= c >> 7 & 1;
        buffer[i+1] ^= c >> 6 & 1;
        buffer[i+2] ^= c >> 5 & 1;
        buffer[i+3] ^= c >> 4 & 1;
        buffer[i+4] ^= c >> 3 & 1;
        buffer[i+5] ^= c >> 2 & 1;
        buffer[i+6] ^= c >> 1 & 1;
        buffer[i+7] ^= c & 1;
    }
    initialize(key);
    encrypt(buffer);
    return password;
}

static unsigned char MIXER1[DES_KEY_SIZE] =
{
    1,0,1,0,0,0,0,0,0,1,
        0,1,0,0,1,1,0,1,0,0,
        1,1,0,1,1,1,0,1,1,0,
        0,0,0,0,1,0,0,1,0,1,
        1,1,0,0,0,0,1,1,1,0,
        0,1,0,1,1,0
};
static unsigned char MIXER2[DES_KEY_SIZE] =
{
    1,0,1,0,1,1,0,0,0,0,
        0,1,1,1,1,0,1,0,0,1,
        1,1,1,0,1,0,0,0,0,0,
        0,1,1,0,1,0,1,0,0,0,
        1,1,0,0,0,0,1,1,0,0,
        0,0,0,0,0,0
};
static unsigned char MIXER3[DES_KEY_SIZE] =
{
    1,0,0,0,1,1,1,1,1,0,
        1,0,0,0,1,1,0,0,1,0,
        0,1,0,1,1,0,0,0,0,0,
        0,0,1,1,1,0,0,0,1,0,
        1,0,0,0,1,0,0,0,1,1,
        1,1,1,1,0,0
};
static unsigned char MIXER4[DES_KEY_SIZE] =
{
    0,1,1,0,1,0,0,0,0,1,
        0,1,0,0,0,1,1,0,0,1,
        0,1,0,1,1,1,0,0,0,1,
        0,0,1,1,1,0,1,1,0,1,
        1,1,1,1,1,0,0,0,1,0,
        0,1,1,1,0,0
};

#ifdef TRIPLEDES

static unsigned char MIXER5[DES_KEY_SIZE] =
{
    1,1,0,1,0,0,1,1,0,1,
        1,1,1,0,1,1,1,0,1,1,
        0,1,1,1,0,1,0,0,1,1,
        0,0,0,1,1,0,1,0,0,1,
        1,1,0,1,0,1,0,1,1,0,
        1,0,0,1,1,0
};

static unsigned char MIXER6[DES_KEY_SIZE] =
{
    0,1,0,1,1,1,1,0,0,1,
        1,1,1,0,1,0,0,1,1,1,
        0,0,0,1,1,1,0,0,1,1,
        0,0,0,1,0,0,0,0,1,1,
        0,1,0,0,1,1,1,0,0,1,
        0,1,1,1,1,0
};

static unsigned char MIXER7[DES_KEY_SIZE] =
{
    1,0,1,0,0,1,1,0,1,0,
        0,0,0,1,1,1,1,1,1,0,
        0,0,0,0,1,0,0,0,0,0,
        0,1,1,1,1,0,0,0,1,1,
        1,0,0,1,1,1,0,0,0,0,
        0,0,1,1,1,1
};

static unsigned char MIXER8[DES_KEY_SIZE] =
{
    1,0,0,1,1,0,0,1,0,0,
        1,1,1,0,0,1,1,1,0,1,
        0,0,1,0,1,0,0,1,1,1,
        0,1,0,1,0,1,1,1,1,0,
        0,1,1,0,0,1,1,1,0,0,
        1,1,0,0,1,1
};

static unsigned char MIXER9[DES_KEY_SIZE] =
{
    1,1,1,0,1,0,0,1,1,1,
        1,1,0,1,0,1,0,1,1,1,
        0,0,0,1,1,0,1,0,0,0,
        0,1,1,1,1,0,0,0,1,1,
        0,1,1,1,1,0,1,1,1,1,
        1,0,1,0,1,0
};

static unsigned char MIXER10[DES_KEY_SIZE] =
{
    0,0,1,0,1,0,1,1,0,0,
        1,0,1,1,0,0,1,0,1,0,
        0,1,1,1,1,0,0,0,0,0,
        0,1,1,1,0,1,0,0,1,1,
        0,0,0,0,0,0,1,0,1,0,
        1,0,0,0,0,1
};

static unsigned char MIXER11[DES_KEY_SIZE] =
{
    0,0,1,1,0,0,1,1,1,0,
        1,0,1,0,1,0,0,0,1,0,
        0,1,1,1,0,1,1,1,1,0,
        0,0,1,0,0,1,1,0,1,0,
        0,0,1,0,0,0,0,1,0,0,
        0,0,1,0,0,1
};

static unsigned char MIXER12[DES_KEY_SIZE] =
{
    0,1,0,1,1,0,0,1,0,1,
        0,1,0,0,1,1,0,1,0,0,
        0,1,0,0,0,0,0,0,1,0,
        1,1,0,0,1,0,1,0,1,0,
        0,1,0,1,0,1,0,1,0,0,
        0,1,0,0,0,0
};

static unsigned char MIXER13[DES_KEY_SIZE] =
{
    1,0,1,0,0,0,0,1,0,1,
        1,0,0,1,0,1,0,1,0,0,
        1,0,1,1,1,1,0,0,1,1,
        1,1,0,0,0,1,1,1,0,0,
        1,0,0,1,0,1,0,0,0,0,
        0,1,0,0,1,1
};

static unsigned char MIXER14[DES_KEY_SIZE] =
{
    1,0,0,0,0,0,1,0,0,1,
        1,1,0,0,1,1,0,1,0,0,
        0,1,0,1,1,0,1,0,0,1,
        1,1,0,0,0,0,1,0,1,0,
        1,0,1,1,0,0,0,0,0,1,
        1,1,1,0,0,0
};

static unsigned char MIXER15[DES_KEY_SIZE] =
{
    0,0,1,1,1,0,0,0,1,1,
        0,0,1,1,0,0,1,0,1,0,
        1,0,0,0,1,0,1,0,0,1,
        0,0,0,1,1,0,1,1,1,1,
        0,0,0,0,0,0,1,0,0,1,
        0,1,0,0,1,1
};

static unsigned char MIXER16[DES_KEY_SIZE] =
{
    0,0,0,0,1,1,0,1,0,0,
        0,0,1,0,0,1,1,1,1,1,
        0,0,0,0,1,1,0,1,0,1,
        0,0,0,1,1,0,0,1,0,1,
        1,0,0,0,1,0,1,0,0,1,
        1,0,0,0,0,0
};

static unsigned char MIXER17[DES_KEY_SIZE] =
{
    0,0,0,0,1,1,1,0,0,1,
        0,0,0,0,1,0,0,1,0,1,
        0,0,1,0,0,0,1,0,1,0,
        0,1,0,0,1,0,0,1,1,1,
        1,1,0,0,1,0,1,0,0,0,
        0,1,0,1,1,1
};

static unsigned char MIXER18[DES_KEY_SIZE] =
{
    1,1,1,0,0,0,0,1,1,0,
        1,1,0,1,0,1,1,1,0,1,
        0,0,1,0,1,0,1,1,1,0,
        0,1,0,0,1,0,1,0,1,1,
        0,1,1,1,0,1,1,1,0,1,
        0,0,1,0,0,1
};

#endif

/*----------------------------------------------------------------------------
This function hashes a password and turns it into a key. Then it initializes
the key.
----------------------------------------------------------------------------*/

void des::password(const char *p)
{
    unsigned char buffer[DES_DATA_SIZE];
    memset(buffer, 0, sizeof(buffer));
    p = xmix(p, buffer, MIXER1);
    p = xmix(p, buffer, MIXER2);
    p = xmix(p, buffer, MIXER3);
    xmix(p, buffer, MIXER4);
    initialize(buffer);
}

#ifdef TRIPLEDES

void triple_des::password(const char *pwd)
{
    unsigned char buffer[DES_DATA_SIZE];
    memset(buffer, 0, sizeof(buffer));
    const char *p = pwd;
    p = part[0].xmix(p, buffer, MIXER1);
    p = part[0].xmix(p, buffer, MIXER2);
    p = part[0].xmix(p, buffer, MIXER3);
    p = part[0].xmix(p, buffer, MIXER4);
    p = part[0].xmix(p, buffer, MIXER5);
    part[0].xmix(p, buffer, MIXER6);
    part[0].initialize(buffer);
    p = pwd;
    p = part[1].xmix(p, buffer, MIXER7);
    p = part[1].xmix(p, buffer, MIXER8);
    p = part[1].xmix(p, buffer, MIXER9);
    p = part[1].xmix(p, buffer, MIXER10);
    p = part[1].xmix(p, buffer, MIXER11);
    part[1].xmix(p, buffer, MIXER12);
    part[1].initialize(buffer);
    p = pwd;
    p = part[2].xmix(p, buffer, MIXER13);
    p = part[2].xmix(p, buffer, MIXER14);
    p = part[2].xmix(p, buffer, MIXER15);
    p = part[2].xmix(p, buffer, MIXER16);
    p = part[2].xmix(p, buffer, MIXER17);
    part[2].xmix(p, buffer, MIXER18);
    part[2].initialize(buffer);
}

#endif


/*

If Triple DES is desired (in addition to regular DES), the label TRIPLEDES must be defined, usually by a -D option on the compiler command line. 

For the fastest operation, data used by the package is packed one bit per byte. Each byte must be either 0 or 1. The results will be highly anomalous if this is not the case. 

To DES encrypt or decrypt, first declare an object of the des encryption class: 

des crypto;

To Triple DES encrypt or decrypt, first declare an object of the triple_des encryption class: 

triple_des crypto;

If you have a 56-bit key, you can initialize a des object to encrypt and decrypt with the specified key by calling a member function: 

crypto.initialize(key);

const unsigned char key[DES_KEY_SIZE];
56-bit encryption and decryption
key, packed one bit per byte (each
byte must be either 0 or 1)

If you have a 168-bit key, you can initialize a triple_des object to encrypt and decrypt with the specified key by calling a member function: 

crypto.initialize(key);

const unsigned char key[3*DES_KEY_SIZE];
168-bit encryption and decryption
key, packed one bit per byte (each
byte must be either 0 or 1)

Alternatively, you may generate a key and initialize the object with a password: 

crypto.password(p);

const char *p;   pointer to nul-terminated password

The password may be any length (except zero), but only the first 32 characters will be used for regular DES, and only the first 48 characters will be used for Triple DES. It may contain any characters except nuls. It is case-sensitive; i.e., passwords that differ only in capitalization will produce different keys. 

Then to encrypt or decrypt a block of 64 bits, call the member functions: 

crypto.encrypt(data);

crypto.decrypt(data);

unsigned char data[DES_DATA_SIZE];
64-bit block of data to be
encrypted or decrypted, packed one
bit per byte (each byte must be
either 0 or 1)

The encrypted or decrypted data is written back into the same buffer in the same format (one bit per byte). 

*/




//#include <sys\stat.h>
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//
//static FILE *input;
//static FILE *output;
//
//const unsigned char ENCRYPTION_SIGNATURE[16] =
//{
//    85, 66, 67, 127, 128, 248, 92, 152, 15, 252, 175, 38, 158, 218, 22, 141
//};
//
//const char HELP[] =
//"\n"
//"des  password  input  output\n"
//"\n"
//"This utility encrypts or decrypts the input file and writes the result\n"
//"to the output file.\n"
//"\n"
//"The password may contain any characters appropriate for a command-line\n"
//"argument.\n"
//"\n"
//"For example, the following command lines encrypt and decrypt a file:\n"
//"\n"
//"   des password  message1.txt  message.cry\n"
//"   des password  message.cry  message2.txt\n"
//"\n"
//"The files message1.txt and message2.txt will be identical, and the file\n"
//"message.cry will be thoroughly scrambled.\n"
//"\n"
//"The algorithm used is DES with a 56-bit key derived from the password.";
//
//static void error_exit(const char *format, ...)
//{
//    fprintf(stderr, "\ndes: ");
//    vfprintf(stderr, format, &format + 1);
//    fprintf(stderr, "\n");
//    exit(1);
//}
//
//static int get_byte(void)
//{
//    int c = getc(input);
//    if (c == EOF)
//        error_exit("Unexpected end of file");
//    return c;
//}
//
//int main(int argc, char **argv)
//{
//    if (argc < 4)
//    {
//        puts(HELP);
//        return 1;
//    }
//
//#ifdef TRIPLEDES
//    triple_des crypto;
//#else
//    des crypto;
//#endif
//    // get key
//    crypto.password(argv[1]);
//
//    // open input and output files
//    input = fopen(argv[2], "rb");
//    if (input == NULL)
//        error_exit("Can't open %s", argv[2]);
//    output = fopen(argv[3], "wb");
//    if (output == NULL)
//        error_exit("Can't open %s", argv[3]);
//
//    // get input file length
//    long size;
//    {
//        struct stat s;
//        fstat(fileno(input), &s);
//        size = s.st_size;
//    }
//
//    // read first 16 bytes of input file and determine whether it is an
//    // encryption signature
//    int /* boolean */ encrypt;
//    {
//        unsigned char buffer[sizeof(ENCRYPTION_SIGNATURE)];
//        if (fread(buffer, sizeof(buffer), 1, input) != 1 ||
//            memcmp(buffer, ENCRYPTION_SIGNATURE, sizeof(buffer)) != 0)
//        {
//            rewind(input);
//            // write encryption signature to output
//            fwrite(ENCRYPTION_SIGNATURE, sizeof(ENCRYPTION_SIGNATURE), 1, output);
//            // write number of padding bytes to output file
//            putc( - (int) size & 7, output);
//            encrypt = 1 /* true */;
//        }
//        else
//        {
//            if (((int) size & 7) != 1)
//                error_exit("Size error in input file");
//            size -= sizeof(ENCRYPTION_SIGNATURE) + 1 + get_byte();
//            encrypt = 0 /* false */;
//        }
//    }
//
//    while (size > 0)
//    {
//        int count;
//        if (size < 8)
//            count = size;
//        else
//            count = 8;
//        size -= count;
//        static unsigned char buffer[64];
//        int i;
//        if (encrypt)
//        {
//            i = 0;
//            while (count-- != 0)
//            {
//                int c = get_byte();
//                buffer[i++] = c >> 7 & 1;
//                buffer[i++] = c >> 6 & 1;
//                buffer[i++] = c >> 5 & 1;
//                buffer[i++] = c >> 4 & 1;
//                buffer[i++] = c >> 3 & 1;
//                buffer[i++] = c >> 2 & 1;
//                buffer[i++] = c >> 1 & 1;
//                buffer[i++] = c & 1;
//            }
//            while (i < 64)
//                buffer[i++] = 0;
//            crypto.encrypt(buffer);
//            for (i = 0; i < 64; i += 8)
//            {
//                putc(buffer[i] << 7 |
//                    buffer[i+1] << 6 |
//                    buffer[i+2] << 5 |
//                    buffer[i+3] << 4 |
//                    buffer[i+4] << 3 |
//                    buffer[i+5] << 2 |
//                    buffer[i+6] << 1 |
//                    buffer[i+7], output);
//            }
//        }
//        else
//        {
//            for (i = 0; i < 64; i+= 8)
//            {
//                int c = get_byte();
//                buffer[i] = c >> 7 & 1;
//                buffer[i+1] = c >> 6 & 1;
//                buffer[i+2] = c >> 5 & 1;
//                buffer[i+3] = c >> 4 & 1;
//                buffer[i+4] = c >> 3 & 1;
//                buffer[i+5] = c >> 2 & 1;
//                buffer[i+6] = c >> 1 & 1;
//                buffer[i+7] = c & 1;
//            }
//            crypto.decrypt(buffer);
//            for (i = 0; count-- != 0; i += 8)
//            {
//                putc(buffer[i] << 7 |
//                    buffer[i+1] << 6 |
//                    buffer[i+2] << 5 |
//                    buffer[i+3] << 4 |
//                    buffer[i+4] << 3 |
//                    buffer[i+5] << 2 |
//                    buffer[i+6] << 1 |
//                    buffer[i+7], output);
//            }
//        }
//    }
//    fclose(input);
//    fclose(output);
//    return 0;
//}

/* *****************************  ANOTHER DES ALGO, SECOND ONE ************************ */

int deskey[64]={
    0,0,0,1,0,0,1,1,
        0,0,1,1,0,1,0,0,
        0,1,0,1,0,1,1,1,
        0,1,1,1,1,0,0,1,
        1,0,0,1,1,0,1,1,
        1,0,1,1,1,1,0,0,
        1,1,0,1,1,1,1,1,
        1,1,1,1,0,0,0,1
};

void Des::IP() //Initial Permutation
{
    int k=58,i;
    for(i=0;i<32;i++)
    {
        ip[i]=total[k-1];
        if(k-8>0)  k=k-8;
        else       k=k+58;
    }
    k=57;
    for( i=32;i<64;i++)
    {
        ip[i]=total[k-1];
        if(k-8>0)   k=k-8;
        else        k=k+58;
    }
}
void Des::PermChoice1() //Permutation Choice-1
{
    int k=57,i;
    for(i=0;i<28;i++)
    {
        pc1[i]=deskey[k-1];
        if(k-8>0)    k=k-8;
        else         k=k+57;
    }
    k=63;
    for( i=28;i<52;i++)
    {
        pc1[i]=deskey[k-1];
        if(k-8>0)    k=k-8;
        else         k=k+55;
    }
    k=28;
    for(i=52;i<56;i++)
    {
        pc1[i]=deskey[k-1];
        k=k-8;
    }

}
void Des::Expansion() //Expansion Function applied on `right' half
{
    int exp[8][6],i,j,k;
    for( i=0;i<8;i++)
    {
        for( j=0;j<6;j++)
        {
            if((j!=0)||(j!=5))
            {
                k=4*i+j;
                exp[i][j]=right[k-1];
            }
            if(j==0)
            {
                k=4*i;
                exp[i][j]=right[k-1];
            }
            if(j==5)
            {
                k=4*i+j;
                exp[i][j]=right[k-1];
            }
        }
    }
    exp[0][0]=right[31];
    exp[7][5]=right[0];

    k=0;
    for(i=0;i<8;i++)
        for(j=0;j<6;j++)
            expansion[k++]=exp[i][j];
}
void Des::PermChoice2()
{
    int per[56],i,k;
    for(i=0;i<28;i++) per[i]=ck[i];
    for(k=0,i=28;i<56;i++) per[i]=dk[k++];

    z[0]=per[13];z[1]=per[16];z[2]=per[10];z[3]=per[23];z[4]=per[0];z[5]=per[4];z[6]=per[2];z[7]=per[27];
    z[8]=per[14];z[9]=per[5];z[10]=per[20];z[11]=per[9];z[12]=per[22];z[13]=per[18];z[14]=per[11];z[15]=per[3];
    z[16]=per[25];z[17]=per[7];z[18]=per[15];z[19]=per[6];z[20]=per[26];z[21]=per[19];z[22]=per[12];z[23]=per[1];
    z[24]=per[40];z[25]=per[51];z[26]=per[30];z[27]=per[36];z[28]=per[46];z[29]=per[54];z[30]=per[29];z[31]=per[39];
    z[32]=per[50];z[33]=per[46];z[34]=per[32];z[35]=per[47];z[36]=per[43];z[37]=per[48];z[38]=per[38];z[39]=per[55];
    z[40]=per[33];z[41]=per[52];z[42]=per[45];z[43]=per[41];z[44]=per[49];z[45]=per[35];z[46]=per[28];z[47]=per[31];
}
void Des::xor_oneE(int round) //for Encrypt
{
    int i;
    for(i=0;i<48;i++)
        xor1[i]=expansion[i]^keyi[round-1][i];
}
void Des::xor_oneD(int round) //for Decrypt
{
    int i;
    for(i=0;i<48;i++)
        xor1[i]=expansion[i]^keyi[16-round][i];
}

void Des::substitution()
{
    int s1[4][16]={
        14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,
            0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,
            4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,
            15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13
    };

    int s2[4][16]={
        15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,
            3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,
            0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,
            13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9
    };

    int s3[4][16]={
        10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,
            13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,
            13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,
            1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12
    };

    int s4[4][16]={
        7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,
            13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,
            10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,
            3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14
    };

    int s5[4][16]={
        2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,
            14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,
            4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,
            11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3
    };

    int s6[4][16]={
        12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,
            10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
            9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,
            4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13
    };

    int s7[4][16]={
        4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,
            13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,
            1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,
            6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12
    };

    int s8[4][16]={
        13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,
            1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,
            7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,
            2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11
    };
    int a[8][6],k=0,i,j,p,q,count=0,g=0,v;

    for(i=0;i<8;i++)
    {
        for(j=0;j<6;j++)
        {
            a[i][j]=xor1[k++];
        }
    }

    for( i=0;i<8;i++)
    {
        p=1;q=0;
        k=(a[i][0]*2)+(a[i][5]*1);
        j=4;
        while(j>0)
        {
            q=q+(a[i][j]*p);
            p=p*2;
            j--;
        }
        count=i+1;
        switch(count)
        {
        case 1:    v=s1[k][q];    break;
        case 2:    v=s2[k][q];    break;
        case 3:    v=s3[k][q];    break;
        case 4:    v=s4[k][q];    break;
        case 5:    v=s5[k][q];    break;
        case 6:    v=s6[k][q];    break;
        case 7:    v=s7[k][q];    break;
        case 8:    v=s8[k][q];    break;
        }

        int d,i=3,a[4];
        while(v>0)
        {
            d=v%2;
            a[i--]=d;
            v=v/2;
        }
        while(i>=0)
        {
            a[i--]=0;
        }

        for(i=0;i<4;i++)
            sub[g++]=a[i];
    }
}

void Des::permutation()
{
    p[0]=sub[15];p[1]=sub[6];p[2]=sub[19];p[3]=sub[20];p[4]=sub[28];p[5]=sub[11];p[6]=sub[27];p[7]=sub[16];
    p[8]=sub[0];p[9]=sub[14];p[10]=sub[22];p[11]=sub[25];p[12]=sub[4];p[13]=sub[17];p[14]=sub[30];p[15]=sub[9];
    p[16]=sub[1];p[17]=sub[7];p[18]=sub[23];p[19]=sub[13];p[20]=sub[31];p[21]=sub[26];p[22]=sub[2];p[23]=sub[8];
    p[24]=sub[18];p[25]=sub[12];p[26]=sub[29];p[27]=sub[5];p[28]=sub[21];p[29]=sub[10];p[30]=sub[3];p[31]=sub[24];
}

void Des::xor_two()
{
    int i;
    for(i=0;i<32;i++)
    {
        xor2[i]=left[i]^p[i];
    }
}

void Des::inverse()
{
    int p=40,q=8,k1,k2,i,j;
    for(i=0;i<8;i++)
    {
        k1=p;k2=q;
        for(j=0;j<8;j++)
        {
            if(j%2==0)
            {
                inv[i][j]=temp[k1-1];
                k1=k1+8;
            }
            else if(j%2!=0)
            {
                inv[i][j]=temp[k2-1];
                k2=k2+8;
            }
        }
        p=p-1;q=q-1;
    }
}

char * Des::Encrypt(char *Text1)
{
    int i,a1,j,nB,m,iB,k,K,B[8],n,t,d,round;
    char *Text=new char[1000];
    strcpy(Text,Text1);
    i=strlen(Text);
    int mc=0;
    a1=i%8;
    if(a1!=0) for(j=0;j<8-a1;j++,i++) Text[i]=' '; Text[i]='\0';
    keygen();
    for(iB=0,nB=0,m=0;m<(strlen(Text)/8);m++) //Repeat for TextLenth/8 times.
    {
        for(iB=0,i=0;i<8;i++,nB++)
        {
            n=(int)Text[nB];
            for(K=7;n>=1;K--)
         {
             B[K]=n%2;  //Converting 8-Bytes to 64-bit Binary Format
             n/=2;
         } for(;K>=0;K--) B[K]=0;
            for(K=0;K<8;K++,iB++) total[iB]=B[K]; //Now `total' contains the 64-Bit binary format of 8-Bytes
        }
        IP(); //Performing initial permutation on `total[64]'
        for(i=0;i<64;i++) total[i]=ip[i]; //Store values of ip[64] into total[64]

        for(i=0;i<32;i++) left[i]=total[i]; //           +--> left[32]
        // total[64]--|
        for(;i<64;i++) right[i-32]=total[i];//            +--> right[32]
        for(round=1;round<=16;round++)
        {
            Expansion(); //Performing expansion on `right[32]' to get  `expansion[48]'
            xor_oneE(round); //Performing XOR operation on expansion[48],z[48] to get xor1[48]
            substitution();//Perform substitution on xor1[48] to get sub[32]
            permutation(); //Performing Permutation on sub[32] to get p[32]
            xor_two(); //Performing XOR operation on left[32],p[32] to get xor2[32]
            for(i=0;i<32;i++) left[i]=right[i]; //Dumping right[32] into left[32]
            for(i=0;i<32;i++) right[i]=xor2[i]; //Dumping xor2[32] into right[32]
        }
        for(i=0;i<32;i++) temp[i]=right[i]; // Dumping   -->[ swap32bit ]
        for(;i<64;i++) temp[i]=left[i-32];  //    left[32],right[32] into temp[64]

        inverse(); //Inversing the bits of temp[64] to get inv[8][8]
        /* Obtaining the Cypher-Text into final[1000]*/
        k=128;   d=0;
        for(i=0;i<8;i++)
        {
            for(j=0;j<8;j++)
            {
                d=d+inv[i][j]*k;
                k=k/2;
            }
            final[mc++]=(char)d;
            k=128;   d=0;
        }
    } //for loop ends here
    final[mc]='\0';
    return(final);
}
char * Des::Decrypt(char *Text1)
{
    int i,a1,j,nB,m,iB,k,K,B[8],n,t,d,round;
    char *Text=new char[1000];
    unsigned char ch;
    strcpy(Text,Text1);
    i=strlen(Text);
    keygen();
    int mc=0;
    for(iB=0,nB=0,m=0;m<(strlen(Text)/8);m++) //Repeat for TextLenth/8 times.
    {
        for(iB=0,i=0;i<8;i++,nB++)
        {
            ch=Text[nB];
            n=(int)ch;//(int)Text[nB];
            for(K=7;n>=1;K--)
         {
             B[K]=n%2;  //Converting 8-Bytes to 64-bit Binary Format
             n/=2;
         } for(;K>=0;K--) B[K]=0;
            for(K=0;K<8;K++,iB++) total[iB]=B[K]; //Now `total' contains the 64-Bit binary format of 8-Bytes
        }
        IP(); //Performing initial permutation on `total[64]'
        for(i=0;i<64;i++) total[i]=ip[i]; //Store values of ip[64] into total[64]

        for(i=0;i<32;i++) left[i]=total[i]; //           +--> left[32]
        // total[64]--|
        for(;i<64;i++) right[i-32]=total[i];//            +--> right[32]
        for(round=1;round<=16;round++)
        {
            Expansion(); //Performing expansion on `right[32]' to get  `expansion[48]'
            xor_oneD(round);
            substitution();//Perform substitution on xor1[48] to get sub[32]
            permutation(); //Performing Permutation on sub[32] to get p[32]
            xor_two(); //Performing XOR operation on left[32],p[32] to get xor2[32]
            for(i=0;i<32;i++) left[i]=right[i]; //Dumping right[32] into left[32]
            for(i=0;i<32;i++) right[i]=xor2[i]; //Dumping xor2[32] into right[32]
        } //rounds end here
        for(i=0;i<32;i++) temp[i]=right[i]; // Dumping   -->[ swap32bit ]
        for(;i<64;i++) temp[i]=left[i-32];  //    left[32],right[32] into temp[64]

        inverse(); //Inversing the bits of temp[64] to get inv[8][8]
        /* Obtaining the Cypher-Text into final[1000]*/
        k=128;   d=0;
        for(i=0;i<8;i++)
        {
            for(j=0;j<8;j++)
            {
                d=d+inv[i][j]*k;
                k=k/2;
            }
            final[mc++]=(char)d;
            k=128;   d=0;
        }
    } //for loop ends here
    final[mc]='\0';
    char *final1=new char[1000];
    for(i=0,j=strlen(Text);i<strlen(Text);i++,j++)
        final1[i]=final[j]; final1[i]='\0';
    return(final);
}


void Des::keygen()
{
    PermChoice1();

    int i,j,k=0;
    for(i=0;i<28;i++)
    {
        ck[i]=pc1[i];
    }
    for(i=28;i<56;i++)
    {
        dk[k]=pc1[i];
        k++;
    }
    int noshift=0,round;
    for(round=1;round<=16;round++)
    {
        if(round==1||round==2||round==9||round==16)
            noshift=1;
        else
            noshift=2;
        while(noshift>0)
        {
            int t;
            t=ck[0];
            for(i=0;i<28;i++)
                ck[i]=ck[i+1];
            ck[27]=t;
            t=dk[0];
            for(i=0;i<28;i++)
                dk[i]=dk[i+1];
            dk[27]=t;
            noshift--;
        }
        PermChoice2();
        for(i=0;i<48;i++)
            keyi[round-1][i]=z[i];
    }
}

/*
int main()
{

Des d1,d2;
char *str=new char[1000];
char *str1=new char[1000];
//clrscr();
//strcpy(str,"PHOENIX it & ece solutions.");
cout<<"Enter a string : ";
gets(str);
str1=d1.Encrypt(str);
cout<<"\ni/p Text: "<<str<<endl;
cout<<"\nCypher  : "<<str1<<endl;
//     ofstream fout("out2_fil.txt"); fout<<str1; fout.close();
cout<<"\no/p Text: "<<d2.Decrypt(str1)<<endl;
//getch();

return 0;
}
*/
/******************************************  DONT MODIFY THINGS ABOVE HERE ****************************** */

CryptoDES::CryptoDES()
{
}

CryptoDES::~CryptoDES()
{
}

bool CryptoDES::Crypt_From_Data_To_Data(const std::string sPass, const std::string sIn, std::string& sOut)
{
    this->sIn = sIn;
    this->sOut.clear();

    cDes.password(sPass.c_str());
    string sSig = sIn.substr(0, DES_ENCRYPTION_SIGNATURE.length());

    if (sSig.compare(DES_ENCRYPTION_SIGNATURE) != 0)
    {
        this->sOut = DES_ENCRYPTION_SIGNATURE;
        this->sOut += (-(int) this->sIn.length() & 7);        // add paddings
        this->Encrypt();
    }
    else 
    {
        this->Decrypt();
    }
    sOut = this->sOut;
    return true;
}

bool CryptoDES::Crypt_From_Data_To_File(const std::string sPass, const std::string sIn, std::string sOut)
{
    if (!this->Crypt_From_Data_To_Data(sPass, sIn, this->sOut))
        return false;

    if (!this->WritFile(sOut))
        return false;

    return true;
}

bool CryptoDES::Crypt_From_File_To_Data(const std::string sPass, const std::string sIn, std::string& sOut)
{
    if (!this->ReadFile(sIn))
        return false;

    if (!this->Crypt_From_Data_To_Data(sPass, this->sIn, sOut))
        return false;

    return true;
}

bool CryptoDES::Crypt_From_File_To_File(const std::string sPass, const std::string sIn, std::string sOut)
{
    if (!this->ReadFile(sIn))
        return false;

    if (!this->Crypt_From_Data_To_Data(sPass, this->sIn, this->sOut))
        return false;

    if (!this->WritFile(sOut))
        return false;

    return true;
}

void CryptoDES::Encrypt()
{
    int nCount = 0;
    int size = this->sIn.length();

    while (size > 0)
    {
        int count;

        if (size < 8)
            count = size;
        else
            count = 8;

        size -= count;
        static unsigned char buffer[64];

        int    i = 0;

        while (count-- != 0)
        {
            int c = this->sIn[nCount++];

            buffer[i++] = c >> 7 & 1;
            buffer[i++] = c >> 6 & 1;
            buffer[i++] = c >> 5 & 1;
            buffer[i++] = c >> 4 & 1;
            buffer[i++] = c >> 3 & 1;
            buffer[i++] = c >> 2 & 1;
            buffer[i++] = c >> 1 & 1;
            buffer[i++] = c & 1;
        }

        while (i < 64)
            buffer[i++] = 0;

        cDes.encrypt(buffer);

        for (i = 0; i < 64; i += 8)
        {
            int c = (buffer[i] << 7 |
                buffer[i+1] << 6 |
                buffer[i+2] << 5 |
                buffer[i+3] << 4 |
                buffer[i+4] << 3 |
                buffer[i+5] << 2 |
                buffer[i+6] << 1 |
                buffer[i+7]);

            this->sOut += c;
        }
    }
}

void CryptoDES::Decrypt()
{
    int nCount = DES_ENCRYPTION_SIGNATURE.length();
    int size = this->sIn.length() - nCount - 1 - this->sIn[nCount++];

    while (size > 0)
    {
        int count;
        if (size < 8)
            count = size;
        else
            count = 8;
        size -= count;
        static unsigned char buffer[64];
        int i;

        for (i = 0; i < 64; i+= 8)
        {
            int c = this->sIn[nCount++];

            buffer[i] = c >> 7 & 1;
            buffer[i+1] = c >> 6 & 1;
            buffer[i+2] = c >> 5 & 1;
            buffer[i+3] = c >> 4 & 1;
            buffer[i+4] = c >> 3 & 1;
            buffer[i+5] = c >> 2 & 1;
            buffer[i+6] = c >> 1 & 1;
            buffer[i+7] = c & 1;
        }
        cDes.decrypt(buffer);

        for (i = 0; count-- != 0; i += 8)
        {
            int c = (buffer[i] << 7 |
                buffer[i+1] << 6 |
                buffer[i+2] << 5 |
                buffer[i+3] << 4 |
                buffer[i+4] << 3 |
                buffer[i+5] << 2 |
                buffer[i+6] << 1 |
                buffer[i+7]);

            this->sOut += c;
        }
    }
}

bool CryptoDES::ReadFile(const std::string sFile)
{
    FILE* iFile = NULL;

    if ((iFile = fopen(sFile.c_str(), "rb")) != NULL)
    {
        fseek(iFile, 0L, SEEK_END);
        long nSize = ftell(iFile);
        char *pBuffer = new char[nSize+1];
        fseek(iFile, 0L, SEEK_SET);
        fread(pBuffer, 1, nSize, iFile);
        pBuffer[nSize] = 0;

        this->sIn.clear();
        this->sIn.assign(pBuffer, pBuffer + nSize);        // may contain multibyte binary data

        delete pBuffer;
        fclose(iFile);

        return true;
    }
    return false;
}

bool CryptoDES::WritFile(const std::string sFile)
{
    FILE* oFile = NULL;

    if ((oFile = fopen(sFile.c_str(), "wb")) != NULL)
    {
        fwrite(this->sOut.c_str(), this->sOut.length(), 1, oFile);
        fclose(oFile);

        return true;
    }
    return false;
}

bool CryptoDES::Encrypt_From_Data_To_Data(const std::string sIn, std::string& sOut)
{
    Des dd;

    char* pStr = new char[sIn.length()+1];

    if (pStr)
    {
        this->sIn = sIn;
        memset(pStr, 0, sIn.length()+1);
        memcpy(pStr, sIn.c_str(), sIn.length());
        this->sOut = sOut = dd.Encrypt(pStr);
        delete pStr;

        return true;
    }
    return false;
}

bool CryptoDES::Decrypt_From_Data_To_Data(const std::string sIn, std::string& sOut)
{
    Des dd;

    char* pStr = new char[sIn.length()+1];

    if (pStr)
    {
        this->sIn = sIn;
        memset(pStr, 0, sIn.length()+1);
        memcpy(pStr, sIn.c_str(), sIn.length());
        this->sOut = sOut = dd.Decrypt(pStr);
        delete pStr;

        return true;
    }
    return false;
}