Steganography
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 <QtDebug> | |
#include <QImage> | |
#include <QString> | |
#include <QBitArray> | |
#include <QByteArray> | |
#include <QFile> | |
#include <QCommandLineParser> | |
namespace { | |
enum { headerSize = 32 }; | |
QByteArray bitArrayToByteArray(const QBitArray& bits) { | |
QByteArray bytes; | |
bytes.resize(bits.count() / 8); | |
bytes.fill(0); | |
for (int b = 0; b < bits.count(); ++b) | |
bytes[b / 8] = (bytes.at(b / 8) | ((bits[b] ? 1 : 0) << (b % 8))); | |
return bytes; | |
} | |
QBitArray byteArrayToBitarray(const QByteArray& bytes) { | |
QBitArray bits(bytes.count() * 8); | |
for (int i = 0; i < bytes.count(); ++i) | |
for (int b = 0; b < 8; ++b) | |
bits.setBit(i * 8 + b, bytes.at(i) & (1 << b)); | |
return bits; | |
} | |
} | |
QByteArray read(const QString& filename) { | |
QBitArray bits(8); | |
QByteArray bytes; | |
bytes.reserve(headerSize); | |
int bytesToRead = 0; | |
QImage image; | |
if (image.load(filename)) { | |
for (int y = 0; y < image.height(); ++y) { | |
for (int x = 0; x < image.width(); ++x) { | |
QRgb pixel = image.pixel(x, y); | |
uint32_t index = 0; | |
bits[index++] = qRed(pixel) & 1 << 0x00; | |
bits[index++] = qGreen(pixel) & 1 << 0x00; | |
bits[index++] = qBlue(pixel) & 1 << 0x00; | |
bits[index++] = qAlpha(pixel) & 1 << 0x00; | |
bits[index++] = qRed(pixel) & 1 << 0x01; | |
bits[index++] = qGreen(pixel) & 1 << 0x01; | |
bits[index++] = qBlue(pixel) & 1 << 0x01; | |
bits[index++] = qAlpha(pixel) & 1 << 0x01; | |
bytes += bitArrayToByteArray(bits); | |
if (!bytesToRead && bytes.size() == headerSize) { | |
bool ok; | |
bytesToRead = bytes.toInt(&ok); | |
if (!ok) | |
return bytes; | |
bytes.clear(); | |
bytes.reserve(bytesToRead); | |
} | |
if (bytes.size() == bytesToRead) { | |
return bytes; | |
} | |
} | |
} | |
} | |
return bytes; | |
} | |
bool write(const QString& in, const QString& out, const QByteArray& message){ | |
QImage image; | |
if (!image.load(in)) | |
return false; | |
QImage result = image.copy(); | |
int size = message.size(); | |
QByteArray bytes; | |
bytes.reserve(size + headerSize); | |
bytes += QString("%1").arg(size, headerSize, 10, QChar('0')); | |
bytes += message; | |
QBitArray bits = byteArrayToBitarray(bytes); | |
for (int index = 0, y = 0; y < image.height(); ++y) { | |
for (int x = 0; x < image.width(); ++x) { | |
if (index >= bits.count()) | |
break; | |
QRgb pixel = image.pixel(x, y); | |
int red = qRed(pixel); | |
int green = qGreen(pixel); | |
int blue = qBlue(pixel); | |
int alpha = qAlpha(pixel); | |
red = bits[index + 0] ? red | (1 << 0x00) : red & ~(1 << 0x00); | |
green = bits[index + 1] ? green | (1 << 0x00) : green & ~(1 << 0x00); | |
blue = bits[index + 2] ? blue | (1 << 0x00) : blue & ~(1 << 0x00); | |
alpha = bits[index + 3] ? alpha | (1 << 0x00) : alpha & ~(1 << 0x00); | |
red = bits[index + 4] ? red | (1 << 0x01) : red & ~(1 << 0x01); | |
green = bits[index + 5] ? green | (1 << 0x01) : green & ~(1 << 0x01); | |
blue = bits[index + 6] ? blue | (1 << 0x01) : blue & ~(1 << 0x01); | |
alpha = bits[index + 7] ? alpha | (1 << 0x01) : alpha & ~(1 << 0x01); | |
result.setPixel(x, y, qRgba(red, green, blue, alpha)); | |
index += 8; | |
} | |
} | |
return result.save(out); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
QCoreApplication app(argc, argv); | |
QCoreApplication::setApplicationName("stenog"); | |
QCoreApplication::setApplicationVersion("1.0"); | |
const QCommandLineOption readOption("i", "The input image", "read"); | |
const QCommandLineOption writeOption("o", "The output image", "write"); | |
const QCommandLineOption messageOption("m", "The message", "message"); | |
QCommandLineParser parser; | |
parser.setApplicationDescription("This tool can read and write a message onto a image using steganography"); | |
parser.addHelpOption(); | |
parser.addVersionOption(); | |
parser.addOption(readOption); | |
parser.addOption(writeOption); | |
parser.addOption(messageOption); | |
parser.process(app); | |
if (parser.isSet(readOption) && !parser.isSet(writeOption)) { | |
const QString in_filename = parser.value(readOption); | |
auto result = qPrintable(read(in_filename)); | |
fputs(result, stdout); | |
} else { | |
const QString out_filename = parser.value(writeOption); | |
const QString in_filename = parser.value(readOption); | |
const QString message = parser.value(messageOption); | |
write(in_filename, out_filename, message.toLocal8Bit()); | |
} | |
return 0; | |
} |
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
QT += core | |
CONFIG += c++11 | |
CONFIG -= app_bundle | |
TARGET = stenog | |
TEMPLATE = app | |
SOURCES += \ | |
main.cpp |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment