Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #Region " Usage Examples "
- 'Public Class Form1
- ' ''' <summary>
- ' ''' Instance of a Class containing most of the methods involving image-related actions,
- ' ''' common to both encryption and decryption.
- ' ''' </summary>
- ' Dim curentIO As New IO
- ' Private Sub Test() Handles MyBase.Load
- ' ' Encrypt text into image:
- ' Dim Encrypt As New Encrypting(Color.Red, "Hello World!", curentIO, 0)
- ' Dim EncryptedImage As Bitmap = Nothing
- ' Select Case Encrypt.errors
- ' Case False
- ' ' Encrypts the text and returns the encrypted Bitmap.
- ' EncryptedImage = curentIO.Encrypt(500, 500, Encrypt)
- ' ' Or encrypts the text and save it directlly in a image file.
- ' Encrypt = curentIO.SaveImageFile("C:\File.png", 500, 500, Encrypt)
- ' Case True
- ' MessageBox.Show(Encrypt.errorMessage, "There was an error while encrypting the text.")
- ' End Select
- ' ' Decrypt image into text:
- ' Dim Decrypt As New Decrypting(Color.Red, EncryptedImage, curentIO, 0)
- ' ' Dim Decrypt As New Decrypting(Color.Red, Bitmap.FromFile("C:\File.png"), curentIO, 0)
- ' If Not Decrypt.errors Then
- ' MsgBox(Decrypt.decryptedString)
- ' Else
- ' MessageBox.Show(Decrypt.errorMessage, "Either the input parameters or the image are wrong.")
- ' End If
- ' End Sub
- 'End Class
- #End Region
- #Region " Imports "
- Imports System.Globalization
- Imports System.IO
- #End Region
- #Region " Chromatic Encryption/Decryption "
- ''' <summary>
- ''' Class storing the main methods dealing with the encryption process (i.e., application of the "hashed values" to the input characters).
- ''' Pretty small class, as far as most of the actions are performed in Hashing and while dealing with image (in IO).
- ''' </summary>
- Public Class Encrypting
- ''' <summary>
- ''' List of colors representing the true output from this class.
- ''' These are the only pixels containing information the remaining ones in the output picture are just to "make dummy space".
- ''' </summary>
- Public encryptedString As List(Of Color)
- ''' <summary>
- ''' In some cases, the input text might be changed
- ''' (e.g., characters with no color equivalent); this variable will store this variations.
- ''' </summary>
- Public modifiedText As String
- ''' <summary>
- ''' This list include all the characters which are not encrypted (if any).
- ''' </summary>
- Public ignoredChars As List(Of Char)
- ''' <summary>
- ''' Very important in the encryption process as far as it represents the
- ''' only parameter which cannot deduced from the picture.
- ''' </summary>
- Public errors As Boolean
- Public origText As String
- Public curHashing As Hashing
- Public errorMessage As String
- Public encryptingNumber As Integer
- ''' <summary>
- ''' Contructor carrying out the main actions for this class
- ''' </summary>
- ''' <param name="startColor">The start color.</param>
- ''' <param name="temp_origText">The temp_orig text.</param>
- ''' <param name="curIO">The current io.</param>
- ''' <param name="temp_encryptingNumber">The temp_encrypting number.</param>
- Public Sub New(ByVal startColor As Color,
- ByVal temp_origText As String,
- ByVal curIO As IO,
- ByVal temp_encryptingNumber As Integer)
- If temp_origText Is Nothing AndAlso temp_origText.Trim.Length < 1 Then
- errorMessage = "Please, introduce the string to be encrypted."
- errors = True
- Return
- End If
- ignoredChars = New List(Of Char)
- origText = temp_origText
- modifiedText = origText
- encryptingNumber = temp_encryptingNumber
- ' Creating the "hash table" (list of colors associated to the characters) has, logically, to be done before starting the encryption.
- ' Note that the input string (it's length) is also brought into picture while hashing.
- curHashing = New Hashing(startColor, Me, Nothing, curIO)
- 'Performing the actual encryption
- If Not curHashing.errors Then
- encryptText(startColor, origText)
- Else
- errorMessage = curHashing.errorMessage
- errors = True
- End If
- End Sub
- ''' <summary>
- ''' Method performing the pure encription, that is:
- ''' Conversion of each character from the input string into the corresponding color.
- ''' </summary>
- ''' <param name="curColor">Current color.</param>
- ''' <param name="curText">Current text to encrypt.</param>
- Public Sub encryptText(curColor As Color, curText As String)
- ignoredChars = New List(Of Char)
- encryptedString = New List(Of Color)
- For Each curChar As Char In origText
- If curHashing.charsVsColors.ContainsKey(curChar) Then
- encryptedString.Add(curHashing.charsVsColors(curChar))
- Else
- 'Due to the limited number of available colors (to ease the usability),
- ' quite a few characters are not accounted for.
- encryptedString.Add(curHashing.charsVsColors(" "c))
- If Not ignoredChars.Contains(curChar) Then
- ignoredChars.Add(curChar)
- modifiedText = modifiedText.Replace(curChar, " "c)
- End If ' ignoredChars.Contains(curChar)
- End If ' curHashing.charsVsColors.ContainsKey(curChar)
- Next ' curChar
- End Sub
- End Class
- ''' <summary>
- ''' Class storing the main methods dealing with the decryption process
- ''' (i.e., extracting the encrypted information contained in the input image).
- ''' Pretty small class, as far as most of the actions are performed in Hashing and while dealing with image (in IO).
- ''' </summary>
- Public Class Decrypting
- Public origBitmap As Bitmap
- ' Number input via numericUpDown.
- ' Very important in the encryption process as far as it represents the only parameter which cannot deduced from the picture.
- Public encryptingNumber As Integer
- Public curHashing As Hashing
- Public decryptedString As String
- Public errors As Boolean
- Public errorMessage As String
- ''' <summary>
- ''' Constructor with the required "pre-actions" (e.g., hashing) before starting the process
- ''' </summary>
- ''' <param name="startColor">The start color.</param>
- ''' <param name="curBitMap">The current bit map.</param>
- ''' <param name="curIO">The current IO object.</param>
- ''' <param name="temp_encryptingNumber">The temporal encrypting number.</param>
- Public Sub New(ByVal startColor As Color,
- ByVal curBitMap As Bitmap,
- ByVal curIO As IO,
- ByVal temp_encryptingNumber As Integer)
- origBitmap = curBitMap
- encryptingNumber = temp_encryptingNumber
- curHashing = New Hashing(startColor, Nothing, Me, curIO)
- If Not curHashing.errors Then
- startDecrypting(curIO)
- Else
- errorMessage = curHashing.errorMessage
- errors = True
- End If
- End Sub
- ''' <summary>
- ''' Decrypting process which, as far as it involves image management, is located in the 'IO' class.
- ''' </summary>
- ''' <param name="curIO">Indicates the current 'IO' object.</param>
- Public Sub startDecrypting(ByVal curIO As IO)
- curIO.decryptImage(Me)
- End Sub
- End Class
- ''' <summary>
- ''' Class containing all the hashing-related methods. This is an extremely important pre-step for both encryption and decryption
- ''' </summary>
- Public Class Hashing
- Public curIO As IO
- Public charsVsColors As Dictionary(Of Char, Color)
- Public startColor As Color
- Public curColors As List(Of Color)
- Public replacePair As KeyValuePair(Of Char, Color) 'Color not present in the current hashing table and used to replace the startColor if required (e.g., char assigned to startColor used in the offset before the first start pixel)
- Public encryptingNumber As Integer 'Input value, of high importance in the hashing process (also in the encrypting/decrypting ones)
- Public curStep As Integer 'Variable determining the variation color-to-color (in the original array of colors) accounted for while assigning a color to each variable. It is influenced by numerous parameters
- Public curLength As Integer 'Total length of the encrypted string. This value is always bigger than the actual length of the string (to store further information). It is part of the information accounted for while encrypting/decrypting
- Public errors As Boolean
- Public errorMessage As String
- '----- Decrypting
- Public startPixel As Point, endPixel As Point 'This has to be calculated here because the length is accounted for while hashing
- Public startPixelOrig As Point 'Stores the "fake start point", relevant while analysing the next pixels storing length information
- Public pixelsToIgnore As List(Of Point) 'List of pixels storing security information which does not have to be decrypted (e.g., length of the original string)
- Public pixelsLength As pixelsLengthInfo 'Instance referring the information regarding the pixels storing the length of the encrypted text
- Public startOffset As startOffsetInfo
- '-----
- ''' <summary>
- ''' Starting actions on account of the given process (encryption/decription)
- ''' </summary>
- ''' <param name="temp_startColor">Color of the temp_start.</param>
- ''' <param name="curEncrypting">The current encrypting.</param>
- ''' <param name="curDecrypting">The current decrypting.</param>
- ''' <param name="temp_curIO">The temp_cur io.</param>
- Public Sub New(temp_startColor As Color, curEncrypting As Encrypting, curDecrypting As Decrypting, temp_curIO As IO)
- startColor = temp_startColor
- curIO = temp_curIO
- curColors = New List(Of Color)(curIO.allKnownColor)
- startOffset = New startOffsetInfo()
- If curEncrypting IsNot Nothing Then
- If curEncrypting.origText Is Nothing OrElse curEncrypting.origText.Length < 1 Then
- errors = True
- Return
- End If
- curLength = curEncrypting.origText.Length + 2 + (curEncrypting.origText.Length + 2).ToString.Length 'Length considered while decrypting
- encryptingNumber = curEncrypting.encryptingNumber
- Else
- If curDecrypting.origBitmap Is Nothing Then
- errorMessage = "There was a problem while accessing the image file."
- errors = True
- Return
- End If
- encryptingNumber = curDecrypting.encryptingNumber
- pixelsToIgnore = New List(Of Point)
- 'Preliminary validaty check by looking for the startColor (in the right position) and determining the length (and the offset, if applicable)
- curIO.getBoundaryPixels(curDecrypting, Me)
- If curLength <= 0 Then
- errors = True
- Return
- End If
- End If
- 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 IsNot Nothing Then
- '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 Not curIO.lengthIsOK(curDecrypting, Me) Then errors = True
- End If
- End Sub
- ''' <summary>
- ''' To increase the importance of the startIndex
- ''' (first KnownColors index considered while populating the charsVsColors collection),
- ''' the original array of known colors is completely reordered on account of it.
- ''' This is a new way to increase the randomness/complexity of the encryption and make sure that the
- ''' effect from the Encrypting Number is influential enough, mainly for short texts.
- ''' </summary>
- ''' <param name="startIndex">Indicates the start index.</param>
- Private Sub reorderKnownColors(startIndex As Integer)
- Dim newList As List(Of Color) = New List(Of Color)
- For i As Integer = startIndex To curColors.Count - 1
- Dim newIndex As Integer = i + encryptingNumber
- If newIndex >= curColors.Count Then newIndex = 0
- Dim iterations As Integer = 0
- While newIndex < curColors.Count AndAlso newList.Contains(curColors(newIndex))
- newIndex = newIndex + 1
- If newIndex >= curColors.Count Then
- If iterations = 0 Then
- newIndex = 0
- iterations = iterations + 1
- Else
- Exit While
- End If
- End If
- End While
- If Not newList.Contains(curColors(newIndex)) Then newList.Add(curColors(newIndex))
- If newList.Count = curColors.Count Then Exit For
- If i >= curColors.Count - 1 AndAlso newList.Count < curColors.Count Then i = 0
- Next
- curColors = New List(Of Color)(newList)
- End Sub
- ''' <summary>
- ''' Building the basic "hashing dictionary", charsVsColors,
- ''' where each (recognised) character is related to a given color.
- ''' The relationships characters->colors is different every time and varies
- ''' on account of different variables (e.g., encrypting integer or length of the input text)
- ''' </summary>
- Private Sub buildCharsVsColors()
- charsVsColors = New Dictionary(Of Char, Color)
- Dim curColor As Color = startColor
- Dim minIndex As Integer = 0
- Dim maxIndex As Integer = 240 'The restricted number of colors forces to choose just specific characters
- Dim curRGB As RGBInfo = New RGBInfo
- curRGB.lastR = startColor.R
- curRGB.lastG = startColor.G
- curRGB.lastB = startColor.B
- curRGB.lastIndex = calculateFirst() 'Calculating the start index (from the original List of known colors) from which all the analysis will be started
- reorderKnownColors(curRGB.lastIndex) 'Reordering the original list with all the known colors on account of the inputs
- Dim availableColors As List(Of Color) = New List(Of Color)(curColors)
- For i As Integer = minIndex To maxIndex - 1
- If Not (i >= 127 AndAlso i <= 160) Then 'The restricted number of colors forces to choose just specific characters
- Dim noDiacritics As String = Me.ConvertDiacritics(Convert.ToChar(i).ToString())
- If Not (noDiacritics <> Convert.ToChar(i).ToString) Then 'The restricted number of colors forces to choose just specific characters
- curRGB = updateRGB(curRGB, availableColors)
- curColor = availableColors(curRGB.curIndex)
- curRGB.lastR = curColor.R
- curRGB.lastG = curColor.G
- curRGB.lastB = curColor.B
- charsVsColors.Add(Convert.ToChar(i), curColor)
- availableColors.RemoveAt(curRGB.curIndex) 'Avoiding the given color to be considered for a different character
- End If
- End If
- Next
- If availableColors.Count > 0 AndAlso charsVsColors.ContainsValue(startColor) Then
- Dim replaceColor As Color = availableColors(0) 'There has to be always unused availableColors
- Dim tempPair As KeyValuePair(Of Char, Color) = charsVsColors.FirstOrDefault(Function(x) IO.twoColorsAreEqual(x.Value, startColor))
- replacePair = New KeyValuePair(Of Char, Color)(tempPair.Key, replaceColor)
- availableColors.RemoveAt(0)
- End If
- Dim afterIndex As Integer = curIO.allKnownColor.IndexOf(startColor) + encryptingNumber
- If afterIndex > curIO.allKnownColor.Count - 1 Then afterIndex = encryptingNumber
- Dim afterOffset As Color = curIO.allKnownColor(afterIndex)
- startOffset.afterOffset = afterOffset
- If availableColors.Count > 0 AndAlso charsVsColors.ContainsValue(startOffset.afterOffset) Then
- Dim replaceColor As Color = availableColors(0) 'There has to be always unused availableColors
- Dim tempPair As KeyValuePair(Of Char, Color) = charsVsColors.First(Function(x) IO.twoColorsAreEqual(x.Value, startOffset.afterOffset))
- startOffset.replaceAfter = New KeyValuePair(Of Char, Color)(tempPair.Key, replaceColor)
- availableColors.RemoveAt(0)
- End If
- End Sub
- ''' <summary>
- ''' Determining the first index from which the arrays populations will be started on account of the inputs.
- ''' The over-complication is meant to increase the realibility of the encryption:
- ''' the more random is the behaviour when the value is not exactly the right input, the more secure.
- ''' </summary>
- ''' <returns>System.Int32.</returns>
- Private Function calculateFirst() As Integer
- Dim firstIndex As Integer = curColors.IndexOf(startColor)
- Dim firstColorI As Integer = encryptingNumber
- Dim secondColorI As Integer = -1
- If firstColorI > startColor.Name.Length - 1 Then
- firstColorI = startColor.Name.Length - 1
- Else
- secondColorI = firstColorI + Convert.ToInt32(Math.Floor(Convert.ToDouble(encryptingNumber) / 2.0))
- If secondColorI > startColor.Name.Length - 1 Then secondColorI = startColor.Name.Length - 1
- End If
- firstIndex = firstIndex + firstColorI
- Dim firstColor As Color = curColors(firstColorI)
- If firstColor.R > startColor.R Then firstIndex = firstIndex + 2
- If secondColorI > -1 Then
- Dim secondColor As Color = curColors(secondColorI)
- If Convert.ToInt32(secondColor.G.ToString()) < Convert.ToInt32(firstColor.G.ToString()) Then firstIndex = firstIndex + Convert.ToInt32(Math.Floor(2.0 * Convert.ToDouble(secondColorI) / Convert.ToDouble(firstColorI)))
- End If
- If firstIndex < 0 Then
- firstIndex = 0
- ElseIf firstIndex > curColors.Count - 1 Then
- firstIndex = curColors.Count - 1
- End If
- Return firstIndex
- End Function
- ''' <summary>
- ''' Function called from the loop populate the main array chars->colors to determine the index to be considered next.
- ''' It includes various arbitrary modifications increasing the security of the method.
- ''' </summary>
- ''' <param name="curRGB">Indicates the current RGB.</param>
- ''' <param name="availableColors">Indicates the available colors.</param>
- ''' <returns>RGBInfo.</returns>
- Private Function updateRGB(curRGB As RGBInfo, availableColors As List(Of Color)) As RGBInfo
- Dim curIndex As Integer = curStep
- If curRGB.lastR >= 100 Then curIndex = curIndex + 1
- If curRGB.lastG < 100 Then curIndex = curIndex + 2
- If curRGB.lastB >= 100 Then curIndex = curIndex - 2
- If curIndex + curRGB.lastIndex < availableColors.Count - 10 Then curIndex = curIndex + curRGB.lastIndex
- If curLength <= 10 Then
- curIndex = curIndex - 1
- Else
- curIndex = curIndex + 1
- End If
- If curIndex < 0 Then
- curIndex = curIndex = 0
- ElseIf curIndex > availableColors.Count - 1 Then
- curIndex = availableColors.Count - 1
- End If
- curRGB.curIndex = curIndex
- curRGB.lastIndex = curRGB.curIndex
- Return curRGB
- End Function
- ''' <summary>
- ''' The "step" represents the basic variable in charge of determining the next color to be considered
- ''' while populating the char->color array.
- ''' This variable is one of the most "randomly-affected" ones,
- ''' as far as is very relevant in the main hash-table population.
- ''' </summary>
- Private Sub calculateStartStep()
- curStep = 0
- If startColor.R >= 120 Then curStep = curStep + 1
- If startColor.G >= 120 Then curStep = curStep + 2
- If startColor.B >= 120 Then curStep = curStep + 1
- If encryptingNumber < 3 Then
- curStep = curStep + 2
- ElseIf encryptingNumber >= 3 AndAlso encryptingNumber < 7 Then
- curStep = curStep + 1
- Else
- curStep = curStep - 1
- End If
- If curLength > 0 Then
- Dim addStep As Integer = Convert.ToInt32(Math.Floor(Convert.ToDouble(curLength) / 100.0))
- If addStep <= 1 Then
- addStep = 1
- ElseIf addStep > 80 Then
- addStep = 3
- End If
- curStep = curStep + addStep
- End If
- If curStep < 1 Then
- curStep = 1
- ElseIf curStep > 10 Then
- curStep = 10 'Otherwise colors might be too concentrated
- End If
- End Sub
- ' Convert Diacritics
- '
- ' Usage Examples:
- ' MsgBox(RemoveDiacritics("áéÃóú à èìòù äëïöü ñÑ çÇ", UnicodeNormalization:=System.Text.NormalizationForm.FormKD))
- ' Result: 'aeiou aeiou aeiou nN cC'
- '
- ''' <summary>
- ''' Converts the diacritic characters in a String to an equivalent normalized English characters.
- ''' </summary>
- ''' <param name="String">
- ''' Indicates the string that contains diacritic characters.
- ''' </param>
- ''' <param name="UnicodeNormalization">
- ''' Defines the type of Unicode character normalization to perform.
- ''' (Default is 'NormalizationForm.FormKD')
- ''' </param>
- ''' <returns>System.String.</returns>
- Public Function ConvertDiacritics(ByVal [String] As String,
- Optional ByVal UnicodeNormalization As System.Text.NormalizationForm =
- System.Text.NormalizationForm.FormKD) As String
- Dim Characters As String = String.Empty
- For Each c As Char In [String].Normalize(UnicodeNormalization)
- Select Case Globalization.CharUnicodeInfo.GetUnicodeCategory(c)
- Case Globalization.UnicodeCategory.NonSpacingMark,
- Globalization.UnicodeCategory.SpacingCombiningMark,
- Globalization.UnicodeCategory.EnclosingMark
- ' Do nothing.
- Exit Select
- Case Else
- Characters &= CStr(c)
- End Select
- Next c
- Return Characters
- End Function
- End Class
- ''' <summary>
- ''' Small accessory class storing some of the variables used in the loop populating the char->color dictionary
- ''' </summary>
- Public Class RGBInfo
- Public curIndex As Integer
- Public lastR As Integer
- Public lastG As Integer
- Public lastB As Integer
- Public lastIndex As Integer
- End Class
- ''' <summary>
- ''' Class storing all the information required by the pixels in charge of storing the lenght information (security check reducing the options of a false positive)
- ''' </summary>
- Public Class pixelsLengthInfo
- Public startPixel As Point
- Public endPixel As Point
- Public length As Integer
- ''' <summary>
- ''' Initializes a new instance of the <see cref="pixelsLengthInfo"/> class.
- ''' </summary>
- Public Sub New()
- startPixel = New Point
- endPixel = New Point
- End Sub
- End Class
- ''' <summary>
- ''' Class dealing with the offset start. This is a new security feature making varying the position of the color indicating the start of the encrypted string
- ''' </summary>
- Public Class startOffsetInfo
- Public replaceAfter As KeyValuePair(Of Char, Color) 'To replace afterOffset in case it would have to be used
- Public startOffsetCount As Integer
- Public startPoint As Point
- Public afterOffset As Color 'Additional pixel telling the decryptor that an offset exists. Without this pixel, there might be cases where the presence of the offset might be ignored
- ''' <summary>
- ''' Initializes a new instance of the <see cref="startOffsetInfo"/> class.
- ''' </summary>
- Public Sub New()
- startOffsetCount = -1
- End Sub
- End Class
- ''' <summary>
- ''' Class storing all the methods dealing with I/O system, that is, with the image file.
- ''' As far as the image file plays an important role in both processes (encryption/decryption), the methods in this class are used systematically from everywhere
- ''' </summary>
- Public Class IO
- Public imageExtensions As List(Of String)
- Public allKnownColor As List(Of Color)
- ''' <summary>
- ''' Constructor populating the two main arrays of this class: list of valid extensions and all the known colors
- ''' </summary>
- Public Sub New()
- imageExtensions = GetType(System.Drawing.Imaging.ImageFormat).GetProperties().Select(Function(x) x.Name.ToLower).ToList
- populateKnownColors()
- End Sub
- ''' <summary>
- ''' There are various colors in the default known colors list which are identical.
- ''' The List created by this method does not include repeated colors..
- ''' </summary>
- Private Sub populateKnownColors()
- allKnownColor = New List(Of Color)
- For Each colorName As String In [Enum].GetNames(GetType(KnownColor))
- Dim curColor As Color = Color.FromName(colorName)
- If allKnownColor.FirstOrDefault(Function(x) twoColorsAreEqual(x, curColor)).IsEmpty Then allKnownColor.Add(curColor)
- Next
- allKnownColor = allKnownColor.OrderBy(Function(x) x.Name).ToList
- End Sub
- ''' <summary>
- ''' Method determining if the selected path contains a valid image or not.
- ''' </summary>
- ''' <param name="_path">Indicates the _path.</param>
- ''' <returns>Bitmap.</returns>
- Public Function fileValidImage(_path As String) As Bitmap
- Dim outBitmap As Bitmap = Nothing
- Dim curExtension As String = Path.GetExtension(_path)
- If curExtension.Trim.Length > 0 Then
- curExtension = curExtension.Substring(1, curExtension.Length - 1).ToLower
- If imageExtensions.Contains(curExtension) Then
- outBitmap = Bitmap.FromFile(_path)
- End If
- End If
- Return outBitmap
- End Function
- ''' <summary>
- ''' The mere "=" is not enough while comparing the stored, known colors against the ones from the pixels being read.
- ''' </summary>
- ''' <param name="color1">Indicates the color1.</param>
- ''' <param name="color2">Indicates the color2.</param>
- ''' <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- Public Shared Function twoColorsAreEqual(color1 As Color, color2 As Color) As Boolean
- Return color1.R = color2.R AndAlso color1.G = color2.G AndAlso color1.B = color2.B
- End Function
- '------------------------------- ENCRYPTING
- ''' <summary>
- ''' Method performing the last actions in the encryption process:
- ''' the ones required to create the output image with the encrypted pixels and the other irrelevant, surrounding ones.
- ''' </summary>
- ''' <param name="width">Indicates the width.</param>
- ''' <param name="height">Indicates the height.</param>
- ''' <param name="curEncrypting">Indicates the current encrypting.</param>
- ''' <returns>Encrypting.</returns>
- Public Function SaveImageFile(ByVal ImagePath As String,
- ByVal width As Integer,
- ByVal height As Integer,
- ByVal curEncrypting As Encrypting) As Encrypting
- Try
- Dim curBitMap = createImage(width, height, curEncrypting)
- If curBitMap IsNot Nothing Then
- curBitMap.Save(ImagePath, Drawing.Imaging.ImageFormat.Png)
- End If
- If Not File.Exists(ImagePath) Then
- curEncrypting.errors = True
- End If
- Catch
- curEncrypting.errors = True
- End Try
- Return curEncrypting
- End Function
- ''' <summary>
- ''' Encrypts the text into an image.
- ''' </summary>
- ''' <param name="width">Indicates the width.</param>
- ''' <param name="height">Indicates the height.</param>
- ''' <param name="curEncrypting">Indicates the current encrypting.</param>
- ''' <returns>Encrypting.</returns>
- Public Function Encrypt(ByVal width As Integer,
- ByVal height As Integer,
- ByVal curEncrypting As Encrypting) As Bitmap
- Try
- Dim curBitMap As Bitmap = createImage(width, height, curEncrypting)
- Return curBitMap
- Catch
- curEncrypting.errors = True
- Return Nothing
- End Try
- End Function
- ''' <summary>
- ''' Method called by the one above to actually create the image.
- ''' </summary>
- ''' <param name="width">Indicates the width.</param>
- ''' <param name="height">Indicates the height.</param>
- ''' <param name="curEncrypting">Indicates the current encrypting.</param>
- ''' <returns>Bitmap.</returns>
- Private Function createImage(width As Integer, height As Integer, curEncrypting As Encrypting) As Bitmap
- Dim curHashing As Hashing = curEncrypting.curHashing
- Dim allColors As List(Of Color) = curHashing.charsVsColors.Values.ToList 'Colors being considered in the current encryption: neither their number nor their order is kept constant
- curEncrypting = setBoundaryColor(curEncrypting) 'Including the additional pixels surrounding the ones including the encrypted information
- 'Accounting for the fact that the default size (500*500) is not enough to store all the required information
- Dim totSize As Integer = width * height
- If totSize < curHashing.curLength Then
- Dim ratio As Double = Math.Ceiling(Math.Sqrt(Math.Ceiling(Convert.ToDouble(allColors.Count) / Convert.ToDouble(curHashing.curLength))))
- height = Convert.ToInt32(Math.Ceiling(height * ratio))
- width = Convert.ToInt32(Math.Ceiling(width * ratio))
- End If
- Dim outBitmap As Bitmap = New Bitmap(width, height)
- Dim curPixel As pixelInfo = New pixelInfo()
- 'Determining the start/end pixels (where the encrypted string + additional info will be located)
- curPixel.startI = calculateStartI(width, height, curEncrypting)
- If curEncrypting.encryptedString IsNot Nothing Then curPixel.endI = curPixel.startI + curEncrypting.encryptedString.Count - 1
- 'Main loop populating the bitmap with all the pixels: ones containing encrypted information and all the other ones
- curPixel.i = -1
- For x As Integer = 0 To width - 1
- For y As Integer = 0 To height - 1
- curPixel.i = curPixel.i + 1
- curPixel.x = x
- curPixel.y = y
- outBitmap = addColorToPixel(curPixel, outBitmap, allColors, curEncrypting)
- Next
- Next
- Return outBitmap
- End Function
- ''' <summary>
- ''' Method determining the start position from which the encrypted string will be added to the image.
- ''' </summary>
- ''' <param name="width">Indicates the width.</param>
- ''' <param name="height">Indicates the height.</param>
- ''' <param name="curEncrypting">Indicates the current encrypting.</param>
- ''' <returns>System.Int32.</returns>
- Public Function calculateStartI(width As Integer, height As Integer, curEncrypting As Encrypting) As Integer
- If curEncrypting Is Nothing OrElse curEncrypting.encryptedString Is Nothing Then Return -1
- Dim curHashing As Hashing = curEncrypting.curHashing
- Dim availableSize As Integer = width * height - curEncrypting.encryptedString.Count
- Dim startI As Integer = availableSize
- If startI > 0 Then
- 'Curious (, required?!) method to force VB.NET to treat the RGB values as integers
- Dim tempStart As Integer = Convert.ToInt32(curHashing.startColor.R.ToString()) + Convert.ToInt32(curHashing.startColor.G.ToString()) + Convert.ToInt32(curHashing.startColor.B.ToString())
- If tempStart <= availableSize Then
- startI = tempStart
- Else
- tempStart = Convert.ToInt32(curHashing.startColor.R.ToString()) + Convert.ToInt32(curHashing.startColor.G.ToString())
- If tempStart <= availableSize Then
- startI = tempStart
- Else
- If curHashing.startColor.R <= availableSize Then
- startI = Convert.ToInt32(curHashing.startColor.R.ToString())
- Else
- startI = availableSize - 1
- End If
- End If
- End If
- End If
- Return startI
- End Function
- ''' <summary>
- ''' Determining the color of the current pixel on account of the given position: inside start/end pixels or outside them.
- ''' </summary>
- ''' <param name="curPixelInfo">Indicates the current pixel information.</param>
- ''' <param name="curBitmap">Indicates the current bitmap.</param>
- ''' <param name="allColors">Indicates all colors.</param>
- ''' <param name="curEncrypting">Indicates the current encrypting.</param>
- ''' <returns>Bitmap.</returns>
- Public Function addColorToPixel(curPixelInfo As pixelInfo, curBitmap As Bitmap, allColors As List(Of Color), curEncrypting As Encrypting) As Bitmap
- Dim noChange As Boolean = False
- Dim curIndex As Integer = curPixelInfo.i
- If curPixelInfo.startI > -1 AndAlso curIndex >= curPixelInfo.startI AndAlso curIndex <= curPixelInfo.endI Then
- noChange = True
- End If
- Dim curColor As Color = New Color
- If Not noChange Then
- 'The current pixel is randomly assigned
- curIndex = curPixelInfo.random.Next(0, allColors.Count - 1)
- While IO.twoColorsAreEqual(allColors(curIndex), curEncrypting.curHashing.startColor) 'StartColor determines where the encrypted chunk starts/ends and thus cannot be used outside it
- curIndex = curPixelInfo.random.Next(0, allColors.Count - 1)
- End While
- curColor = allColors(curIndex)
- Else
- 'This is part of the "encrypted chunk" and thus the pixels, as calculated so far, have to be added
- curPixelInfo.encryptedAdded = True
- curIndex = curIndex - curPixelInfo.startI
- curColor = curEncrypting.encryptedString(curIndex)
- If curEncrypting.curHashing.startOffset.startOffsetCount = -1 Then
- 'There is no offset; thus the color in the "offset position" cannot be curEncrypting.curHashing.startOffset.afterOffset
- If twoColorsAreEqual(curColor, curEncrypting.curHashing.startOffset.afterOffset) AndAlso Not curEncrypting.curHashing.startOffset.replaceAfter.Value.IsEmpty Then
- If curEncrypting.encryptingNumber > 0 AndAlso curIndex = curEncrypting.encryptingNumber + 1 Then
- curColor = curEncrypting.curHashing.startOffset.replaceAfter.Value
- End If
- End If
- End If
- End If
- curBitmap.SetPixel(curPixelInfo.x, curPixelInfo.y, curColor)
- Return curBitmap
- End Function
- ''' <summary>
- ''' Method defining the pixels "surrounding" the encrypted string.
- ''' These pixels are very important to allow the decryptor to undoubtedly locate the bunch of pixels to be decrypted.
- ''' </summary>
- ''' <param name="curEncrypting">Indicates the current encrypting.</param>
- ''' <returns>Encrypting.</returns>
- Private Function setBoundaryColor(curEncrypting As Encrypting) As Encrypting
- Dim curHashing As Hashing = curEncrypting.curHashing
- Dim analyseOffset As Boolean = curEncrypting.encryptingNumber > 0 AndAlso curEncrypting.encryptedString.Count - curEncrypting.encryptingNumber > 1
- If analyseOffset Then
- 'startColor at the "encryptingNumber position"
- curEncrypting.encryptedString.Insert(curEncrypting.encryptingNumber, curHashing.startColor)
- curEncrypting.curHashing.startOffset.startOffsetCount = curEncrypting.encryptingNumber + 1
- curEncrypting.encryptedString.Insert(curEncrypting.encryptingNumber + 1, curHashing.startOffset.afterOffset)
- Else
- 'startColor as first pixel
- curEncrypting.encryptedString.Insert(0, curHashing.startColor)
- End If
- 'Method encrypting the current length in the required position
- addLength(curEncrypting, curHashing, analyseOffset)
- 'startColor as last pixel
- curEncrypting.encryptedString.Add(curHashing.startColor)
- Return curEncrypting
- End Function
- ''' <summary>
- ''' Adding pixels with information regarding the length of the string.
- ''' </summary>
- ''' <param name="curEncrypting">Indicates the current encrypting.</param>
- ''' <param name="curHashing">Indicates the current hashing.</param>
- ''' <param name="analyseOffset">if set to <c>true</c> [analyse offset].</param>
- ''' <returns>Encrypting.</returns>
- Private Function addLength(curEncrypting As Encrypting, curHashing As Hashing, analyseOffset As Boolean) As Encrypting
- Dim remString As String = curHashing.curLength.ToString
- Dim curIndex As Integer = 0
- If analyseOffset Then curIndex = curEncrypting.encryptingNumber + 1 'AfterOffset has also to be accounted
- 'Loop creating one new pixel per digit defining the current length
- While remString.Trim.Length > 0
- Dim curLength As Integer = remString.Length
- curIndex = curIndex + 1
- Dim curChar As Char = Convert.ToChar(remString.Substring(0, 1))
- curEncrypting.encryptedString.Insert(curIndex, curHashing.charsVsColors(curChar))
- If curLength <= 1 Then Exit While
- remString = remString.Substring(1, remString.Length - 1)
- End While
- If analyseOffset Then
- 'The default population of encryptedString already avoids any pixel before the start one to have startColor. This loop confirms this for all the pixels between
- 'the formal start and the actual start (offset)
- If curEncrypting.encryptingNumber > 0 AndAlso curEncrypting.encryptedString.Count >= curEncrypting.encryptingNumber Then
- For i As Integer = 0 To curEncrypting.encryptingNumber - 1
- If twoColorsAreEqual(curEncrypting.encryptedString(i), curHashing.startColor) Then
- 'The start point is after this; thus the color of this pixel cannot be the startColor, it will be replaced with the replaceColor
- curEncrypting.encryptedString(i) = curHashing.replacePair.Value
- End If
- Next
- End If
- End If
- Return curEncrypting
- End Function
- '------------------------------- DECRYPTING
- ''' <summary>
- ''' 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.
- ''' </summary>
- ''' <param name="curDecrypting">Indicates the current decrypting.</param>
- ''' <param name="curHashing">Indicates the current hashing.</param>
- Public Sub getBoundaryPixels(curDecrypting As Decrypting, curHashing As Hashing)
- Dim tempLast As Point = New Point(-1, -1)
- Dim tempLength As Integer = -1
- Dim lastLength As Integer = 0
- Dim nextPixel As Color = New Color
- Dim storeNext As Boolean = False
- curHashing.curLength = -1
- For x As Integer = 0 To curDecrypting.origBitmap.Width - 1
- For y As Integer = 0 To curDecrypting.origBitmap.Height - 1
- If tempLength >= 0 Then tempLength = tempLength + 1
- Dim curColor As Color = curDecrypting.origBitmap.GetPixel(x, y)
- If storeNext Then
- 'This is the "after pixel" which confirms that an offset actually exists
- If Not twoColorsAreEqual(curColor, curHashing.startColor) Then nextPixel = curColor
- storeNext = False
- End If
- 'StartColor determines where the "relevant chunk" starts/ends, what is done by this condition
- If twoColorsAreEqual(curColor, curHashing.startColor) Then
- If tempLength < 0 Then
- curHashing.startPixel = New Point(x, y)
- curHashing.startPixelOrig = New Point(x, y)
- storeNext = True
- tempLength = 0
- Else
- tempLast = New Point(x, y)
- lastLength = tempLength
- End If
- End If
- Next
- Next
- If tempLast <> New Point(-1, -1) AndAlso lastLength > 0 Then
- 'The collected information seems right
- curHashing.endPixel = New Point(tempLast.X, tempLast.Y)
- curHashing.curLength = lastLength + 1
- Dim afterIndex As Integer = curHashing.curIO.allKnownColor.IndexOf(curHashing.startColor) + curDecrypting.encryptingNumber
- If afterIndex > curHashing.curIO.allKnownColor.Count - 1 Then afterIndex = curDecrypting.encryptingNumber
- Dim afterOffset As Color = curHashing.curIO.allKnownColor(afterIndex)
- Dim analyseOffset As Boolean = Not nextPixel.IsEmpty AndAlso twoColorsAreEqual(afterOffset, nextPixel)
- If analyseOffset Then
- '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)
- End If
- lengthCorrection(curHashing)
- End If
- End Sub
- ''' <summary>
- ''' Correction of the length under very specific conditions:
- ''' cases "close enough" to get a new digit, that is 10, 11, 100, etc.
- ''' This has been proven a very serious limitation of the approach (without an accurate length, lots of errors might be provoked),
- ''' which I might correct in next version by changing the way in which the length is being accounte for.
- ''' </summary>
- ''' <param name="curHashing">Indicates the current hashing.</param>
- Public Sub lengthCorrection(curHashing As Hashing)
- If curHashing.curLength >= 10 Then
- If (curHashing.curLength - 1).ToString.Length <> curHashing.curLength.ToString.Length OrElse (curHashing.curLength - 2).ToString.Length <> curHashing.curLength.ToString.Length Then
- curHashing.curLength = curHashing.curLength - 1
- End If
- End If
- End Sub
- ''' <summary>
- ''' 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
- ''' </summary>
- ''' <param name="curStart">Indicates the current start.</param>
- ''' <param name="offset">Indicates the offset.</param>
- ''' <param name="curDecrypting">Indicates the current decrypting.</param>
- ''' <returns>Point.</returns>
- Private Function newStartFromOffset(curStart As Point, offset As Integer, curDecrypting As Decrypting) As Point
- Dim newStart As Point = New Point
- Dim curCount As Integer = 0
- Dim firstTime As Boolean = True
- For x As Integer = curDecrypting.origBitmap.Width - 1 To 0 Step -1
- For y As Integer = curDecrypting.origBitmap.Height - 1 To 0 Step -1
- If firstTime Then
- x = curStart.X
- y = curStart.Y
- firstTime = False
- End If
- curCount = curCount + 1
- If curCount > offset Then
- newStart.X = x
- newStart.Y = y
- Exit For
- End If
- Next
- If curCount >= offset Then Exit For
- Next
- Return newStart
- End Function
- ''' <summary>
- ''' 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.
- ''' </summary>
- ''' <param name="curDecrypting">Indicates the current decrypting.</param>
- ''' <param name="curHashing">Indicates the current hashing.</param>
- ''' <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- Public Function lengthIsOK(curDecrypting As Decrypting, curHashing As Hashing) As Boolean
- Dim isOK As Boolean = True
- curHashing.pixelsLength = New pixelsLengthInfo
- Dim count As Integer = -1
- Dim calcLength As Integer = 0
- Dim lengthString As String = ""
- Dim firstTime As Boolean = True
- Dim foundStart As Boolean = False
- Dim startVal As Integer = 1
- If curHashing.startOffset.startOffsetCount > -1 Then startVal = startVal + 1 '"After pixel" of the offSet has also to be skipped
- For x As Integer = 0 To curDecrypting.origBitmap.Width - 1
- For y As Integer = 0 To curDecrypting.origBitmap.Height - 1
- If firstTime Then
- x = curHashing.startPixelOrig.X
- y = curHashing.startPixelOrig.Y
- firstTime = False
- End If
- count = count + 1
- If count >= startVal Then 'to skip startColor and, eventually, offset after pixel
- Dim curColor As Color = curDecrypting.origBitmap.GetPixel(x, y)
- Dim tempPair As KeyValuePair(Of Char, Color) = curHashing.charsVsColors.FirstOrDefault(Function(x2) twoColorsAreEqual(x2.Value, curColor))
- If Char.IsDigit(tempPair.Key) Then
- curHashing.pixelsToIgnore.Add(New Point(x, y))
- lengthString = lengthString & tempPair.Key.ToString
- If foundStart Then
- curHashing.pixelsLength.startPixel = New Point(x, y)
- foundStart = True
- End If
- Else
- Return False
- End If
- If Integer.TryParse(lengthString, calcLength) Then
- If calcLength = curHashing.curLength Then
- curHashing.pixelsLength.length = calcLength
- curHashing.pixelsLength.endPixel = New Point(x, y)
- Return True
- End If
- Else
- Return False
- End If
- End If
- Next
- Next
- Return isOK
- End Function
- ''' <summary>
- ''' Final stage of the decryption process: application of all the previous calculations to the image to extract the encrypted message.
- ''' </summary>
- ''' <param name="curDecrypting">Indicates the current decrypting.</param>
- ''' <returns>Decrypting.</returns>
- Public Function decryptImage(curDecrypting As Decrypting) As Decrypting
- Dim curBitmap As Bitmap = curDecrypting.origBitmap
- curDecrypting.decryptedString = ""
- Dim curHashing As Hashing = curDecrypting.curHashing
- Dim origFound As Boolean = False
- Dim firstTime As Boolean = True
- Dim decryptColor As Boolean = False
- For x As Integer = 0 To curDecrypting.origBitmap.Width - 1 'The analysis starts from the startPixel, already calculated while creating the Hash table
- For y As Integer = 0 To curDecrypting.origBitmap.Height - 1
- Dim analyseStart As Boolean = False
- Dim goAhead As Boolean = False
- If firstTime Then
- x = curDecrypting.curHashing.startPixel.X
- y = curDecrypting.curHashing.startPixel.Y
- End If
- Dim curColor As Color = curDecrypting.origBitmap.GetPixel(x, y)
- If firstTime Then
- If curHashing.startOffset.startOffsetCount = -1 Then 'No offset
- analyseStart = True
- Else
- decryptColor = True
- End If
- firstTime = False
- ElseIf curHashing.startOffset.startOffsetCount <> -1 Then 'Offset
- If Not origFound AndAlso twoColorsAreEqual(curColor, curHashing.startColor) Then
- analyseStart = True
- End If
- End If
- If analyseStart Then
- 'No offset and thus the restrictions in the conversions start already here
- If Not twoColorsAreEqual(curDecrypting.origBitmap.GetPixel(x, y), curHashing.startColor) Then
- curDecrypting.errors = True
- Return curDecrypting
- Else
- decryptColor = False
- End If
- End If
- If decryptColor Then
- '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 AndAlso y = curHashing.endPixel.Y Then
- Return curDecrypting
- End If
- goAhead = True
- Else
- If Not origFound Then
- If x = curHashing.pixelsLength.endPixel.X AndAlso y = curHashing.pixelsLength.endPixel.Y Then
- origFound = True
- decryptColor = True 'from the next pixel onwards, all the information should be decrypted
- End If
- Else
- curDecrypting.errors = True
- Return curDecrypting
- End If
- End If
- If goAhead Then
- Dim tempPair As KeyValuePair(Of Char, Color) = curHashing.charsVsColors.FirstOrDefault(Function(x2) twoColorsAreEqual(x2.Value, curColor))
- If tempPair.Value.IsEmpty AndAlso twoColorsAreEqual(curColor, curHashing.startColor) Then
- Dim isOK As Boolean = False
- If curDecrypting.encryptingNumber > 0 Then
- If Not curHashing.replacePair.Value.IsEmpty AndAlso twoColorsAreEqual(curColor, curHashing.replacePair.Value) Then
- tempPair = New KeyValuePair(Of Char, Color)(curHashing.replacePair.Key, curColor)
- isOK = True
- ElseIf Not curHashing.startOffset.replaceAfter.Value.IsEmpty And twoColorsAreEqual(curColor, curHashing.startOffset.replaceAfter.Value) Then
- tempPair = New KeyValuePair(Of Char, Color)(curHashing.startOffset.replaceAfter.Key, curColor)
- isOK = True
- End If
- End If
- If Not isOK Then
- curDecrypting.errors = True
- Return curDecrypting
- End If
- End If
- curDecrypting.decryptedString = curDecrypting.decryptedString & tempPair.Key.ToString
- End If
- Next
- Next
- Return curDecrypting
- End Function
- End Class
- ''' <summary>
- ''' Class storing some pixel-related information relevant while encrypting/decrypting an image.
- ''' </summary>
- Public Class pixelInfo
- Public x As Integer
- Public y As Integer
- '---- Encrypting
- Public random As Random
- Public startI As Integer
- Public endI As Integer
- Public i As Integer
- Public encryptedAdded As Boolean
- '----
- '---- Decrypting
- Public color As Color
- Public decryptedSofar As String
- '----
- Public Sub New()
- random = New Random
- End Sub
- End Class
- #End Region
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement