This clipboard protector is a neat little Windows tool that makes copy-paste way more secure by automatically encrypting your text with AES-128-CTR whenever you hit Ctrl+C. It tags the encrypted data and swaps it into your clipboard, then seamlessly decrypts and "smart pastes" it back when you do Ctrl+V—positioning the cursor at line end, toggling insert mode, and typing character-by-character to handle huge texts without glitches. With fixed test keys and low-level keyboard hooks, it's a solid starting point for keeping sensitive info safe from casual snooping, all running smoothly in the background once launched as admin.
The program works for copying/pasting text and hasn't been tested on other data types.
aes_ctr.hpp
C++:
// aes_ctr.hpp
/*
MIT License
Copyright (c) 2025 CoTon_TiGe_MoUaRf
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
This project is divided into two parts for sharing purposes due to its length. Each part can be used independently while maintaining the same terms outlined in this license.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <array>
#include <cstdint>
#include <cstring>
#include <vector>
#include <algorithm>
// -----------------------------------------------------------------------------
// Minimal AES-128 + CTR mode (inspired by TinyAES, public domain)
// -----------------------------------------------------------------------------
class AES128_CTR {
public:
// clé 16 octets, iv 16 octets (counter)
AES128_CTR(const uint8_t key_[16], const uint8_t iv_[16]) {
memcpy(roundKey.data(), key_, 16);
memcpy(counter.data(), iv_, 16);
keyExpansion();
}
// CTR est symétrique
void process(uint8_t* data, size_t len) {
std::vector<uint8_t> stream(len);
generateKeyStream(stream.data(), len);
for (size_t i = 0; i < len; ++i) {
data[i] ^= stream[i];
}
}
private:
std::array<uint8_t, 176> expandedKey; // 11 × 16
std::array<uint8_t, 16> roundKey;
std::array<uint8_t, 16> counter;
// la S-box complète AES
static constexpr uint8_t sbox[256] = {
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
};
static void rotWord(uint8_t w[4]) {
uint8_t t = w[0];
w[0]=w[1]; w[1]=w[2]; w[2]=w[3]; w[3]=t;
}
static void subWord(uint8_t w[4]) {
for(int i=0;i<4;++i) w[i]=sbox[w[i]];
}
void keyExpansion() {
uint8_t* dst = expandedKey.data();
memcpy(dst, roundKey.data(), 16);
int bytesGen = 16;
uint8_t rcon = 1;
uint8_t temp[4];
while(bytesGen < 176) {
memcpy(temp, dst + bytesGen - 4, 4);
if (bytesGen % 16 == 0) {
rotWord(temp);
subWord(temp);
temp[0] ^= rcon;
rcon = xtime(rcon);
}
for(int i=0;i<4;++i) {
dst[bytesGen] = dst[bytesGen - 16] ^ temp[i];
++bytesGen;
}
}
}
static uint8_t xtime(uint8_t x) {
return (x << 1) ^ ((x & 0x80) ? 0x1b : 0x00);
}
void cipher(const uint8_t in[16], uint8_t out[16]) {
uint8_t state[16];
memcpy(state, in, 16);
addRoundKey(state, expandedKey.data());
for(int round=1; round<=9; ++round) {
subBytes(state);
shiftRows(state);
mixColumns(state);
addRoundKey(state, expandedKey.data() + 16*round);
}
subBytes(state);
shiftRows(state);
addRoundKey(state, expandedKey.data() + 160);
memcpy(out, state, 16);
}
void generateKeyStream(uint8_t* stream, size_t len) {
size_t blocks = (len + 15) / 16;
for(size_t b=0; b<blocks; ++b) {
uint8_t out[16];
cipher(counter.data(), out);
// incr counter en big-endian
for(int i=15; i>=0; --i) {
if (++counter[i]) break;
}
size_t chunk = std::min<size_t>(16, len - b*16);
memcpy(stream + b*16, out, chunk);
}
}
static void addRoundKey(uint8_t s[16], const uint8_t* rk) {
for(int i=0;i<16;++i) s[i] ^= rk[i];
}
void subBytes(uint8_t s[16]) {
for(int i=0;i<16;++i) s[i]=sbox[s[i]];
}
static void shiftRows(uint8_t s[16]) {
uint8_t t[16];
// ligne 0
t[0]=s[0]; t[4]=s[4]; t[8]=s[8]; t[12]=s[12];
// ligne 1
t[1]=s[5]; t[5]=s[9]; t[9]=s[13]; t[13]=s[1];
// ligne 2
t[2]=s[10]; t[6]=s[14]; t[10]=s[2]; t[14]=s[6];
// ligne 3
t[3]=s[15]; t[7]=s[3]; t[11]=s[7]; t[15]=s[11];
memcpy(s,t,16);
}
static void mixColumns(uint8_t s[16]) {
for(int c=0;c<4;++c){
int i=c*4;
uint8_t a0=s[i], a1=s[i+1], a2=s[i+2], a3=s[i+3];
uint8_t r0 = xtime(a0) ^ a1 ^ xtime(a1) ^ a2 ^ a3;
uint8_t r1 = a0 ^ xtime(a1) ^ a2 ^ xtime(a2) ^ a3;
uint8_t r2 = a0 ^ a1 ^ xtime(a2) ^ a3 ^ xtime(a3);
uint8_t r3 = xtime(a0) ^ a1 ^ a2 ^ xtime(a3) ^ a3;
s[i]=r0; s[i+1]=r1; s[i+2]=r2; s[i+3]=r3;
}
}
};
main.cpp :
C++:
/*
MIT License
Copyright (c) 2025 CoTon_TiGe_MoUaRf
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
This project is divided into two parts for sharing purposes due to its length. Each part can be used independently while maintaining the same terms outlined in this license.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <Windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include "aes_ctr.hpp"
#pragma comment(lib, "user32.lib")
// Clés fixes simples pour test
const uint8_t KEY[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
const uint8_t IV[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
// Globals
bool ctrl_down = false;
bool typing = false;
bool processing = false;
std::string enc_tag = "AES128:";
// Get clipboard as string (support large data)
std::string clipboard_get() {
std::string data;
if (OpenClipboard(NULL)) {
HANDLE h = GetClipboardData(CF_TEXT);
if (h) {
size_t size = GlobalSize(h);
char *text = (char*)GlobalLock(h);
if (text && size > 0) {
data.assign(text, size - 1);
GlobalUnlock(h);
}
}
CloseClipboard();
}
return data;
}
// Set clipboard from string (large data support)
bool clipboard_set(const std::string& data) {
if (OpenClipboard(NULL)) {
EmptyClipboard();
HGLOBAL glob = GlobalAlloc(GMEM_MOVEABLE, data.size() + 1);
if (glob) {
char *buf = (char*)GlobalLock(glob);
if (buf) {
memcpy(buf, data.c_str(), data.size());
buf[data.size()] = 0;
GlobalUnlock(glob);
SetClipboardData(CF_TEXT, glob);
CloseClipboard();
return true;
}
GlobalFree(glob);
}
CloseClipboard();
}
return false;
}
// AES CTR encrypt/decrypt
std::string aes_process(const std::string& input) {
if (input.empty()) return "";
std::vector<uint8_t> buf(input.begin(), input.end());
{
AES128_CTR aes(KEY, IV);
aes.process(buf.data(), buf.size());
}
return std::string(buf.begin(), buf.end());
}
// SMART Paste: Position cursor + Insert mode (NO DELETION)
void smart_paste(const std::string& text) {
typing = true;
Sleep(150);
HWND hwnd = GetForegroundWindow();
if (!hwnd) {
typing = false;
return;
}
// Focus window
SetForegroundWindow(hwnd);
SetFocus(hwnd);
Sleep(50);
// Move cursor to end of line (End key)
keybd_event(VK_END, 0, 0, 0);
Sleep(30);
keybd_event(VK_END, 0, KEYEVENTF_KEYUP, 0);
Sleep(50);
// Ensure Insert mode (Insert key)
keybd_event(VK_INSERT, 0, 0, 0);
Sleep(20);
keybd_event(VK_INSERT, 0, KEYEVENTF_KEYUP, 0);
Sleep(30);
// Type text character by character with adaptive delays
for (size_t i = 0; i < text.size(); ++i) {
char c = text[i];
// Special handling for newlines
if (c == '\r' || c == '\n') {
keybd_event(VK_RETURN, 0, 0, 0);
Sleep(15);
keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
Sleep(20);
continue;
}
// Unicode SendInput for all characters
INPUT input[2] = {0};
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0;
input[0].ki.dwFlags = KEYEVENTF_UNICODE;
input[0].ki.wScan = (unsigned short)c;
input[1] = input[0];
input[1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
SendInput(2, input, sizeof(INPUT));
// Adaptive delay: slower for large texts
Sleep((text.size() > 1000) ? 12 : (text.size() > 500 ? 8 : 4));
}
Sleep(150);
typing = false;
}
// Paste thread function
void paste_thread(std::string text) {
try {
smart_paste(text);
} catch (...) {
typing = false;
}
}
// Low level keyboard hook
LRESULT CALLBACK kb_hook(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0 && !typing && !processing) {
KBDLLHOOKSTRUCT *kb = (KBDLLHOOKSTRUCT*)lParam;
// Track all CTRL keys
if (kb->vkCode == VK_CONTROL || kb->vkCode == VK_LCONTROL || kb->vkCode == VK_RCONTROL) {
ctrl_down = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
// CTRL+C - Encrypt
if (ctrl_down && (kb->vkCode == 0x43 || kb->vkCode == 'C') && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) {
std::cout << "[+] Ctrl+C intercepted" << std::endl;
Sleep(400); // Increased wait for large clipboard
processing = true;
std::string original = clipboard_get();
processing = false;
std::cout << "[+] Original (" << original.length() << " chars): '"
<< (original.size() > 60 ? original.substr(0,60) + "..." : original) << "'" << std::endl;
if (!original.empty()) {
std::string encrypted = aes_process(original);
std::string tagged = enc_tag + encrypted;
if (clipboard_set(tagged)) {
std::cout << "[+] Encrypted (" << tagged.length() << " bytes) ✓" << std::endl;
std::cout << "[+] Preview: '" << (tagged.size() > 70 ? tagged.substr(0,70) + "..." : tagged) << "'" << std::endl;
} else {
std::cout << "[!] Clipboard set FAILED" << std::endl;
}
}
return 1;
}
// CTRL+V - Decrypt & Smart Paste
if (ctrl_down && (kb->vkCode == 0x56 || kb->vkCode == 'V') && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) {
std::cout << "[+] Ctrl+V intercepted" << std::endl;
processing = true;
std::string clipboard_data = clipboard_get();
processing = false;
std::cout << "[+] Clipboard (" << clipboard_data.length() << " bytes): '"
<< (clipboard_data.size() > 70 ? clipboard_data.substr(0,70) + "..." : clipboard_data) << "'" << std::endl;
if (clipboard_data.find(enc_tag) == 0) {
std::string encrypted = clipboard_data.substr(enc_tag.length());
std::string decrypted = aes_process(encrypted);
std::cout << "[+] Decrypted (" << decrypted.length() << " chars): '"
<< (decrypted.size() > 60 ? decrypted.substr(0,60) + "..." : decrypted) << "'" << std::endl;
std::cout << "[+] Smart pasting " << decrypted.length() << " chars..." << std::endl;
std::thread(paste_thread, std::move(decrypted)).detach();
} else {
std::cout << "[!] Not encrypted (no '" << enc_tag << "')" << std::endl;
}
return 1;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
// Entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
AllocConsole();
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
freopen_s((FILE**)stderr, "CONOUT$", "w", stderr);
char title[] = "AES Clipboard v4 - Smart Paste";
SetConsoleTitleA(title);
std::cout << "=== AES-128-CTR Clipboard Protector v4 - SMART PASTE ===" << std::endl;
std::cout << "Tag: '" << enc_tag << "' | Supports LARGE texts!" << std::endl << std::endl;
// Extended AES test
std::string test = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
std::string enc = aes_process(test);
std::string dec = aes_process(enc);
std::cout << "AES Test (" << test.length() << " chars):" << std::endl;
std::cout << " OK: " << (test == dec ? "✓" : "✗") << " | Encoded: " << enc.length() << " bytes" << std::endl << std::endl;
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, kb_hook, GetModuleHandle(NULL), 0);
if (!hook) {
std::cout << "❌ Hook failed! Run as ADMINISTRATOR!" << std::endl;
Sleep(5000);
return 1;
}
std::cout << "✅ HOOK ACTIVE - Smart paste enabled!" << std::endl;
std::cout << "💡 Features: Large text support | No data loss | Insert mode" << std::endl;
std::cout << "📋 Test: Copy LONG text → Ctrl+C → Ctrl+V" << std::endl << std::endl;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hook);
FreeConsole();
return 0;
}