mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 16:57:16 +01:00
240 lines
8.2 KiB
C++
240 lines
8.2 KiB
C++
// ------------------------------------------------------------------------------------------------
|
|
#include "Library/Crypt.hpp"
|
|
#include "Base/Shared.hpp"
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <sqstdstring.h>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <crc32.h>
|
|
#include <keccak.h>
|
|
#include <md5.h>
|
|
#include <sha1.h>
|
|
#include <sha256.h>
|
|
#include <sha3.h>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
namespace SqMod {
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
SQInteger AES256::Typename(HSQUIRRELVM vm)
|
|
{
|
|
static SQChar name[] = _SC("SqAES");
|
|
sq_pushstring(vm, name, sizeof(name));
|
|
return 1;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
AES256::AES256()
|
|
: m_Context(), m_Buffer()
|
|
{
|
|
aes256_done(&m_Context);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
AES256::AES256(CSStr key)
|
|
: m_Context(), m_Buffer()
|
|
{
|
|
Init(key);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Int32 AES256::Cmp(const AES256 & o) const
|
|
{
|
|
return memcmp(m_Buffer, o.m_Buffer, sizeof(m_Buffer));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr AES256::ToString() const
|
|
{
|
|
return ToStrF("%s", m_Buffer);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr AES256::GetKey() const
|
|
{
|
|
return reinterpret_cast< CSStr >(m_Buffer);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void AES256::Init(CSStr key)
|
|
{
|
|
// Clear current key, if any
|
|
aes256_done(&m_Context);
|
|
// Is the specified key empty?
|
|
if (!key || *key == 0)
|
|
return; // Leave the context with an empty key
|
|
// Obtain the specified key size
|
|
const Uint32 size = (strlen(key) * sizeof(SQChar));
|
|
// See if the key size is accepted
|
|
if (size > sizeof(m_Buffer))
|
|
SqThrowF("The specified key is out of bounds: %u > %u", size, sizeof(m_Buffer));
|
|
// Initialize the key buffer to 0
|
|
memset(m_Buffer, 0, sizeof(m_Buffer));
|
|
// Copy the key into the key buffer
|
|
memcpy(m_Buffer, key, size);
|
|
// Initialize the context with the specified key
|
|
aes256_init(&m_Context, m_Buffer);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void AES256::Done()
|
|
{
|
|
aes256_done(&m_Context);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
String AES256::Encrypt(CSStr data)
|
|
{
|
|
// Is there any data to encrypt?
|
|
if (!data || *data == 0)
|
|
return String();
|
|
// Copy the data into an editable string
|
|
String str(data);
|
|
// Make sure that we have a size with a multiple of 16
|
|
if ((str.size() % 16) != 0)
|
|
str.resize(str.size() - (str.size() % 16) + 16);
|
|
// Encrypt in chunks of 16 characters
|
|
for (Uint32 n = 0; n < str.size(); n += 16)
|
|
aes256_encrypt_ecb(&m_Context, reinterpret_cast< Uint8 * >(&str[n]));
|
|
// Return ownership of the encrypted string
|
|
return std::move(str);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
String AES256::Decrypt(CSStr data)
|
|
{
|
|
// Is there any data to decrypt?
|
|
if (!data || *data == 0)
|
|
return String();
|
|
// Copy the data into an editable string
|
|
String str(data);
|
|
// Make sure that we have a size with a multiple of 16
|
|
if ((str.size() % 16) != 0)
|
|
str.resize(str.size() - (str.size() % 16) + 16);
|
|
// Decrypt inc chunks of 16 characters
|
|
for (Uint32 n = 0; n < str.size(); n += 16)
|
|
aes256_decrypt_ecb(&m_Context, reinterpret_cast< Uint8 * >(&str[n]));
|
|
// Remove null characters in case the string was not a multiple of 16 when encrypted
|
|
while (!str.empty() && str.back() == 0)
|
|
str.pop_back();
|
|
// Return ownership of the encrypted string
|
|
return std::move(str);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Utility to avoid creating encoder instances for each call.
|
|
*/
|
|
template < class T > struct BaseHash
|
|
{
|
|
static T Algo;
|
|
};
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
template < class T > T BaseHash< T >::Algo;
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Hash the specified value or the result of a formatted string.
|
|
*/
|
|
template < class T > static SQInteger HashF(HSQUIRRELVM vm)
|
|
{
|
|
const Int32 top = sq_gettop(vm);
|
|
// Was the hash value specified?
|
|
if (top <= 1)
|
|
return sq_throwerror(vm, "Missing hash value");
|
|
// Do we have enough values to call the format function?
|
|
else if (top > 2)
|
|
{
|
|
SStr val = NULL;
|
|
SQInteger len = 0;
|
|
// Attempt to generate the specified string format
|
|
SQRESULT ret = sqstd_format(vm, 2, &len, &val);
|
|
// Did the format failed?
|
|
if (SQ_FAILED(ret))
|
|
return ret; // Propagate the exception
|
|
// Hash the resulted string
|
|
String str(BaseHash< T >::Algo(val));
|
|
// Push the string on the stack
|
|
sq_pushstring(vm, str.data(), str.size());
|
|
}
|
|
else
|
|
{
|
|
// Attempt to retrieve the value from the stack as a string
|
|
Var< CSStr > val(vm, 2);
|
|
// See if the obtained value is a valid string
|
|
if (!val.value)
|
|
return sq_throwerror(vm, "Unable to retrieve the value");
|
|
// Hash the resulted string
|
|
String str(BaseHash< T >::Algo(val.value));
|
|
// Push the string on the stack
|
|
sq_pushstring(vm, str.data(), str.size());
|
|
}
|
|
// At this point we have a valid string on the stack
|
|
return 1;
|
|
}
|
|
|
|
// ================================================================================================
|
|
template < class T > static void RegisterWrapper(Table & hashns, CCStr cname)
|
|
{
|
|
typedef HashWrapper< T > Hash;
|
|
hashns.Bind(cname, Class< Hash >(hashns.GetVM(), cname)
|
|
/* Constructors */
|
|
.Ctor()
|
|
/* Metamethods */
|
|
.Func(_SC("_tostring"), &Hash::ToString)
|
|
/* Properties */
|
|
.Prop(_SC("Hash"), &Hash::GetHash)
|
|
/* Functions */
|
|
.Func(_SC("Reset"), &Hash::Reset)
|
|
.Func(_SC("Compute"), &Hash::Compute)
|
|
.Func(_SC("GetHash"), &Hash::GetHash)
|
|
.Func(_SC("Add"), &Hash::AddStr)
|
|
.Func(_SC("AddStr"), &Hash::AddStr)
|
|
);
|
|
}
|
|
|
|
// ================================================================================================
|
|
void Register_Crypt(HSQUIRRELVM vm)
|
|
{
|
|
Table hashns(vm);
|
|
|
|
RegisterWrapper< CRC32 >(hashns, _SC("CRC32"));
|
|
RegisterWrapper< Keccak >(hashns, _SC("Keccak"));
|
|
RegisterWrapper< MD5 >(hashns, _SC("MD5"));
|
|
RegisterWrapper< SHA1 >(hashns, _SC("SHA1"));
|
|
RegisterWrapper< SHA256 >(hashns, _SC("SHA256"));
|
|
RegisterWrapper< SHA3 >(hashns, _SC("SHA3"));
|
|
|
|
hashns.SquirrelFunc(_SC("GetCRC32"), &HashF< CRC32 >);
|
|
hashns.SquirrelFunc(_SC("GetKeccak"), &HashF< Keccak >);
|
|
hashns.SquirrelFunc(_SC("GetMD5"), &HashF< MD5 >);
|
|
hashns.SquirrelFunc(_SC("GetSHA1"), &HashF< SHA1 >);
|
|
hashns.SquirrelFunc(_SC("GetSHA256"), &HashF< SHA256 >);
|
|
hashns.SquirrelFunc(_SC("GetSHA3"), &HashF< SHA3 >);
|
|
|
|
RootTable(vm).Bind(_SC("SqHash"), hashns);
|
|
|
|
RootTable(vm).Bind("SqAES256", Class< AES256 >(vm, "SqAES256")
|
|
/* Constructors */
|
|
.Ctor()
|
|
.Ctor< CSStr >()
|
|
/* Metamethods */
|
|
.Func(_SC("_cmp"), &AES256::Cmp)
|
|
.SquirrelFunc(_SC("_typename"), &AES256::Typename)
|
|
.Func(_SC("_tostring"), &AES256::ToString)
|
|
/* Properties */
|
|
.Prop(_SC("Key"), &AES256::GetKey)
|
|
/* Functions */
|
|
.Func(_SC("Init"), &AES256::Init)
|
|
.Func(_SC("Done"), &AES256::Done)
|
|
.Func(_SC("Encrypt"), &AES256::Encrypt)
|
|
.Func(_SC("Decrypt"), &AES256::Decrypt)
|
|
);
|
|
}
|
|
|
|
} // Namespace:: SqMod
|