/*
 * User Defined Function for MySQL
 * SHA512, SHA384 and SHA256
 *
 * Using a modified version of Crypto++
 * (type declaration for byte moved into namespace)
 *
 * Author: Kristian Fiskerstrand
 * Website: http://www.kfwebs.net
 * Project: http://www.kfwebs.net/mysql/sha2
 *
 * Date: 2005-07-14
 * Copyright (C) 2005 Kristian Fiskerstrand
 *
 * CREATE FUNCTION sha512 RETURNS STRING SONAME 'mysql_sha.so';
 * CREATE FUNCTION sha384 RETURNS STRING SONAME 'mysql_sha.so';
 * CREATE FUNCTION sha256 RETURNS STRING SONAME 'mysql_sha.so';
*/

#include <stdio.h>
#include <string.h>

#include <my_global.h>
#include <my_sys.h>

#include <mysql.h>
#include <m_ctype.h>
#include <m_string.h>

#include <iostream>
#include <string>
#include <sys/time.h>

#include <cryptopp/sha.h>
#include <cryptopp/hex.h>
#include <cryptopp/filters.h>
#include <cryptopp/base64.h>

using namespace std;
using namespace CryptoPP;

static pthread_mutex_t LOCK_hostname;

extern "C" {
my_bool sha512_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char *sha512(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);
my_bool sha384_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char *sha384(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);
my_bool sha256_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char *sha256(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);
}

int lower_case ( int c )
{
	  return tolower ( c );
}

string doSHA512(string input)
{
 string output;
 SHA512 sha;
 StringSource s(input.c_str(),true, new HashFilter(sha,new HexEncoder(new StringSink(output))));
 return output;
}

string doSHA384(string input)
{
 string output;
 SHA384 sha;
 StringSource s(input.c_str(),true, new HashFilter(sha,new HexEncoder(new StringSink(output))));
 return output;
}

string doSHA256(string input)
{
 string output;
 SHA256 sha;
 StringSource s(input.c_str(),true, new HashFilter(sha,new HexEncoder(new StringSink(output))));
 return output;
}

my_bool sha512_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
  if (args->arg_count != 1)
  {
    strmov(message,"This function takes 1 argument");
    return 1;
  }

  return 0;
}

char *sha512(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
 const char *word=args->args[0];

 if (!word)					// Null argument
 {
  *is_null=1;
  *error=1;
  return 0;
 } 
 string a,b;
 b = word;
 a = doSHA512(b);
 transform (a.begin(),a.end(), a.begin(), lower_case);
 *length=a.length();
 memcpy(result,a.c_str(),*length);
 return result;
}

my_bool sha384_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
  if (args->arg_count != 1)
  {
    strmov(message,"This function takes 1 argument");
    return 1;
  }

  return 0;
}

char *sha384(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
 const char *word=args->args[0];

 if (!word)					// Null argument
 {
  *is_null=1;
  *error=1;
  return 0;
 } 
 string a,b;
 b = word;
 a = doSHA384(b);
 transform (a.begin(),a.end(), a.begin(), lower_case);
 *length=a.length();
 memcpy(result,a.c_str(),*length);
 return result;
}

my_bool sha256_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
  if (args->arg_count != 1)
  {
    strmov(message,"This function takes 1 argument");
    return 1;
  }

  return 0;
}

char *sha256(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
 const char *word=args->args[0];

 if (!word)					// Null argument
 {
  *is_null=1;
  *error=1;
  return 0;
 } 
 string a,b;
 b = word;
 a = doSHA256(b);
 transform (a.begin(),a.end(), a.begin(), lower_case);
 *length=a.length();
 memcpy(result,a.c_str(),*length);
 return result;
}
