LSB Image Steganography
$begingroup$
After learning the concept of steganography, I've decided to code an application for it in PHP out of all languages, using the Least Significant Bit technique.
A pixel of a colored image generally has 3 channels, one for Red, one for Green and one for Blue. 8 bits are usually used to encode the value for each channel, which gives a range of 0 to 255 in decimal. The idea is to put the bits of my payload into the least significant bits of the color channel values.
Theoretically, you could hide text or any type of file in an image as long as that image is large enough. The length of that text or file in bits must be smaller than the width * height * 3.
From a visual perspective, the difference is not noticeable to the naked eye, which is why "steganalysis" tools are used to detect it.
What I'm looking for is ways to maximize the performance and improve the logic. Converting the contents of my payload to binary form (inside a string) each time and processing all those 1's and 0's is probably a lot of work, or so I've noticed. The code that follows hides a simple, short text, but I've tried hiding the contents of an entire image inside another image and I either screwed up, or that really takes a long time since I set my max execution limit to 5 minutes and it exceeded even that. Maybe I'm just used to things running fast in this day and age.
functions.php
<?php
function toBinary(string $message) {
$result = '';
for($i = 0; $i < strlen($message); $i++) {
$result .= str_pad(decbin(ord($message[$i])), 8, "0", STR_PAD_LEFT);
}
return $result;
}
?>
encode.php
<?php
include('functions.php');
// Number of bytes in an integer.
$INTEGER_BYTES = 4;
$BYTE_BITS = 8;
$message = "Hello from outer space, it's your commander speaking.";
$binaryMessage = toBinary($message);
// The number of bits contained in the message, aka the size of the payload as an integer.
$messageLength = strlen($binaryMessage);
// Convert the length to binary as well and make sure to pad it with 32 0's.
$binaryMessageLength = str_pad(decbin($messageLength), $INTEGER_BYTES * $BYTE_BITS, "0", STR_PAD_LEFT);
// The payload will incorporate the length and the message.
$payload = $binaryMessageLength.$binaryMessage;
$src = 'wilderness.jpg';
$image = imagecreatefromjpeg($src);
$size = getimagesize($src);
$width = $size[0];
$height = $size[1];
function encodePayload(string $payload, $image, $width, $height) {
$payloadLength = strlen($payload);
// We are able to store 3 bits per pixel (1 LSB for each color channel) times the width, times the height.
if($payloadLength > $width * $height * 3) {
echo "Image not big enough to hold data.";
return false;
}
$bitIndex = 0;
for($y = 0; $y < $height; $y++) {
for($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// Each color channel's value is extracted from the original integer.
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// LSB's are cleared by ANDing with 0xFE and filled by ORing with the current payload bit, as long as the payload length isn't hit.
$r = ($bitIndex < $payloadLength) ? (($r & 0xFE) | $payload[$bitIndex++]) : $r;
$g = ($bitIndex < $payloadLength) ? (($g & 0xFE) | $payload[$bitIndex++]) : $g;
$b = ($bitIndex < $payloadLength) ? (($b & 0xFE) | $payload[$bitIndex++]) : $b;
$color = imagecolorallocate($image, $r, $g, $b);
imagesetpixel($image, $x, $y, $color);
if($bitIndex >= $payloadLength) {
return true;
}
}
}
}
if(encodePayload($payload, $image, $width, $height)) {
echo 'Payload delivered.'.'<br>';
} else {
echo 'Something went wrong.'.'<br>';
}
imagepng($image, 'encoded.png');
imagedestroy($image);
?>
decode.php
<?php
$INTEGER_BITS = 32;
$src = 'encoded.png';
$image = imagecreatefrompng($src);
$size = getimagesize($src);
$width = $size[0];
$height = $size[1];
// Returns the message length in bits as an integer.
function decodeMessageLength($image, $width, $height) {
// We need to process the first 32 LSB's of the image to retrieve the int.
$numOfBits = 32;
$bitIndex = 0;
$binaryMessageLength = 0;
for($y = 0; $y < $height; $y++) {
for($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// We extract each component's LSB by simply ANDing with 1.
$r = ($rgb >> 16) & 1;
$g = ($rgb >> 8) & 1;
$b = $rgb & 1;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $r) : $binaryMessageLength;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $g) : $binaryMessageLength;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $b) : $binaryMessageLength;
if($bitIndex >= $numOfBits) {
return $binaryMessageLength;
}
}
}
}
function decodeBinaryMessage($image, $width, $height, $offset, $messageLength) {
$offsetRemainder = $offset % 3;
// We get 3 bits for each pixel, so the offset needs to be divided by 3.
$offset /= 3;
// Instead of looping through all the pixels, an offset is used for the starting indices.
$line = $offset / $width;
$col = $offset % $width;
$binaryMessage = '';
$bitIndex = 0;
for($y = $line; $y < $height; $y++) {
for($x = $col; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// We extract each component's LSB by simply ANDing with 1.
$r = ($rgb >> 16) & 1;
$g = ($rgb >> 8) & 1;
$b = $rgb & 1;
// Depending on the remainder, we will start with a different LSB.
if($offsetRemainder == 1) {
$binaryMessage .= $g;
$binaryMessage .= $b;
$offsetRemainder = 0;
$bitIndex += 2;
} else if($offsetRemainder == 2) {
$binaryMessage .= $b;
$offsetRemainder = 0;
$bitIndex++;
} else {
// As long as the bit index is lower than the length of the message, concatenate each component's LSB to the message.
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$r) : $binaryMessage;
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$g) : $binaryMessage;
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$b) : $binaryMessage;
if($bitIndex >= $messageLength) {
return $binaryMessage;
}
}
}
}
}
$decodedMessageLength = decodeMessageLength($image, $width, $height);
$decodedBinaryMessage = decodeBinaryMessage($image, $width, $height, $INTEGER_BITS, $decodedMessageLength);
$decodedMessage = implode(array_map('chr', array_map('bindec', str_split($decodedBinaryMessage, 8))));
echo 'The hidden message was:'.'<br>'.$decodedMessage.'<br>';
imagedestroy($image);
?>
performance php image steganography
$endgroup$
add a comment |
$begingroup$
After learning the concept of steganography, I've decided to code an application for it in PHP out of all languages, using the Least Significant Bit technique.
A pixel of a colored image generally has 3 channels, one for Red, one for Green and one for Blue. 8 bits are usually used to encode the value for each channel, which gives a range of 0 to 255 in decimal. The idea is to put the bits of my payload into the least significant bits of the color channel values.
Theoretically, you could hide text or any type of file in an image as long as that image is large enough. The length of that text or file in bits must be smaller than the width * height * 3.
From a visual perspective, the difference is not noticeable to the naked eye, which is why "steganalysis" tools are used to detect it.
What I'm looking for is ways to maximize the performance and improve the logic. Converting the contents of my payload to binary form (inside a string) each time and processing all those 1's and 0's is probably a lot of work, or so I've noticed. The code that follows hides a simple, short text, but I've tried hiding the contents of an entire image inside another image and I either screwed up, or that really takes a long time since I set my max execution limit to 5 minutes and it exceeded even that. Maybe I'm just used to things running fast in this day and age.
functions.php
<?php
function toBinary(string $message) {
$result = '';
for($i = 0; $i < strlen($message); $i++) {
$result .= str_pad(decbin(ord($message[$i])), 8, "0", STR_PAD_LEFT);
}
return $result;
}
?>
encode.php
<?php
include('functions.php');
// Number of bytes in an integer.
$INTEGER_BYTES = 4;
$BYTE_BITS = 8;
$message = "Hello from outer space, it's your commander speaking.";
$binaryMessage = toBinary($message);
// The number of bits contained in the message, aka the size of the payload as an integer.
$messageLength = strlen($binaryMessage);
// Convert the length to binary as well and make sure to pad it with 32 0's.
$binaryMessageLength = str_pad(decbin($messageLength), $INTEGER_BYTES * $BYTE_BITS, "0", STR_PAD_LEFT);
// The payload will incorporate the length and the message.
$payload = $binaryMessageLength.$binaryMessage;
$src = 'wilderness.jpg';
$image = imagecreatefromjpeg($src);
$size = getimagesize($src);
$width = $size[0];
$height = $size[1];
function encodePayload(string $payload, $image, $width, $height) {
$payloadLength = strlen($payload);
// We are able to store 3 bits per pixel (1 LSB for each color channel) times the width, times the height.
if($payloadLength > $width * $height * 3) {
echo "Image not big enough to hold data.";
return false;
}
$bitIndex = 0;
for($y = 0; $y < $height; $y++) {
for($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// Each color channel's value is extracted from the original integer.
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// LSB's are cleared by ANDing with 0xFE and filled by ORing with the current payload bit, as long as the payload length isn't hit.
$r = ($bitIndex < $payloadLength) ? (($r & 0xFE) | $payload[$bitIndex++]) : $r;
$g = ($bitIndex < $payloadLength) ? (($g & 0xFE) | $payload[$bitIndex++]) : $g;
$b = ($bitIndex < $payloadLength) ? (($b & 0xFE) | $payload[$bitIndex++]) : $b;
$color = imagecolorallocate($image, $r, $g, $b);
imagesetpixel($image, $x, $y, $color);
if($bitIndex >= $payloadLength) {
return true;
}
}
}
}
if(encodePayload($payload, $image, $width, $height)) {
echo 'Payload delivered.'.'<br>';
} else {
echo 'Something went wrong.'.'<br>';
}
imagepng($image, 'encoded.png');
imagedestroy($image);
?>
decode.php
<?php
$INTEGER_BITS = 32;
$src = 'encoded.png';
$image = imagecreatefrompng($src);
$size = getimagesize($src);
$width = $size[0];
$height = $size[1];
// Returns the message length in bits as an integer.
function decodeMessageLength($image, $width, $height) {
// We need to process the first 32 LSB's of the image to retrieve the int.
$numOfBits = 32;
$bitIndex = 0;
$binaryMessageLength = 0;
for($y = 0; $y < $height; $y++) {
for($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// We extract each component's LSB by simply ANDing with 1.
$r = ($rgb >> 16) & 1;
$g = ($rgb >> 8) & 1;
$b = $rgb & 1;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $r) : $binaryMessageLength;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $g) : $binaryMessageLength;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $b) : $binaryMessageLength;
if($bitIndex >= $numOfBits) {
return $binaryMessageLength;
}
}
}
}
function decodeBinaryMessage($image, $width, $height, $offset, $messageLength) {
$offsetRemainder = $offset % 3;
// We get 3 bits for each pixel, so the offset needs to be divided by 3.
$offset /= 3;
// Instead of looping through all the pixels, an offset is used for the starting indices.
$line = $offset / $width;
$col = $offset % $width;
$binaryMessage = '';
$bitIndex = 0;
for($y = $line; $y < $height; $y++) {
for($x = $col; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// We extract each component's LSB by simply ANDing with 1.
$r = ($rgb >> 16) & 1;
$g = ($rgb >> 8) & 1;
$b = $rgb & 1;
// Depending on the remainder, we will start with a different LSB.
if($offsetRemainder == 1) {
$binaryMessage .= $g;
$binaryMessage .= $b;
$offsetRemainder = 0;
$bitIndex += 2;
} else if($offsetRemainder == 2) {
$binaryMessage .= $b;
$offsetRemainder = 0;
$bitIndex++;
} else {
// As long as the bit index is lower than the length of the message, concatenate each component's LSB to the message.
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$r) : $binaryMessage;
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$g) : $binaryMessage;
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$b) : $binaryMessage;
if($bitIndex >= $messageLength) {
return $binaryMessage;
}
}
}
}
}
$decodedMessageLength = decodeMessageLength($image, $width, $height);
$decodedBinaryMessage = decodeBinaryMessage($image, $width, $height, $INTEGER_BITS, $decodedMessageLength);
$decodedMessage = implode(array_map('chr', array_map('bindec', str_split($decodedBinaryMessage, 8))));
echo 'The hidden message was:'.'<br>'.$decodedMessage.'<br>';
imagedestroy($image);
?>
performance php image steganography
$endgroup$
add a comment |
$begingroup$
After learning the concept of steganography, I've decided to code an application for it in PHP out of all languages, using the Least Significant Bit technique.
A pixel of a colored image generally has 3 channels, one for Red, one for Green and one for Blue. 8 bits are usually used to encode the value for each channel, which gives a range of 0 to 255 in decimal. The idea is to put the bits of my payload into the least significant bits of the color channel values.
Theoretically, you could hide text or any type of file in an image as long as that image is large enough. The length of that text or file in bits must be smaller than the width * height * 3.
From a visual perspective, the difference is not noticeable to the naked eye, which is why "steganalysis" tools are used to detect it.
What I'm looking for is ways to maximize the performance and improve the logic. Converting the contents of my payload to binary form (inside a string) each time and processing all those 1's and 0's is probably a lot of work, or so I've noticed. The code that follows hides a simple, short text, but I've tried hiding the contents of an entire image inside another image and I either screwed up, or that really takes a long time since I set my max execution limit to 5 minutes and it exceeded even that. Maybe I'm just used to things running fast in this day and age.
functions.php
<?php
function toBinary(string $message) {
$result = '';
for($i = 0; $i < strlen($message); $i++) {
$result .= str_pad(decbin(ord($message[$i])), 8, "0", STR_PAD_LEFT);
}
return $result;
}
?>
encode.php
<?php
include('functions.php');
// Number of bytes in an integer.
$INTEGER_BYTES = 4;
$BYTE_BITS = 8;
$message = "Hello from outer space, it's your commander speaking.";
$binaryMessage = toBinary($message);
// The number of bits contained in the message, aka the size of the payload as an integer.
$messageLength = strlen($binaryMessage);
// Convert the length to binary as well and make sure to pad it with 32 0's.
$binaryMessageLength = str_pad(decbin($messageLength), $INTEGER_BYTES * $BYTE_BITS, "0", STR_PAD_LEFT);
// The payload will incorporate the length and the message.
$payload = $binaryMessageLength.$binaryMessage;
$src = 'wilderness.jpg';
$image = imagecreatefromjpeg($src);
$size = getimagesize($src);
$width = $size[0];
$height = $size[1];
function encodePayload(string $payload, $image, $width, $height) {
$payloadLength = strlen($payload);
// We are able to store 3 bits per pixel (1 LSB for each color channel) times the width, times the height.
if($payloadLength > $width * $height * 3) {
echo "Image not big enough to hold data.";
return false;
}
$bitIndex = 0;
for($y = 0; $y < $height; $y++) {
for($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// Each color channel's value is extracted from the original integer.
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// LSB's are cleared by ANDing with 0xFE and filled by ORing with the current payload bit, as long as the payload length isn't hit.
$r = ($bitIndex < $payloadLength) ? (($r & 0xFE) | $payload[$bitIndex++]) : $r;
$g = ($bitIndex < $payloadLength) ? (($g & 0xFE) | $payload[$bitIndex++]) : $g;
$b = ($bitIndex < $payloadLength) ? (($b & 0xFE) | $payload[$bitIndex++]) : $b;
$color = imagecolorallocate($image, $r, $g, $b);
imagesetpixel($image, $x, $y, $color);
if($bitIndex >= $payloadLength) {
return true;
}
}
}
}
if(encodePayload($payload, $image, $width, $height)) {
echo 'Payload delivered.'.'<br>';
} else {
echo 'Something went wrong.'.'<br>';
}
imagepng($image, 'encoded.png');
imagedestroy($image);
?>
decode.php
<?php
$INTEGER_BITS = 32;
$src = 'encoded.png';
$image = imagecreatefrompng($src);
$size = getimagesize($src);
$width = $size[0];
$height = $size[1];
// Returns the message length in bits as an integer.
function decodeMessageLength($image, $width, $height) {
// We need to process the first 32 LSB's of the image to retrieve the int.
$numOfBits = 32;
$bitIndex = 0;
$binaryMessageLength = 0;
for($y = 0; $y < $height; $y++) {
for($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// We extract each component's LSB by simply ANDing with 1.
$r = ($rgb >> 16) & 1;
$g = ($rgb >> 8) & 1;
$b = $rgb & 1;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $r) : $binaryMessageLength;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $g) : $binaryMessageLength;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $b) : $binaryMessageLength;
if($bitIndex >= $numOfBits) {
return $binaryMessageLength;
}
}
}
}
function decodeBinaryMessage($image, $width, $height, $offset, $messageLength) {
$offsetRemainder = $offset % 3;
// We get 3 bits for each pixel, so the offset needs to be divided by 3.
$offset /= 3;
// Instead of looping through all the pixels, an offset is used for the starting indices.
$line = $offset / $width;
$col = $offset % $width;
$binaryMessage = '';
$bitIndex = 0;
for($y = $line; $y < $height; $y++) {
for($x = $col; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// We extract each component's LSB by simply ANDing with 1.
$r = ($rgb >> 16) & 1;
$g = ($rgb >> 8) & 1;
$b = $rgb & 1;
// Depending on the remainder, we will start with a different LSB.
if($offsetRemainder == 1) {
$binaryMessage .= $g;
$binaryMessage .= $b;
$offsetRemainder = 0;
$bitIndex += 2;
} else if($offsetRemainder == 2) {
$binaryMessage .= $b;
$offsetRemainder = 0;
$bitIndex++;
} else {
// As long as the bit index is lower than the length of the message, concatenate each component's LSB to the message.
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$r) : $binaryMessage;
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$g) : $binaryMessage;
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$b) : $binaryMessage;
if($bitIndex >= $messageLength) {
return $binaryMessage;
}
}
}
}
}
$decodedMessageLength = decodeMessageLength($image, $width, $height);
$decodedBinaryMessage = decodeBinaryMessage($image, $width, $height, $INTEGER_BITS, $decodedMessageLength);
$decodedMessage = implode(array_map('chr', array_map('bindec', str_split($decodedBinaryMessage, 8))));
echo 'The hidden message was:'.'<br>'.$decodedMessage.'<br>';
imagedestroy($image);
?>
performance php image steganography
$endgroup$
After learning the concept of steganography, I've decided to code an application for it in PHP out of all languages, using the Least Significant Bit technique.
A pixel of a colored image generally has 3 channels, one for Red, one for Green and one for Blue. 8 bits are usually used to encode the value for each channel, which gives a range of 0 to 255 in decimal. The idea is to put the bits of my payload into the least significant bits of the color channel values.
Theoretically, you could hide text or any type of file in an image as long as that image is large enough. The length of that text or file in bits must be smaller than the width * height * 3.
From a visual perspective, the difference is not noticeable to the naked eye, which is why "steganalysis" tools are used to detect it.
What I'm looking for is ways to maximize the performance and improve the logic. Converting the contents of my payload to binary form (inside a string) each time and processing all those 1's and 0's is probably a lot of work, or so I've noticed. The code that follows hides a simple, short text, but I've tried hiding the contents of an entire image inside another image and I either screwed up, or that really takes a long time since I set my max execution limit to 5 minutes and it exceeded even that. Maybe I'm just used to things running fast in this day and age.
functions.php
<?php
function toBinary(string $message) {
$result = '';
for($i = 0; $i < strlen($message); $i++) {
$result .= str_pad(decbin(ord($message[$i])), 8, "0", STR_PAD_LEFT);
}
return $result;
}
?>
encode.php
<?php
include('functions.php');
// Number of bytes in an integer.
$INTEGER_BYTES = 4;
$BYTE_BITS = 8;
$message = "Hello from outer space, it's your commander speaking.";
$binaryMessage = toBinary($message);
// The number of bits contained in the message, aka the size of the payload as an integer.
$messageLength = strlen($binaryMessage);
// Convert the length to binary as well and make sure to pad it with 32 0's.
$binaryMessageLength = str_pad(decbin($messageLength), $INTEGER_BYTES * $BYTE_BITS, "0", STR_PAD_LEFT);
// The payload will incorporate the length and the message.
$payload = $binaryMessageLength.$binaryMessage;
$src = 'wilderness.jpg';
$image = imagecreatefromjpeg($src);
$size = getimagesize($src);
$width = $size[0];
$height = $size[1];
function encodePayload(string $payload, $image, $width, $height) {
$payloadLength = strlen($payload);
// We are able to store 3 bits per pixel (1 LSB for each color channel) times the width, times the height.
if($payloadLength > $width * $height * 3) {
echo "Image not big enough to hold data.";
return false;
}
$bitIndex = 0;
for($y = 0; $y < $height; $y++) {
for($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// Each color channel's value is extracted from the original integer.
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// LSB's are cleared by ANDing with 0xFE and filled by ORing with the current payload bit, as long as the payload length isn't hit.
$r = ($bitIndex < $payloadLength) ? (($r & 0xFE) | $payload[$bitIndex++]) : $r;
$g = ($bitIndex < $payloadLength) ? (($g & 0xFE) | $payload[$bitIndex++]) : $g;
$b = ($bitIndex < $payloadLength) ? (($b & 0xFE) | $payload[$bitIndex++]) : $b;
$color = imagecolorallocate($image, $r, $g, $b);
imagesetpixel($image, $x, $y, $color);
if($bitIndex >= $payloadLength) {
return true;
}
}
}
}
if(encodePayload($payload, $image, $width, $height)) {
echo 'Payload delivered.'.'<br>';
} else {
echo 'Something went wrong.'.'<br>';
}
imagepng($image, 'encoded.png');
imagedestroy($image);
?>
decode.php
<?php
$INTEGER_BITS = 32;
$src = 'encoded.png';
$image = imagecreatefrompng($src);
$size = getimagesize($src);
$width = $size[0];
$height = $size[1];
// Returns the message length in bits as an integer.
function decodeMessageLength($image, $width, $height) {
// We need to process the first 32 LSB's of the image to retrieve the int.
$numOfBits = 32;
$bitIndex = 0;
$binaryMessageLength = 0;
for($y = 0; $y < $height; $y++) {
for($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// We extract each component's LSB by simply ANDing with 1.
$r = ($rgb >> 16) & 1;
$g = ($rgb >> 8) & 1;
$b = $rgb & 1;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $r) : $binaryMessageLength;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $g) : $binaryMessageLength;
$binaryMessageLength = ($bitIndex++ < $numOfBits) ? (($binaryMessageLength << 1) | $b) : $binaryMessageLength;
if($bitIndex >= $numOfBits) {
return $binaryMessageLength;
}
}
}
}
function decodeBinaryMessage($image, $width, $height, $offset, $messageLength) {
$offsetRemainder = $offset % 3;
// We get 3 bits for each pixel, so the offset needs to be divided by 3.
$offset /= 3;
// Instead of looping through all the pixels, an offset is used for the starting indices.
$line = $offset / $width;
$col = $offset % $width;
$binaryMessage = '';
$bitIndex = 0;
for($y = $line; $y < $height; $y++) {
for($x = $col; $x < $width; $x++) {
$rgb = imagecolorat($image, $x, $y);
// We extract each component's LSB by simply ANDing with 1.
$r = ($rgb >> 16) & 1;
$g = ($rgb >> 8) & 1;
$b = $rgb & 1;
// Depending on the remainder, we will start with a different LSB.
if($offsetRemainder == 1) {
$binaryMessage .= $g;
$binaryMessage .= $b;
$offsetRemainder = 0;
$bitIndex += 2;
} else if($offsetRemainder == 2) {
$binaryMessage .= $b;
$offsetRemainder = 0;
$bitIndex++;
} else {
// As long as the bit index is lower than the length of the message, concatenate each component's LSB to the message.
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$r) : $binaryMessage;
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$g) : $binaryMessage;
$binaryMessage = ($bitIndex++ < $messageLength) ? ($binaryMessage.$b) : $binaryMessage;
if($bitIndex >= $messageLength) {
return $binaryMessage;
}
}
}
}
}
$decodedMessageLength = decodeMessageLength($image, $width, $height);
$decodedBinaryMessage = decodeBinaryMessage($image, $width, $height, $INTEGER_BITS, $decodedMessageLength);
$decodedMessage = implode(array_map('chr', array_map('bindec', str_split($decodedBinaryMessage, 8))));
echo 'The hidden message was:'.'<br>'.$decodedMessage.'<br>';
imagedestroy($image);
?>
performance php image steganography
performance php image steganography
asked 3 mins ago
MarekMarek
262
262
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f212666%2flsb-image-steganography%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f212666%2flsb-image-steganography%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown