} // End method Crossover(). /// <summary> /// Mutate (XOR) the intermediate image with a secret /// image stored in the key. /// </summary> /// <param name="s3"> /// The stream array that is used to select a pseudo-random row index /// for XOR-ing with a secret image. /// </param> /// <param name="s4"> /// The stream array that is used to select a pseudo-random column /// index for XOR-ing with a secret image. /// </param> private void Mutate(int[] s3, int[] s4) { int m = PlaintextImage.Height; // Number of rows. int n = PlaintextImage.Width; // Number of columns. // The (x, y) pixel value from the intermediate image. uint intermediate = 0; // The (s3[x], s4[y]) pixel value from the secret image. uint secret = 0; // The "mutated" pixel is the exclusive-or (XOR) of the // intermediate pixel and the secret key pixel. uint xor = 0; for (int y = 0; y < m; ++y) { for (int x = 0; x < n; ++x) { intermediate = (uint)CiphertextImage. GetPixel(x, y).ToArgb(); secret = (uint)Key.SecretImage. GetPixel(s3[x], s4[y]).ToArgb(); xor = ((uint)(intermediate ^ secret) | 0xff000000); CiphertextImage.SetPixel(x, y, Color.FromArgb((int)xor)); } } } // End method Mutate().
/// <summary> /// Applies the k-epsilon dissipative turbulence /// value to the secret image. /// </summary> private void ApplyDissipativeTurbulence() { // Retrieve the size of the image in pixels. int m = PlaintextImage.Width; int n = PlaintextImage.Height; // This is the scalar value to apply to the XOR operation. byte scalar = GetTurbulenceMultiplier(); // For every pixel in the image, XOR its value with the // value of the secret image and the turbulence scalar value. for (int y = 0; y < n; ++y) { for (int x = 0; x < m; ++x) { int pixel = CiphertextImage.GetPixel(x, y).ToArgb(); int secPixel = Key.SecretImage.GetPixel(x, y).ToArgb(); // The luminance value of the XOR of the // input image and the secret image. byte Y = (byte)((pixel & 0x000000ff) ^ (secPixel & 0x000000ff)); // Apply the scalar value. int xor = Y ^ scalar; Color newPix = Color.FromArgb(0xff, xor, xor, xor); CiphertextImage.SetPixel(x, y, newPix); } } } // End method ApplyDissipativeTurbulence().
} // End method Encrypt(). /// <summary> /// This method applies the row-wise (scanline) momentum (mass) fluxes. /// </summary> private void ApplyMomentumFlux() { // Retrieve the size of the image in pixels. int n = PlaintextImage.Height; int m = PlaintextImage.Width; // Generate a logistic map to seed the mass flow rate vector. double[] logisticMap = GenerateLogisticMap(Key.R_mdot, Key.MassFlowRateInitializer, n); // The row-wise mass flow rates are a true set of integers [0, n]. int[] rowMassFlowRate = new int[n]; for (int i = 0; i < n; ++i) { rowMassFlowRate[i] = i; } // Randomize the mass flow rates by the sort order // of the logistic map vector. Array.Sort(logisticMap, rowMassFlowRate); // Right circular rotate each scanline in the image. int row = 0; for (int y = 0; y < n; ++y) { for (int x = 0; x < m; ++x) { int replacementIndex = (x + rowMassFlowRate[row]) % m; Color replaceWith = PlaintextImage.GetPixel(replacementIndex, y); CiphertextImage.SetPixel(x, y, replaceWith); } row++; } } // End method ApplyMomentumFlux().
} // End method ApplyMomentumFlux(). /// <summary> /// This method applies the column-wise heat fluxes. /// </summary> private void ApplyHeatFlux() { // Retrieve the size of the image in pixels. int n = PlaintextImage.Height; int m = PlaintextImage.Width; // Generate a logistic map to seed the mass flow rate vector. double[] logisticMap = GenerateLogisticMap(Key.R_qdot, Key.HeatTransferInitializer, m); // The elements of the heat flux vector are in // the integer set [0, 255]. This is effectively an // initialization vector for the bottom scanline. int[] columnHeatFlux = new int[m]; for (int i = 0; i < m; ++i) { columnHeatFlux[i] = (int)(255 * logisticMap[i]); } // For every pixel in the image, XOR its value with the // value of the pixel beneath it. for (int x = 0; x < m; ++x) { for (int y = 0; y < n; ++y) { Color source = CiphertextImage.GetPixel(x, y); int Tj = (source.ToArgb() & 0x000000ff); int Tj1 = Tj ^ columnHeatFlux[x]; Color replaceWith = Color.FromArgb(0xff, Tj1, Tj1, Tj1); CiphertextImage.SetPixel(x, y, replaceWith); } } } // End method ApplyHeatFlux().
/// <summary> /// Perform row and column crossover operations to permute the /// image data into an intermediate image. /// </summary> /// <param name="s1"> /// The stream array that is used to perform row-wise crossover. /// </param> /// <param name="s2"> /// The stream array that is used to perform columnn-wise crossover. /// </param> private void CrossOver(int[] s1, int[] s2) { int m = PlaintextImage.Height; // Number of rows. int n = PlaintextImage.Width; // Number of columns. // Ensure that the number of cut points is even! int numRowCutPoints = (int)Math.Floor((double)n / 2.0); int numColCutPoints = (int)Math.Floor((double)m / 2.0); int[] rowCutPoints = new int[numRowCutPoints]; int[] colCutPoints = new int[numColCutPoints]; // Perform row-wise crossovers for (int y = 1; y < m; ++y) { rowCutPoints[0] = Math.Abs(s1[y - 1] - s1[y]) % m; for (int k = 1; k < numRowCutPoints; ++k) { rowCutPoints[k] = (rowCutPoints[k - 1] + Math.Abs(s1[y - 1] - s1[y])) % m; } Array.Sort(rowCutPoints); for (int k = 1; k < numRowCutPoints; ++k) { for (int x = rowCutPoints[k - 1]; x < rowCutPoints[k]; ++x) { // Swap the pixels. Color pix1 = CiphertextImage.GetPixel(x, s1[y]); Color pix2 = CiphertextImage.GetPixel(x, s1[y - 1]); CiphertextImage.SetPixel(x, s1[y], pix2); CiphertextImage.SetPixel(x, s1[y - 1], pix1); } } } // End row-wise crossovers. // Perform column-wise crossovers for (int x = 1; x < n; ++x) { colCutPoints[0] = Math.Abs(s2[x - 1] - s2[x]) % n; for (int k = 1; k < numColCutPoints; ++k) { colCutPoints[k] = (colCutPoints[k - 1] + Math.Abs(s2[x - 1] - s2[x])) % n; } Array.Sort(colCutPoints); for (int k = 1; k < numColCutPoints; ++k) { for (int y = colCutPoints[k - 1]; y < colCutPoints[k]; ++y) { // Swap the pixels. Color pix1 = CiphertextImage.GetPixel(s2[x], y); Color pix2 = CiphertextImage.GetPixel(s2[x - 1], y); CiphertextImage.SetPixel(s2[x], y, pix2); CiphertextImage.SetPixel(s2[x - 1], y, pix1); } } } // End column-wise crossovers. } // End method Crossover().
/************************************************** * Public Methods * **************************************************/ /// <summary> /// Encrypt the plaintext image with the given key. /// </summary> public void Encrypt() { // Make sure we have a key! if (Key == null) { throw new System.ArgumentException( "The key has not been instantiated."); } // Ensure that a plaintext image is available for encryption. if (PlaintextImage == null) { throw new System.NullReferenceException( "The plaintext image is not defined."); } // We need to ensure that the plaintext image is grayscale. PlaintextImage = GrayScale( PlaintextImage.Clone(new Rectangle(0, 0, PlaintextImage.Width, PlaintextImage.Height), System.Drawing.Imaging.PixelFormat.Format24bppRgb)); // Ensure that we have a 24bpp image to work with since SetPixel() // won't work with an indexed image. CiphertextImage = PlaintextImage.Clone( new Rectangle(0, 0, PlaintextImage.Width, PlaintextImage.Height), System.Drawing.Imaging.PixelFormat.Format24bppRgb); int [,] schedule = GenerateStateSchedule(Key.Seed); int [] attractorRing = MakeAttractorRing(Key.StateOne, Key.Rule); int lum = 0; // The luminance value of a given pixel. int stateIndex = 0; for (int y = 0; y < PlaintextImage.Height; ++y) { for (int x = 0; x < PlaintextImage.Width; ++x) { // Since the image is grayscale we only need // one channel's data. lum = PlaintextImage.GetPixel(x, y).ToArgb() & 0x000000ff; // Jin recommends each pixel's starting state use the // attractor ring index (x + y) mod 8. stateIndex = (x + y) % 8; lum ^= attractorRing[stateIndex]; // This provides the avalanche effect. for (int i = 0; i < schedule[x, y]; ++i) { stateIndex = (++stateIndex) % 8; lum ^= attractorRing[stateIndex]; } // Write the pixel data to the ciphertext image. CiphertextImage.SetPixel( x, y, Color.FromArgb(0xff, lum, lum, lum)); } } } // End method Encrypt().