8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 16:43:03 +01:00

Moved cryptographic hashes to separate function crypt_hash(), crc32 - into function hash()

This commit is contained in:
AlexPeshkoff 2020-08-26 18:46:53 +03:00
parent 9900e56cbc
commit e9f3eb360d
8 changed files with 164 additions and 121 deletions

View File

@ -361,18 +361,26 @@ Example:
select cot(x) from y;
-----
CRC32
-----
----------
CRYPT_HASH
----------
Function:
Returns CRC-32 with the polynomial 0x04C11DB7. Accepts argument of any type.
Returns a cryptograpic hash of an argument using a specified algorithm.
Format:
CRC32( <any value> )
CRYPT_HASH( <any value> USING <algorithm> )
algorithm ::= { MD5 | SHA1 | SHA256 | SHA512 }
Important:
- This function returns VARCHAR strings with OCTETS charset with length depended on algorithm.
- MD5 and SHA1 algorithms are not recommended for use due to known severe issues, that algorithms
are provided ONLY for backward compatibility.
Example:
select crc32(job_title) from job;
select crypt_hash(x using sha256) from y;
-------
@ -560,21 +568,25 @@ HASH
----
Function:
Returns a HASH of a string using a specified algorithm.
Returns a hash of an argument using a specified algorithm.
Format:
HASH( <string> [ USING <algorithm> ] )
HASH( <any value> [ USING <algorithm> ] )
algorithm ::= { MD5 | SHA1 | SHA256 | SHA512 }
algorithm ::= { CRC32 }
Important:
- The syntax without USING is very discouraged and maintained for backward compatibility.
It returns a 64 bit integer and produces very bad hashes that easily result in collisions.
- The syntax with USING is introduced in FB 4.0 and returns VARCHAR strings with OCTETS charset.
- The syntax with USING is introduced in FB 4.0 and returns an integer of appropriate size.
- Implemented in firebird CRC32 is using polynomial 0x04C11DB7.
Example:
select hash(x) from y;
select hash(x using sha256) from y;
select hash(x using crc32) from y;
-----------------------------

View File

@ -22,6 +22,7 @@
#include "firebird.h"
#include "../common/classes/Hash.h"
#include "../common/dsc.h"
#if defined(_M_IX86) || defined(_M_X64) || defined(__x86_64__) || defined(__i386__)
#ifdef _MSC_VER
@ -126,8 +127,7 @@ void WeakHashContext::update(const void* data, FB_SIZE_T length)
}
}
void WeakHashContext::finish(Buffer& result)
void WeakHashContext::finish(dsc& result)
{
UCHAR* resultBuffer = result.getBuffer(sizeof(hashNumber));
memcpy(resultBuffer, &hashNumber, sizeof(hashNumber));
result.makeInt64(0, &hashNumber);
}

View File

@ -30,6 +30,8 @@
#include "../common/classes/array.h"
struct dsc;
namespace Firebird
{
template <typename K>
@ -341,12 +343,8 @@ namespace Firebird
}
};
class HashContext
{
public:
typedef HalfStaticArray<UCHAR, 256> Buffer;
public:
virtual ~HashContext()
{
@ -354,14 +352,14 @@ namespace Firebird
public:
virtual void update(const void* data, FB_SIZE_T length) = 0;
virtual void finish(Buffer& result) = 0;
virtual void finish(dsc& result) = 0;
};
class WeakHashContext FB_FINAL : public HashContext
{
public:
virtual void update(const void* data, FB_SIZE_T length);
virtual void finish(Buffer& result);
virtual void finish(dsc& result);
private:
SINT64 hashNumber = 0;
@ -383,11 +381,12 @@ namespace Firebird
public:
virtual void update(const void* data, FB_SIZE_T length);
virtual void finish(Buffer& result);
virtual void finish(dsc& result);
private:
const Descriptor* descriptor;
State* statePtr;
UCharBuffer buffer;
};
class Md5HashContext FB_FINAL : public LibTomCryptHashContext
@ -413,6 +412,22 @@ namespace Firebird
public:
Sha512HashContext(MemoryPool& pool);
};
class Crc32HashContext FB_FINAL : public HashContext
{
public:
Crc32HashContext(MemoryPool& pool);
~Crc32HashContext();
virtual void update(const void* data, FB_SIZE_T length);
virtual void finish(dsc& result);
private:
struct State;
State* statePtr;
SLONG hash;
};
} // namespace Firebird
#endif // CLASSES_HASH_H

