Added system to block malware or illegal plugins (bug 5289, r=dvander).
authorAsher Baker <asherkin@gmail.com>
Thu Aug 09 01:54:43 2012 +0100 (2012-08-09)
changeset 3601d3a2fb7b3a1e
parent 3600 8b38b6996600
child 3603 d3fd010be8fe
Added system to block malware or illegal plugins (bug 5289, r=dvander).
configs/core.cfg
core/PluginSys.cpp
core/PluginSys.h
gamedata/core.games/blacklist.plugins.txt
gamedata/core.games/master.games.txt
public/sourcepawn/sp_vm_api.h
sourcepawn/jit/AMBuilder
sourcepawn/jit/BaseRuntime.cpp
sourcepawn/jit/BaseRuntime.h
sourcepawn/jit/md5/md5.cpp
sourcepawn/jit/md5/md5.h
     1.1 --- a/configs/core.cfg	Tue Aug 07 18:04:10 2012 +0100
     1.2 +++ b/configs/core.cfg	Thu Aug 09 01:54:43 2012 +0100
     1.3 @@ -115,4 +115,14 @@
     1.4  	 * In general, this option should be set to "yes" to increase the security of your server.
     1.5  	 */
     1.6  	"SteamAuthstringValidation"	"yes"
     1.7 +	
     1.8 +	/**
     1.9 +	 * Enables or disables whether SourceMod blocks known or potentially malicious plugins from loading.
    1.10 +	 * It is STRONGLY advised that this is left enabled, there have been cases in the past with plugins that
    1.11 +	 * allow anyone to delete files on the server, gain full rcon control, etc.
    1.12 +	 *
    1.13 +	 * "yes"	- Block malware or illegal plugins from loading (default)
    1.14 +	 * "no"		- Warn about malware or illegal plugins loading
    1.15 +	 */
    1.16 +	"BlockBadPlugins"	"yes"
    1.17  }
     2.1 --- a/core/PluginSys.cpp	Tue Aug 07 18:04:10 2012 +0100
     2.2 +++ b/core/PluginSys.cpp	Thu Aug 09 01:54:43 2012 +0100
     2.3 @@ -789,6 +789,8 @@
     2.4  	m_AllPluginsLoaded = false;
     2.5  	m_MyIdent = NULL;
     2.6  	m_LoadingLocked = false;
     2.7 +	
     2.8 +	m_bBlockBadPlugins = true;
     2.9  }
    2.10  
    2.11  CPluginManager::~CPluginManager()
    2.12 @@ -1030,6 +1032,41 @@
    2.13  			}
    2.14  		}
    2.15  	}
    2.16 +	
    2.17 +	if (pPlugin->GetStatus() == Plugin_Created)
    2.18 +	{
    2.19 +		unsigned char *pCodeHash = pPlugin->m_pRuntime->GetCodeHash();
    2.20 +		
    2.21 +		char codeHashBuf[40];
    2.22 +		UTIL_Format(codeHashBuf, 40, "plugin_");
    2.23 +		for (int i = 0; i < 16; i++)
    2.24 +			UTIL_Format(codeHashBuf + 7 + (i * 2), 3, "%02x", pCodeHash[i]);
    2.25 +		
    2.26 +		const char *bulletinUrl = g_pGameConf->GetKeyValue(codeHashBuf);
    2.27 +		if (bulletinUrl != NULL)
    2.28 +		{
    2.29 +			if (m_bBlockBadPlugins)
    2.30 +			{
    2.31 +				if (error)
    2.32 +				{
    2.33 +					if (bulletinUrl[0] != '\0')
    2.34 +					{
    2.35 +						UTIL_Format(error, maxlength, "Known malware detected and blocked. See %s for more info", bulletinUrl);
    2.36 +					} else {
    2.37 +						UTIL_Format(error, maxlength, "Possible malware or illegal plugin detected and blocked");
    2.38 +					}
    2.39 +				}
    2.40 +				pPlugin->m_status = Plugin_BadLoad;
    2.41 +			} else {
    2.42 +				if (bulletinUrl[0] != '\0')
    2.43 +				{
    2.44 +					g_Logger.LogMessage("%s: Known malware detected. See %s for more info, blocking disabled in core.cfg", pPlugin->GetFilename(), bulletinUrl);
    2.45 +				} else {
    2.46 +					g_Logger.LogMessage("%s: Possible malware or illegal plugin detected, blocking disabled in core.cfg", pPlugin->GetFilename());
    2.47 +				}
    2.48 +			}
    2.49 +		}
    2.50 +	}
    2.51  
    2.52  	LoadRes loadFailure = LoadRes_Failure;
    2.53  	/* Get the status */
    2.54 @@ -1129,7 +1166,7 @@
    2.55  
    2.56  	if ((res=_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) == LoadRes_Failure)
    2.57  	{
    2.58 -		g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error);
    2.59 +		g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s.", plugin, error);
    2.60  		pl->SetErrorState(
    2.61  			pl->GetStatus() <= Plugin_Created ? Plugin_BadLoad : pl->GetStatus(), 
    2.62  			"%s",
    2.63 @@ -1889,6 +1926,27 @@
    2.64  	g_ShareSys.DestroyIdentity(m_MyIdent);
    2.65  }
    2.66  
    2.67 +ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key, 
    2.68 +												 const char *value, 
    2.69 +												 ConfigSource source, 
    2.70 +												 char *error, 
    2.71 +												 size_t maxlength)
    2.72 +{
    2.73 +	if (strcmp(key, "BlockBadPlugins") == 0) {
    2.74 +		if (strcasecmp(value, "yes") == 0)
    2.75 +		{
    2.76 +			m_bBlockBadPlugins = true;
    2.77 +		} else if (strcasecmp(value, "no") == 0) {
    2.78 +			m_bBlockBadPlugins = false;
    2.79 +		} else {
    2.80 +			UTIL_Format(error, maxlength, "Invalid value: must be \"yes\" or \"no\"");
    2.81 +			return ConfigResult_Reject;
    2.82 +		}
    2.83 +		return ConfigResult_Accept;
    2.84 +	}
    2.85 +	return ConfigResult_Ignore;
    2.86 +}
    2.87 +
    2.88  void CPluginManager::OnHandleDestroy(HandleType_t type, void *object)
    2.89  {
    2.90  	/* We don't care about the internal object, actually */
    2.91 @@ -2269,6 +2327,15 @@
    2.92  				{
    2.93  					g_RootMenu.ConsolePrint("  Timestamp: %s", pl->m_DateTime);
    2.94  				}
    2.95 +				
    2.96 +				unsigned char *pCodeHash = pl->m_pRuntime->GetCodeHash();
    2.97 +				unsigned char *pDataHash = pl->m_pRuntime->GetDataHash();
    2.98 +				
    2.99 +				char combinedHash[33];
   2.100 +				for (int i = 0; i < 16; i++)
   2.101 +					UTIL_Format(combinedHash + (i * 2), 3, "%02x", pCodeHash[i] ^ pDataHash[i]);
   2.102 +				
   2.103 +				g_RootMenu.ConsolePrint("  Hash: %s", combinedHash);
   2.104  			}
   2.105  			else
   2.106  			{
     3.1 --- a/core/PluginSys.h	Tue Aug 07 18:04:10 2012 +0100
     3.2 +++ b/core/PluginSys.h	Thu Aug 09 01:54:43 2012 +0100
     3.3 @@ -57,6 +57,7 @@
     3.4  #include "convar_sm.h"
     3.5  #endif
     3.6  #include "ITranslator.h"
     3.7 +#include "IGameConfigs.h"
     3.8  #include "NativeOwner.h"
     3.9  #include "ShareSys.h"
    3.10  
    3.11 @@ -326,6 +327,7 @@
    3.12  public: //SMGlobalClass
    3.13  	void OnSourceModAllInitialized();
    3.14  	void OnSourceModShutdown();
    3.15 +	ConfigResult OnSourceModConfigChanged(const char *key, const char *value, ConfigSource source, char *error, size_t maxlength);
    3.16  	void OnSourceModMaxPlayersChanged(int newvalue);
    3.17  public: //IHandleTypeDispatch
    3.18  	void OnHandleDestroy(HandleType_t type, void *object);
    3.19 @@ -470,6 +472,9 @@
    3.20  	List<FakeNative *> m_Natives;
    3.21  
    3.22  	bool m_LoadingLocked;
    3.23 +	
    3.24 +	// Config
    3.25 +	bool m_bBlockBadPlugins;
    3.26  };
    3.27  
    3.28  extern CPluginManager g_PluginSys;
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/gamedata/core.games/blacklist.plugins.txt	Thu Aug 09 01:54:43 2012 +0100
     4.3 @@ -0,0 +1,16 @@
     4.4 +/**
     4.5 + * Do not edit this file.  Any changes will be overwritten by the gamedata
     4.6 + * updater or by upgrading your SourceMod install.
     4.7 + *
     4.8 + * For more information, see http://wiki.alliedmods.net/Gamedata_Updating_(SourceMod)
     4.9 + */
    4.10 +
    4.11 +"Games"
    4.12 +{
    4.13 +	"#default"
    4.14 +	{
    4.15 +		"Keys"
    4.16 +		{
    4.17 +		}
    4.18 +	}
    4.19 +}
     5.1 --- a/gamedata/core.games/master.games.txt	Tue Aug 07 18:04:10 2012 +0100
     5.2 +++ b/gamedata/core.games/master.games.txt	Thu Aug 09 01:54:43 2012 +0100
     5.3 @@ -65,4 +65,7 @@
     5.4  		"engine"	"csgo"
     5.5  	}
     5.6  
     5.7 +	"blacklist.plugins.txt"
     5.8 +	{
     5.9 +	}
    5.10  }
     6.1 --- a/public/sourcepawn/sp_vm_api.h	Tue Aug 07 18:04:10 2012 +0100
     6.2 +++ b/public/sourcepawn/sp_vm_api.h	Thu Aug 09 01:54:43 2012 +0100
     6.3 @@ -40,7 +40,7 @@
     6.4  
     6.5  /** SourcePawn Engine API Version */
     6.6  #define SOURCEPAWN_ENGINE_API_VERSION	4
     6.7 -#define SOURCEPAWN_ENGINE2_API_VERSION	3
     6.8 +#define SOURCEPAWN_ENGINE2_API_VERSION	4
     6.9  
    6.10  #if !defined SOURCEMOD_BUILD
    6.11  #define SOURCEMOD_BUILD
    6.12 @@ -479,6 +479,20 @@
    6.13  		 * @return				Memory usage, in bytes.
    6.14  		 */
    6.15  		virtual size_t GetMemUsage() =0;
    6.16 +
    6.17 +		/**
    6.18 +		 * @brief Returns the MD5 hash of the plugin's P-Code.
    6.19 +		 *
    6.20 +		 * @return				16-byte buffer with MD5 hash of the plugin's P-Code.
    6.21 +		 */
    6.22 +		virtual unsigned char *GetCodeHash() =0;
    6.23 +		
    6.24 +		/**
    6.25 +		 * @brief Returns the MD5 hash of the plugin's Data.
    6.26 +		 *
    6.27 +		 * @return				16-byte buffer with MD5 hash of the plugin's Data.
    6.28 +		 */
    6.29 +		virtual unsigned char *GetDataHash() =0;
    6.30  	};
    6.31  
    6.32  	/**
     7.1 --- a/sourcepawn/jit/AMBuilder	Tue Aug 07 18:04:10 2012 +0100
     7.2 +++ b/sourcepawn/jit/AMBuilder	Thu Aug 09 01:54:43 2012 +0100
     7.3 @@ -36,6 +36,7 @@
     7.4  	'zlib/trees.c',
     7.5  	'zlib/uncompr.c',
     7.6  	'zlib/zutil.c',
     7.7 +	'md5/md5.cpp',
     7.8  	'../../knight/shared/KeCodeAllocator.cpp'
     7.9  	])
    7.10  SM.AutoVersion('sourcepawn/jit', binary)
     8.1 --- a/sourcepawn/jit/BaseRuntime.cpp	Tue Aug 07 18:04:10 2012 +0100
     8.2 +++ b/sourcepawn/jit/BaseRuntime.cpp	Thu Aug 09 01:54:43 2012 +0100
     8.3 @@ -8,6 +8,8 @@
     8.4  #include "sp_vm_basecontext.h"
     8.5  #include "engine2.h"
     8.6  
     8.7 +#include "md5/md5.h"
     8.8 +
     8.9  using namespace SourcePawn;
    8.10  
    8.11  BaseRuntime::BaseRuntime() : m_Debug(&m_plugin), m_pPlugin(&m_plugin), m_pCtx(NULL), 
    8.12 @@ -18,6 +20,9 @@
    8.13  	m_FuncCache = NULL;
    8.14  	m_MaxFuncs = 0;
    8.15  	m_NumFuncs = 0;
    8.16 +	
    8.17 +	memset(m_CodeHash, 0, sizeof(m_CodeHash));
    8.18 +	memset(m_DataHash, 0, sizeof(m_DataHash));
    8.19  }
    8.20  
    8.21  BaseRuntime::~BaseRuntime()
    8.22 @@ -227,6 +232,16 @@
    8.23  		memset(m_PubJitFuncs, 0, sizeof(JitFunction *) * m_pPlugin->num_publics);
    8.24  	}
    8.25  
    8.26 +	MD5 md5_pcode;
    8.27 +	md5_pcode.update(plugin->pcode, plugin->pcode_size);
    8.28 +	md5_pcode.finalize();
    8.29 +	md5_pcode.raw_digest(m_CodeHash);
    8.30 +	
    8.31 +	MD5 md5_data;
    8.32 +	md5_data.update(plugin->data, plugin->data_size);
    8.33 +	md5_data.finalize();
    8.34 +	md5_data.raw_digest(m_DataHash);
    8.35 +
    8.36  	m_pPlugin->profiler = g_engine2.GetProfiler();
    8.37  	m_pCtx = new BaseContext(this);
    8.38  	m_pCo = g_Jit.StartCompilation(this);
    8.39 @@ -483,6 +498,16 @@
    8.40  	return mem;
    8.41  }
    8.42  
    8.43 +unsigned char *BaseRuntime::GetCodeHash()
    8.44 +{
    8.45 +	return m_CodeHash;
    8.46 +}
    8.47 +
    8.48 +unsigned char *BaseRuntime::GetDataHash()
    8.49 +{
    8.50 +	return m_DataHash;
    8.51 +}
    8.52 +
    8.53  BaseContext *BaseRuntime::GetBaseContext()
    8.54  {
    8.55  	return m_pCtx;
     9.1 --- a/sourcepawn/jit/BaseRuntime.h	Tue Aug 07 18:04:10 2012 +0100
     9.2 +++ b/sourcepawn/jit/BaseRuntime.h	Thu Aug 09 01:54:43 2012 +0100
     9.3 @@ -48,6 +48,8 @@
     9.4  	virtual void SetPauseState(bool paused);
     9.5  	virtual bool IsPaused();
     9.6  	virtual size_t GetMemUsage();
     9.7 +	virtual unsigned char *GetCodeHash();
     9.8 +	virtual unsigned char *GetDataHash();
     9.9  	JitFunction *GetJittedFunction(uint32_t idx);
    9.10  	uint32_t AddJittedFunction(JitFunction *fn);
    9.11  public:
    9.12 @@ -65,6 +67,9 @@
    9.13  	JitFunction **m_PubJitFuncs;
    9.14  	ICompilation *m_pCo;
    9.15  	unsigned int m_CompSerial;
    9.16 +	
    9.17 +	unsigned char m_CodeHash[16];
    9.18 +	unsigned char m_DataHash[16];
    9.19  };
    9.20  
    9.21  #endif //_INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/sourcepawn/jit/md5/md5.cpp	Thu Aug 09 01:54:43 2012 +0100
    10.3 @@ -0,0 +1,476 @@
    10.4 +// MD5.CC - source code for the C++/object oriented translation and 
    10.5 +//          modification of MD5.
    10.6 +
    10.7 +// Translation and modification (c) 1995 by Mordechai T. Abzug 
    10.8 +
    10.9 +// This translation/ modification is provided "as is," without express or 
   10.10 +// implied warranty of any kind.
   10.11 +
   10.12 +// The translator/ modifier does not claim (1) that MD5 will do what you think 
   10.13 +// it does; (2) that this translation/ modification is accurate; or (3) that 
   10.14 +// this software is "merchantible."  (Language for this disclaimer partially 
   10.15 +// copied from the disclaimer below).
   10.16 +
   10.17 +/* based on:
   10.18 +
   10.19 +   MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
   10.20 +   MDDRIVER.C - test driver for MD2, MD4 and MD5
   10.21 +
   10.22 +
   10.23 +   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
   10.24 +rights reserved.
   10.25 +
   10.26 +License to copy and use this software is granted provided that it
   10.27 +is identified as the "RSA Data Security, Inc. MD5 Message-Digest
   10.28 +Algorithm" in all material mentioning or referencing this software
   10.29 +or this function.
   10.30 +
   10.31 +License is also granted to make and use derivative works provided
   10.32 +that such works are identified as "derived from the RSA Data
   10.33 +Security, Inc. MD5 Message-Digest Algorithm" in all material
   10.34 +mentioning or referencing the derived work.
   10.35 +
   10.36 +RSA Data Security, Inc. makes no representations concerning either
   10.37 +the merchantability of this software or the suitability of this
   10.38 +software for any particular purpose. It is provided "as is"
   10.39 +without express or implied warranty of any kind.
   10.40 +
   10.41 +These notices must be retained in any copies of any part of this
   10.42 +documentation and/or software.
   10.43 +
   10.44 + */
   10.45 +
   10.46 +#include "md5.h"
   10.47 +
   10.48 +#include <assert.h>
   10.49 +#include <string.h>
   10.50 +
   10.51 +// MD5 simple initialization method
   10.52 +
   10.53 +MD5::MD5(){
   10.54 +
   10.55 +  init();
   10.56 +
   10.57 +}
   10.58 +
   10.59 +
   10.60 +// MD5 block update operation. Continues an MD5 message-digest
   10.61 +// operation, processing another message block, and updating the
   10.62 +// context.
   10.63 +
   10.64 +void MD5::update (uint1 *input, uint4 input_length) {
   10.65 +
   10.66 +  uint4 input_index, buffer_index;
   10.67 +  uint4 buffer_space;                // how much space is left in buffer
   10.68 +
   10.69 +  if (finalized){  // so we can't update!
   10.70 +    /*cerr << "MD5::update:  Can't update a finalized digest!" << endl;*/
   10.71 +    return;
   10.72 +  }
   10.73 +
   10.74 +  // Compute number of bytes mod 64
   10.75 +  buffer_index = (unsigned int)((count[0] >> 3) & 0x3F);
   10.76 +
   10.77 +  // Update number of bits
   10.78 +  if (  (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) )
   10.79 +    count[1]++;
   10.80 +
   10.81 +  count[1] += ((uint4)input_length >> 29);
   10.82 +
   10.83 +
   10.84 +  buffer_space = 64 - buffer_index;  // how much space is left in buffer
   10.85 +
   10.86 +  // Transform as many times as possible.
   10.87 +  if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
   10.88 +    // fill the rest of the buffer and transform
   10.89 +    memcpy (buffer + buffer_index, input, buffer_space);
   10.90 +    transform (buffer);
   10.91 +
   10.92 +    // now, transform each 64-byte piece of the input, bypassing the buffer
   10.93 +    for (input_index = buffer_space; input_index + 63 < input_length; 
   10.94 +	 input_index += 64)
   10.95 +      transform (input+input_index);
   10.96 +
   10.97 +    buffer_index = 0;  // so we can buffer remaining
   10.98 +  }
   10.99 +  else
  10.100 +    input_index=0;     // so we can buffer the whole input
  10.101 +
  10.102 +
  10.103 +  // and here we do the buffering:
  10.104 +  memcpy(buffer+buffer_index, input+input_index, input_length-input_index);
  10.105 +}
  10.106 +
  10.107 +
  10.108 +
  10.109 +// MD5 update for files.
  10.110 +// Like above, except that it works on files (and uses above as a primitive.)
  10.111 +
  10.112 +void MD5::update(FILE *file){
  10.113 +
  10.114 +  unsigned char buffer[1024];
  10.115 +  int len;
  10.116 +
  10.117 +  while ((len=fread(buffer, 1, 1024, file)))
  10.118 +    update(buffer, len);
  10.119 +
  10.120 +  fclose (file);
  10.121 +
  10.122 +}
  10.123 +
  10.124 +
  10.125 +// MD5 finalization. Ends an MD5 message-digest operation, writing the
  10.126 +// the message digest and zeroizing the context.
  10.127 +
  10.128 +
  10.129 +void MD5::finalize (){
  10.130 +
  10.131 +  unsigned char bits[8];
  10.132 +  unsigned int index, padLen;
  10.133 +  static uint1 PADDING[64]={
  10.134 +    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  10.135 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  10.136 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  10.137 +    };
  10.138 +
  10.139 +  if (finalized){
  10.140 +   /* cerr << "MD5::finalize:  Already finalized this digest!" << endl;*/
  10.141 +    return;
  10.142 +  }
  10.143 +
  10.144 +  // Save number of bits
  10.145 +  encode (bits, count, 8);
  10.146 +
  10.147 +  // Pad out to 56 mod 64.
  10.148 +  index = (uint4) ((count[0] >> 3) & 0x3f);
  10.149 +  padLen = (index < 56) ? (56 - index) : (120 - index);
  10.150 +  update (PADDING, padLen);
  10.151 +
  10.152 +  // Append length (before padding)
  10.153 +  update (bits, 8);
  10.154 +
  10.155 +  // Store state in digest
  10.156 +  encode (digest, state, 16);
  10.157 +
  10.158 +  // Zeroize sensitive information
  10.159 +  memset (buffer, 0, sizeof(*buffer));
  10.160 +
  10.161 +  finalized=1;
  10.162 +
  10.163 +}
  10.164 +
  10.165 +
  10.166 +
  10.167 +
  10.168 +MD5::MD5(FILE *file){
  10.169 +
  10.170 +  init();  // must be called be all constructors
  10.171 +  update(file);
  10.172 +  finalize ();
  10.173 +}
  10.174 +
  10.175 +unsigned char *MD5::raw_digest(){
  10.176 +
  10.177 +  uint1 *s = new uint1[16];
  10.178 +
  10.179 +  if (!finalized){
  10.180 +/*    cerr << "MD5::raw_digest:  Can't get digest if you haven't "<<
  10.181 +      "finalized the digest!" <<endl;*/
  10.182 +    return ( (unsigned char*) "");
  10.183 +  }
  10.184 +
  10.185 +  memcpy(s, digest, 16);
  10.186 +  return s;
  10.187 +}
  10.188 +
  10.189 +unsigned char *MD5::raw_digest(unsigned char buffer[16])
  10.190 +{
  10.191 +	if (!finalized)
  10.192 +	{
  10.193 +		return ( (unsigned char*) "");
  10.194 +	}
  10.195 +
  10.196 +	 memcpy(buffer, digest, 16);
  10.197 +	 return buffer;
  10.198 +}
  10.199 +
  10.200 +
  10.201 +
  10.202 +char *MD5::hex_digest(){
  10.203 +
  10.204 +  int i;
  10.205 +  char *s= new char[33];
  10.206 +
  10.207 +  assert(finalized);
  10.208 +
  10.209 +  for (i=0; i<16; i++)
  10.210 +    sprintf(s+i*2, "%02x", digest[i]);
  10.211 +
  10.212 +  s[32]='\0';
  10.213 +
  10.214 +  return s;
  10.215 +}
  10.216 +
  10.217 +
  10.218 +char *MD5::hex_digest(char buffer[33]){
  10.219 +
  10.220 +  int i;
  10.221 +
  10.222 +  assert(finalized);
  10.223 +
  10.224 +  for (i=0; i<16; i++)
  10.225 +    sprintf(buffer+i*2, "%02x", digest[i]);
  10.226 +
  10.227 +  buffer[32]='\0';
  10.228 +
  10.229 +  return buffer;
  10.230 +}
  10.231 +
  10.232 +
  10.233 +// PRIVATE METHODS:
  10.234 +
  10.235 +
  10.236 +
  10.237 +void MD5::init(){
  10.238 +  finalized=0;  // we just started!
  10.239 +
  10.240 +  // Nothing counted, so count=0
  10.241 +  count[0] = 0;
  10.242 +  count[1] = 0;
  10.243 +
  10.244 +  // Load magic initialization constants.
  10.245 +  state[0] = 0x67452301;
  10.246 +  state[1] = 0xefcdab89;
  10.247 +  state[2] = 0x98badcfe;
  10.248 +  state[3] = 0x10325476;
  10.249 +}
  10.250 +
  10.251 +
  10.252 +
  10.253 +// Constants for MD5Transform routine.
  10.254 +// Although we could use C++ style constants, defines are actually better,
  10.255 +// since they let us easily evade scope clashes.
  10.256 +
  10.257 +#define S11 7
  10.258 +#define S12 12
  10.259 +#define S13 17
  10.260 +#define S14 22
  10.261 +#define S21 5
  10.262 +#define S22 9
  10.263 +#define S23 14
  10.264 +#define S24 20
  10.265 +#define S31 4
  10.266 +#define S32 11
  10.267 +#define S33 16
  10.268 +#define S34 23
  10.269 +#define S41 6
  10.270 +#define S42 10
  10.271 +#define S43 15
  10.272 +#define S44 21
  10.273 +
  10.274 +
  10.275 +
  10.276 +
  10.277 +// MD5 basic transformation. Transforms state based on block.
  10.278 +void MD5::transform (uint1 block[64]){
  10.279 +
  10.280 +  uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
  10.281 +
  10.282 +  decode (x, block, 64);
  10.283 +
  10.284 +  assert(!finalized);  // not just a user error, since the method is private
  10.285 +
  10.286 +  /* Round 1 */
  10.287 +  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
  10.288 +  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
  10.289 +  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
  10.290 +  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
  10.291 +  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
  10.292 +  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
  10.293 +  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
  10.294 +  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
  10.295 +  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
  10.296 +  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
  10.297 +  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
  10.298 +  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
  10.299 +  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
  10.300 +  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
  10.301 +  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
  10.302 +  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
  10.303 +
  10.304 + /* Round 2 */
  10.305 +  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
  10.306 +  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
  10.307 +  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
  10.308 +  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
  10.309 +  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
  10.310 +  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
  10.311 +  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
  10.312 +  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
  10.313 +  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
  10.314 +  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
  10.315 +  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
  10.316 +  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
  10.317 +  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
  10.318 +  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
  10.319 +  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
  10.320 +  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
  10.321 +
  10.322 +  /* Round 3 */
  10.323 +  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
  10.324 +  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
  10.325 +  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
  10.326 +  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
  10.327 +  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
  10.328 +  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
  10.329 +  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
  10.330 +  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
  10.331 +  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
  10.332 +  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
  10.333 +  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
  10.334 +  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
  10.335 +  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
  10.336 +  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
  10.337 +  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
  10.338 +  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
  10.339 +
  10.340 +  /* Round 4 */
  10.341 +  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
  10.342 +  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
  10.343 +  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
  10.344 +  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
  10.345 +  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
  10.346 +  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
  10.347 +  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
  10.348 +  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
  10.349 +  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
  10.350 +  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
  10.351 +  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
  10.352 +  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
  10.353 +  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
  10.354 +  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
  10.355 +  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
  10.356 +  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
  10.357 +
  10.358 +  state[0] += a;
  10.359 +  state[1] += b;
  10.360 +  state[2] += c;
  10.361 +  state[3] += d;
  10.362 +
  10.363 +  // Zeroize sensitive information.
  10.364 +  memset ( (uint1 *) x, 0, sizeof(x));
  10.365 +
  10.366 +}
  10.367 +
  10.368 +
  10.369 +
  10.370 +// Encodes input (UINT4) into output (unsigned char). Assumes len is
  10.371 +// a multiple of 4.
  10.372 +void MD5::encode (uint1 *output, uint4 *input, uint4 len) {
  10.373 +
  10.374 +  unsigned int i, j;
  10.375 +
  10.376 +  for (i = 0, j = 0; j < len; i++, j += 4) {
  10.377 +    output[j]   = (uint1)  (input[i] & 0xff);
  10.378 +    output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
  10.379 +    output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
  10.380 +    output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
  10.381 +  }
  10.382 +}
  10.383 +
  10.384 +
  10.385 +
  10.386 +
  10.387 +// Decodes input (unsigned char) into output (UINT4). Assumes len is
  10.388 +// a multiple of 4.
  10.389 +void MD5::decode (uint4 *output, uint1 *input, uint4 len){
  10.390 +
  10.391 +  unsigned int i, j;
  10.392 +
  10.393 +  for (i = 0, j = 0; j < len; i++, j += 4)
  10.394 +    output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
  10.395 +      (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
  10.396 +}
  10.397 +
  10.398 +
  10.399 +
  10.400 +
  10.401 +
  10.402 +// Note: Replace "for loop" with standard memcpy if possible.
  10.403 +void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){
  10.404 +
  10.405 +  unsigned int i;
  10.406 +
  10.407 +  for (i = 0; i < len; i++)
  10.408 +    output[i] = input[i];
  10.409 +}
  10.410 +
  10.411 +
  10.412 +
  10.413 +// Note: Replace "for loop" with standard memset if possible.
  10.414 +void MD5::memset (uint1 *output, uint1 value, uint4 len){
  10.415 +
  10.416 +  unsigned int i;
  10.417 +
  10.418 +  for (i = 0; i < len; i++)
  10.419 +    output[i] = value;
  10.420 +}
  10.421 +
  10.422 +
  10.423 +
  10.424 +// ROTATE_LEFT rotates x left n bits.
  10.425 +
  10.426 +inline unsigned int MD5::rotate_left  (uint4 x, uint4 n){
  10.427 +  return (x << n) | (x >> (32-n))  ;
  10.428 +}
  10.429 +
  10.430 +
  10.431 +
  10.432 +
  10.433 +// F, G, H and I are basic MD5 functions.
  10.434 +
  10.435 +inline unsigned int MD5::F            (uint4 x, uint4 y, uint4 z){
  10.436 +  return (x & y) | (~x & z);
  10.437 +}
  10.438 +
  10.439 +inline unsigned int MD5::G            (uint4 x, uint4 y, uint4 z){
  10.440 +  return (x & z) | (y & ~z);
  10.441 +}
  10.442 +
  10.443 +inline unsigned int MD5::H            (uint4 x, uint4 y, uint4 z){
  10.444 +  return x ^ y ^ z;
  10.445 +}
  10.446 +
  10.447 +inline unsigned int MD5::I            (uint4 x, uint4 y, uint4 z){
  10.448 +  return y ^ (x | ~z);
  10.449 +}
  10.450 +
  10.451 +
  10.452 +
  10.453 +// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
  10.454 +// Rotation is separate from addition to prevent recomputation.
  10.455 +
  10.456 +
  10.457 +inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
  10.458 +		    uint4  s, uint4 ac){
  10.459 + a += F(b, c, d) + x + ac;
  10.460 + a = rotate_left (a, s) +b;
  10.461 +}
  10.462 +
  10.463 +inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
  10.464 +		    uint4 s, uint4 ac){
  10.465 + a += G(b, c, d) + x + ac;
  10.466 + a = rotate_left (a, s) +b;
  10.467 +}
  10.468 +
  10.469 +inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
  10.470 +		    uint4 s, uint4 ac){
  10.471 + a += H(b, c, d) + x + ac;
  10.472 + a = rotate_left (a, s) +b;
  10.473 +}
  10.474 +
  10.475 +inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
  10.476 +			     uint4 s, uint4 ac){
  10.477 + a += I(b, c, d) + x + ac;
  10.478 + a = rotate_left (a, s) +b;
  10.479 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/sourcepawn/jit/md5/md5.h	Thu Aug 09 01:54:43 2012 +0100
    11.3 @@ -0,0 +1,106 @@
    11.4 +// MD5.CC - source code for the C++/object oriented translation and 
    11.5 +//          modification of MD5.
    11.6 +
    11.7 +// Translation and modification (c) 1995 by Mordechai T. Abzug 
    11.8 +
    11.9 +// This translation/ modification is provided "as is," without express or 
   11.10 +// implied warranty of any kind.
   11.11 +
   11.12 +// The translator/ modifier does not claim (1) that MD5 will do what you think 
   11.13 +// it does; (2) that this translation/ modification is accurate; or (3) that 
   11.14 +// this software is "merchantible."  (Language for this disclaimer partially 
   11.15 +// copied from the disclaimer below).
   11.16 +
   11.17 +/* based on:
   11.18 +
   11.19 +   MD5.H - header file for MD5C.C
   11.20 +   MDDRIVER.C - test driver for MD2, MD4 and MD5
   11.21 +
   11.22 +   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
   11.23 +rights reserved.
   11.24 +
   11.25 +License to copy and use this software is granted provided that it
   11.26 +is identified as the "RSA Data Security, Inc. MD5 Message-Digest
   11.27 +Algorithm" in all material mentioning or referencing this software
   11.28 +or this function.
   11.29 +
   11.30 +License is also granted to make and use derivative works provided
   11.31 +that such works are identified as "derived from the RSA Data
   11.32 +Security, Inc. MD5 Message-Digest Algorithm" in all material
   11.33 +mentioning or referencing the derived work.
   11.34 +
   11.35 +RSA Data Security, Inc. makes no representations concerning either
   11.36 +the merchantability of this software or the suitability of this
   11.37 +software for any particular purpose. It is provided "as is"
   11.38 +without express or implied warranty of any kind.
   11.39 +
   11.40 +These notices must be retained in any copies of any part of this
   11.41 +documentation and/or software.
   11.42 +
   11.43 +*/
   11.44 +
   11.45 +#include <stdio.h>
   11.46 +//#include <fstream.h>
   11.47 +//#include <iostream.h>
   11.48 +
   11.49 +class MD5 {
   11.50 +
   11.51 +public:
   11.52 +// methods for controlled operation:
   11.53 +  MD5              ();  // simple initializer
   11.54 +  void  update     (unsigned char *input, unsigned int input_length);
   11.55 +  void  update     (FILE *file);
   11.56 +  void  finalize   ();
   11.57 +
   11.58 +// constructors for special circumstances.  All these constructors finalize
   11.59 +// the MD5 context.
   11.60 +  MD5              (unsigned char *string); // digest string, finalize
   11.61 +  MD5              (FILE *file);            // digest file, close, finalize
   11.62 +
   11.63 +// methods to acquire finalized result
   11.64 +  unsigned char    *raw_digest ();  // digest as a 16-byte binary array
   11.65 +  unsigned char		*raw_digest(unsigned char buffer[16]);
   11.66 +  char *            hex_digest ();  // digest as a 33-byte ascii-hex string
   11.67 +  char *			hex_digest (char buffer[33]); //same as above, passing buffer
   11.68 +
   11.69 +
   11.70 +
   11.71 +private:
   11.72 +
   11.73 +// first, some types:
   11.74 +  typedef unsigned       int uint4; // assumes integer is 4 words long
   11.75 +  typedef unsigned short int uint2; // assumes short integer is 2 words long
   11.76 +  typedef unsigned      char uint1; // assumes char is 1 word long
   11.77 +
   11.78 +// next, the private data:
   11.79 +  uint4 state[4];
   11.80 +  uint4 count[2];     // number of *bits*, mod 2^64
   11.81 +  uint1 buffer[64];   // input buffer
   11.82 +  uint1 digest[16];
   11.83 +  uint1 finalized;
   11.84 +
   11.85 +// last, the private methods, mostly static:
   11.86 +  void init             ();               // called by all constructors
   11.87 +  void transform        (uint1 *buffer);  // does the real update work.  Note 
   11.88 +                                          // that length is implied to be 64.
   11.89 +
   11.90 +  static void encode    (uint1 *dest, uint4 *src, uint4 length);
   11.91 +  static void decode    (uint4 *dest, uint1 *src, uint4 length);
   11.92 +  static void memcpy    (uint1 *dest, uint1 *src, uint4 length);
   11.93 +  static void memset    (uint1 *start, uint1 val, uint4 length);
   11.94 +
   11.95 +  static inline uint4  rotate_left (uint4 x, uint4 n);
   11.96 +  static inline uint4  F           (uint4 x, uint4 y, uint4 z);
   11.97 +  static inline uint4  G           (uint4 x, uint4 y, uint4 z);
   11.98 +  static inline uint4  H           (uint4 x, uint4 y, uint4 z);
   11.99 +  static inline uint4  I           (uint4 x, uint4 y, uint4 z);
  11.100 +  static inline void   FF  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
  11.101 +			    uint4 s, uint4 ac);
  11.102 +  static inline void   GG  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
  11.103 +			    uint4 s, uint4 ac);
  11.104 +  static inline void   HH  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
  11.105 +			    uint4 s, uint4 ac);
  11.106 +  static inline void   II  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
  11.107 +			    uint4 s, uint4 ac);
  11.108 +
  11.109 +};