Kelick Tech Hub

Build, learn & keep up — tech, Linux & sports news included.

C++ File Encryptor/Decryptor Project

Beginner•Half a day•file streams, bitwise XOR, binary data

Scramble any file with a key so it can't be read — then unscramble it.

Share on X

What you will build

Read a file byte by byte, XOR each byte with a key, and write the scrambled result; run it again with the same key to restore the original. It's a real (if basic) cipher, and it teaches the binary file handling that underpins compression, media, and security tools.

What you will learn

Feature checklist

Starter code

#include <iostream>
#include <fstream>
#include <string>

bool transform(const std::string& inPath,
               const std::string& outPath, unsigned char key) {
    std::ifstream in(inPath, std::ios::binary);
    std::ofstream out(outPath, std::ios::binary);
    if (!in || !out) return false;
    char byte;
    while (in.get(byte)) {
        byte = static_cast<char>(byte ^ key);  // XOR flips bits
        out.put(byte);                          // same op decrypts
    }
    return true;
}

int main() {
    std::string in, out; int key;
    std::cout << "Input file: ";  std::cin >> in;
    std::cout << "Output file: "; std::cin >> out;
    std::cout << "Key (0-255): "; std::cin >> key;
    if (transform(in, out, static_cast<unsigned char>(key)))
        std::cout << "Done. Keep the key safe!\n";
    else
        std::cout << "Could not open files.\n";
}

Full walkthrough

Step 1: Understand the one idea: XOR with a key

Encryption here is a single reversible operation — XOR every byte with the key byte. XOR has a magic property: (b ^ k) ^ k == b, so the SAME transform() function encrypts and decrypts. There is no separate decrypt algorithm to write or to get wrong; applying the transform twice restores the original exactly.

Step 2: Write transform() over a whole stream

transform(std::istream& in, std::ostream& out, char key) reads one char at a time with in.get(c), writes c ^ key, and counts the bytes so main() can report them. Working through stream references instead of filenames keeps the function reusable for any source — files today, anything else later.

void transform(std::istream& in, std::ostream& out, char key) {
    char c;
    while (in.get(c)) out.put(c ^ key);
}

Step 3: Open files in binary mode — this is not optional

std::ifstream in(name, std::ios::binary) and ofstream with binary too. In text mode, Windows translates newline bytes on the fly, which silently corrupts images and executables: the file decrypts to something ALMOST right. Binary mode says 'bytes are bytes', which is the only honest mode for a tool that promises 'works on any file'.

Step 4: Refuse to overwrite the input

Compare the input and output filenames before opening anything; if they match, print an error and stop. Opening the output would truncate the input to zero bytes before a single byte is read — the one truly destructive mistake this program can make, guarded by one string comparison.

Step 5: Take the key as a number, use it as a byte

Prompt for a numeric key (say 0–255) and static_cast<char> it. Keys larger than a byte simply wrap, which is fine as long as the SAME key is used to decrypt. Warn the user plainly: wrong key, garbage out — the program cannot tell a wrong key from the right one, because every key produces a valid-looking file.

Step 6: Report bytes processed

Count bytes inside transform() (return the count or use a reference parameter) and print it: 'Encrypted notes.txt -> notes.enc (1284 bytes)'. The count doubles as a verification tool — encrypt and decrypt outputs must be the same size as the input, byte for byte.

Step 7: Test the round-trip on a real file

Copy a text file, encrypt the copy, open it and confirm it is gibberish, decrypt with the same key, and diff the result against the original (fc on Windows, diff on Linux/macOS) — identical output is the only passing grade. Then decrypt once with a WRONG key to see the failure mode your users will meet.

Common mistakes

Compile and run

g++ -std=c++17 -o encryptor encryptor.cpp

Sample run

$ ./encryptor
Encrypt or Decrypt (E/D):
> E
Input file:
> notes.txt
Output file:
> notes.enc
Numeric key (0-255):
> 42
Encrypted notes.txt -> notes.enc (1284 bytes)

$ ./encryptor
Encrypt or Decrypt (E/D):
> D
Input file:
> notes.enc
Output file:
> notes_restored.txt
Numeric key (0-255):
> 42
Decrypted notes.enc -> notes_restored.txt (1284 bytes)
The restored file is byte-for-byte identical to the original.

Try it in your browser

No browser demo is included for this project. Build the C++ version below — that is the real program.

Related Beginner projects

← All 60 projects · Classic site (Learn & Sandbox)

Download Fake GPS