Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Added 8 new builtin functions supporting various encryption algorithms
  • Loading branch information
AlexPeshkoff committed Dec 7, 2018
1 parent 9c3b96d commit aacdeb2
Show file tree
Hide file tree
Showing 10 changed files with 1,419 additions and 2 deletions.
148 changes: 148 additions & 0 deletions doc/sql.extensions/README.builtin_functions.txt
Expand Up @@ -12,6 +12,7 @@ Authors:
Oleg Loa <loa@mail.ru>
Alexey Karyakin <aleksey.karyakin@mail.ru>
Claudio Valderrama C. <cvalde at usa.net>
Alexander Peshkov <peshkoff@mail.ru>


---
Expand Down Expand Up @@ -415,6 +416,40 @@ Example:
select decode(state, 0, 'deleted', 1, 'active', 'unknown') from things;


-------------------
ENCRYPT and DECRYPT
-------------------

Function:
Encrypts/decrypts data using symmetric cipher.

Format:
{ENCRYPT | DECRYPT} ( <string | blob> USING <algorithm> [MODE <mode>] KEY <string> \
[IV <string>] [<endianness>] [CTR_LENGTH <smallint>] [COUNTER <bigint>])

algorithm ::= { block_cipher | stream_cipher }
block_cipher ::= { AES | ANUBIS | BLOWFISH | KHAZAD | RC5 | RC6 | SAFER+ | TWOFISH | XTEA }
stream_cipher ::= { CHACHA20 | RC4 | SOBER128 }
mode ::= { CBC | CFB | CTR | ECB | OFB }
endianness ::= { CTR_BIG_ENDIAN | CTR_LITTLE_ENDIAN }

Important:
- Mode should be specified for block ciphers.
- Initialization vector (IV) should be specified for block ciphers in all modes except ECB and
all stream ciphers except RC4.
- Endianness may be specified only in CTR mode, default is little endian counter.
- Counter length (CTR_LENGTH, bytes) may be specified only in CTR mode, default is the size of IV.
- Initial counter value (COUNTER) may be specified only for CHACHA20 cipher, default is 0.
- Sizes of data strings passed to this functions are according to selected algorithm and mode
requirements.
- Functions return BLOB when first argument is blob and varbinary for all text types.

Example:
select encrypt('897897' using sober128 key 'AbcdAbcdAbcdAbcd' iv '01234567') from rdb$database;
select decrypt(x'0154090759DF' using sober128 key 'AbcdAbcdAbcdAbcd' iv '01234567') from rdb$database;
select decrypt(secret_field using aes mode ofb key '0123456701234567' iv init_vector) from secure_table;


---
EXP
---
Expand Down Expand Up @@ -872,6 +907,119 @@ Example:
select rpad(x, 10) from y;


-----------
RSA_PRIVATE
-----------

Function:
Returns RSA private key of specified length (in bytes) in PKCS#1 format as VARBINARY atring.

This comment has been minimized.

Copy link
@dmitry-lipetsk

dmitry-lipetsk Dec 7, 2018

Contributor

a<<tring

string?

This comment has been minimized.

Copy link
@AlexPeshkoff

AlexPeshkoff Dec 7, 2018

Author Member

definitely yes


Format:
RSA_PRIVATE ( <smallint> )

Example:
select rdb$set_context('USER_SESSION', 'private_key', rsa_private(256)) from rdb$database;


----------
RSA_PUBLIC
----------

Function:
Returns RSA public key for specified RSA private key, all keys are in PKCS#1 format.

Format:
RSA_PUBLIC ( <private key> )

Example:
(tip - start running samples one by one from RSA_PRIVATE function)
select rdb$set_context('USER_SESSION', 'public_key',
rsa_public(rdb$get_context('USER_SESSION', 'private_key'))) from rdb$database;


-----------
RSA_ENCRYPT
-----------

Function:
Pads data using OAEP padding and encrypts using RSA public key. Normally used to encrypt
short symmetric keys which are then used in block ciphers to encrypt a message.

Format:
RSA_ENCRYPT ( <string> KEY <public key> [LPARAM <string>] [HASH <hash>] )
KEY should be a value, returhed by RSA_PUBLIC function.
LPARAM is an additional system specific tag that can be applied to identify which
system encoded the message. Default value is NULL.
hash ::= { MD5 | SHA1 | SHA256 | SHA512 } Default is SHA256.

Example:
(tip - start running samples one by one from RSA_PRIVATE function)
select rdb$set_context('USER_SESSION', 'msg', rsa_encrypt('Some message'
key rdb$get_context('USER_SESSION', 'public_key'))) from rdb$database;


-----------
RSA_DECRYPT
-----------

Function:
Decrypts using RSA private key and OAEP de-pads the resulting data.

Format:
RSA_DECRYPT ( <string> KEY <private key> [LPARAM <string>] [HASH <hash>] )
KEY should be a value, returhed by RSA_PRIVATE function.
LPARAM is the same variable passed to RSA_ENCRYPT. If it does not match
what was used during encoding this function will not decrypt the packet.
hash ::= { MD5 | SHA1 | SHA256 | SHA512 } Default is SHA256.

Example:
(tip - start running samples one by one from RSA_PRIVATE function)
select rsa_decrypt(rdb$get_context('USER_SESSION', 'msg')
key rdb$get_context('USER_SESSION', 'private_key')) from rdb$database;