View File

@ -24,6 +24,8 @@
#include "firebird.h"
#include "../common/classes/Hash.h"
#include "../common/dsc.h"
#include "../intl/charsets.h"
#if !defined(__GNUC__) || defined(__clang__)
#define LTC_NO_ASM // disable ASM in tomcrypt headers
@ -45,9 +47,10 @@ struct LibTomCryptHashContext::State
LibTomCryptHashContext::LibTomCryptHashContext(MemoryPool& pool, const Descriptor* aDescriptor)
: descriptor(aDescriptor)
: descriptor(aDescriptor),
statePtr(FB_NEW_POOL(pool) State),
buffer(pool)
{
statePtr = FB_NEW_POOL(pool) State();
descriptor->tcDesc->init(&statePtr->tcState);
}
@ -61,10 +64,11 @@ void LibTomCryptHashContext::update(const void* data, FB_SIZE_T length)
descriptor->tcDesc->process(&statePtr->tcState, static_cast<const UCHAR*>(data), length);
}
void LibTomCryptHashContext::finish(Buffer& result)
void LibTomCryptHashContext::finish(dsc& result)
{
unsigned char* hashResult = result.getBuffer(descriptor->tcDesc->hashsize);
unsigned char* hashResult = buffer.getBuffer(descriptor->tcDesc->hashsize);
descriptor->tcDesc->done(&statePtr->tcState, hashResult);
result.makeText(descriptor->tcDesc->hashsize, CS_BINARY, hashResult);
}
@ -98,3 +102,37 @@ Sha512HashContext::Sha512HashContext(MemoryPool& pool)
: LibTomCryptHashContext(pool, &sha512Descriptor)
{
}
struct Crc32HashContext::State
{
State()
{
crc32_init(&ctx);
}
crc32_state ctx;
};
Crc32HashContext::Crc32HashContext(MemoryPool& pool)
{
statePtr = FB_NEW_POOL(pool) State();
}
Crc32HashContext::~Crc32HashContext()
{
delete statePtr;
}
void Crc32HashContext::update(const void* data, FB_SIZE_T length)
{
crc32_update(&statePtr->ctx, static_cast<const UCHAR*>(data), length);
}
void Crc32HashContext::finish(dsc& result)
{
crc32_finish(&statePtr->ctx, &hash, sizeof hash);
result.makeLong(0, &hash);
}

View File

@ -145,9 +145,9 @@ static const TOK tokens[] =
{TOK_COUNTER, "COUNTER", true},
{TOK_COVAR_POP, "COVAR_POP", false},
{TOK_COVAR_SAMP, "COVAR_SAMP", false},
{TOK_CRC32, "CRC32", true},
{TOK_CREATE, "CREATE", false},
{TOK_CROSS, "CROSS", false},
{TOK_CRYPT_HASH, "CRYPT_HASH", true},
{TOK_CSTRING, "CSTRING", true},
{TOK_CTR_BIG_ENDIAN, "CTR_BIG_ENDIAN", true},
{TOK_CTR_LENGTH, "CTR_LENGTH", true},

View File

@ -1 +1 @@
60 shift/reduce conflicts, 17 reduce/reduce conflicts.
61 shift/reduce conflicts, 17 reduce/reduce conflicts.

View File

