pennmush-1.8.3p3/game/data/
pennmush-1.8.3p3/game/log/
pennmush-1.8.3p3/game/save/
pennmush-1.8.3p3/game/txt/evt/
pennmush-1.8.3p3/game/txt/nws/
pennmush-1.8.3p3/po/
pennmush-1.8.3p3/win32/msvc.net/
pennmush-1.8.3p3/win32/msvc6/
/**
 * \file funcrypt.c
 *
 * \brief Functions for cryptographic stuff in softcode
 *
 *
 */
#include "copyrite.h"

#include "config.h"
#include <time.h>
#include <string.h>
#include <ctype.h>
#include "conf.h"
#include "case.h"
#include "externs.h"
#include "version.h"
#include "extchat.h"
#include "htab.h"
#include "flags.h"
#include "dbdefs.h"
#include "parse.h"
#include "function.h"
#include "command.h"
#include "game.h"
#include "attrib.h"
#include "ansi.h"
#include "match.h"
#ifdef HAS_OPENSSL
#include <openssl/sha.h>
#include <openssl/evp.h>
#else
#include "shs.h"
#endif
#include "confmagic.h"


static char *crunch_code(char *code);
static char *crypt_code(char *code, char *text, int type);

#ifdef HAS_OPENSSL
static void safe_hexchar(unsigned char c, char *buff, char **bp);
#endif

static void safe_sha0(const char *text, size_t len, char *buff, char **bp);

/* Copy over only alphanumeric chars */
static char *
crunch_code(char *code)
{
  char *in;
  char *out;
  static char output[BUFFER_LEN];

  out = output;
  in = code;
  while (*in) {
    while (*in == ESC_CHAR) {
      while (*in && *in != 'm')
        in++;
      in++;                     /* skip 'm' */
    }
    if ((*in >= 32) && (*in <= 126)) {
      *out++ = *in;
    }
    in++;
  }
  *out = '\0';
  return output;
}

static char *
crypt_code(char *code, char *text, int type)
{
  static char textbuff[BUFFER_LEN];
  char codebuff[BUFFER_LEN];
  int start = 32;
  int end = 126;
  int mod = end - start + 1;
  char *p, *q, *r;

  if (!text && !*text)
    return (char *) "";
  strcpy(codebuff, crunch_code(code));
  if (!code || !*code || !codebuff || !*codebuff)
    return text;
  textbuff[0] = '\0';

  p = text;
  q = codebuff;
  r = textbuff;
  /* Encryption: Simply go through each character of the text, get its ascii
   * value, subtract start, add the ascii value (less start) of the
   * code, mod the result, add start. Continue  */
  while (*p) {
    if ((*p < start) || (*p > end)) {
      p++;
      continue;
    }
    if (type)
      *r++ = (((*p++ - start) + (*q++ - start)) % mod) + start;
    else
      *r++ = (((*p++ - *q++) + 2 * mod) % mod) + start;
    if (!*q)
      q = codebuff;
  }
  *r = '\0';
  return textbuff;
}

static void
safe_sha0(const char *text, size_t len, char *buff, char **bp)
{
#ifdef HAS_OPENSSL
  unsigned char hash[SHA_DIGEST_LENGTH];
  int n;

  SHA((unsigned char *) text, len, hash);

  for (n = 0; n < SHA_DIGEST_LENGTH; n++)
    safe_hexchar(hash[n], buff, bp);
#else
  SHS_INFO shsInfo;
  shsInfo.reverse_wanted = (BYTE) options.reverse_shs;
  shsInit(&shsInfo);
  shsUpdate(&shsInfo, (const BYTE *) text, len);
  shsFinal(&shsInfo);
  safe_format(buff, bp, "%0lx%0lx%0lx%0lx%0lx", shsInfo.digest[0],
              shsInfo.digest[1], shsInfo.digest[2], shsInfo.digest[3],
              shsInfo.digest[4]);
#endif
}

FUNCTION(fun_encrypt)
{
  char tbuff[BUFFER_LEN], *tp;
  char *pass;
  size_t len;
  ansi_string *as = parse_ansi_string(args[0]);

  pass = remove_markup(args[1], &len);

  tp = tbuff;
  safe_str(crypt_code(pass, as->text, 1), tbuff, &tp);
  *tp = '\0';
  memcpy(as->text, tbuff, as->len);
  safe_ansi_string(as, 0, as->len, buff, bp);
  free_ansi_string(as);
}

FUNCTION(fun_decrypt)
{
  char tbuff[BUFFER_LEN], *tp;
  char *pass;
  size_t len;
  ansi_string *as = parse_ansi_string(args[0]);

  pass = remove_markup(args[1], &len);

  tp = tbuff;
  safe_str(crypt_code(pass, as->text, 0), tbuff, &tp);
  *tp = '\0';
  memcpy(as->text, tbuff, as->len + 1);
  safe_ansi_string(as, 0, as->len, buff, bp);
  free_ansi_string(as);
}

FUNCTION(fun_checkpass)
{
  dbref it = match_thing(executor, args[0]);
  if (!(GoodObject(it) && IsPlayer(it))) {
    safe_str(T("#-1 NO SUCH PLAYER"), buff, bp);
    return;
  }
  safe_boolean(password_check(it, args[1]), buff, bp);
}

FUNCTION(fun_sha0)
{
  safe_sha0(args[0], arglens[0], buff, bp);
}

FUNCTION(fun_digest)
{
#ifdef HAS_OPENSSL
  EVP_MD_CTX ctx;
  const EVP_MD *mp;
  unsigned char md[EVP_MAX_MD_SIZE];
  unsigned int n, len = 0;

  if ((mp = EVP_get_digestbyname(args[0])) == NULL) {
    safe_str(T("#-1 UNSUPPORTED DIGEST TYPE"), buff, bp);
    return;
  }

  EVP_DigestInit(&ctx, mp);
  EVP_DigestUpdate(&ctx, args[1], arglens[1]);
  EVP_DigestFinal(&ctx, md, &len);

  for (n = 0; n < len; n++) {
    safe_hexchar(md[n], buff, bp);
  }

#else
  if (strcmp(args[0], "sha") == 0) {
    safe_sha0(args[1], arglens[1], buff, bp);
  } else {
    safe_str(T("#-1 UNSUPPORTED DIGEST TYPE"), buff, bp);
  }
#endif
}

#ifdef HAS_OPENSSL
static void
safe_hexchar(unsigned char c, char *buff, char **bp)
{
  const char *digits = "0123456789abcdef";
  if (*bp - buff < BUFFER_LEN - 1) {
    **bp = digits[c >> 4];
    (*bp)++;
  }
  if (*bp - buff < BUFFER_LEN - 1) {
    **bp = digits[c & 0x0F];
    (*bp)++;
  }
}
#endif