--------
RSA_SIGN
--------

Function:
Performs PSS encoding of message digest to be signed and signs using RSA private key.

Format:
RSA_SIGN ( <string> KEY <private key> [HASH <hash>] [SALT_LENGTH <smallint>] )
KEY should be a value, returhed by RSA_PRIVATE function.
hash ::= { MD5 | SHA1 | SHA256 | SHA512 } Default is SHA256.
SALT_LENGTH indicates the length of the desired salt, and should typically be small.
A good value is between 8 and 16.

Example:
(tip - start running samples one by one from RSA_PRIVATE function)
select rdb$set_context('USER_SESSION', 'msg', rsa_sign(hash('Test message' using sha256)
key rdb$get_context('USER_SESSION', 'private_key'))) from rdb$database;


----------
RSA_VERIFY
----------

Function:
Performs PSS encoding of message digest to be signed and verifies it's digital signature
using RSA public key.

Format:
RSA_VERIFY ( <string> SIGNATURE <string> KEY <public key> [HASH <hash>] [SALT_LENGTH <smallint>] )
SIGNATURE should be a value, returhed by RSA_SIGN function.
KEY should be a value, returhed by RSA_PUBLIC function.
hash ::= { MD5 | SHA1 | SHA256 | SHA512 } Default is SHA256.
SALT_LENGTH indicates the length of the desired salt, and should typically be small.
A good value is between 8 and 16.

Example:
(tip - start running samples one by one from RSA_PRIVATE function)
select rsa_verify(hash('Test message' using sha256) signature rdb$get_context('USER_SESSION', 'msg')
key rdb$get_context('USER_SESSION', 'public_key')) from rdb$database;


----
SIGN
----
Expand Down
8 changes: 8 additions & 0 deletions src/common/classes/fb_string.cpp
Expand Up @@ -28,6 +28,7 @@

#include "firebird.h"
#include "../common/classes/fb_string.h"
#include "../common/classes/MetaName.h"

#include <ctype.h>
#include <stdarg.h>
Expand Down Expand Up @@ -95,6 +96,13 @@ namespace Firebird
memcpy(stringBuffer, v.c_str(), v.length());
}

AbstractString::AbstractString(const size_type limit, const MetaName& v)
: max_length(static_cast<internal_size_type>(limit))
{
initialize(v.length());
memcpy(stringBuffer, v.c_str(), v.length());
}

AbstractString::AbstractString(const size_type limit, const size_type sizeL, const void* dataL)
: max_length(static_cast<internal_size_type>(limit))
{
Expand Down
4 changes: 4 additions & 0 deletions src/common/classes/fb_string.h
Expand Up @@ -41,6 +41,8 @@

namespace Firebird
{
class MetaName;

class AbstractString : private AutoStorage
{
public:
Expand Down Expand Up @@ -163,6 +165,7 @@ namespace Firebird
const_pointer p2, const size_type n2);

AbstractString(const size_type limit, const AbstractString& v);
AbstractString(const size_type limit, const MetaName& v);

explicit AbstractString(const size_type limit) :
max_length(static_cast<internal_size_type>(limit)),
Expand Down Expand Up @@ -644,6 +647,7 @@ namespace Firebird
public:
StringBase() : AbstractString(Comparator::getMaxLength()) {}
StringBase(const StringType& v) : AbstractString(Comparator::getMaxLength(), v) {}
explicit StringBase(const MetaName& v) : AbstractString(Comparator::getMaxLength(), v) {}
StringBase(const void* s, size_type n) : AbstractString(Comparator::getMaxLength(), n, s) {}
StringBase(const_pointer s) : AbstractString(Comparator::getMaxLength(), static_cast<size_type>(strlen(s)), s) {}
explicit StringBase(const unsigned char* s) :
Expand Down
41 changes: 41 additions & 0 deletions src/common/cvt.cpp
Expand Up @@ -3050,6 +3050,47 @@ DecimalFixed CVT_get_dec_fixed(const dsc* desc, SSHORT scale, DecimalStatus decS
}


const UCHAR* CVT_get_bytes(const dsc* desc, unsigned& size)
{
/**************************************
*
* C V T _ g e t _ b y t e s
*
**************************************
*
* Functional description
* Return raw data of descriptor.
*
**************************************/
if (!desc)
{
size = 0;
return nullptr;
}

switch (desc->dsc_dtype)
{
case dtype_varying:
{
vary* v = (vary*)(desc->dsc_address);
size = v->vary_length;
return (const UCHAR*)v->vary_string;
}

case dtype_cstring:
size = strlen((const char*)desc->dsc_address);
return desc->dsc_address;

default:
size = desc->dsc_length;
return desc->dsc_address;
break;
}

return nullptr; // compiler warning silencer
}


SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err)
{
/**************************************
Expand Down
1 change: 1 addition & 0 deletions src/common/cvt.h
Expand Up @@ -102,5 +102,6 @@ SINT64 CVT_get_int64(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction)
SQUAD CVT_get_quad(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
void CVT_string_to_datetime(const dsc*, ISC_TIMESTAMP_TZ*, bool*, const Firebird::EXPECT_DATETIME,
bool, Firebird::Callbacks*);
const UCHAR* CVT_get_bytes(const dsc*, unsigned&);

#endif //COMMON_CVT_H

0 comments on commit aacdeb2

Please sign in to comment.