/*++

Copyright(c) 2000  Microsoft Corporation

Module Name:

    license.cpp

Abstract:

    Windows Load Balancing Service (WLBS)
    Code to encrypt/decrypt passwords and port rules.

Author:

    kyrilf

History:

    JosephJ 11/22/00 Gutted this file and folded in three constants from
                the now defunct license.h. Basically the functions in this
                file used to do lots of things but now only encrypt/decrypt
                port rules and passwords. The port rules stuff is only used
                for upgrading from olde versions of wlbs so that may go away
                as well.

        This file is located in two places:
            WLBS netconfig code -- net\config\netcfg\wlbscfg
            WLBS API code -- net\wlbs\api

        Because this involves password encryption, we don't want to make
        the functions callable via a DLL entrypoint, and setting up
        a static library to be shared between netconfig and api stuff is
        not trivial and overkill because the two trees are far apart.
        
--*/
// #include <precomp.h>
#include <windows.h>
#include "wlbsparm.h"
#include "license.h"


/* CONSTANTS */


static UCHAR    data_key [] =
                            { 0x3f, 0xba, 0x6e, 0xf0, 0xe1, 0x44, 0x1b, 0x45,
                              0x41, 0xc4, 0x9f, 0xfb, 0x46, 0x54, 0xbc, 0x43 };

static UCHAR    str_key [] =

                           { 0xdb, 0x1b, 0xac, 0x1a, 0xb9, 0xb1, 0x18, 0x03,
                             0x55, 0x57, 0x4a, 0x62, 0x36, 0x21, 0x7c, 0xa6 };


/* Encryption and decryption routines are based on a public-domain Tiny
   Encryption Algorithm (TEA) by David Wheeler and Roger Needham at the
   Computer Laboratory of Cambridge University. For reference, please
   consult http://vader.brad.ac.uk/tea/tea.shtml */


static VOID License_decipher (
    PULONG              v,
    PULONG              k)
{
   ULONG                y = v [0],
                        z = v [1],
                        a = k [0],
                        b = k [1],
                        c = k [2],
                        d = k [3],
                        n = 32,
                        sum = 0xC6EF3720,
                        delta = 0x9E3779B9;

    /* sum = delta<<5, in general sum = delta * n */

    while (n-- > 0)
    {
        z -= (y << 4) + c ^ y + sum ^ (y >> 5) + d;
        y -= (z << 4) + a ^ z + sum ^ (z >> 5) + b;
        sum -= delta;
    }

    v [0] = y; v [1] = z;

} /* end License_decipher */


static VOID License_encipher (
    PULONG              v,
    PULONG              k)
{
    ULONG               y = v [0],
                        z = v [1],
                        a = k [0],
                        b = k [1],
                        c = k [2],
                        d = k [3],
                        n = 32,
                        sum = 0,
                        delta = 0x9E3779B9;

    while (n-- > 0)
    {
        sum += delta;
        y += (z << 4) + a ^ z + sum ^ (z >> 5) + b;
        z += (y << 4) + c ^ y + sum ^ (y >> 5) + d;
    }

    v [0] = y; v [1] = z;

} /* end License_encipher */



BOOL License_data_decode (
    PCHAR               data,
    ULONG               len)
{
    ULONG               i;


    if (len % LICENSE_DATA_GRANULARITY != 0)
        return FALSE;

    for (i = 0; i < len; i += LICENSE_DATA_GRANULARITY)
        License_decipher ((PULONG) (data + i), (PULONG) data_key);

    return TRUE;

} /* License_data_decode */


ULONG License_string_encode (
    PCHAR               str)
{
    CHAR                buf [LICENSE_STR_IMPORTANT_CHARS + 1];
    ULONG               code, i;
    PULONG              nibp;


    for (i = 0; i < LICENSE_STR_IMPORTANT_CHARS; i++)
    {
        if (str[i] == 0)
            break;

        buf[i] = str[i];
    }

    for (; i < LICENSE_STR_IMPORTANT_CHARS + 1; i ++)
        buf[i] = 0;

    for (i = 0; i < LICENSE_STR_NIBBLES; i ++)
        License_encipher ((PULONG) (buf + i * LICENSE_DATA_GRANULARITY),
                          (PULONG) str_key);

    for (i = 0, code = 0; i < LICENSE_STR_NIBBLES; i ++)
    {
        nibp = (PULONG) (buf + (i * LICENSE_DATA_GRANULARITY));
        code ^= nibp [0] ^ nibp [1];
    }

    /* V2.2 - if password consists of the same characters - XORing nibbles
       above makes it go to 0 - put some recovery for that special case since
       we cannot modify the algorithm due to legacy issues */

    if (code == 0 && str [0] != 0)
        code = * ((PULONG) buf);

    return code;

} /* License_string_encode */

ULONG License_wstring_encode (
    PWCHAR              str)
{
    CHAR                buf [LICENSE_STR_IMPORTANT_CHARS + 1];
    ULONG               code, i;
    PULONG              nibp;


    for (i = 0; i < LICENSE_STR_IMPORTANT_CHARS; i++)
    {
        if (str[i] == 0)
            break;

        buf[i] = (UCHAR)str[i];
    }

    for (; i < LICENSE_STR_IMPORTANT_CHARS + 1; i ++)
        buf[i] = 0;

    for (i = 0; i < LICENSE_STR_NIBBLES; i ++)
        License_encipher ((PULONG) (buf + i * LICENSE_DATA_GRANULARITY),
                          (PULONG) str_key);

    for (i = 0, code = 0; i < LICENSE_STR_NIBBLES; i ++)
    {
        nibp = (PULONG) (buf + (i * LICENSE_DATA_GRANULARITY));
        code ^= nibp [0] ^ nibp [1];
    }

    /* V2.2 - if password consists of the same characters - XORing nibbles
       above makes it go to 0 - put some recovery for that special case since
       we cannot modify the algorithm due to legacy issues */

    if (code == 0 && str [0] != 0)
        code = * ((PULONG) buf);

    return code;

} /* License_wstring_encode */


BOOL License_data_encode (
    PCHAR               data,
    ULONG               len)
{
    ULONG               i;


    if (len % LICENSE_DATA_GRANULARITY != 0)
        return FALSE;

    for (i = 0; i < len; i += LICENSE_DATA_GRANULARITY)
        License_encipher ((PULONG) (data + i), (PULONG) data_key);

    return TRUE;

} /* License_data_encode */