SilentEye 0.4.1
|
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 }