SilentEye 0.4.1

modules/seformatjpeg/stegotable.cpp

Go to the documentation of this file.
00001 //  This file is part of SilentEye.
00002 //
00003 //  SilentEye is free software: you can redistribute it and/or modify
00004 //  it under the terms of the GNU General Public License as published by
00005 //  the Free Software Foundation, either version 3 of the License, or
00006 //  (at your option) any later version.
00007 //
00008 //  SilentEye is distributed in the hope that it will be useful,
00009 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 //  GNU General Public License for more details.
00012 //
00013 //  You should have received a copy of the GNU General Public License
00014 //  along with SilentEye.  If not, see <http://www.gnu.org/licenses/>.
00015 
00016 #include "stegotable.h"
00017 
00018 #include <moduleexception.h>
00019 
00020 #include <math.h>
00021 
00022 using namespace SilentEyeFramework;
00023 
00024 namespace SEFormatJPEG
00025 {
00027     StegoTable::StegoTable(const QString& passphrase, const quint8 k, QObject* parent) : QObject(parent), _k(k)
00028     {
00029         setObjectName("StegoTable");
00030         m_logger = new Logger(this);
00031 
00032         QString key = "SilentEye";
00033         if (passphrase.trimmed() != "")
00034         {
00035            key = passphrase.trimmed();
00036         }
00037 
00038         QByteArray hash = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Md5);
00039         _md5 = hash.toHex();
00040 
00041         _currentTable = 0;
00042         init_tables();
00043     }
00044 
00045     StegoTable::~StegoTable()
00046     {
00047         // NOTHING TO DO
00048     }
00049 
00051     float StegoTable::computeMiddle(float miv)
00052     {
00053         qint16 inf = floor(miv / (double)_k) * _k;
00054         float val = inf + (_k / 2.0);
00055         /*m_logger->debug("miv: " + QString::number(val)
00056                         + "=> stegotable index: " + QString::number( floor(val / (double)_k)));*/
00057         return val;
00058     }
00059 
00061     quint8 StegoTable::k()
00062     {
00063         return _k;
00064     }
00065 
00066     float StegoTable::computeNewMiv(float oldMiv, bool value)
00067     {
00068         float newMiv = -1;
00069         getNextTable();
00070 
00071         if (computeValue(oldMiv, false) !=  value)
00072         {
00073             for (int i = 1; i<3; i++)
00074             {
00075                 newMiv = oldMiv - (i*_k);
00076                 if (newMiv >= 0)
00077                 {
00078                     if (computeValue(newMiv, false) == value)
00079                     {
00080                         newMiv = computeMiddle(newMiv);
00081                         if (newMiv > 255)
00082                         {
00083                             newMiv = 255;
00084                         }
00085                         if (computeValue(newMiv, false) != value)
00086                         {
00087                             throw ModuleException("Invalid new miv value!", QString::number(newMiv));
00088                         }
00089                         return newMiv;
00090                     }
00091                 }
00092 
00093                 newMiv = oldMiv + (i*_k);
00094                 if (newMiv <= 255)
00095                 {
00096                     if (computeValue(newMiv, false) == value)
00097                     {
00098                         newMiv = computeMiddle(newMiv);
00099                         if (newMiv > 255)
00100                         {
00101                             newMiv = 255;
00102                         }
00103                         if (computeValue(newMiv, false) != value)
00104                         {
00105                             throw ModuleException("Invalid new miv value!", QString::number(newMiv));
00106                         }
00107                         return newMiv;
00108                     }
00109                 }
00110             }
00111 
00112             throw ModuleException("Cannot find interval in stgeoTable", "MIV : " + QString::number(oldMiv));
00113 
00114         } else {
00115             newMiv = computeMiddle(oldMiv);
00116             if (computeValue(newMiv, false) != value)
00117             {
00118                 throw ModuleException("Invalid new miv value!", QString::number(newMiv));
00119             }
00120         }
00121 
00122         return newMiv;
00123     }
00124 
00126     bool StegoTable::computeValue(float miv, bool next)
00127     {
00128         QBitArray stegoTable = next ? getNextTable() : _stTables[_indexTable[_currentTable]];
00129         int index = floor(miv / (double)_k);
00130         /*m_logger->debug("miv: " + QString::number(miv)
00131                         + "=> stegotable index: " + QString::number(index));*/
00132         return stegoTable.at(index);
00133     }
00134 
00136     QBitArray StegoTable::getNextTable()
00137     {
00138         _currentTable++;
00139         if (_currentTable >= _indexTable.size())
00140         {
00141             _currentTable = 0;
00142         }
00143         return _stTables[_indexTable[_currentTable]];
00144     }
00145 
00147     void StegoTable::init_tables()
00148     {
00149         int currentMD5position = 0; // using char index of the md5 string
00150 
00151         // Converts the first character of md5 into int
00152         int currentMD5value = -48 + _md5[currentMD5position].digitValue();
00153 
00154         int stSize = (int)ceil(255 / (double)_k); // stego table length
00155         stSize = stSize % 2 == 0 ? stSize : stSize + 1;
00156 
00157         _stTables.clear();
00158         _stTables.resize(_k);
00159         for (int stNumber = 0; stNumber < _k; stNumber++)
00160         {
00161             _stTables[stNumber] = QBitArray(stSize);
00162             // nbBitInsered: number of bits insered into the current stego table
00163             int nbBitInsered = 0; bool bit = false;
00164             do
00165             {
00166                 // compute and add the next bit into the current stego stable
00167                 if (nbBitInsered < stSize)
00168                 {
00169                     // get the bit to set into the table (&1 logical and operator, likes subnet mask)
00170                     bit = ((currentMD5value & 1) == 1);
00171                     //Add the curent bit into the stego table
00172                     _stTables[stNumber][nbBitInsered++] = bit;
00173                 }
00174                 // force next bit for no continious bits like 000 or 111 in a table.
00175                 if (nbBitInsered != 0 && nbBitInsered < stSize)
00176                 {
00177                     _stTables[stNumber][nbBitInsered++] = !bit;
00178                 }
00179 
00180                 // update the current md5 char (move index or update bits)
00181                 if ((stNumber * stSize + nbBitInsered) % 5 != 0) // %5 because a char is coded on 5 bits
00182                 {
00183                     // remove the used bit from the current number. (decalage de bit)
00184                     currentMD5value = currentMD5value >> 1;
00185                 }
00186                 else if (currentMD5position + 1 < _md5.size())
00187                 {
00188                     // get the next number if the current is over.
00189                     currentMD5value = -48 + (int)_md5[++currentMD5position].toAscii();
00190                 }
00191                 else
00192                 {
00193                     // get the next number if the current is over.
00194                     currentMD5value = -48 + (int)_md5[0].toAscii();
00195                     currentMD5position = 0;
00196                 }
00197                 //throw Exception("MD5 string is too short for an interval of " + _k + " (k)");
00198 
00199             } while (nbBitInsered < stSize);
00200 
00201         }
00202 
00203         initIndexTable();
00204     }
00205 
00207     void StegoTable::initIndexTable()
00208     {
00209         int value = 0;
00210         int currentPosition = 0;
00211 
00212         _indexTable.clear();
00213         _indexTable.resize((_stTables[0].size() * _k) / 8.0); // floor
00214 
00215         // cut bits by 8
00216         for (int stNumber = 0; stNumber < _k; stNumber++)
00217         {
00218             for (int i = 0; i < _stTables[0].size(); i++)
00219             {
00220                 value = value << 1;
00221 
00222                 value += _stTables[stNumber][i] ? 1 : 0; // convert bool into int
00223 
00224                 // When we go a full octet (8 bits read)
00225                 if (stNumber+i!=0 && (stNumber * _stTables[0].size() + i) % 8 == 0 && currentPosition!=_indexTable.size())
00226                 {
00227                     _indexTable[currentPosition++] = value % _k;
00228                     value = 0;
00229                 }
00230             }
00231         }
00232     }
00233 
00235     QString StegoTable::toString()
00236     {
00237         QString str = "> Stego tables\n";
00238         for (int i=0; i < _stTables.size(); i++)
00239         {
00240             str += i+": ";
00241             for (int j = 0; j < _stTables[i].size(); j++)
00242             {
00243                 str += _stTables[i][j] + QString(",");
00244             }
00245             str += "\n";
00246         }
00247 
00248         str += "> Index Table:\n";
00249         for (int i = 0; i < _indexTable.size(); i++)
00250         {
00251             str += QString::number(_indexTable.at(i));
00252         }
00253         return str;
00254     }
00255 }