@ -457,7 +457,6 @@ using namespace Firebird;
%token <metaNamePtr> COS
%token <metaNamePtr> COSH
%token <metaNamePtr> COT
%token <metaNamePtr> CRC32
%token <metaNamePtr> DATEADD
%token <metaNamePtr> DATEDIFF
%token <metaNamePtr> DECODE
@ -599,6 +598,7 @@ using namespace Firebird;
%token <metaNamePtr> COMPARE_DECFLOAT
%token <metaNamePtr> CONSISTENCY
%token <metaNamePtr> COUNTER
%token <metaNamePtr> CRYPT_HASH
%token <metaNamePtr> CTR_BIG_ENDIAN
%token <metaNamePtr> CTR_LENGTH
%token <metaNamePtr> CTR_LITTLE_ENDIAN
@ -8067,7 +8067,6 @@ system_function_std_syntax
| COS
| COSH
| COT
| CRC32
| EXP
| FLOOR
| GEN_UUID
@ -8152,7 +8151,7 @@ system_function_special_syntax
}
| HASH '(' value ')'
{ $$ = newNode<SysFuncCallNode>(*$1, newNode<ValueListNode>($3)); }
| HASH '(' value USING valid_symbol_name ')'
| hash_func '(' value USING valid_symbol_name ')'
{
$$ = newNode<SysFuncCallNode>(*$1,
newNode<ValueListNode>($3)->add(MAKE_str_constant(newIntlString($5->c_str()), CS_ASCII)));
@ -8211,6 +8210,11 @@ system_function_special_syntax
}
;
%type <metaNamePtr> hash_func
hash_func
: HASH | CRYPT_HASH
;
%type <metaNamePtr> rsa_encrypt_decrypt
rsa_encrypt_decrypt
: RSA_DECRYPT | RSA_ENCRYPT
@ -8948,7 +8952,7 @@ non_reserved_word
| COMPARE_DECFLOAT
| CONNECTIONS
| CONSISTENCY
| CRC32
| CRYPT_HASH
| CTR_BIG_ENDIAN
| CTR_LENGTH
| CTR_LITTLE_ENDIAN

View File

