SHA-256-ing an email address in Velocity

Level 10 - Community Moderator
Level 10 - Community Moderator

Can't believe someone other than me has thought about cryptographic techniques in Marketo! But in this recent Nation thread, a user asked about attaching the SHA-256 hash of a recipient's email address to (email) links.

The aim being to send a secure representation of a lead's email to an external (non-Marketo) site, where it could be looked up as part of a 3rd-party subscription center.

In other words, a link would look like this:


The target site's database would hold pre-computed hashes of all their registered users' emails, the hash being stored in a separate column from the email itself.[1]

A match would then be done from hash-to-hash (the way hashes are always used, since they can never be reversed to the original input) to load the user's record.

Mind you, I have no idea why this would actually be done as opposed to sending the URL-encoded email address:


Or the easily reversed, Base64-encoded (not encrypted) address, which wouldn't require a hash lookup:


Being a realist, I suspect the justification is merely that they want the links to look more “technical” than they would with Base64 (?) and they don't truly have any need for security (as it makes little sense to care about the security of the recipient's own email address![2]). UPDATE: OP says the client now wants AES encryption instead of hashing, so they really are trying to securely transport stuff in the URL. That gives me a chance to bring out the big guns and show you how encryption is done in VTL... at some point.

Anyway, should you need it, here's a utility Velocimacro to gen a SHA-256 hash:


    HashTool in VTL v2

    @copyright (c) 2018 Sanford Whiteman, FigureOne, Inc.

    @license MIT License: all reproductions of this software must include the data above


#macro( SHA256_v2 $mktoField )

## reflect some dependencies

#set( $Class = $context.getClass() )

#set( $java = {} )

#set( $java.lang = {

     "StringBuilder" : $Class.forName("java.lang.StringBuilder"),

     "Appendable" : $Class.forName("java.lang.Appendable")

} )

#set( $ = {

    "MessageDigest" : $Class.forName("")

} )

#set( $java.util = {

    "Formatter" : $Class.forName("java.util.Formatter").getConstructor($java.lang.Appendable)

} )

## get an MD and make it go, then (important) reset MD singleton for reuse

#set( $MD = $"SHA-256") )

#set( $digestBytes = $MD.digest( $mktoField.getBytes("utf8")) )

#set( $void = $MD.reset() )

## gen hex string representation

#set( $hexString = $java.lang.StringBuilder.newInstance() )

#set( $hexer = $java.util.Formatter.newInstance($hexString) )

#foreach( $B in $digestBytes )

#set( $void = $hexer.format("%02x",$B) )


## return uppercase, but note a hex string should be treated as case-insensitive



After including the above in its own token (best to not pollute your user code with utility functions) use the macro like so:

#set( $emailHash = "#SHA256_v2($lead.Email.toLowerCase())" )

<a href="${emailHash}">Click here</a>

Note that I toLowerCase()d the Email before passing it, as that's appropriate for that particular field (as I've written about before, though SMTP addresses are actually case-sensitive, they're commonly matched case-insensitively for sanity's sake).


[1] Hope I'm not hoping for too much here. They'd better be already pre-computing hashes for all the stuff in their database, or this idea goes from merely frivolous to very bad. If they didn't pre-hash, they'd have to hash every record in the database, on-the-fly, for every lookup. This would absolutely destroy performance and be a sign that the back end was not well thought out.

[2] Long as the destination site runs SSL. But if the site doesn't run SSL then the connection could be intercepted and you have a lot worse problems than showing the attacker an email address.