1. Function: Create_HASH function

  1. Function: Create_HASH function
    1. A practical example
  2. Function Create_HMAC

This function creates a md5, sha1, sha256, sha384, or sha512 hash of a source string. This is used in security functions to protect data; to avoid storing clear text passwords, and in some API calls a hash key is required. When sending data and a hash key, the receiver can verify if the data has been tampered with in transit.

Hashing is not encryption, as it is impossible to decrypt and get the original data. However, the slightest change in the data will produce a completely different hash.

A note about MD5

The MD5 hashing function is considered outdated and should not be used for new cryptographic applications, particularly where security is a concern. This is because MD5 is no longer considered cryptographically secure due to vulnerabilities that allow for collision attacks (where two different inputs produce the same hash).

While MD5 is deprecated for secure applications, it is still used in some contexts where cryptographic security is not a primary concern, such as checksums for file integrity verification in non-security-critical situations. However, for any new development, especially in security-related applications, it's recommended to use more secure hash functions like SHA-256

Prototype:

string hash = create_hash ( hash method, data, encoding); 

Parameters:

Parameter name  Type  Description
Hash method  Int  Use the constants: md5, sha1, sha256, sha384 or sha512
data  string  any string containing file content, encrypted text, or anything you want to create a hash from
encoding  Int  Output encoding, use the constants: hexenc or base64enc

Return value: Type String : The hash value

Example:

I set up a test based on the works of myiako (4d Common crypto plugin). He has a test for his plugin, which I adopted to test and validate the functions based on an external source.

// helper function to validate the tests. 
function assert ( string a1, string a2, string message )
    if ( a1 != a2 ) then
        throw "Error: " + message;
    end if
    return true; 
end

// The main test function. 
function test_hashFunctions ()
    bool a; 
    string source = "Hello World!"; 
    try
        // MD5
        a = assert(create_hash(md5, source, base64enc), "7Qdih1MuhjZehB6Sv8UNjA==", "MD5/Base64 failed");
        a = assert(create_hash(md5, source, hexenc), "ed076287532e86365e841e92bfc50d8c", "MD5/Hex failed");

        // SHA1
        a = assert(create_hash(sha1, source, base64enc), "Lve95gjOVATpfV8EL5X4nxwjKHE=", "SHA1/Base64 failed");
        a = assert(create_hash(sha1, source, hexenc), "2ef7bde608ce5404e97d5f042f95f89f1c232871", "SHA1/Hex failed");

        // SHA256
        a = assert(create_hash(sha256, source, base64enc), "f4OxZX/x/FO5LcGBSKHWXfwtSx+j1ncoSt3SABJtkGk=", "SHA256/Base64 failed");
        a = assert(create_hash(sha256, source, hexenc), "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069", "SHA256/Hex failed");

        // SHA384
        a = assert(create_hash(sha384, source, base64enc), "v9dsDrvQBv7lg0EFR8GIewKSvnbVgtlsJC0qeScj4/1v0GH51c/RO4+WE1jmrbpK", "SHA384/Base64 failed");
        a = assert(create_hash(sha384, source, hexenc), "bfd76c0ebbd006fee583410547c1887b0292be76d582d96c242d2a792723e3fd6fd061f9d5cfd13b8f961358e6adba4a", "SHA384/Hex failed");

        // SHA512
        a = assert(create_hash(sha512, source, base64enc), "hhhE1nBOhXP+w02WfiC8/vPUJM9IvgTm3AjyvVjHKXQzcQFerYkcw88cnTS0kmS1EHUbH/nlN5N7xGtdb/TsyA==", "SHA512/Base64 failed");
        a = assert(create_hash(sha512, source, hexenc), "861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8", "SHA512/Hex failed");
        
    
    catch
        alert ( "Error: " + last_error); 
        a = false; 
    end try
    return a; 
end
    

All the tests worked as expected, and the function returned true. I also tested to modify one of the result values to see that the assert logic worked as expected and it did.

1.1. A practical example

Let's say, you have a password stored in the database. As this is treated as insecure, let's modify the logic to make it secure. Instead of storing the clear text password in the database, let's store a sha512 version of the password instead, to make it secure. We use the create_hash function to hash the clear text password and store its result in the database. When we verify the password, we hash again the given clear password and compare the hashed result with the database.

