Skip to content

Instantly share code, notes, and snippets.

@zlatinz
Last active December 15, 2025 12:55
Show Gist options
  • Select an option

  • Save zlatinz/077f3cb990262686cf05d9e8bd7cb877 to your computer and use it in GitHub Desktop.

Select an option

Save zlatinz/077f3cb990262686cf05d9e8bd7cb877 to your computer and use it in GitHub Desktop.
ARC300: Password Validator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace PasswordDemo
{
public static class PasswordValidator
{
// HMAC SHA512 uses a 128 byte key
private const int KEY_LENGTH = 128;
public static bool ValidatePassword(string pwToValidate, string storedHash, string storedSalt)
{
string hashToValidate = EncodePassword(pwToValidate, storedSalt);
return hashToValidate.Equals(storedHash);
}
private static string EncodePassword(string pass, string salt)
{
// Convert provided unicode password string into a byte array
byte[] bIn = Encoding.Unicode.GetBytes(pass);
// Convert the Base64 salt into a byte array
byte[] bSalt = Convert.FromBase64String(salt);
// As HMAC SHA512 is a keyed algorithm, we need a key.
// http://ASP.NET creates this by repeating the salt bytes until they hit the required length
// Essentially this uses the salt as a key, rather than mixing it in with the username.
byte[] bKey = new byte[KEY_LENGTH];
for (int iter = 0; iter < bKey.Length;)
{
int len = Math.Min(bSalt.Length, bKey.Length - iter);
Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
iter += len;
}
// Create an instance of the hashing algorithm using our key, and hash the provided password bytes
byte[] bRet = null;
using (HMACSHA512 kha = new HMACSHA512(bKey))
{
bRet = kha.ComputeHash(bIn);
}
// Return the hash bytes as a Base64 string
return Convert.ToBase64String(bRet);
}
static void Main(string[] args)
{
Console.WriteLine(EncodePassword("Guardian02", "DU6oc2em+kFoP0C7GXJQ1g=="));
}
}
}
function PasswordValidator() {
// HMAC SHA512 uses a 128 byte key
const KEY_LENGTH = 128;
this.validatePassword = function (pwToValidate, storedHash, storedSalt) {
var
hashToValidate = this.encodePassword(pwToValidate, storedSalt);
return hashToValidate == storedHash;
}
this.encodePassword = function (pass, salt) {
var
Bytes = require("dw/util/Bytes"),
Encoding = require("dw/crypto/Encoding"),
Mac = require("dw/crypto/Mac");
// Convert provided unicode password string into a byte array
var bIn = new Bytes(pass, "UTF-16LE"); // Encoding.Unicode.GetBytes(pass) is UTF-16 format using the little endian byte order
// Convert the Base64 salt into a byte array
var bSalt = Encoding.fromBase64(salt);
// As HMAC SHA512 is a keyed algorithm, we need a key.
// http://ASP.NET creates this by repeating the salt bytes until they hit the required length
// Essentially this uses the salt as a key, rather than mixing it in with the username.
var bKeyHex = "";
var bSaltHex = Encoding.toHex(bSalt);
var iter = 0;
while (iter < KEY_LENGTH*2) {
var len = Math.min(bSaltHex.length, KEY_LENGTH*2 - iter);
bKeyHex += bSaltHex.substr(0, len);
iter += len;
}
var bKey = Encoding.fromHex(bKeyHex);
// Create an instance of the hashing algorithm using our key, and hash the provided password bytes
var bRet = null;
var kha = new Mac(Mac.HMAC_SHA_512);
bRet = kha.digest(bIn, bKey);
// Return the hash bytes as a Base64 string
return Encoding.toBase64(bRet);
}
this.unitTest = function() {
var
Status = require("dw/system/Status");
var
tests = [
{password: "Guardian02", salt: "DU6oc2em+kFoP0C7GXJQ1g==", hash: "KCdvGm7EHo8XwE9/QuXh4kDMz32gpUqpDjPc5r4/0OOBlEiK+1zZeUmcvknMWGD6IXeIeR0xWol4JxKn1pscrg=="},
{password: "Alpha1234", salt: "RU2p9x6eZi+Sj/3yp+4w8A==", hash: "CmRPRFiLcFvhuSeFE6ggNCIS+c21qNVLaKz2imaEXtDmeHXVHOu1FeAERIzMFMFCHBUCC+c+1rMpekqdhL7kZg=="},
{password: "Beta5678", salt: "vIm6pKU+ZNqJN9aP/b5AQw==", hash: "pxn2RNR/STnurJ9H2soBC2e9ur4OXPJgSR+pWqwtytM+wnFudyWSQ0TW+b2g1Hx3DDP/jN2xr+7MDiNm+r2Wpg=="},
{password: "Gamma9012", salt: "WcJgQqNfdTHy+sIFnqPy+A==", hash: "i+Txsf+v1XPVcIpBSsexagTVfRJvdcMUedqg6LoJXIkbfoy3Ip2pM3x3+exq1Nz+PeN+NZ3GOmCl+QNXKVM2og=="}
];
var passed = 0;
for (var i=0; i<tests.length; i++) {
if ( this.validatePassword(tests[i].password, tests[i].hash, tests[i].salt) ) {
passed++;
} else {
trace("test " + i + " failed");
}
}
return new Status(passed == tests.length ? Status.OK : Status.ERROR, "Passed " + passed + " from " + tests.length + " tests");
}
}
var pwValidator = new PasswordValidator();
return pwValidator.unitTest();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment