//btnDecrypt Click Event starting the decryption private void btnDecrypt_Click(object sender, EventArgs e) { txtBxDecrypt.Text = ""; OpenFileDialog curDialog = new OpenFileDialog(); if (curDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { using (Bitmap curBitmap = curIO.fileValidImage(curDialog.FileName)) { if (curBitmap != null) { Decrypting curDecrypting = new Decrypting((Color)cmbBxDecryptStart.SelectedItem, curBitmap, curIO, (int)numUpDwnDecrypt.Value); if (!curDecrypting.errors) { txtBxDecrypt.Text = curDecrypting.decryptedString; } else { displayError("Either the input parameters or the image are wrong.", curDecrypting.errorMessage, false); } } else displayError("Please, selected a valid image file.", null, false); } } }
public Point startPixelOrig; //Stores the "fake start point", relevant while analysing the next pixels storing length information #endregion Fields #region Constructors //--- //Starting actions on account of the given process (encryption/decription) public Hashing(Color temp_startColor, Encrypting curEncrypting, Decrypting curDecrypting, IO temp_curIO) { startColor = temp_startColor; curIO = temp_curIO; curColors = new List<Color>(curIO.allKnownColors); startOffset = new startOffsetInfo(); if (curEncrypting != null) { if (curEncrypting.origText == null || curEncrypting.origText.Length < 1) { errors = true; return; } curLength = curEncrypting.origText.Length + 2 + (curEncrypting.origText.Length + 2).ToString().Length; //Length considered while decrypting encryptingNumber = curEncrypting.encryptingNumber; } else { if (curDecrypting.origBitmap == null) { errorMessage = "There was a problem while accessing the image file."; errors = true; return; } encryptingNumber = curDecrypting.encryptingNumber; pixelsToIgnore = new List<Point>(); //Preliminary validity check by looking for the startColor (in the right position) and determining the length (and the offset, if applicable) curIO.getBoundaryPixels(curDecrypting, this); if (curLength <= 0) { errors = true; return; } } calculateStartStep(); //Calculating curStep buildCharsVsColors(); //Building the hash table (dictionary with all the accounted characters and their equivalent color) which will be used in the current encryption/decryption process if (curDecrypting != null) { //For decryption. Confirming that the length value, calculated above, matches the information in the pixels enconding the actual length. //The reason for not having this analysis before is the fact that the charsVsColors is required if (!curIO.lengthIsOK(curDecrypting, this)) this.errors = true; } }
//There is an offset and thus the actual start of the encrypted chunk is certain; but this determination is not evident as far as it is stored as an integer (= distance). //This integer has to be converted into actual pixel/point position; this is what this function does: returning the actual start point by bringing the offset into account private Point newStartFromOffset(Point curStart, int offSet, Decrypting curDecrypting) { Point newStart = new Point(); int curCount = 0; bool firstTime = true; for (int x = curDecrypting.origBitmap.Width - 1; x >= 0; x--) { for (int y = curDecrypting.origBitmap.Height - 1; y >= 0; y--) { if (firstTime) { x = curStart.X; y = curStart.Y; firstTime = false; } curCount = curCount + 1; if (curCount > offSet) { newStart.X = x; newStart.Y = y; break; } } if (curCount >= offSet) break; } return newStart; }
//Last check performed while hashing (for decryption): the previously-calculated length has to match the value encrypted in some of the pixels of the image in order //to confirm that this is a right image and to go ahead with the decryption public bool lengthIsOK(Decrypting curDecrypting, Hashing curHashing) { bool isOK = true; curHashing.pixelsLength = new pixelsLengthInfo(); int count = -1; int calcLength = 0; string lengthString = ""; bool firstTime = true; bool foundStart = false; int startVal = 1; if (curHashing.startOffset.startOffsetCount > -1) startVal = startVal + 1; //"After pixel" of the offSet has also to be skipped for (int x = 0; x < curDecrypting.origBitmap.Width; x++) { for (int y = 0; y < curDecrypting.origBitmap.Height; y++) { if (firstTime) { x = curHashing.startPixelOrig.X; y = curHashing.startPixelOrig.Y; firstTime = false; } count = count + 1; if (count >= startVal) //to skip startColor and, eventually, offset after pixel { Color curColor = curDecrypting.origBitmap.GetPixel(x, y); KeyValuePair<char, Color> tempPair = curHashing.charsVsColors.FirstOrDefault(x2 => twoColorsAreEqual(x2.Value, curColor)); if (Char.IsDigit(tempPair.Key)) { curHashing.pixelsToIgnore.Add(new Point(x, y)); lengthString = lengthString + tempPair.Key.ToString(); if (!foundStart) { curHashing.pixelsLength.startPixel = new Point(x, y); foundStart = true; } } else { return false; } if (int.TryParse(lengthString, out calcLength)) { if (calcLength == curHashing.curLength) { curHashing.pixelsLength.length = calcLength; curHashing.pixelsLength.endPixel = new Point(x, y); return true; } } else return false; } } } return isOK; }
//-------------------- //------------------------------- DECRYPTING //Method call soon in the hashing (for decrypting) process: it does not only extract valuable information (start pixel, length and, eventually, offset), //but also avoids any wrong image to be analysed further. public void getBoundaryPixels(Decrypting curDecrypting, Hashing curHashing) { Point tempLast = new Point(-1, -1); int tempLength = -1; int lastLength = 0; Color nextPixel = new Color(); bool storeNext = false; curHashing.curLength = -1; for (int x = 0; x < curDecrypting.origBitmap.Width; x++) { for (int y = 0; y < curDecrypting.origBitmap.Height; y++) { if (tempLength >= 0) tempLength = tempLength + 1; Color curColor = curDecrypting.origBitmap.GetPixel(x, y); if (storeNext) { //This is the "after pixel" which confirms that an offset actually exists if (!twoColorsAreEqual(curColor, curHashing.startColor)) nextPixel = curColor; storeNext = false; } //StartColor determines where the "relevant chunk" starts/ends, what is done by this condition if (twoColorsAreEqual(curColor, curHashing.startColor)) { if (tempLength < 0) { curHashing.startPixel = new Point(x, y); curHashing.startPixelOrig = new Point(x, y); storeNext = true; tempLength = 0; } else { tempLast = new Point(x, y); lastLength = tempLength; } } } } if (tempLast != new Point(-1, -1) && lastLength > 0) { //The collected information seems right curHashing.endPixel = new Point(tempLast.X, tempLast.Y); curHashing.curLength = lastLength + 1; int afterIndex = curHashing.curIO.allKnownColors.IndexOf(curHashing.startColor) + curDecrypting.encryptingNumber; if (afterIndex > curHashing.curIO.allKnownColors.Count - 1) afterIndex = curDecrypting.encryptingNumber; Color afterOffset = curHashing.curIO.allKnownColors[afterIndex]; bool analyseOffset = !nextPixel.IsEmpty && twoColorsAreEqual(afterOffset, nextPixel); if (analyseOffset) { //There is an offset and thus some variables have to be updated curHashing.curLength = curHashing.curLength - 1; //afterOffset is not included withing the length value curHashing.startOffset.afterOffset = afterOffset; curHashing.startOffset.startOffsetCount = curDecrypting.encryptingNumber; curHashing.startOffset.startPoint = new Point(curHashing.startPixel.X, curHashing.startPixel.Y); curHashing.curLength = curHashing.curLength + curHashing.startOffset.startOffsetCount; curHashing.startPixel = newStartFromOffset(curHashing.startPixel, curHashing.startOffset.startOffsetCount, curDecrypting); } lengthCorrection(curHashing); } }
//Final stage of the decryption process: application of all the previous calculations to the image to extract the encrypted message public Decrypting decryptImage(Decrypting curDecrypting) { Bitmap curBitmap = curDecrypting.origBitmap; curDecrypting.decryptedString = ""; Hashing curHashing = curDecrypting.curHashing; bool origFound = false; bool firstTime = true; bool decryptColor = false; for (int x = 0; x < curDecrypting.origBitmap.Width; x++) //The analysis starts from the startPixel, already calculated while creating the Hash table { for (int y = 0; y < curDecrypting.origBitmap.Height; y++) { bool analyseStart = false; bool goAhead = false; if (firstTime) { x = curDecrypting.curHashing.startPixel.X; y = curDecrypting.curHashing.startPixel.Y; } Color curColor = curDecrypting.origBitmap.GetPixel(x, y); if (firstTime) { if (curHashing.startOffset.startOffsetCount == -1) //No offset { analyseStart = true; } else decryptColor = true; firstTime = false; } else if (curHashing.startOffset.startOffsetCount != -1) //Offset { if (!origFound && twoColorsAreEqual(curColor, curHashing.startColor)) { analyseStart = true; } } if (analyseStart) { //No offset and thus the restrictions in the conversions start already here if (!twoColorsAreEqual(curDecrypting.origBitmap.GetPixel(x, y), curHashing.startColor)) { curDecrypting.errors = true; return curDecrypting; } else { decryptColor = false; } } if (decryptColor) { //The original start point hasn't either be found or was found and all the surrounding, irrelevant information has already been skipped if (x == curHashing.endPixel.X && y == curHashing.endPixel.Y) { return curDecrypting; } goAhead = true; } else { if (!origFound) { if (x == curHashing.pixelsLength.endPixel.X && y == curHashing.pixelsLength.endPixel.Y) { origFound = true; decryptColor = true; //from the next pixel onwards, all the information should be decrypted } } else { curDecrypting.errors = true; return curDecrypting; } } if (goAhead) { KeyValuePair<char, Color> tempPair = curHashing.charsVsColors.FirstOrDefault(x2 => twoColorsAreEqual(x2.Value, curColor)); if (tempPair.Value.IsEmpty && !twoColorsAreEqual(curColor, curHashing.startColor)) { bool isOK = false; if (curDecrypting.encryptingNumber > 0) { if (!curHashing.replacePair.Value.IsEmpty && twoColorsAreEqual(curColor, curHashing.replacePair.Value)) { tempPair = new KeyValuePair<char, Color>(curHashing.replacePair.Key, curColor); isOK = true; } else if (!curHashing.startOffset.replaceAfter.Value.IsEmpty && twoColorsAreEqual(curColor, curHashing.startOffset.replaceAfter.Value)) { tempPair = new KeyValuePair<char, Color>(curHashing.startOffset.replaceAfter.Key, curColor); isOK = true; } } if (!isOK) { curDecrypting.errors = true; return curDecrypting; } } curDecrypting.decryptedString = curDecrypting.decryptedString + tempPair.Key.ToString(); } } } return curDecrypting; }