Lets make an small ACF function to generate the hash:

function PasswordHash ( string clearPW )
    return create_hash(sha512, clearPW, hexenc); 
end

Then in the change password FileMaker script:

Set Field [Users::hashPassword; ACF_Run("PasswordHash";Users::ClearPW)]
Set Field [Users::ClearPW; ""]

Then to verify, lets say we have the given password in $GivenPassword

if [ACF_Run("PasswordHash";$GivenPassword) = Users::hashPassword]
# The password match, access granted
Else
# Wrong Password
    show custom dialog ["Wrong Password"; "Access denied"]
    Exit Application
End If

2. Function Create_HMAC

What is HMAC?

HMAC, short for Hash-based Message Authentication Code, is a specific construction for creating a message authentication code (MAC) involving a cryptographic hash function in combination with a secret cryptographic key. As an integral part of various security protocols and applications, HMAC provides both data integrity and authentication. The process involves applying a hash function to both the data to be authenticated and the secret key. The strength of HMAC lies in its use of the key, which makes it resistant to certain types of cryptographic attacks such as collision attacks. HMAC can be used with a variety of hash functions, such as MD5, SHA1, and SHA256, adapting to their respective length and strength. Commonly, HMAC is utilized in scenarios requiring secure message transmission over untrusted channels, digital signature implementations, and ensuring the authenticity and integrity of transmitted data. Its widespread adoption is a testament to its effectiveness in contemporary cryptographic practices.

Prototype:

string hash = create_hmac ( hash method, string key, string data, encoding)

Parameters:

Parameter name Type Description
Hash method Int Use the constants: md5, sha1, sha256, sha384 or sha512
key  string The key
data string any string containing file content, encrypted text, or anything you want to create a hash from
encoding Int Output encoding, use the constants: hexenc or base64enc

.

As we did with the HASH functions above, we implemented similar tests as in the test function above. We added these lines to the test:

// HMAC MD5
        a = assert(create_hmac(md5, key, source, base64enc), "AYH2AOvu2Cbt3Ef/hR9k7A==", "Failed HMAC MD5/base64");
        a = assert(create_hmac(md5, key, source, hexenc), "0181f600ebeed826eddc47ff851f64ec", "Failed HMAC MD5/hex");
        
        // HMAC SHA1
        a = assert(create_hmac(sha1, key, source, base64enc), "BwpO356r2gx9SYj3UFVvc/BfdVA=", "Failed HMAC SHA1/base64");
        a = assert(create_hmac(sha1, key, source, hexenc), "070a4edf9eabda0c7d4988f750556f73f05f7550", "Failed HMAC SHA1/hex");

       // HMAC SHA256
        a = assert(create_hmac(sha256, key, source, base64enc), "5z1prOAxmam9lz5nlHgudpxIhksTY8pClCivq7RUytQ=", "Failed HMAC SHA256/base64");
        a = assert(create_hmac(sha256, key, source, hexenc), "e73d69ace03199a9bd973e6794782e769c48864b1363ca429428afabb454cad4", "Failed HMAC SHA256/hex");

       // HMAC SHA384
        a = assert(create_hmac(sha384, key, source, base64enc), "UDZdkjSVyMpFJQu9dmeAlKg+LW97o6yq1pfBj3QZJM4YMmgZxkoUVVUzyMDcP3DT", "Failed HMAC SHA384/base64");
        a = assert(create_hmac(sha384, key, source, hexenc), "50365d923495c8ca45250bbd76678094a83e2d6f7ba3acaad697c18f741924ce18326819c64a14555533c8c0dc3f70d3", "Failed HMAC SHA384/hex");

       // HMAC SHA512
        a = assert(create_hmac(sha512, key, source, base64enc), "x38L+mMFPEM+QqGrPMOzx2l7rTlmNePxPdaYllFiLQm+G9K2Bf/9oQcci861HAF4NTNqsPZS8gPEiQ0KoznMlA==", "Failed HMAC SHA512/base64");
        a = assert(create_hmac(sha512, key, source, hexenc), "c77f0bfa63053c433e42a1ab3cc3b3c7697bad396635e3f13dd6989651622d09be1bd2b605fffda1071c8bceb51c017835336ab0f652f203c4890d0aa339cc94", "Failed HMAC SHA512/hex");

The test executed with no error, returning a as true.

References: