Watermark your data with hash value

In this video, I take a look at hash values, how the work and how you can use them in Business Central.

https://youtu.be/WMS1KhQC57o

In this video, Erik demonstrates how to use hash values in AL and Business Central. He explains the fundamental concept behind hashing, walks through the Cryptography Management codeunit available in the System Application, and shows practical uses including data integrity verification (watermarking), password storage concepts, salting, and change detection on records.

What Is a Hash Value?

A hash value is a fixed-size identifier calculated from an arbitrary amount of data. The key properties of a hash are:

  • One-way: You cannot reverse-engineer the original data from the hash value.
  • Deterministic: The same input always produces the same hash.
  • Sensitive to change: Even a single bit change in the source data produces a completely different hash.
  • Fixed size: Regardless of input size, the output is always the same length for a given algorithm.

Erik illustrates this with a simple analogy using the Windows calculator. If you take any number and apply mod 2, you always get either 0 or 1. That’s technically a hash — it’s a fixed-size result that you can’t reverse. Of course, mod 2 is a terrible hash algorithm because every number in the world maps to just two possible values, giving a 50/50 chance of collision. Real hash algorithms like SHA-256 produce outputs with astronomically low collision probability.

The Golden Rule: Do Not Roll Your Own Cryptography

Erik emphasizes one critical rule: do not create your own hash algorithm, encryption algorithm, or any cryptographic primitive. There are only a handful of people in the world who are truly qualified to design these systems, and they spend most of their time trying to break each other’s work. Even battle-tested software running for decades occasionally reveals vulnerabilities (like Heartbleed). Use the proven implementations that are already available to you.

The Cryptography Management Codeunit

Business Central’s System Application includes a Cryptography Management codeunit that provides hash generation functionality. It supports multiple hash algorithms:

  • MD5 — considered insecure; only use if required by an external system.
  • SHA-1 — also considered insecure; same caveat applies.
  • SHA-256 — the current de facto standard, considered secure. Produces a 256-bit (32-byte) hash.
  • SHA-384 — larger hash, more computation time.
  • SHA-512 — largest available, most computation time.

The codeunit provides two main functions for generating hashes:

  • GenerateHash(InputString, HashAlgorithm) — returns the hash as a hexadecimal string.
  • GenerateHashAsBase64String(InputString, HashAlgorithm) — returns the hash as a Base64-encoded string, which is shorter but contains the same information since it uses a larger character set.

The algorithm parameter is an option value indexed from zero (0 = MD5, 1 = SHA-1, 2 = SHA-256, etc.). As a minimum, use SHA-256 (option value 2) unless you have a specific reason to use something else.

Building a Hash Test Page

Erik builds a simple card page to demonstrate hash generation. The page has an input field, a hash output field, and actions to calculate hashes:

page 50100 "Hash Test"
{
    PageType = Card;
    layout
    {
        area(Content)
        {
            field(Input; Input)
            {
                CAption = 'Input';
                ApplicationArea = all;
                MultiLine = true;
            }
            field(Hash; Hash)
            {
                Caption = 'Hash';
                ApplicationArea = all;
            }
        }
    }
    actions
    {
        area(Processing)
        {
            action(Calc)
            {
                Caption = 'Calculate';
                ApplicationArea = all;
                Promoted = true;
                PromotedCategory = Process;
                PromotedOnly = True;
                trigger OnAction()
                var
                    Crypt: Codeunit "Cryptography Management";
                begin
                    Hash := Crypt.GenerateHashAsBase64String(Input, 2);
                end;
            }
            action(Customer)
            {
                Caption = 'Calculate Customer';
                ApplicationArea = all;
                Promoted = true;
                PromotedCategory = Process;
                PromotedOnly = True;
                trigger OnAction()
                var
                    Crypt: Codeunit "Cryptography Management";
                    Customer: Record Customer;
                begin
                    Customer.FindFirst();
                    Hash := Crypt.GenerateHash(format(Customer), 2);
                end;
            }
        }
    }
    var
        Input: Text;
        Hash: Text;
}

It’s essentially a one-liner to generate a hash: call Crypt.GenerateHash() or Crypt.GenerateHashAsBase64String() with your input and the algorithm option.

Demonstrating Hash Sensitivity

When Erik types “Erik Hougaard” and calculates the hash, he gets a specific value. Then he changes just the uppercase “E” to a lowercase “e” — and the entire hash is completely different. He then demonstrates changing a single character from “Hougaard” to “Hougabrd” (a single-bit difference behind the scenes), and again the hash is entirely different. This illustrates a crucial property of good hash algorithms: even the smallest change in the input produces a dramatically different output.

Practical Use Case 1: Password Storage

One classic use of hash values is password storage. Instead of storing the actual password, you store its hash. When a user logs in, you hash their input and compare it against the stored hash. If someone gains access to the stored hashes, they can’t directly determine the passwords — they would need to perform a computationally expensive trial-and-error process.

Practical Use Case 2: Data Integrity / Watermarking

Imagine you have a CSV file containing sensitive banking data — dates, account numbers, amounts, and receiving accounts. This file needs to travel from sender to receiver, and you need to guarantee it hasn’t been tampered with along the way.

The solution is to calculate a hash of the entire file contents and include that hash with the file (as the first line, last line, or however you choose). When the receiver gets the file, they calculate the hash of the data portion and verify it matches the included hash. If anyone modified even a single character in transit, the hashes won’t match.

Adding Salt for Extra Security

But what if an attacker modifies the data and simply recalculates the hash? This is where salting comes in. A salt is a secret value that you append to (or mix into) the data before hashing. Only the sender and the intended receiver know the salt. So even if an attacker changes the data and tries to recalculate the hash, they won’t know the salt and therefore can’t produce a valid hash.

The same technique applies to password storage: rather than hashing just the raw password, you add a secret salt before hashing. This makes it dramatically harder for an attacker who obtains the hash values to work backwards to the original passwords.

Practical Use Case 3: Change Detection on Records

Erik demonstrates another practical use: detecting whether a Business Central record has changed. Using a neat trick, he calls Format(Customer) to convert an entire customer record into a tab-separated text string, then hashes that string:

Customer.FindFirst();
Hash := Crypt.GenerateHash(Format(Customer), 2);

If you calculate this hash, store it, and then calculate it again later, you can instantly tell whether anything on that record has changed — without comparing field by field. This technique works on any data structure you can serialize to a string: records, JSON documents, XML, and so on.

If you haven’t seen the Format(Record) trick before, Erik mentions he has a separate video where he builds a search app using this technique to turn records into searchable strings.

Hexadecimal vs. Base64 Output

The two hash generation functions differ in their output encoding:

  • Hexadecimal (GenerateHash): Uses characters 0-9 and A-F. Each character represents 4 bits, so a SHA-256 hash produces a 64-character string.
  • Base64 (GenerateHashAsBase64String): Uses uppercase letters, lowercase letters, digits, and a couple of special characters. This produces a shorter string that contains the same information. This can be more convenient for things like license keys where a shorter, more human-friendly value is preferred.

Summary

Hash values are a fundamental tool with many practical applications in Business Central development. The Cryptography Management codeunit in the System Application gives you access to industry-standard hash algorithms with a single function call. Key takeaways:

  • Use SHA-256 or higher as your default hash algorithm.
  • Never roll your own cryptography — use the battle-tested implementations in .NET that Business Central exposes.
  • Hash values are excellent for password storage, data integrity verification (watermarking), and change detection.
  • Use salting when you need to prevent an attacker from simply recalculating the hash after modifying data.
  • The Format(Record) trick combined with hashing gives you an elegant way to detect record changes.