Skip to content

Instantly share code, notes, and snippets.

@thewheat
Last active May 21, 2024 09:04
Show Gist options
  • Save thewheat/7342c76ade46e7322c3e to your computer and use it in GitHub Desktop.
Save thewheat/7342c76ade46e7322c3e to your computer and use it in GitHub Desktop.

Intercom user_hash

Remember that your secret key should never be exposed to the public

  • So Javascript code below should only be used for testing unless modified and used to run on a server

Javascript

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js"></script>
<script>
  var hash = CryptoJS.HmacSHA256("Message", "secret");
  var hashInHex = CryptoJS.enc.Hex.stringify(hash);
  document.write(hashInHex); // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597
</script>

Node

const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'secret');
hmac.update('Message');
console.log(hmac.digest('hex')); // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

PHP

<?php
echo hash_hmac('sha256', 'Message', 'secret'); // thanks @AshleyPinner https://gist.github.com/thewheat/7342c76ade46e7322c3e#gistcomment-1820677
?>

Java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class Test {
  public static void main(String[] args) {
  try {
      String secret = "secret";
      String message = "Message";

      Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
      SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
      sha256_HMAC.init(secret_key);

      byte[] hash = (sha256_HMAC.doFinal(message.getBytes()));
      StringBuffer result = new StringBuffer();
      for (byte b : hash) {
        result.append(String.format("%02x", b)); // thanks sachins! https://gist.github.com/thewheat/7342c76ade46e7322c3e#gistcomment-1863031 
      }
      System.out.println(result.toString()); // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597
    }
    catch (Exception e){
      System.out.println("Error");
    }
  }
}

Groovy

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;

def hmac_sha256(String secretKey, String data) {
 try {
    Mac mac = Mac.getInstance("HmacSHA256")
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256")
    mac.init(secretKeySpec)
    byte[] digest = mac.doFinal(data.getBytes())
    return digest
   } catch (InvalidKeyException e) {
    throw new RuntimeException("Invalid key exception while converting to HMac SHA256")
  }
}

def hash = hmac_sha256("secret", "Message")
StringBuffer result = new StringBuffer();
for (byte b : hash) {
result.append(String.format("%02x", b)); // thanks sachins! https://gist.github.com/thewheat/7342c76ade46e7322c3e#gistcomment-1863031
}
print(result.toString()); // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

C#

using System.Security.Cryptography;

namespace Test
{
	public class MyHmac
	{
		public static void Main(string[] args){
			var hmac = new MyHmac ();
			System.Console.WriteLine(hmac.CreateToken ("Message", "secret")); // AA747C502A898200F9E4FA21BAC68136F886A0E27AEC70BA06DAF2E2A5CB5597
		}
		private string CreateToken(string message, string secret)
		{
			secret = secret ?? "";
			var encoding = new System.Text.ASCIIEncoding();
			byte[] keyByte = encoding.GetBytes(secret);
			byte[] messageBytes = encoding.GetBytes(message);
			using (var hmacsha256 = new HMACSHA256(keyByte))
			{
				byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);

				var sb = new System.Text.StringBuilder();
				for (var i = 0; i <= hashmessage.Length - 1; i++)
				{
					sb.Append(hashmessage[i].ToString("x2")); // Thanks! @ermirbeqiraj https://gist.github.com/thewheat/7342c76ade46e7322c3e#gistcomment-3180664
				}
				return sb.ToString();
			}
		}
	}
}

Objective C

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonHMAC.h>

NSData *hmacForKeyAndData(NSString *key, NSString *data)
{
    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}

// http://stackoverflow.com/a/9084784
NSString *hexadecimalString(NSData *data){
    /* Returns hexadecimal string of NSData. Empty string if data is empty.   */

    const unsigned char *dataBuffer = (const unsigned char *)[data bytes];

    if (!dataBuffer)
        return [NSString string];

    NSUInteger          dataLength  = [data length];
    NSMutableString     *hexString  = [NSMutableString stringWithCapacity:(dataLength * 2)];

    for (int i = 0; i < dataLength; ++i)
        [hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];

    return [NSString stringWithString:hexString];
}
int main (int argc, const char * argv[])
{
    @autoreleasepool {
        NSLog(@"%@", hexadecimalString(hmacForKeyAndData(@"secret", @"Message")));
    }
    return 0;
}

