Steganography is a method of hiding digital information so that it will escape detection that has been used by al-Qaeda, drug cartels, and others. Properly-executed steganography allows for large quantities of information to be hidden inside a file, while making no perceivable changes to that file's contents. Steganography can be applied to many types of data, including audio, video, and images and can hide any kind of digital information. Steganography provides a significant challenge to security as it hides the act of communication; if illicit communication is not discovered it cannot be prevented or decoded. Unlike encryption, which secures the content of a message, steganography hides the message’s existence. The term “steganography” derives from the Greek for “covered writing” [9], which is a good representation of the central idea of steganography. The end goal of steganography is to hide data in a digital object so that it cannot be detected through observation (or even complex analysis). Least Significant Bit Embeddings (LSB) are a general steganographic technique that may be employed to embed data into a variety of digital media, but one of the most studied applications is using LSB embedding to hide one image inside another. My work focuses on LSB embedding with grayscale images, but the general principles extend to other applications of LSB embedding. LSB embeddings are remarkable for their simple design and alarming effectiveness. The simplest of LSB embeddings allow for large amounts of data to be embedded without observable changes. The balance of ease of implementation and effectiveness make LSB embedding an interesting area of study.
A significant amount of work in steganography has been published since the late 1990s. Vision of the Unseen provides a survey of the current work in steganography and other topics in digital forensics [6]. Steganography has been evolving over the last decade, as designers of embedding algorithms have developed more complex embedding strategies and others try to detect and decode them [8]. In LSB embedding with images, work has been done to naively detect embedding in images with a variety of embedding strategies [1, 2, 5, 9]. Steganographic tools for embedding and decoding have been made freely available online as published and proprietary techniques for both embedding are implemented [4, 7].
In a digital system, colors are most frequently represented as additive combinations of red (R), blue (B), and green (G). Each of these primary colors is assigned a value from 0 to a maximum. This maximum is dictated by the size of the numbers used to represent the amount of the primary color. Thus, if 8 bits are used to represent the amount of a single primary color we can represent 256 hues of a single primary. Since we have three primaries, we can represent over 16 million colors with 24 bits. Here we will represent RGB colors in a [R, G, B] format (eg. "[120, 100, 10]"). In the 8-bit RGB colorspace, [0, 0, 0] is black, [255, 255, 255] is white, and [124, 216, 255] is a light blue. It is also possible to represent grayscale in a similar fashion. Where RGB has a value for each of the three primary colors, grayscale values need only represent an intensity. This intensity value will determine how black or white the gray is. Grayscale colors will be referred to by a single number. In one byte grayscale, black has a value of 0, white is 255, and a light gray is 200.
A pixel is the fundamental unit of digital imagery. It is the smallest point whose color can be controlled. In a digital camera, a single receptor pixel senses the color of light that is hitting it and records that value to make an image. On a computer monitor, a pixel does the reverse and emits a color of light. When we record images, we size them in pixels. Each pixel is laid out in a grid and is given a specified color.
Each color channel R, G, and B in the RGB colorspace is represented by a number, and this number is represented by a number of bits. In my work with grayscale images the number of bits is eight. A bit-plane refers to all the bits at a single bit position across an image. Consider the number ten, whose 8-bit binary representation is "00001010". Starting from the right, we have a "0" in the zeroth bit-plane, a "1" in the first, a "0" in the second, and so on for all eight bits. In an image, a bit-plane refers to the 0 or 1 value at a given position for all pixels, laid out in the same format. In LSB Steganography, the least significant bit-planes are manipulated.
Steganography requires two pieces of data: the cover, and the data to be hidden. The cover is the medium into which we will embed the data. Choosing an appropriate cover is an important decision, as it is a large part of what determines the effectiveness of the steganographic technique. Steganography’s reliance on ‘hiding’ the data behind the cover prevents it from being considered secure, unlike encryption. Once embedding is suspected it may be trivial to retrieve the embedded data. The cover will also be the container for the given message. If the cover itself raises suspicion, it could result in detection. A Brazilian drug trafficker had messages hidden with steganographic algorithms hidden on his computer inside images of a cartoon character [6]. Perhaps if the cover image were more innocuous the messages would have escaped detection. While any image can serve as a cover, the images which make the best covers have several properties that make it possible for more of the image's data to be replaced without creating any visually detectable distortion. The most important characteristic of a potential cover is that the image should have a large variety of colors. Images with few colors will make the embedding easier to detect. If, for example, the image is a single color there will be two colors after embedding. These colors will be very similar, but not the same. In Fig. 1, there are two grays that would be produced by a least significant bit embedding. The left side has the gray value 125, and the right 124.
Upon careful observation it is possible to detect this difference visually, allowing discovery of the embedding. An image with many colors after an embedding still has many colors; an observer will see the difference between the colors in the cover medium, not the small differences created by the steganographic embedding. The distribution of these colors should be varied. If the image contains blocks or swaths with the same color it should be avoided as a cover image. An embedding crossing a boundary of a color will also be more easily detected. Westfeld and Pftizmann found that a photo of a flooring tile made an exceptionally good cover, as the minor variations in the tile's coloring created enough distribution of colors to prevent the crossing of any edges that would let an embedding be more easily detected [9]. The other advantage to the flooring image being used as a cover was that the distribution of 1s and 0s in the low bit-planes was close to random. The process of embedding content into the cover makes the least significant bit planes more noisy as a greater amount of the cover’s information is changed and there is no longer as strong a correlation between the content of the least significant bit plane and the above planes [5]. If the cover images have least significant bit planes that are already close to random noise it is more difficult to detect an embedding.
The data must be serializable, so that it may be embedded bit by bit into the cover. The data must be no larger than the cover, or the cover would not be able to contain all of the data’s information. For an image, the cover and the data could have the same number of pixels, but the cover will have significantly more color information per pixel than the hidden data. Examples of data that may be embedded include text messages encoded with ASCII values of characters, audio messages, images, or even video.
Steganography is a technique for transmitting information without detection. It has been used in drug cartels and other organizations to avoid detection of their illicit communication [6]. Steganography relies on the fact that it is difficult to detect in order to remain secure. It uses parts of an image that do not strongly influence the colors shown to embed data. Where embedding is most practical varies with different image formats, but one technique that works well across formats is least significant bit embedding. Other algorithms, such as Jsteg, exploit the design of a specific image file format to embed without detection. The general principle of steganography is that perturbing a particular value in an image using a value from the data will create a small difference in the original image. The image created by this process is a stego object. The stego object contains data from the cover and information about the data that was used to perturb the cover image. The stego object can then be decoded by the intended recipient(s) and the hidden message retrieved. Because the values in the original image are only changed slightly, an observer will struggle to visually detect that an embedding has taken place. Through this series of minor perturbations based on the message’s contents the data is hidden in the cover image. A third party will have to analyze the image in order to determine if an embedding has taken place. The development of different analyses has led to an arms race between those developing steganographic algorithms and those trying to detect embeddings. From this point forward, it is assumed that the cover and data to hide are both images.
Least Significant Bit (LSB) embedding is a simple strategy to implement steganography. Like all steganographic methods, it embeds the data into the cover so that it cannot be detected by a casual observer. The technique works by replacing some of the information in a given pixel with information from the data in the image. While it is possible to embed data into an image on any bit-plane, LSB embedding is performed on the least significant bit(s). This minimizes the variation in colors that the embedding creates. For example, embedding into the least significant bit changes the color value by one. Embedding into the second bit-plane can change the color value by 2. If embedding is performed on the least significant two pixels, the result is that a color in the cover can be any of four colors after embedding. Steganography avoids introducing as much variation as possible, to minimize the likelihood of detection. In a LSB embedding, we always lose some information from the cover image. This is an effect of embedding directly into a pixel. To do this we must discard some of the cover’s information and replace it with information from the data to hide. LSB algorithms have a choice about how they embed that data to hide. They can embed losslessly, preserving all information about the data, or the data may be generalized so that it takes up less space.
Strategies for embedding content vary in their complexity and purpose. The simplest embeddings are lossy embeddings which do not preserve all of the data intended to be hidden and instead compresses the data by storing a representative value. Instead, each color channel in the data image is assigned a zero or a one and this value is then embedded. Thus, a grayscale image with a single color channel specifying intensity becomes black or white, or a color image goes from sixteen million colors (256×256×256) to eight (2×2×2). This significantly reduces the amount of data that needs to be stored, and the single bits of data are easily embedded as the least significant bit in the cover. This technique may be expanded. Spy Pix is an iPhone application which uses steganography to send secret messages. It accepts two images from the iPhone's camera roll and embeds one into the other, and offers a slider to control the level of embedding (Fig. 2).
To do this, Spy Pix adjusts the number of bits in the stego object that are devoted to the cover and the data. In a LSB embedding, the seven most-significant bits are devoted to the cover and only the least significant bit contains the data. This division helps to minimize detection, but it is possible to use more than just the least significant bit for embedding. This will produce more significant variations in color in the stego object, but it allows for the data to be embedded at a higher quality. It's also possible to create a stego object without losing any information at all. Since all digital information is stored as bits, any data can be embedded bit-by-bit into the pixel's least significant bits as a series of zeros and ones. This requires a much larger cover, since a single gray pixel in the data to embed would be spread over eight pixels in the cover image. This method is most valuable for data that must be embedded losslessly. For example, text encoded in ASCII or UTF-8 represents each character as a series of bytes. Changing a bit of the text’s data during steganographic encoding changes the characters that comprise the text. Text with modified characters loses its meaning, so a lossless embedding strategy would be required.
Not all steganographic techniques rely on embedding directly into a pixel. Image formats, especially those that use compression, use mathematical functions to reduce the size of an image. The functions may also be manipulated slightly to allow for the embedding of data. Jsteg is one such algorithm which exploits the format of the JPEG image format to avoid embedding data directly into pixels.
JPEG, which is a lossy image compression technique, successfully compresses image data by dividing an image into 8 by 8 blocks of pixels. The color assigned to these pixels is determined by a discrete cosine transform (DCT) table [2]. Instead of storing the color values that are assigned to each pixel, the JPEG format stores the coefficients of the cosines; representing the frequency of a value. Jsteg embeds its data into the coefficients which describes the values of the pixels. Because Jsteg embeds its data into the DCT table, the effect of embedding is spread among as many as 256 pixels [9]. Jsteg serves as an exemplary embedding strategy that avoids embedding the data directly into pixels.
Detection of LSB embeddings is done through two types of attacks. The first is a simple visual attack, which relies on the human eye to evaluate an image. The second is a statistical attack, which analyzes images in a statistical manner.
A visual attack is the simplest way of trying to detect an embedding. It is particularly effective against LSB embeddings, but it is useless against more advanced algorithms that do not embed into the pixels of the image directly like Jsteg. A visual attack begins by looking at the image as a whole. If an embedding is detected through color abnormalities the steganographic algorithm has been successfully attacked. If an embedding is not detected by the observer, the bit planes of the image are then examined, beginning with the least significant plane. An embedding is typically evidenced by a localized section of noise in this plane (See Fig. 3).If this noise is easily detected it is possible to extract the data from that plane. Figure 4 offers a simple example of a visual attack.
Statistical attacks on LSB embeddings are much more effective than a visual attack. Statistical attacks make use of the relationship between bit-planes in an image or the relationship between pixels within a bit-plane to determine if a message is embedded into an image. Statistical attacks are typically tuned to work against a particular embedding algorithm, since different embedding strategies affect the perturbing of pixel values in a unique manner. For example, a particular kind of statistical attack may detect any embedding algorithms that embed in the Discrete Cosine Table of a JPEG image like Jsteg. This same attack will likely not be effective against the simplest form of LSB embedding. Other statistical attacks are particularly effective against LSB embeddings since LSB embeddings are constrained to perturbing a small subset of bits in an image. The RS Steganalysis developed by Fridrich et. al serves as an exemplary statistical attack. RS Steganalysis begins by defining a set of discrete groups G of pixels in the image. The pixels of each group are flipped according to a mask M. The flippings defined in the mask reassign a pixel's value v to be v+1, v-1, or v (mimicking the effect of an LSB embedding). Each flipping is invertible, so M(M(g))=g. The groups are measured using a function that quantifies the noisiness of a group. If a group is noisier after flipping, the group is Regular. If a group is less noisy post-flipping, it is Singular. If there is no change, the group is Unusable. RS Steganalysis then measures the effect on an image of the flipping operations defined by a mask M and the negative mask -M. After applying mask M to an image, R_M denotes the number of regular groups as a percentage and S_M the percent of singular groups. The application of the negative mask yields R_-M and S_-M in the same fashion. An image without steganographic content should have an equal percentage of regular groups resulting from being flipped by masks M and -M, and by extension an equal percentage of singular groups as well. A stego object created with a LSB embedding behaves differently when flipped by M and -M. In a stego object, the authors find that as the length of the embedded message increases R_M-S_M approaches 0 while the difference between R_-M and S_-M increases. Through experimentation and observation, it was found that the change in R_-M and S_-M for a stego object could be modeled linearly and that R_M and S_M can be modeled with a second-degree polynomial. Next, several points are generated which will define the models for R_M, S_M, R_-M, and S_-M. These points are generated through counting the number of regular and singular groups, flipping all values of the LSB plane, and randomizing the LSB plane. The linear model for R_-M and the polynomial model for R_M intersect on the left axis when plotted, and S_-M and S_M intersect in a similar fashion. The average of the x coordinates of each intersection yield an estimate for the message length, l. The authors are able to simplify the estimation to finding a root for a quadratic equation using the differences between calculated points as variables. The estimated message length can be calculated from the root with the smallest magnitude, r, by l=r/(r-0.5). Once l has been calculated, it indicates the number of pixels that have had their least significant bit flipped. The message length will be 0 if no embedding is suspected, or the size of the suspected embedding. RS Steganalysis is remarkably effective; to avoid detection, a LSB embedding would have to flip fewer than 0.005 bits per pixel in the cover image, meaning that less than 0.5% of pixels have had their LSB modified [1]. The authors state that RS Steganalysis is less effective against images with high levels of noise, and that it is not as effective against embeddings in localized areas. Regardless, RS Steganalysis is a powerful example of the sophistication and efficacy of statistical attacks.
While LSB embeddings may be attacked visually and statistically, other techniques may only be attacked using statistical analysis. Jsteg is an example of such an algorithm where embedding does not take place in the pixels of an image, and instead the effects of small changes to the DCT coefficients must be detected. In such cases a statistical attack is the only viable option. Again, these attacks are typically tailored to an embedding strategy, as is evidenced by Westfeld and Pfitzmann’s success attacking several steganographic algorithms with their Chi-square attack by measuring the expected distribution of values with those observed in a given image [9].
The Spiral Embedding is novel embedding technique designed by the author for grayscale images to resist a visual attack. It avoids embedding data in the same dimensions as it was received, and its embedding pattern should reduce the effectiveness of statistical attacks that prefer a random distribution of embedded pixels in the cover image.
The goal of the Spiral Embedding is to have a simple algorithm to embed content into an image using LSB embedding that will resist a visual attack. A straightforward LSB embedding might embed the pixels in the same grid format that they appeared in the original image. When the bit planes of the image are examined by an observer, the location of the embedding will be easily detected. Since the pixels of the image are organized in the same manner as the original image, the observer will be able to decode the image without any extra effort. The Spiral Embedding orders the pixels of the image in a spiral pattern to prevent the embedding from being as easily decoded. The Spiral Embedding has two main ideas that allow it to be decoded successfully and help thwart visual attacks. The first is that metadata about the image's contents are embedded into known locations. This information makes it possible to decode the stego object and retrieve the secret message. The second is that the data is serialized and embedded in a pattern that destroys the ability to decode the message in a visual attack.
The Spiral Embedding begins by building a vector containing all the data that will be embedded into the cover including the metadata and the message contents. The dimensions of the message are embedded losslessly into the first 32 positions in the vector as unsigned 16-bit integers. A bit representing the vector’s content is written into the LSB of the cover in a spiral pattern from the outside in, pixel by pixel, as is demonstrated in Figure 5.
Figure 6 shows the various elements of embedding into the cover shown at the top left. Moving clockwise, the message is shown. Embedded using a lossy embedding technique, it produces the stego object shown at top left. Below the stego object, the pixels that may have been flipped are shown in black around the edge of the image. The white pixels in the center are left unchanged. The LSB plane is shown to the left, and the embedding area is not as obtrusive as that seen in Figure 4. Last shown is the decoded message, which is still legible.
Decoding a stego object created with the Spiral Embedding is simply a process of reading in the stored dimensions and then following the same spiral pattern that governed the embedding. The values of the LSBs of the stego object are read into a vector. When the embedded data has been read in its entirety, the vector is partitioned to create a new image with the message’s original dimensions. The result of this embedding can then be displayed. Figure 5 demonstrates the complete process of embedding and decoding a spiral embedding. 7.4 Review of Spiral Embedding
Spiral Embedding embeds the contents of an image and metadata into the cover image in a format that reduces the threat of decoding a visual attack. While it is still potentially vulnerable to detection, interpreting the data of a Spiral Embedding stego object with a visual attack is significantly more difficult than that of a standard LSB embedding. Spiral Embedding should be as vulnerable as other LSB embeddings to statistical attacks. Stego objects produced with the Spiral Embedding were examined with XStegSecret and VSL, two free tools designed to detect steganographic embedding [4, 7]. No embedding was detected by either software. Logically, the Spiral Embedding should be equally vulnerable to those attacks that compare the distribution of ones and zeros in the least significant bit plane to the expected distribution.
Steganography proves to be an incredibly effective way of hiding the act of communication. The ease and effectiveness of LSB embedding make it an attractive method to transmit messages without detection. With the rise in popularity of image sharing services on the Internet, it is increasingly likely that an image shared online for a short period of time would not be be analyzed. It is important to note that while steganography does not guarantee that a message cannot be decoded, paring steganography with encryption provides a means of communication that is difficult to detect and can be nearly impossible for a third party to decode. While steganography can be detected by statistical attacks, relying on safety in numbers and obscure embedding patterns can limit the decoding of any particular hidden message. Steganography’s effectiveness, ease of implementation, and extensibility all suggest that it will be a considerable security concern for the foreseeable future.
A multitude of possible LSB embedding strategies exist, and interesting future work could be applied to strengthening the Spiral Embedding technique to further resist detecting and decoding by spreading out the embedding pattern. This would further distribute the Spiral Embedding's changed pixels around the cover image, reducing the ease of detecting the stego object. Support for encryption with a shared key could also be added to eliminate the ability to decode the spiral object. Further work should be done to explain why the Spiral Embedding was not detected by StegSecret and VSL. Verification with a larger sample of images should be run to verify that Spiral Embedding stego objects are not detected, and then RS Steganalysis should be implemented to determine if the implementation of these techniques in VSL and XStegSecret is flawed. The pattern of embedding while spiraling around a space could also be extended to other spaces, embedding into an image's colorspace, or across several bit planes if an image has a greater color depth than 8 bits per pixel.
The reversible perturbation of values used in steganography enables the embedding of data into a cover medium. Choosing to modify values that have a small affect on the cover medium limits the ability to detect the embedding. Embedding strategies may be easily derived and implemented to complicate detection and inhibit the retrieval of the message by a third party, while still allowing easy retrieval by the intended recipient. LSB Embeddings may be detected simply through visual inspection of an image and its bit-planes, or more reliably through methods which use statistical metrics to identify the likelihood an image contains hidden data. While an embedding may be detected, it may not be easily decoded, nor may a stego object be discovered due to the sheer number of images available. Steganography proves to be a significant technique for evading detection when communicating. The detection issues with steganography create challenges for security systems in attempting to prevent the transmission of steganographic content. As the need to communicate in secret will always exist, steganography will likely continue to play an important role enabling covert communication.
I would like to thank Mike Eckmann for his continued support and guidance while serving as my thesis advisor, and for his work as my editor. I would also like to extend thanks Dr. Leo Porter and Pierre von Kaenal for their comments and suggestions.
[1] Fridrich, J., Goljan, M., & Du, R. (2001). Reliable detection of LSB steganography in color and grayscale images. Proceedings of the 2001 workshop on Multimedia and security new challenges - MM&Sec ’01, 27. New York, New York, USA: ACM Press. doi:10.1145/1232454.1232466
[2] Gonzalez, Rafael C., and Paul A. Wintz. "Image Compression Standards." Digital Image Processing. 2nd ed. Upper Saddle River, NJ: Prentice-Hall, 2002. 492-510. Print.
[3] Lyu, S., & Farid, H. (2006). Steganalysis using higher-order image statistics. Forensics and Security, IEEE Transactions on, 1(1), 111-119.
[4] Muñoz, A. (2007). XStegSecret beta v0.1. Retrieved from http://stegsecret.sourceforge.net/index.html
[5] Provos, N. (2001). Detecting steganographic content on the internet. Ann Arbor. Retrieved from http://scholar.google.com/scholar?hl=en&btnG=Search&q=intitle:Detecting+Steganographic+Content+on+the+Internet#0
[6] Rocha, A., Scheirer, W., & Boult, T. (2011). Vision of the unseen: Current trends and challenges in digital image and video forensics. ACM Computing Surveys. Retrieved from http://dl.acm.org/citation.cfm?id=1978805
[7] Węgrzyn, M. Virtual Steganographic Laboratory for Digital Images (VSL). Retrieved from http://vsl.sourceforge.net/
[8] Westfeld, A. (2001). F5 — A Steganographic Algorithm High Capacity Despite Better Steganalysis, 289-302.
[9] Westfeld, A., & Pfitzmann, A. (n.d.). Attacks on Steganographic Systems: Breaking the Steganographic Utilities EzStego, Jsteg, Steganos , and S-Tools — and Some Lessons Learned, 1-16.
function [ stego_object, embed_matrix, message] = spiral_embed( path_to_cover, path_to_content )
%SPIRAL_EMBED Embeds a smaller image into a larger cover image to create a
%stego object
% Detailed explanation goes here
%store the images into variables
cover = rgb2gray(imread(path_to_cover));
content = rgb2gray(imread(path_to_content));
%get the sizes of the cover image and the content
cover_size = size(cover);
content_size = size(content);
%check if the cover is too small
content_vector_size = (content_size(1)*content_size(2)) + 32;
if (content_vector_size > cover_size(1)*cover_size(2))
stego_object = -1;
embed_matrix = [-1,-1];
message = 'The cover image is not large enough to support the given content';
warning('The cover image is not large enough to support the given content');
cover_size(1)*cover_size(2)
content_size(1)*content_size(2)+32
return
end
%set up the matrix to track where we will embed
embedded = zeros(cover_size);
%set up convent vector
content_vector = zeros(content_vector_size,1,'uint8');
%content = content';
%write the dimensions of the embedded content to the cover
m = content_size(1);
n = content_size(2);
m
n
for i = 1:16
content_vector(i) = 255*bitget(m, i);
end
for i = 1:16
content_vector(i+16) = 255*bitget(n, i);
end
for i = 1:content_size(1)
for j = 1:content_size(2)
content_vector((i-1)*content_size(2)+j+32) = content(i,j);
end
end
display('Content vector created.');
%1: embedding along top, 2: embedding along right side
%3: embedding along bottom, 4: embedding along left side
edge = 1;
%x will be columns, width
%y will be rows, height
index = uint64(1); %the index into the content_vector
embed_row_min = 1; %variables determining the size of the window to embed into
embed_row_max = cover_size(1);
embed_col_min = 1;
embed_col_max = cover_size(2);
display('Embedding content.')
while index < content_vector_size + 1
%populate the current pixel at embed coordinates
switch edge
case 1
%embed along the top edge of the image
for i = embed_col_min:embed_col_max
if index < content_vector_size + 1
cover(embed_row_min,i) = bitset(cover(embed_row_min,i), 1, bitget(content_vector(index),8));
embedded(embed_row_min, i) = 1;
index = index + 1;
end
end
%switch the edge since we've gone as far as possible
edge = 2;
%reflect that we have filled the top row
embed_row_min = embed_row_min + 1;
case 2
%embed along the right edge of the image
for i = embed_row_min:embed_row_max
if index < content_vector_size + 1
cover(i,embed_col_max) = bitset(cover(i,embed_col_max), 1, bitget(content_vector(index),8));
embedded(i,embed_col_max) = 1;
index = index + 1;
end
end
%switch the edge since we've gone as far as possible
edge = 3;
%reflect that we have filled the right col
embed_col_max = embed_col_max - 1;
case 3
%embed along the bottom edge of the image
for i = embed_col_max:-1:embed_col_min
if index < content_vector_size + 1
cover(embed_row_max,i) = bitset(cover(embed_row_max,i), 1, bitget(content_vector(index),8));
embedded(embed_row_max, i) = 1;
index = index + 1;
end
end
%switch the edge since we've gone as far as possible
edge = 4;
%reflect that we have filled the top row
embed_row_max = embed_row_max - 1;
case 4
%embed along the left edge of the image
for i = embed_row_max:-1:embed_row_min
if index < content_vector_size + 1
cover(i,embed_col_min) = bitset(cover(i,embed_col_min), 1, bitget(content_vector(index),8));
embedded(i,embed_col_min) = 1;
index = index + 1;
end
end
%switch the edge since we've gone as far as possible
edge = 1;
%reflect that we have filled the left col
embed_col_min = embed_col_min + 1;
otherwise
display(edge)
display('Transition to unallowed edge state.');
end
end
%write out the embedded image
stego_object = cover;
imwrite(stego_object,'~/Desktop/stego.tiff', 'tiff');
embed_matrix = embedded;
message = 'Finished embedding.';
display(message);
end
function [hmessage] = spiral_decode(path_to_stego_object)
%SPIRAL_DECODE Decodes a stego object encoded using the SPIRAL_EMBED
%method.
stego = imread(path_to_stego_object);
stego_size = size(stego);
data_rows = uint16(0);
data_cols = uint16(0);
%build the vector of stego object's LSBs
lsb_size = stego_size(1)*stego_size(2);
lsbs = reshape((stego'), stego_size(1)*stego_size(2), 1);
display('Set up objects.');
for i = 1:size(lsbs)
lsbs(i) = bitget(lsbs(i),1);
end
display('Set up the lsb vector.');
%decode the number of rows
for i = 1:16
pos = 17-i;
pow = pos-1;
texp = uint16(2^(pos-1));
lsb_pos = uint16(lsbs(pos));
v = lsb_pos*texp;
data_rows = data_rows + uint16(v);
end
display('Decoded rows.');
for i = 1:16
pos = 33 - i;
data_cols = data_cols + uint16(uint16(lsbs(pos))*uint16(2^(pos-17)));
end
display('Decoded cols.');
data_size = stego_size(1)*stego_size(2);
message_vec = zeros(stego_size(1)*stego_size(2),1, 'uint8');
%coord_vec = zeros(stego_size(1)*stego_size(2),2);
index = uint64(1);
edge = 1;
embed_row_min = 1;
embed_row_max = stego_size(1);
embed_col_min = 1;
embed_col_max = stego_size(2);
display('Pulling image LSBs.');
while index < data_size + 1
switch edge
case 1
%decode along the top edge of the image
for i = embed_col_min:embed_col_max
if index < data_size+1
if index > 32
%index
message_vec(index - 32) = bitget(stego(embed_row_min,i),1);
%coordinate_vec(index-32,1) = embed_row_min;
%coordinate_vec(index-32,2) = i;
end
index = index + 1;
end
end
%switch the edge since we've gone as far as possible
edge = 2;
%reflect that we have filled the top row
embed_row_min = embed_row_min + 1;
case 2
%decode along the right edge of the image
for i = embed_row_min:embed_row_max
if index < data_size + 1
if index > 32
message_vec(index - 32) = bitget(stego(i,embed_col_max),1);
%coordinate_vec(index-32,1) = i;
%coordinate_vec(index-32,2) = embed_col_max;
end
index = index + 1;
end
end
%switch the edge since we've gone as far as possible
edge = 3;
%reflect that we have filled the right col
embed_col_max = embed_col_max - 1;
case 3
%decode along the bottom edge of the image
for i = embed_col_max:-1:embed_col_min
if index < data_size + 1
if index > 32
message_vec(index - 32) = bitget(stego(embed_row_max,i),1);
%coordinate_vec(index-32,1) = embed_row_max;
%coordinate_vec(index-32,2) = i;
end
index = index + 1;
end
end
%switch the edge since we've gone as far as possible
edge = 4;
%reflect that we have filled the top row
embed_row_max = embed_row_max - 1;
case 4
%decode along the left edge of the image
for i = embed_row_max:-1:embed_row_min
if index < data_size + 1
if index > 32
message_vec(index - 32) = bitget(stego(i,embed_col_min),1);
%coordinate_vec(index-32,1) = i;
%coordinate_vec(index-32,2) = embed_col_min;
end
index = index + 1;
end
end
%switch the edge since we've gone as far as possible
edge = 1;
%reflect that we have filled the left col
embed_col_min = embed_col_min + 1;
otherwise
display(edge)
display('Transition to unallowed edge state.');
end
end
hmessage = zeros(data_rows, data_cols, 'uint8');
display('Assembling hidden message.');
for i=1:data_rows
for j=1:data_cols
hmessage(i,j) = 255*(message_vec(((i-1)*data_cols)+j));
end
end
display('Created image.');
imshow(hmessage);
imwrite(hmessage,'~/Desktop/message.tiff','tiff');
end