SilentEye 0.4.1

modules/seformatjpegold/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 <crypto.h>
00019 #include <moduleexception.h>
00020 
00021 #include <math.h>
00022 
00023 using namespace SilentEyeFramework;
00024 
00025 namespace SEFormatJPEG
00026 {
00028     StegoTable::StegoTable(const QString& passphrase, const quint8 k, QObject* parent) : QObject(parent), _k(k)
00029     {
00030         setObjectName("StegoTable");
00031         m_logger = new Logger(this);
00032 
00033         if (passphrase.trimmed() == "")
00034         {
00035            _md5 = Crypto::md5("SilentEye");
00036         }
00037         else
00038         {
00039            _md5 = Crypto::md5(passphrase.trimmed());
00040         }
00041 
00042         _currentTable = 0;
00043         init_tables();
00044     }
00045 
00046     StegoTable::~StegoTable()
00047     {
00048         // NOTHING TO DO
00049     }
00050 
00052     float StegoTable::computeMiddle(float miv)
00053     {
00054         qint16 inf = floor(miv / (double)_k) * _k;
00055         float val = inf + (_k / 2.0);
00056         /*m_logger->debug("miv: " + QString::number(val)
00057                         + "=> stegotable index: " + QString::number( floor(val / (double)_k)));*/
00058         return val;
00059     }
00060 
00062     quint8 StegoTable::k()
00063     {
00064         return _k;
00065     }
00066 
00067     float StegoTable::computeNewMiv(float oldMiv, bool value)
00068     {
00069         float newMiv = -1;
00070         getNextTable();
00071 
00072         if (computeValue(oldMiv, false) !=  value)
00073         {
00074             for (int i = 1; i<3; i++)
00075             {
00076                 newMiv = oldMiv - (i*_k);
00077                 if (newMiv < 0)
00078                 {
00079                     newMiv = 0;
00080                 }
00081 
00082                 if (computeValue(newMiv, false) == value)
00083                 {
00084                     newMiv = computeMiddle(newMiv);
00085                     if (computeValue(newMiv, false) != value)
00086                     {
00087                         throw ModuleException("Invalid new miv value!", QString::number(newMiv));
00088                     }
00089                     return newMiv;
00090                 }
00091 
00092                 newMiv = oldMiv + (i*_k);
00093                 if (newMiv > 255)
00094                 {
00095                     newMiv = 255;
00096                 }
00097 
00098                 if (computeValue(newMiv, false) == value)
00099                 {
00100                     newMiv = computeMiddle(newMiv);
00101                     if (computeValue(newMiv, false) != value)
00102                     {
00103                         throw ModuleException("Invalid new miv value!", QString::number(newMiv));
00104                     }
00105                     return newMiv;
00106                 }
00107             }
00108 
00109             throw ModuleException("Cannot find interval in stgeoTable", "MIV : " + QString::number(oldMiv));
00110 
00111         } else {
00112             newMiv = computeMiddle(oldMiv);
00113             if (computeValue(newMiv, false) != value)
00114             {
00115                 throw ModuleException("Invalid new miv value!", QString::number(newMiv));
00116             }
00117         }
00118 
00119         return newMiv;
00120     }
00121 
00123     bool StegoTable::computeValue(float miv, bool next)
00124     {
00125         QBitArray stegoTable = next ? getNextTable() : _stTables[_indexTable[_currentTable]];
00126         int index = floor(miv / (double)_k);
00127         /*m_logger->debug("miv: " + QString::number(miv)
00128                         + "=> stegotable index: " + QString::number(index));*/
00129         return stegoTable.at(index);
00130     }
00131 
00133     QBitArray StegoTable::getNextTable()
00134     {
00135         _currentTable++;
00136         if (_currentTable >= _indexTable.size())
00137         {
00138             _currentTable = 0;
00139         }
00140         return _stTables[_indexTable[_currentTable]];
00141     }
00142 
00144     void StegoTable::init_tables()
00145     {
00146         int currentMD5position = 0; // using char index of the md5 string
00147 
00148         // Converts the first character of md5 into int
00149         int currentMD5value = -48 + _md5[currentMD5position].digitValue();
00150 
00151         int stSize = (int)ceil(255 / (double)_k); // stego table length
00152         stSize = stSize % 2 == 0 ? stSize : stSize + 1;
00153 
00154         _stTables.clear();
00155         _stTables.resize(_k);
00156         for (int stNumber = 0; stNumber < _k; stNumber++)
00157         {
00158             _stTables[stNumber] = QBitArray(stSize);
00159             // nbBitInsered: number of bits insered into the current stego table
00160             int nbBitInsered = 0; bool bit = false;
00161             do
00162             {
00163                 // compute and add the next bit into the current stego stable
00164                 if (nbBitInsered < stSize)
00165                 {
00166                     // get the bit to set into the table (&1 logical and operator, likes subnet mask)
00167                     bit = ((currentMD5value & 1) == 1);
00168                     //Add the curent bit into the stego table
00169                     _stTables[stNumber][nbBitInsered++] = bit;
00170                 }
00171                 // force next bit for no continious bits like 000 or 111 in a table.
00172                 if (nbBitInsered != 0 && nbBitInsered < stSize)
00173                 {
00174                     _stTables[stNumber][nbBitInsered++] = !bit;
00175                 }
00176 
00177                 // update the current md5 char (move index or update bits)
00178                 if ((stNumber * stSize + nbBitInsered) % 5 != 0) // %5 because a char is coded on 5 bits
00179                 {
00180                     // remove the used bit from the current number. (decalage de bit)
00181                     currentMD5value = currentMD5value >> 1;
00182                 }
00183                 else if (currentMD5position + 1 < _md5.size())
00184                 {
00185                     // get the next number if the current is over.
00186                     currentMD5value = -48 + (int)_md5[++currentMD5position].toAscii();
00187                 }
00188                 else
00189                 {
00190                     // get the next number if the current is over.
00191                     currentMD5value = -48 + (int)_md5[0].toAscii();
00192                     currentMD5position = 0;
00193                 }
00194                 //throw Exception("MD5 string is too short for an interval of " + _k + " (k)");
00195 
00196             } while (nbBitInsered < stSize);
00197 
00198         }
00199 
00200         initIndexTable();
00201     }
00202 
00204     void StegoTable::initIndexTable()
00205     {
00206         int value = 0;
00207         int currentPosition = 0;
00208 
00209         _indexTable.clear();
00210         _indexTable.resize((_stTables[0].size() * _k) / 8.0); // floor
00211 
00212         // cut bits by 8
00213         for (int stNumber = 0; stNumber < _k; stNumber++)
00214         {
00215             for (int i = 0; i < _stTables[0].size(); i++)
00216             {
00217                 value = value << 1;
00218 
00219                 value += _stTables[stNumber][i] ? 1 : 0; // convert bool into int
00220 
00221                 // When we go a full octet (8 bits read)
00222                 if (stNumber+i!=0 && (stNumber * _stTables[0].size() + i) % 8 == 0 && currentPosition!=_indexTable.size())
00223                 {
00224                     _indexTable[currentPosition++] = value % _k;
00225                     value = 0;
00226                 }
00227             }
00228         }
00229     }
00230 
00232     QString StegoTable::toString()
00233     {
00234         QString str = "> Stego tables\n";
00235         for (int i=0; i < _stTables.size(); i++)
00236         {
00237             str += i+": ";
00238             for (int j = 0; j < _stTables[i].size(); j++)
00239             {
00240                 str += _stTables[i][j] + QString(",");
00241             }
00242             str += "\n";
00243         }
00244 
00245         str += "> Index Table:\n";
00246         for (int i = 0; i < _indexTable.size(); i++)
00247         {
00248             str += QString::number(_indexTable.at(i));
00249         }
00250         return str;
00251     }
00252 }