@ -125,7 +125,7 @@ struct HashAlgorithmDescriptor
USHORT length;
HashContext* (*create)(MemoryPool&);
static const HashAlgorithmDescriptor* find(const char* name);
static const HashAlgorithmDescriptor* find(const HashAlgorithmDescriptor** hashDescriptor, const MetaName name);
};
template <typename T>
@ -149,21 +149,25 @@ struct HashAlgorithmDescriptorFactory
template <typename T> HashAlgorithmDescriptor HashAlgorithmDescriptorFactory<T>::desc;
static const HashAlgorithmDescriptor* hashAlgorithmDescriptors[] = {
static const HashAlgorithmDescriptor* cryptHashAlgorithmDescriptors[] = {
HashAlgorithmDescriptorFactory<Md5HashContext>::getInstance("MD5", 16),
HashAlgorithmDescriptorFactory<Sha1HashContext>::getInstance("SHA1", 20),
HashAlgorithmDescriptorFactory<Sha256HashContext>::getInstance("SHA256", 32),
HashAlgorithmDescriptorFactory<Sha512HashContext>::getInstance("SHA512", 64)
HashAlgorithmDescriptorFactory<Sha512HashContext>::getInstance("SHA512", 64),
nullptr
};
const HashAlgorithmDescriptor* HashAlgorithmDescriptor::find(const char* name)
{
unsigned count = FB_NELEM(hashAlgorithmDescriptors);
static const HashAlgorithmDescriptor* hashAlgorithmDescriptors[] = {
HashAlgorithmDescriptorFactory<Crc32HashContext>::getInstance("CRC32", 4),
nullptr
};
for (unsigned i = 0; i < count; ++i)
const HashAlgorithmDescriptor* HashAlgorithmDescriptor::find(const HashAlgorithmDescriptor** hashDescriptor, const MetaName name)
{
for (; *hashDescriptor; hashDescriptor++)
{
if (strcmp(name, hashAlgorithmDescriptors[i]->name) == 0)
return hashAlgorithmDescriptors[i];
if (name == (*hashDescriptor)->name)
return *hashDescriptor;
}
status_exception::raise(Arg::Gds(isc_sysf_invalid_hash_algorithm) << name);
@ -171,6 +175,22 @@ const HashAlgorithmDescriptor* HashAlgorithmDescriptor::find(const char* name)
}
const HashAlgorithmDescriptor* getHashAlgorithmDesc(thread_db* tdbb, const SysFunction* function, const dsc* algDsc, bool* cHash = nullptr)
{
bool cryptHash = (strcmp(function->name, "CRYPT_HASH") == 0);
if (cHash)
*cHash = cryptHash;
if (!algDsc->dsc_address || !algDsc->isText())
status_exception::raise(Arg::Gds(isc_sysf_invalid_hash_algorithm) << "<not a string constant>");
MetaName algorithmName;
MOV_get_metaname(tdbb, algDsc, algorithmName);
return HashAlgorithmDescriptor::find(cryptHash ? cryptHashAlgorithmDescriptors : hashAlgorithmDescriptors, algorithmName);
}
// constants
const int oneDay = 86400;
const unsigned getContextLen = 255;
@ -200,6 +220,7 @@ void setParamsDateDiff(DataTypeUtilBase* dataTypeUtil, const SysFunction* functi
void setParamsEncrypt(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args);
void setParamsFirstLastDay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
void setParamsGetSetContext(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
void setParamsHash(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args);
void setParamsMakeDbkey(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
void setParamsOverlay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
void setParamsPosition(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
@ -268,7 +289,6 @@ dsc* evlBin(thread_db* tdbb, const SysFunction* function, const NestValueArray&
dsc* evlBinShift(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlCeil(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlCharToUuid(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlCrc32(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlDateDiff(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlDecode64(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
@ -761,6 +781,14 @@ void setParamsGetSetContext(DataTypeUtilBase*, const SysFunction*, int argsCount
}
void setParamsHash(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args)
{
fb_assert(argsCount == 1 || argsCount == 2);
setParamVarying(args[0], ttype_binary);
}
void setParamsMakeDbkey(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args)
{
// MAKE_DBKEY ( REL_NAME | REL_ID, RECNUM [, DPNUM [, PPNUM] ] )
@ -1275,13 +1303,22 @@ void makeHash(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc*
makeInt64Result(dataTypeUtil, function, result, argsCount, args);
else if (argsCount >= 2)
{
if (!args[1]->dsc_address || !args[1]->isText()) // not a constant
status_exception::raise(Arg::Gds(isc_sysf_invalid_hash_algorithm) << "<not a string constant>");
bool cryptHash;
const HashAlgorithmDescriptor* d = getHashAlgorithmDesc(JRD_get_thread_data(), function, args[1], &cryptHash);
MetaName algorithmName;
MOV_get_metaname(JRD_get_thread_data(), args[1], algorithmName);
result->makeVarying(HashAlgorithmDescriptor::find(algorithmName.c_str())->length, ttype_binary);
if (cryptHash)
result->makeVarying(d->length, ttype_binary);
else
{
switch(d->length)
{
case 4:
result->makeLong(0);
break;
default:
fb_assert(false);
}
}
result->setNullable(args[0]->isNullable());
}
}
@ -3330,50 +3367,6 @@ dsc* evlEncodeHex(thread_db* tdbb, const SysFunction* function, const NestValueA
return evlEncodeDecodeHex(tdbb, true, function, args, impure);
}
dsc* evlCrc32(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure)
{
crc32_state ctx;
crc32_init(&ctx);
const dsc* arg = EVL_expr(tdbb, tdbb->getRequest(), args[0]);
if (!arg) // return NULL if value is NULL
return NULL;
if (arg->isBlob())
{
blb* blob = blb::open2(tdbb, tdbb->getRequest()->req_transaction, reinterpret_cast<const bid*>(arg->dsc_address),
sizeof(streamBpb), streamBpb);
UCHAR buf[4096];
for(;;)
{
const unsigned l = blob->BLB_get_data(tdbb, buf, sizeof buf, false);
if (!l)
break;
crc32_update(&ctx, buf, l);
}
blob->BLB_close(tdbb);
}
else
{
unsigned len;
const UCHAR* ptr = CVT_get_bytes(arg, len);
crc32_update(&ctx, ptr, len);
}
SLONG hash;
crc32_finish(&ctx, &hash, sizeof hash);
dsc result;
result.makeLong(0, &hash);
EVL_make_value(tdbb, &result, impure);
return &impure->vlu_desc;
}
dsc* evlRsaEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestValueArray& args,
impure_value* impure, bool encryptFlag)
{
@ -4558,7 +4551,7 @@ dsc* evlGetTranCN(thread_db* tdbb, const SysFunction* function, const NestValueA
}
dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
dsc* evlHash(thread_db* tdbb, const SysFunction* function, const NestValueArray& args,
impure_value* impure)
{
fb_assert(args.getCount() >= 1);
@ -4578,12 +4571,8 @@ dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
if (request->req_flags & req_null) // return NULL if algorithm is NULL
return NULL;
if (!algorithmDesc->isText())
status_exception::raise(Arg::Gds(isc_sysf_invalid_hash_algorithm) << "<not a string constant>");
MetaName algorithmName;
MOV_get_metaname(tdbb, algorithmDesc, algorithmName);
hashContext.reset(HashAlgorithmDescriptor::find(algorithmName.c_str())->create(pool));
const HashAlgorithmDescriptor* d = getHashAlgorithmDesc(tdbb, function, algorithmDesc);
hashContext.reset(d->create(pool));
}
else
{
@ -4607,29 +4596,14 @@ dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
}
else
{
UCHAR* address;
MoveBuffer buffer;
const ULONG length = MOV_make_string2(tdbb, value, value->getTextType(), &address, buffer, false);
hashContext->update(address, length);
unsigned len;
const UCHAR* ptr = CVT_get_bytes(value, len);
hashContext->update(ptr, len);
}
HashContext::Buffer resultBuffer;
hashContext->finish(resultBuffer);
if (args.getCount() >= 2)
{
dsc result;
result.makeText(resultBuffer.getCount(), ttype_binary, resultBuffer.begin());
EVL_make_value(tdbb, &result, impure);
}
else
{
fb_assert(resultBuffer.getCount() == sizeof(SINT64));
memcpy(&impure->vlu_misc.vlu_int64, resultBuffer.begin(), sizeof(SINT64));
// make descriptor for return value
impure->vlu_desc.makeInt64(0, &impure->vlu_misc.vlu_int64);
}
dsc result;
hashContext->finish(result);
EVL_make_value(tdbb, &result, impure);
return &impure->vlu_desc;
}
@ -6369,7 +6343,6 @@ const SysFunction SysFunction::functions[] =
{"ATAN2", 2, 2, setParamsDouble, makeDoubleResult, evlAtan2, NULL},
{"BASE64_DECODE", 1, 1, NULL, makeDecode64, evlDecode64, NULL},
{"BASE64_ENCODE", 1, 1, NULL, makeEncode64, evlEncode64, NULL},
{"CRC32", 1, 1, NULL, makeLongResult, evlCrc32, NULL},
{"BIN_AND", 2, -1, setParamsBin, makeBin, evlBin, (void*) funBinAnd},
{"BIN_NOT", 1, 1, setParamsBin, makeBin, evlBin, (void*) funBinNot},
{"BIN_OR", 2, -1, setParamsBin, makeBin, evlBin, (void*) funBinOr},
@ -6385,6 +6358,7 @@ const SysFunction SysFunction::functions[] =
{"COS", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCos},
{"COSH", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCosh},
{"COT", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCot},
{"CRYPT_HASH", 2, 2, setParamsHash, makeHash, evlHash, NULL},
{"DATEADD", 3, 3, setParamsDateAdd, makeDateAdd, evlDateAdd, NULL},
{"DATEDIFF", 3, 3, setParamsDateDiff, makeInt64Result, evlDateDiff, NULL},
{"DECRYPT", 7, 7, setParamsEncrypt, makeDecrypt, evlDecrypt, NULL},
@ -6393,7 +6367,7 @@ const SysFunction SysFunction::functions[] =
{"FIRST_DAY", 2, 2, setParamsFirstLastDay, makeFirstLastDayResult, evlFirstLastDay, (void*) funFirstDay},
{"FLOOR", 1, 1, setParamsDblDec, makeCeilFloor, evlFloor, NULL},
{"GEN_UUID", 0, 0, NULL, makeUuid, evlGenUuid, NULL},
{"HASH", 1, 2, NULL, makeHash, evlHash, NULL},
{"HASH", 1, 2, setParamsHash, makeHash, evlHash, NULL},
{"HEX_DECODE", 1, 1, NULL, makeDecodeHex, evlDecodeHex, NULL},
{"HEX_ENCODE", 1, 1, NULL, makeEncodeHex, evlEncodeHex, NULL},
{"LAST_DAY", 2, 2, setParamsFirstLastDay, makeFirstLastDayResult, evlFirstLastDay, (void*) funLastDay},