# -*- Fundamental -*-
#
# (C) Tenable Network Security
#
# crypto_func.inc 
# $Revision: 1.3 $
#

#---------------------------------------------------------#
# DES encryption code                                     #
#---------------------------------------------------------#


perm1 = raw_string (57, 49, 41, 33, 25, 17,  9,
                     1, 58, 50, 42, 34, 26, 18,
                    10,  2, 59, 51, 43, 35, 27,
                    19, 11,  3, 60, 52, 44, 36,
                    63, 55, 47, 39, 31, 23, 15,
                     7, 62, 54, 46, 38, 30, 22,
                    14,  6, 61, 53, 45, 37, 29,
                    21, 13,  5, 28, 20, 12,  4 );


perm2 = raw_string (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 );

perm3 = raw_string (58, 50, 42, 34, 26, 18, 10,  2,
                    60, 52, 44, 36, 28, 20, 12,  4,
                    62, 54, 46, 38, 30, 22, 14,  6,
                    64, 56, 48, 40, 32, 24, 16,  8,
                    57, 49, 41, 33, 25, 17,  9,  1,
                    59, 51, 43, 35, 27, 19, 11,  3,
                    61, 53, 45, 37, 29, 21, 13,  5,
                    63, 55, 47, 39, 31, 23, 15,  7 );

perm4 = raw_string (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 );

perm5 = raw_string (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 );

perm6 = raw_string (40,  8, 48, 16, 56, 24, 64, 32,
                    39,  7, 47, 15, 55, 23, 63, 31,
                    38,  6, 46, 14, 54, 22, 62, 30,
                    37,  5, 45, 13, 53, 21, 61, 29,
                    36,  4, 44, 12, 52, 20, 60, 28,
                    35,  3, 43, 11, 51, 19, 59, 27,
                    34,  2, 42, 10, 50, 18, 58, 26,
                    33,  1, 41,  9, 49, 17, 57, 25 );

sc = raw_string (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1);

sbox =           raw_string (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 ) +
             raw_string (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 ) +
             raw_string (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 ) +
             raw_string ( 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 ) +
             raw_string ( 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 ) +
         raw_string (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 ) +
         raw_string ( 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 ) +
             raw_string (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 );

function permute (in, p)
{
 local_var buf, i;

 buf = NULL;
 for (i = 0; i < strlen(p); i++)
    buf += in[ord(p[i]) - 1];
 
 return buf;
}

function lshift (d, count)
{
 local_var buf, i;

 buf = NULL;
 for (i = 0; i < strlen(d); i++)
   buf += d[(i+count)%strlen(d)];
  
 return buf;


function xor (in1, in2)
{
 local_var buf, i;

 buf = NULL;
 for (i = 0; i < strlen(in2); i++)
   buf += raw_string (ord(in1[i]) ^ ord(in2[i]));
 
 return buf;
}

function des_encrypt (in, key)
{
 local_var buff, i, j, k, c, d, cd, ki, pd1, l, r, rl, pk1;
 local_var er, erk, b, cb, pcb, r2, tmp, val;
 local_var m, n;
 
 buf = c = d = cb = NULL;

 pk1 = permute (in:key, p:perm1);
 
 c = substr (pk1, 0, 27);
 d = substr (pk1, 28, 55);

 for (i = 0; i < 16; i++)
 {
  c = lshift (d:c, count:ord(sc[i]));
  d = lshift (d:d, count:ord(sc[i]));

  cd = c + d;
  ki[i] = permute (in:cd, p:perm2);
 }
 
 pd1 = permute (in:in, p:perm3);

 l = substr(pd1, 0, 31);
 r = substr(pd1, 32, 63);
 
 for (i = 0; i < 16; i++)
 {
  er = permute (in:r, p:perm4);
  erk = xor (in1:er, in2:ki[i]);
  
  for (j = 0; j < 8; j++)
    for (k = 0; k < 6; k++)
      b[j*6 + k] = erk[j*6 + k];

  for (j = 0; j < 8; j++)
  {
   m = (ord(b[j*6 + 0]) << 1) | ord(b[j*6 + 5]);
   n = (ord(b[j*6 + 1]) << 3) | (ord(b[j*6 + 2]) << 2) | (ord(b[j*6 + 3]) << 1) | ord(b[j*6 + 4]);

   for (k = 0; k < 4; k++)
      if ((ord(sbox[j*4*16 + m*16 + n]) & (1<<(3-k))) == 0)
        b[j*6 + k] = raw_string (0);
      else
        b[j*6 + k] = raw_string (1);
  }
 
  cb = NULL;
  for (j = 0; j < 8; j++)
    for (k = 0; k < 4; k++)
      cb += b[j*6 + k];

  pcb = permute (in:cb, p:perm5);
 
  r2 = xor (in1:l, in2:pcb);

  l = r;
  r = r2;
 }
 
 rl = r + l;
 buf = permute (in:rl, p:perm6);
 
 return buf;
}


function str_to_key (str)
{
 local_var key, i;

 key = raw_string ( ((ord(str[0])>>1) << 1) ,
                    ((((ord(str[0])&0x01)<<6) | (ord(str[1])>>2)) << 1) ,
                    ((((ord(str[1])&0x03)<<5) | (ord(str[2])>>3)) << 1) ,
                    ((((ord(str[2])&0x07)<<4) | (ord(str[3])>>4)) << 1) ,
                    ((((ord(str[3])&0x0F)<<3) | (ord(str[4])>>5)) << 1) ,
                    ((((ord(str[4])&0x1F)<<2) | (ord(str[5])>>6)) << 1) ,
                    ((((ord(str[5])&0x3F)<<1) | (ord(str[6])>>7)) << 1) ,
                    ((ord(str[6])&0x7F) << 1) );

 return key;
}


function DES (in, key)
{
 local_var inb, keyb, key2, outb, out, buff, i;

 key2 = str_to_key (str:key);

 for (i=0;i<64;i++)
 {
  if ((ord(in[i/8]) & (1<<(7-(i%8)))) == 0)
    inb += raw_string (0);
  else
    inb += raw_string (1);
    
  if ((ord(key2[i/8]) & (1<<(7-(i%8)))) == 0)
    keyb += raw_string (0);
  else
    keyb += raw_string (1);
 }

 outb = des_encrypt(in:inb, key:keyb);
 
 for (i=0;i<8;i++)
 {
  out[i] = 0;
 }

 for (i=0;i<64;i++) 
 {
  if (ord(outb[i]) == 1)
    out[i/8] = out[i/8] | (1<<(7-(i%8)));
 }

 for (i=0;i<8;i++)
 {
  buf += raw_string (out[i]);
 }

 return buf;
}



#---------------------------------------------------------#
# LANMAN2.1 Challenge/Response                            #
#---------------------------------------------------------#


function LM_Hash (password)
{
 local_var len, pass, K1, K2, hash;

 len = strlen (password) & 14;
 pass = substr (password, 0, len);

 while (strlen(pass) < 14)
   pass += raw_string (0);

 pass = toupper (pass);

 K1 = substr (pass, 0, 6);
 K2 = substr (pass, 7, 13);

 hash = DES (in:"KGS!@#$%", key:K1) + DES (in:"KGS!@#$%", key:K2);

 return hash;
}


function LM_Response (password, challenge)
{
 local_var hash, key1, key2, key3, response;

 hash = LM_Hash (password:password);
 reponse[1] = substr (hash, 0, 7) + raw_string (0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);

 hash += raw_string (0x00,0x00,0x00,0x00,0x00);

 key1 = substr (hash, 0, 6);
 key2 = substr (hash, 7, 13);
 key3 = substr (hash, 14, 20);

 response[0] = DES (in:challenge, key:key1) + DES (in:challenge, key:key2) + DES (in:challenge, key:key3);

 return response;
}




#---------------------------------------------------------#
# NTLM 0.12 Challenge/Response                            #
#---------------------------------------------------------#


function NTLM_Hash (password)
{
 return MD4 (password);
}

function NTLM_Response (password, challenge)
{
 local_var hash, key1, key2, key3, response;

 hash = NTLM_Hash (password:password);

 response[1] = MD4 (hash);

 hash += raw_string (0x00,0x00,0x00,0x00,0x00);

 key1 = substr (hash, 0, 6);
 key2 = substr (hash, 7, 13);
 key3 = substr (hash, 14, 20);

 response[0] = DES (in:challenge, key:key1) + DES (in:challenge, key:key2) + DES (in:challenge, key:key3);

 return response;
}


function NTLMv2_Hash (password, login, domain)
{
 local_var hash, user, dest, data;

 hash = NTLM_Hash (password:password);
 user = toupper (login);
 if (domain)
   dest = toupper (domain);
 else
   dest = NULL;
 
 data = user + dest;
 hash = HMAC_MD5 (data:data, key:hash);

 return hash;
}


function NTLMv2_Response (password, login, domain, challenge)
{
 local_var hash, data, blob, hmac, resp, TimeStamp, blip;

 hash = NTLMv2_Hash (password:password, login:login, domain:domain);

 blip = NULL;

 for (i = 0; i < 8; i++)
    blip += raw_string (rand() % 256);
 
 TimeStamp = raw_string (0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00) ; # To change !!
 
 blob = raw_string ( 0x01,                    # Response Type Identification Number
                     0x01,                    # Maximum Response Type Identification Number
             0x00, 0x00,              # Reserved
             0X00, 0x00, 0x00, 0x00 ) # Reserved ?
    +
    TimeStamp
    +
    blip
    +
    raw_string (0x00,0x00,0x00,0x00)  # Unknown value
    +
    raw_string (0x00,0x00,0x00,0x00)  # List of Netbios Name. Emtpy for the moment.
    +
    raw_string (0x00,0x00,0x00,0x00); # Unknown value
    
 data = challenge + blob;
 hmac = HMAC_MD5 (data:data, key:hash);
 resp[0] = hmac + blob;
 resp[1] = HMAC_MD5 (data:hash, key:hmac);

 return resp;
}


function LMv2_Response (password, login, domain, challenge)
{
 local_var hash, data, blob, hmac, resp, TimeStamp, blip;
 
 hash = NTLMv2_Hash (password:password, login:login, domain:domain);

 blip = NULL;

 for (i = 0; i < 8; i++)
    blip += raw_string (rand() % 256);
 
 data = challenge + blip;
 hmac = HMAC_MD5 (data:data, key:hash);
 resp[0] = hmac + blip;
 resp[1] = HMAC_MD5 (data:hash, key:hmac);

 return resp;
}