Go

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
)

func ComputeHmac256(message string, secret string) string {
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(message))
    return hex.EncodeToString(h.Sum(nil))
}

func main() {
    fmt.Println(ComputeHmac256("Message", "secret")) // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597
}

Ruby

require 'openssl'

OpenSSL::HMAC.hexdigest('sha256', "secret", "Message") # aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

Python (2.x)

import hashlib
import hmac

KEY = "secret"
MESSAGE = "Message"
result = hmac.new(KEY, MESSAGE, hashlib.sha256).hexdigest()
print result # aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

Python (3.x)

import hashlib
import hmac

KEY = "secret"
KEY_BYTES=KEY.encode('ascii')
MESSAGE = "Message"
MESSAGE_BYTES=MESSAGE.encode('ascii')
result = hmac.new(KEY_BYTES, MESSAGE_BYTES, hashlib.sha256).hexdigest()

print (result) # aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

Perl

use Digest::SHA qw(hmac_sha256_hex);
$digest = hmac_sha256_hex("Message", "secret");
print $digest; # aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

Swift

// Add
// #import <CommonCrypto/CommonHMAC.h>
// to the bridging Objective-C bridging header.

import Foundation

enum CryptoAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

    var HMACAlgorithm: CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5:      result = kCCHmacAlgMD5
        case .SHA1:     result = kCCHmacAlgSHA1
        case .SHA224:   result = kCCHmacAlgSHA224
        case .SHA256:   result = kCCHmacAlgSHA256
        case .SHA384:   result = kCCHmacAlgSHA384
        case .SHA512:   result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }

    var digestLength: Int {
        var result: Int32 = 0
        switch self {
        case .MD5:      result = CC_MD5_DIGEST_LENGTH
        case .SHA1:     result = CC_SHA1_DIGEST_LENGTH
        case .SHA224:   result = CC_SHA224_DIGEST_LENGTH
        case .SHA256:   result = CC_SHA256_DIGEST_LENGTH
        case .SHA384:   result = CC_SHA384_DIGEST_LENGTH
        case .SHA512:   result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}

extension String {

    func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
        let str = self.cStringUsingEncoding(NSUTF8StringEncoding)
        let strLen = Int(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
        let digestLen = algorithm.digestLength
        let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)
        let keyStr = key.cStringUsingEncoding(NSUTF8StringEncoding)
        let keyLen = Int(key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))

        CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)

        let digest = stringFromResult(result, length: digestLen)

        result.dealloc(digestLen)

        return digest
    }

    private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
        var hash = NSMutableString()
        for i in 0..<length {
            hash.appendFormat("%02x", result[i])
        }
        return String(hash)
    }

}


print("Message".hmac(CryptoAlgorithm.SHA256, key: "secret")) //aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597
@perchrh
Copy link

perchrh commented Nov 26, 2019

Kotlin

The secret parameter is the key received from Intercom, and message is the userId to be hashed.

import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

object IntercomIdentifyHasher {

    fun createHash(secret: String, message: String): String {
        val algorithm = Mac.getInstance("HmacSHA256")
        val secretKey = SecretKeySpec(secret.toByteArray(), "HmacSHA256")
        algorithm.init(secretKey)

        val hash = algorithm.doFinal(message.toByteArray())
        val result = StringBuffer()
        for (b in hash) {
            result.append(String.format("%02x", b))
        }
        return result.toString()
    }
}

@ermirbeqiraj
Copy link

C# snipped needs .ToString("x2") instead of .ToString("X2")

@thewheat
Copy link
Author

Thanks @ermirbeqiraj I've updated it 👍

@raaowx
Copy link

raaowx commented Jun 17, 2020

Update for Swift 5

Update for Swift 4 and also returns the string in lower case for API satisfaction.

import Foundation
import CommonCrypto.CommonHMAC // !! ADDED

enum CryptoAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
    
    var HMACAlgorithm: CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5:      result = kCCHmacAlgMD5
        case .SHA1:     result = kCCHmacAlgSHA1
        case .SHA224:   result = kCCHmacAlgSHA224
        case .SHA256:   result = kCCHmacAlgSHA256
        case .SHA384:   result = kCCHmacAlgSHA384
        case .SHA512:   result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }
    
    var digestLength: Int {
        var result: Int32 = 0
        switch self {
        case .MD5:      result = CC_MD5_DIGEST_LENGTH
        case .SHA1:     result = CC_SHA1_DIGEST_LENGTH
        case .SHA224:   result = CC_SHA224_DIGEST_LENGTH
        case .SHA256:   result = CC_SHA256_DIGEST_LENGTH
        case .SHA384:   result = CC_SHA384_DIGEST_LENGTH
        case .SHA512:   result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}

extension String {
    
    func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = algorithm.digestLength
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        let keyStr = key.cString(using: String.Encoding.utf8)
        let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8))
        
        CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)
        
        let digest = stringFromResult(result: result, length: digestLen)
        
        result.deallocate() // !! UPDATED: Error: deallocate(capacity:)' is unavailable: Swift currently only supports freeing entire heap blocks, use deallocate() instead
        
        return digest
    }
    
    private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
        let hash = NSMutableString()
        for i in 0..<length {
            hash.appendFormat("%02x", result[i])
        }
        return String(hash).lowercased()
    }
}

@jchavarri
Copy link

OCaml

Using ahrefs/ocaml-sodium:

let hex_of_bytes b =
  let s = Buffer.create (Bytes.length b * 2) in
  Bytes.iter (fun c -> Printf.bprintf s "%02x" (Char.code c)) b;
  Buffer.contents s

let hmac_sha256 ~key payload =
  let open Sodium.Auth.Hmac_sha256.Bytes in
  let state = init (Bytes.of_string key) in
  update state (Bytes.of_string payload);
  hex_of_bytes (of_auth (Sodium.Auth.Hmac_sha256.final state))

@luizvnegrini
Copy link

luizvnegrini commented Sep 29, 2021

Dart

Using cryto (Flutter package):

final key = utf8.encode(__YOUR_SECRET_HERE__);
final bytes = utf8.encode(__DATA__);

final hmacSha256 = Hmac(sha256, key);
final digest = hmacSha256.convert(bytes);

@jamesfernandes
Copy link

jamesfernandes commented Feb 27, 2023

C#

Simpler version

var encoding = new System.Text.ASCIIEncoding();

byte[] keyBytes = encoding.GetBytes("secret"); // secret key
byte[] userIdBytes = encoding.GetBytes("Message"); // user id or email

using var hmacsha256 = new System.Security.Cryptography.HMACSHA256(keyBytes);
byte[] hash = hmacsha256.ComputeHash(userIdBytes);

var token = BitConverter.ToString(hash).Replace("-", string.Empty).ToLowerInvariant();

Console.WriteLine(token); // aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597

Note: this will run exactly as-is in Program.cs of a bare-bones .NET 7 console project.

@simplenotezy
Copy link

simplenotezy commented May 22, 2023

Dart

flutter pub add crypto

import 'dart:convert';
import 'dart:io';

import 'package:crypto/crypto.dart';

String generateIntercomIdentityVerification(String userIdOrEmail) {
  // Create an HMAC instance with the SHA-256 algorithm and the secret key
  final hmac = Hmac(
    sha256,
    utf8.encode('YOUR_SECRET'),
  );

  // Generate the HMAC digest of the data
  final digest = hmac.convert(utf8.encode(userIdOrEmail));

  // Convert the digest to a string representation
  return digest.toString();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment