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