<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tony Tannous</title>
    <description>The latest articles on DEV Community by Tony Tannous (@tonytannous).</description>
    <link>https://dev.to/tonytannous</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F259308%2F0415d0e9-01b2-4c90-80ac-d1806a9bd689.png</url>
      <title>DEV Community: Tony Tannous</title>
      <link>https://dev.to/tonytannous</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tonytannous"/>
    <language>en</language>
    <item>
      <title>Teradata RDBMS: Generating HMAC SHA256, MD5 and SHA1 Hashes</title>
      <dc:creator>Tony Tannous</dc:creator>
      <pubDate>Wed, 04 Mar 2020 22:52:50 +0000</pubDate>
      <link>https://dev.to/tonytannous/teradata-rdbms-generating-hmac-sha256-md5-and-sha1-hashes-14eh</link>
      <guid>https://dev.to/tonytannous/teradata-rdbms-generating-hmac-sha256-md5-and-sha1-hashes-14eh</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AWuzOs-q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zrjrlu6hbmxp4uyr7tw3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AWuzOs-q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zrjrlu6hbmxp4uyr7tw3.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've come across Teradata User-Defined-Functions (UDF) for generating non key-based hashes (such as MD5 &amp;amp; SHA256) but have yet to come across Teradata HMAC equivalents of these (yet).&lt;/p&gt;

&lt;p&gt;That was a good enough reason to work on developing a C/C++ UDF to cover HMAC MD5/SHA256/SHA1 hashing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Need for Hashing?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Data Science/Analytics on Personally Identifiable Information (PII)
&lt;/h3&gt;

&lt;p&gt;➤ Presenting data in its hashed format via Views within the RDBMS allows sensitive attributes to be exposed in their obfuscated/masked format&lt;/p&gt;

&lt;p&gt;➤ Exposing hashed data to a wider audience for analytical purposes mitigates the risks of potential PII "data leaks". Hashing may not be an option for all situations, but should be the first option considered before being ruled out&lt;/p&gt;

&lt;p&gt;Of the three algorithms covered in this article, HMAC-SHA256 provides a cryptographically stronger hash, which is less susceptible to hash collisions and brute force attacks&lt;/p&gt;

&lt;h3&gt;
  
  
  Transmission of Data
&lt;/h3&gt;

&lt;p&gt;➤ Hashing can also add an extra layer of security in cases where transmitting data extracts outside an organization to external partners is required&lt;/p&gt;

&lt;p&gt;➤ Hashed data can be exported directly from Teradata into file extracts, which are encrypted (e.g. using PGP) before transmission&lt;/p&gt;

&lt;p&gt;➤ Breaking the "outer layer" encryption (e.g the PGP'd file), ensures the "inner layer" (i.e hashed content) remains secure&lt;/p&gt;

&lt;h2&gt;
  
  
  Guidelines for HMAC
&lt;/h2&gt;

&lt;p&gt;The RFC2104¹ spec for HMAC states the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2. Definition of HMAC&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;The definition of HMAC requires a cryptographic hash function, which&lt;br&gt;
we denote by H, and a secret key K. We assume H to be a cryptographic&lt;br&gt;
hash function where data is hashed by iterating a basic compression&lt;br&gt;
function on blocks of data. We denote by B the byte-length of such&lt;br&gt;
blocks…and by L the byte-length of hash outputs…The authentication key K can be of any length up to B, the block length of the hash function. Applications that use keys longer than B bytes will first hash the key using H and then use the resultant L byte string as the actual key to HMAC. In any case the minimal recommended length for K is L bytes (as the hash output length).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Keys&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;The key for HMAC can be of any length (keys longer than B bytes are&lt;br&gt;
first hashed using H). However, less than L bytes is strongly&lt;br&gt;
discouraged as it would decrease the security strength of the&lt;br&gt;
function. Keys longer than L bytes are acceptable but the extra&lt;br&gt;
length would not significantly increase the function strength. (A&lt;br&gt;
longer key may be advisable if the randomness of the key is&lt;br&gt;
considered weak.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Keys need to be chosen at random (or using a cryptographically strong&lt;br&gt;
pseudo-random generator seeded with a random seed), and periodically&lt;br&gt;
refreshed. (Current attacks do not indicate a specific recommended&lt;br&gt;
frequency for key changes as these attacks are practically&lt;br&gt;
infeasible. However, periodic key refreshment is a fundamental&lt;br&gt;
security practice that helps against potential weaknesses of the&lt;br&gt;
function and keys, and limits the damage of an exposed key.)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's break down the excerpts above and put them into context for the algorithms discussed in this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Length
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;H&lt;/strong&gt; refers to the &lt;strong&gt;Hash&lt;/strong&gt; algorithms, so for our case that equates to MD5, SHA256 &amp;amp; SHA1&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B&lt;/strong&gt; refers to the respective algorithm's &lt;strong&gt;Blocksize&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;L&lt;/strong&gt; refers to the &lt;strong&gt;Length&lt;/strong&gt; *of the hash output, in bytes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;K&lt;/strong&gt; refers to the secret &lt;strong&gt;Key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By referencing the spec² details for each algorithm, we get the following&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Output Size (L) &lt;br&gt;(bits/bytes)&lt;/th&gt;
&lt;th&gt;Block Size (B) &lt;br&gt;(bits/bytes)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MD5&lt;/td&gt;
&lt;td&gt;128/16&lt;/td&gt;
&lt;td&gt;512/64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA1&lt;/td&gt;
&lt;td&gt;160/20&lt;/td&gt;
&lt;td&gt;512/64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA256&lt;/td&gt;
&lt;td&gt;256/32&lt;/td&gt;
&lt;td&gt;512/64&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;➤ What length should we choose for our secret &lt;em&gt;Key (&lt;/em&gt;&lt;em&gt;K&lt;/em&gt;&lt;em&gt;)?&lt;/em&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The key for HMAC&lt;/em&gt; &lt;strong&gt;&lt;em&gt;can be of any length&lt;/em&gt;&lt;/strong&gt; (keys longer than B bytes are first hashed using H). However, &lt;strong&gt;&lt;em&gt;less than L bytes is strongly discouraged&lt;/em&gt;&lt;/strong&gt; as it would decrease the security strength of the function. &lt;strong&gt;&lt;em&gt;Keys longer than L bytes are acceptable but the extra length would not significantly increase the function strength&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➤ Reading between the lines, the &lt;strong&gt;Key&lt;/strong&gt; &lt;em&gt;size&lt;/em&gt; (in bytes), should be equal to &lt;strong&gt;L (the respective algorithm's Output Size).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;➤ On that basis, these are the recommended key lengths for each algorithm we're covering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    MD5    : K = 128/16 (bits/bytes)
    SHA1   : K = 160/20 (bits/bytes)
    SHA256 : K = 256/32 (bits/bytes)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Generating a Secret Key (K)
&lt;/h3&gt;

&lt;p&gt;The RFC2104 excerpts from above, also tells us that secret keys should be generated using a "&lt;em&gt;Cryptographically Strong Pseudo-Random (Number) Generator&lt;/em&gt;" (CSPRNG).&lt;/p&gt;

&lt;p&gt;The literature on generating secure random numbers is vast and deserves a separate topic for discussion. It's also a topic where I'm still working my way through. A good starting point into gaining an understanding can be found at the following links.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.redhat.com/en/blog/understanding-random-number-generators-and-their-limitations-linux"&gt;Understanding random number generators, and their limitations, in Linux&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator"&gt;Cryptographically secure pseudorandom number generator&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki//dev/random#Linux"&gt;Linux Kernel &amp;amp; Random Number Generators&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For now, we'll assume that we're using a Linux OS that generates random, secure bytes at &lt;code&gt;/dev/urandom&lt;/code&gt;, which we'll use to source our secret key/s.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;hexdump&lt;/code&gt;, we can source the number of bytes we need for each algorithm as follows (bearing in mind what has already been discussed regarding the recommended key length).&lt;/p&gt;

&lt;p&gt;➤ For MD5:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    hexdump -C -n 16/dev/urandom

    ca5af32a784e22de51df623bf13f51b1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;➤ For SHA1:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    hexdump -C -n 20/dev/urandom

    0f04ae0aa54db11c0c53dc36fbefbac27e099dbf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;➤ For SHA256:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    hexdump -C -n 32 /dev/urandom

    6e670ed3e0ebf1daf7570f5f83b45ed48d6df3848c09f38c319c8df3fa5dfc41
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;➤ It's imperative that thought is given into the security measures for preventing exposure of secret key/s outside of a controlled environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  How/Where Should the Keys be Stored?
&lt;/h3&gt;

&lt;p&gt;Again, this also warrants a separate topic for discussion. The UDF accepts the key as a parameter.&lt;/p&gt;

&lt;p&gt;So, how do we securely pass the key value to the UDF?&lt;/p&gt;

&lt;p&gt;➤ Storing the key in a Teradata database table, in its raw format is an option that would likely cause security experts to frown&lt;/p&gt;

&lt;p&gt;➤ Using this approach, however, can serve as an interim solution for purposes of testing scenarios, or proof-of-concept where the key/s are "throw-away" keys used solely for hashing fake/test data&lt;/p&gt;

&lt;p&gt;If you decide that the risk of storing your key in a table is acceptable in a Production environment, then a possible approach would be:&lt;/p&gt;

&lt;p&gt;➤ Use a &lt;em&gt;correlated sub-query&lt;/em&gt; to retrieve the key value as input to the UDF&lt;/p&gt;

&lt;p&gt;➤ The correlated sub-query should return a single row/column which contains the key value&lt;/p&gt;

&lt;p&gt;➤ This ensures the key remains protected in a secure RDBMS table, governed by appropriate security/access control measures&lt;/p&gt;

&lt;p&gt;Here are some points to note if you do decide to go down this path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The key/s should not be loaded using Client utilities such as SQL Assistant, BTEQ. For example, the following statement:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT INTO myproj.k_store (KEY_NAME, KEY_VALUE) 
VALUES (
'hmac_sha256_key'
,'XXXXXXXXXXXXXXXX'
)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;would expose the key value (&lt;strong&gt;XXXXXXXXXXXXXXXX&lt;/strong&gt;) in Teradata's Query (&lt;code&gt;dbc.dbql*&lt;/code&gt;) and Access log (&lt;code&gt;dbc.accesslog&lt;/code&gt;) tables/views&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Instead, look into loading the key/s from a file using Teradata TPT Operators, for which parameter values are not resolved in the Query and Access log tables/views&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once the key has been loaded, its value should never be hard coded into SQL queries/qualifiers (unless it's a throw away key used solely for "sandpit" testing). As an example, the following query would expose the key's value in the RDBMS log tables:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * 
FROM myproj.k_store
WHERE KEY_VALUE = 'XXXXXXXXXXXXXXXX'        
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As mentioned earlier, a correlated sub-query can be used to retrieve the key's value as input to the UDF. Examples of this will be demonstrated later in this article&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensure the key is generated on a machine that conforms to security standards (i.e, encrypted storage, attached to secure network, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  UDF Dependencies
&lt;/h2&gt;

&lt;p&gt;Below are the pre-requisite libraries/headers required for compiling the UDF.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hash Libraries
&lt;/h3&gt;

&lt;p&gt;The UDF utilises headers and functions from this &lt;a href="https://create.stephan-brumme.com/hash-library/"&gt;library&lt;/a&gt;³. The relevant dependencies will be included "as-is" in the &lt;a href="https://github.com/tonys-code-base/teradata-hmac-hash-udf.git"&gt;git repo&lt;/a&gt; for the UDF code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Header File for Teradata Equivalent C Data Types
&lt;/h3&gt;

&lt;p&gt;The sqltypes_td.h header file contains Teradata data types and their equivalent "C" types. It is also included in the UDF repo. It was downloaded "as-is" from a 16.20 Teradata Express VM (directory /usr/tdbms/etc).&lt;/p&gt;

&lt;h2&gt;
  
  
  UDF Installation
&lt;/h2&gt;

&lt;p&gt;➤ Clone the UDF git repo&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    git clone https://github.com/tonys-code-base/teradata-hmac-hash-udf.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or download as a.zip and extract locally&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   https://github.com/tonys-code-base/teradata-hmac-hash-udf/archive/master.zip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;➤ Ensure you have sufficient privileges to install the UDF on the target Teradata database&lt;/p&gt;

&lt;p&gt;➤ Modify the UDF &lt;code&gt;CREATE FUNCTION&lt;/code&gt; code (&lt;code&gt;create_hmac_hash_function.sql&lt;/code&gt;) so that it reflects the correct target database for your installation&lt;/p&gt;

&lt;p&gt;➤ Open a shell/command prompt and change directory into the location where the repo was cloned/unzipped to&lt;/p&gt;

&lt;p&gt;➤ Run &lt;code&gt;BTEQ&lt;/code&gt;, and execute the modified version of &lt;code&gt;create_hmac_hash_function.sql&lt;/code&gt; to install the UDF&lt;/p&gt;

&lt;p&gt;➤ Once complete, the UDF appears as:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;database_name&amp;gt;.hmac_hash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Loading Keys into a Teradata Table
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Please read details under sub-heading "&lt;strong&gt;How/Where Should the Keys be Stored?&lt;/strong&gt;" before continuing&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Table Format
&lt;/h3&gt;

&lt;p&gt;Keys will be loaded into a secure Teradata table with the following structure&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    CREATE TABLE myproj.k_store 
         (
          key_name VARCHAR(30) CHARACTER SET LATIN NOT CASESPECIFIC,
          key_value VARCHAR(512) CHARACTER SET LATIN CASESPECIFIC
       )
    PRIMARY INDEX ( key_name )
    ;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;where:&lt;/p&gt;

&lt;p&gt;◼ &lt;strong&gt;key_name:&lt;/strong&gt; represents the hmac key identifier&lt;br&gt;
◼ &lt;strong&gt;key_value:&lt;/strong&gt; contains the respective secret key value&lt;/p&gt;

&lt;h3&gt;
  
  
  Save Keys to File on Encrypted Drive
&lt;/h3&gt;

&lt;p&gt;Each of the keys that were generated previously under sub-heading "&lt;strong&gt;&lt;em&gt;Generating a Secret Key (K)&lt;/em&gt;&lt;/strong&gt;" can now be saved into a pipe (|) delimited text file ready for loading into the target table.&lt;/p&gt;

&lt;p&gt;➤ Create the file as shown below, saving the keys, as previously generated&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;hmac_sample_keys.txt&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    h_md5_key|ca5af32a784e22de51df623bf13f51b1
    h_sha1_key|0f04ae0aa54db11c0c53dc36fbefbac27e099dbf
    h_sha256_key|6e670ed3e0ebf1daf7570f5f83b45ed48d6df3848c09f38c319c8df3fa5dfc41
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Load Keys using Teradata Parallel Transporter (TPT)
&lt;/h3&gt;

&lt;p&gt;The following TPT script (available in the repo) can be used to load the hmac_sample_keys.txt into the target table.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    USING CHARACTER SET ASCII
    DEFINE JOB Load_Hmac_Keys
    DESCRIPTION 'Load of Keys into Target Table k_store'
    (

        DEFINE SCHEMA hmac_metadata
        DESCRIPTION 'Input hmac_metadata.data Layout Definition'
        (
            key_name    VARCHAR(30),
            key_value   varchar(64)
        );

        APPLY ('INSERT INTO myproj.k_store ( 
            :key_name
            ,:key_value
            );'
        )

        TO OPERATOR ($INSERTER()[1] ATTR (
                TdpId = '&amp;lt;Teradata_Host/IP&amp;gt;'
                ,UserName = '&amp;lt;Teradata_Username&amp;gt;'
                ,UserPassword = '&amp;lt;Teradata_Password&amp;gt;'
                ,PrivateLogName = 'insert_priv_log'
            )
        )

        SELECT * FROM OPERATOR ( 
            $FILE_READER (hmac_metadata)[1]    ATTR (
                FileName = 'hmac_sample_keys.txt'
                     ,Format = 'Delimited'
                     ,DirectoryPath = '.'
            )
        );
    );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;➤ Modify the above script and replace the following to reflect your setup:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;Teradata_Host/IP&amp;gt;
    &amp;lt;Teradata_Username&amp;gt;
    &amp;lt;Teradata_Password&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;➤ You will also need to change the database name from &lt;strong&gt;myproj&lt;/strong&gt;to reflect the location of table k_store for your setup.&lt;/p&gt;

&lt;p&gt;➤ Execute the script using:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    tbuild -f tpt_sample_load_k_store.script -j tpt_sample_load_k_store -s 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  UDF Parameters
&lt;/h2&gt;

&lt;p&gt;The UDF takes in 3 parameters:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    hmac_hashmsg, secret_key, hmac_hash_type
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;◼ &lt;strong&gt;msg&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The "raw" text to be hashed&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Data Type: VARCHAR(2500) CHARACTER SET LATIN
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;◼ &lt;strong&gt;secret_key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The "secret_key" must be the character representation of &lt;em&gt;valid&lt;/em&gt; &lt;strong&gt;HEX bytes&lt;/strong&gt;, used as input into the hmac hash algorithm&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Data Type: VARCHAR(512) CHARACTER SET LATIN
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Examples of acceptable format values are as shown below. Note, these are hard-coded here only to illustrate format, please refer to sub-heading "&lt;em&gt;How/Where Should the Keys be Stored?&lt;/em&gt;" :&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    hmac_hash(msg, '6173646667686a6b6c666531', hmac_hash_type)
    hmac_hash(msg, '6f61696679726568666b6a32', hmac_hash_type)
    hmac_hash(msg, '696f6a666566656665667733', hmac_hash_type)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;◼ &lt;strong&gt;hmac_hash_type&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This parameter defines the output hmac hash type that is required. &lt;br&gt;
Data Type: VARCHAR(30)&lt;/p&gt;

&lt;p&gt;If this parameter value is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;hmac_sha256:&lt;/strong&gt; Then a HMAC SHA256 output hash is generated&lt;br&gt;
&lt;strong&gt;hmac_md5:&lt;/strong&gt; Then a HMAC MD5 output hash is generated&lt;br&gt;
&lt;strong&gt;hmac_sha1:&lt;/strong&gt; Then a HMAC SHA1 output hash is generated&lt;/p&gt;

&lt;h3&gt;
  
  
  "Fetching" the SECRET_KEY as Input to UDF
&lt;/h3&gt;

&lt;p&gt;Using a correlated sub-query, we can obtain the key without exposing it in Teradata's log tables by substituting the following query as input to the SECRET_KEY UDF Parameter:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    SELECT key_value FROM myproj.k_store WHERE key_name = '&amp;lt;key_name&amp;gt;';
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  UDF Usage Examples
&lt;/h2&gt;

&lt;p&gt;The examples of UDF invocations that follow assume the following:&lt;/p&gt;

&lt;p&gt;➤ The test Secret Keys used are sourced from table myproj.k_store&lt;/p&gt;

&lt;p&gt;➤ The UDF has been installed to target database MYPROJ&lt;/p&gt;

&lt;p&gt;➤ The message (MSG) being hashed is &lt;br&gt;
"The quick brown fox jumps over the lazy dog."&lt;/p&gt;
&lt;h3&gt;
  
  
  HMAC SHA256 hash Example
&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    SELECT MYPROJ.hmac_hash(
    'The quick brown fox jumps over the lazy dog.'

    ,(SELECT key_value 
    FROM myproj.k_store WHERE key_name= 'h_sha256_key')
    'HMAC_SHA256'
    )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Output:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    bb60d08740527e04c95f8d7c615a9e5c425951192913976c04c3f3419fa61004
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  HMAC MD5 hash Example
&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    SELECT MYPROJ.hmac_hash(
    'The quick brown fox jumps over the lazy dog.'

    ,(SELECT key_value 
    FROM myproj.k_store WHERE key_name = 'h_md5_key')
    ,'HMAC_MD5'
    )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Output:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    d74a6e93a5bc07422e3e18db7de13bc4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  HMAC SHA1 hash Example
&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    SELECT MYPROJ.hmac_hash(
    'The quick brown fox jumps over the lazy dog.'

    ,(SELECT key_value 
    FROM myproj.k_store WHERE key_name = 'h_sha1_key')
    ,'HMAC_SHA1'
    )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Output:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    9aa16612fc822e77a149896701f65c4aa64d7614
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Closing Comments
&lt;/h2&gt;

&lt;p&gt;➤ Once the UDF has been thoroughly tested, its execution mode can be changed to NON PROTECTED&lt;/p&gt;

&lt;p&gt;➤ The secret_key bytes, as read from /dev/urandom are treated as single 8 bit bytes (base16) loaded into a Teradata column defined as LATIN (server character set). They will not all decode to printable characters&lt;/p&gt;

&lt;p&gt;➤ If you're curious to see the decoded hex key, you can look at using the udf_LatinHex2Char UDF which comes as part of the &lt;a href="https://downloads.teradata.com/download/tools/unicode-tool-kit"&gt;Teradata Unicode ToolKit&lt;/a&gt; , or try running&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select 'XXXXXXXXXXXX'xc 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;where XXXXXXXXXXXX is your secret key in base16 hex. The xc tells Teradata that input is a string of character bytes, represented in hex format.&lt;/p&gt;

&lt;p&gt;➤ You may wish to add a SALT to the input string/MSG for additional security. This should also ideally be generated in the same way as the secret_key&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;[1]:&lt;a href="https://tools.ietf.org/html/rfc2104"&gt; RFC 2104 — HMAC: Keyed-Hashing for Message Authentication&lt;/a&gt;. &lt;br&gt;
(Feb 1997). &lt;em&gt;Definition of HMAC. Keys.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;[2]:&lt;a href="https://tools.ietf.org/html/rfc2104"&gt; &lt;/a&gt;&lt;a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithms"&gt;en.wikipedia.org&lt;/a&gt;. &lt;br&gt;
(Updated Jan 2020). &lt;a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithms"&gt;Secure Hash Algorithms&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[3]:&lt;a href="https://tools.ietf.org/html/rfc2104"&gt; &lt;/a&gt;&lt;a href="https://create.stephan-brumme.com/hash-library/"&gt;Portable C++ Hashing Library&lt;/a&gt;. &lt;br&gt;
(Jun 2014) &lt;a href="https://create.stephan-brumme.com/hash-library/"&gt;*create.stephan-brumme.com&lt;/a&gt;*&lt;/p&gt;

</description>
      <category>hmac</category>
      <category>teradata</category>
      <category>hash</category>
      <category>sha</category>
    </item>
  </channel>
</rss>
