Skip to content

Instantly share code, notes, and snippets.

@hax0r31337
Created September 8, 2023 13:45
Show Gist options
  • Select an option

  • Save hax0r31337/d66da02013f91a658f4894617c2760b0 to your computer and use it in GitHub Desktop.

Select an option

Save hax0r31337/d66da02013f91a658f4894617c2760b0 to your computer and use it in GitHub Desktop.
SteamGuard TOTP Generation
const CryptoJS = require('crypto-js');
function hexStringToUint8Array(hexString) {
const length = hexString.length;
const uint8Array = new Uint8Array(length / 2);
for (let i = 0; i < length; i += 2) {
uint8Array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);
}
return uint8Array;
}
function computeHMAC(inputBytes, base64Key) {
const keyWordArray = CryptoJS.enc.Base64.parse(base64Key);
const inputWordArray = CryptoJS.lib.WordArray.create(inputBytes.buffer);
const hmacWordArray = CryptoJS.HmacSHA1(inputWordArray, keyWordArray);
return hexStringToUint8Array(hmacWordArray.toString(CryptoJS.enc.Hex));
}
async function computeAuthCode(time, sharedSecret) {
const interval = 30;
const roundedTime = Math.floor(Math.floor(time / 1000) / interval);
const hexString = roundedTime.toString(16).padStart(16, '0');
const hmacBytes = computeHMAC(hexStringToUint8Array(hexString), sharedSecret);
const offset = 15 & hmacBytes[hmacBytes.length - 1];
let hashPart = (127 & hmacBytes[offset]) << 24 |
(255 & hmacBytes[offset + 1]) << 16 |
(255 & hmacBytes[offset + 2]) << 8 |
255 & hmacBytes[offset + 3];
const authCodeCharacters = [];
const possibleCharacters = "23456789BCDFGHJKMNPQRTVWXY";
for (let i = 0; i < 5; i++) {
authCodeCharacters.push(possibleCharacters[hashPart % possibleCharacters.length]);
hashPart = Math.floor(hashPart / possibleCharacters.length);
}
return {
code: authCodeCharacters.join(''),
rtExpiry: roundedTime * interval + interval
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment