Last active
September 13, 2022 17:33
-
-
Save fador/138bc8b18e7c532e039f28ca57908b69 to your computer and use it in GitHub Desktop.
Paste TOTP directly to the console with a hotkey in windows
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <errno.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <ctime> | |
#include <openssl/evp.h> | |
#include <openssl/hmac.h> | |
#include <string> | |
#include <windows.h> | |
#include <shobjidl.h> | |
#include <objbase.h> | |
#include <sal.h> | |
#include <stdarg.h> | |
#include <wchar.h> | |
#include <thread> | |
#pragma comment(lib, "ws2_32.lib") | |
#pragma comment (lib, "crypt32") | |
const char* base32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; | |
// Modified from https://github.com/arachsys/totp | |
std::string generate_totp() { | |
int64_t offset; | |
size_t keysize, length; | |
uint8_t digits, * hmac, key[64], msg[8]; | |
uint32_t bits, code, count; | |
uint64_t clock, interval; | |
unsigned int hmacsize; | |
const EVP_MD* digest; | |
keysize = 0; | |
char out[100]; | |
const char* secret = "TOTP_SECRET_KEY "; | |
digest = EVP_sha1(); | |
for (count = bits = length = 0; *secret; secret++) { | |
if (!strchr(base32, *secret)) | |
break; | |
bits = (bits << 5) | (strchr(base32, *secret) - base32); | |
count += 5; | |
while (count >= 8) { | |
while (length >= keysize) { | |
keysize = keysize ? keysize << 1 : 64; | |
if (keysize>64) | |
return ""; | |
} | |
count -= 8, key[length++] = bits >> count; | |
} | |
} | |
offset = 0; | |
if (length > 0) { | |
clock = (time(NULL) - offset) / 30; | |
for (count = 0; count < 8; count++) | |
msg[7 - count] = clock >> 8 * count; | |
hmac = HMAC(digest, key, length, msg, sizeof(msg), NULL, &hmacsize); | |
for (code = count = 0; count < 4; count++) | |
code += hmac[(hmac[hmacsize - 1] & 0x0f) + 3 - count] << 8 * count; | |
code &= 0x7fffffff; | |
sprintf_s(out,"%06u", code % 1000000); | |
} | |
out[6] = '\0'; // Force null byte to end the 6 digits | |
std::string output(out); | |
return output; | |
} | |
bool KeyPress(UINT key) | |
{ | |
INPUT inputs[2]; | |
ZeroMemory(inputs, sizeof(inputs)); | |
inputs[0].type = INPUT_KEYBOARD; | |
inputs[0].ki.wVk = key; | |
inputs[1].type = INPUT_KEYBOARD; | |
inputs[1].ki.wVk = key; | |
inputs[1].ki.dwFlags = KEYEVENTF_KEYUP; | |
SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT)); | |
return true; | |
} | |
bool send_otp() { | |
std::string totp = generate_totp(); | |
INPUT inputs[2]; | |
ZeroMemory(inputs, sizeof(inputs)); | |
// CTRL up before the input | |
inputs[0].type = INPUT_KEYBOARD; | |
inputs[0].ki.wVk = VK_LCONTROL; | |
inputs[0].ki.dwFlags = KEYEVENTF_KEYUP; | |
inputs[1].type = INPUT_KEYBOARD; | |
inputs[1].ki.wScan = ::MapVirtualKey(LOBYTE(VkKeyScan('1')), MAPVK_VK_TO_VSC); | |
inputs[1].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; | |
UINT uSent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT)); | |
for (char key : totp) { | |
if (key >= '0' && key <= '9') { // Force only numbers | |
//const SHORT Vk = VkKeyScan(key); | |
//const UINT VKey = ::MapVirtualKey(LOBYTE(Vk), MAPVK_VK_TO_VSC); | |
KeyPress((key-'0') + 0x30); // Map ASCII to Windows virtual keys | |
Sleep(2); | |
} | |
} | |
return true; | |
} | |
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, | |
_In_opt_ HINSTANCE hPrevInstance, | |
_In_ LPWSTR lpCmdLine, | |
_In_ int nCmdShow) | |
{ | |
UNREFERENCED_PARAMETER(hPrevInstance); | |
UNREFERENCED_PARAMETER(lpCmdLine); | |
if (RegisterHotKey(NULL, 1, MOD_CONTROL, 0x31)) // CTRL+1 | |
{ | |
// Done | |
} | |
MSG msg; | |
while (GetMessage(&msg, NULL, 0, 0)) | |
{ | |
if (msg.message == WM_HOTKEY) | |
{ | |
send_otp(); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment