Last active
December 31, 2020 18:20
-
-
Save hare1039/d0470639c4957d3b04828962ebac427b to your computer and use it in GitHub Desktop.
A simple steganography program stores data in png (red only)
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 <png++/png.hpp> | |
#include <iostream> | |
#include <memory> | |
#include <type_traits> | |
int constexpr bitmask = 0b00000011; | |
constexpr inline auto hash(char const * str, int h = 0) -> long long int { | |
return (!str[h] ? 5381 : (hash(str, h+1)*33) ^ str[h] ); | |
} | |
constexpr inline auto operator "" _(char const * p, size_t) -> long long int { return hash(p); } | |
inline auto hash(std::string const & s) -> long long int { return hash (s.c_str()); } | |
auto bytestream(std::string const & input) -> std::vector<int> | |
{ | |
std::vector<int> result; | |
std::size_t total = input.length() * 4 + 4; | |
result.push_back((total >> 0) & bitmask); | |
result.push_back((total >> 2) & bitmask); | |
result.push_back((total >> 4) & bitmask); | |
result.push_back((total >> 6) & bitmask); | |
for (char c : input) | |
{ | |
result.push_back((c >> 0) & bitmask); | |
result.push_back((c >> 2) & bitmask); | |
result.push_back((c >> 4) & bitmask); | |
result.push_back((c >> 6) & bitmask); | |
} | |
return result; | |
} | |
auto decode(std::vector<int> const &data) -> std::string | |
{ | |
std::string result; | |
auto it = data.begin(); | |
std::size_t size = | |
*(it+0) << 0 | | |
*(it+1) << 2 | | |
*(it+2) << 4 | | |
*(it+3) << 6; | |
std::advance(it, 4); | |
for (; it != data.end() && std::distance(data.begin(), it) < size; std::advance(it, 4)) | |
{ | |
char size = | |
*(it+0) << 0 | | |
*(it+1) << 2 | | |
*(it+2) << 4 | | |
*(it+3) << 6; | |
result += size; | |
} | |
return result; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
if (argc <= 2 or argc >= 5) | |
{ | |
std::cerr << "hide-text [encrypt|decrypt] file.png [Your secret message]\n"; | |
return 1; | |
} | |
std::string command = argv[1], pngfile = argv[2], message; | |
if (argc == 4) | |
message = argv[3]; | |
png::image<png::rgba_pixel> image(pngfile); | |
switch (hash(command)) | |
{ | |
case "encrypt"_: | |
{ | |
std::vector<int> bs = bytestream(message); | |
auto it = bs.begin(); | |
for (png::uint_32 y = 0; y < image.get_height() && it != bs.end(); y++) | |
{ | |
for (png::uint_32 x = 0; x < image.get_width() && it != bs.end(); x++) | |
{ | |
png::rgba_pixel p = image.get_pixel(x, y); | |
auto v = p.red; | |
p.red = (p.red >> 2 << 2) | (*it++); | |
image.set_pixel(x, y, p); | |
} | |
} | |
image.set_compression_type(png::compression_type_default); | |
image.write(pngfile + ".encrypted.png"); | |
break; | |
} | |
case "decrypt"_: | |
{ | |
std::vector<int> data; | |
for (png::uint_32 y = 0; y < image.get_height(); y++) | |
{ | |
for (png::uint_32 x = 0; x < image.get_width(); x++) | |
{ | |
png::rgba_pixel p = image.get_pixel(x, y); | |
data.push_back(p.red & bitmask); | |
} | |
} | |
std::cout << decode(data) << "\n"; | |
break; | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment