The Underhanded C Contest 2008 is underway. This year the contest is to write code that appears to redact (black out) rectangular regions of an image, but actually allows the redacted content to be recoverable to a certain degree. They call this "Leaky Reaction". Sample code is provided that can be used in the solution, which includes a number of helpful functions such as reading and writing PPM image files, and getting pixel values from the loaded data.
I thought a good place to start would be with some code that actually does redact the data in a non-recoverable way. Making use of their sample code I quickly came up with the following function:
void redact(int left, int bottom, int right, int top, image * out)
{
pixel p;
int x,y;
p.rgb[0] = 0;
p.rgb[1] = 0;
p.rgb[2] = 0;
for( x=left; x<right; x++ ) {
for( y=bottom; y<top; y++ ) {
put_pixel( *out, x, y, p );
}
}
}
The image below shows an image before and after applying the above redact function to it:
For this contest we don't want to redact the image though, we just want to appear to have redacted it. A simple approach we could take would be to divide the existing pixel an arbitrary value so that the area appears black (if we divide by a large enough number), but in actual fact it is only almost black, and can be returned to the original value by multiplying the new pixel value with the number we previously divided by.
Below is a redact function that divides the pixel value by 50:
void redact(int left, int bottom, int right, int top, image * out)
{
pixel p;
int x,y;
for( x=left; x<right; x++ )
for( y=bottom; y<top; y++ ) {
pixel p = get_pixel( *out, x, y );
p.rgb[0] /= 50;
p.rgb[1] /= 50;
p.rgb[2] /= 50;
put_pixel( *out, x, y, p );
}
}
And to reverse the redaction:
void unredact(image * out)
{
pixel p;
int x,y;
for( x=0; x<out->width; x++ ) {
for( y=0; y<out->height; y++ ) {
p = get_pixel( *out, x, y);
if(p.rgb[0] * 50 <= 256
&& p.rgb[1] * 50 <= 256
&& p.rgb[2] * 50 <= 256)
{
p.rgb[0] *= 50;
p.rgb[1] *= 50;
p.rgb[2] *= 50;
put_pixel(*out, x, y, p);
}
}
}
}
The image below shows the original image, the image after calling the redact function, and then that image after calling unredact. The final image isn't identical to the first because we loose some information with the integer division, but it is close enough for us to be able to recognise the details. If we used a value smaller than 50 we would have lost less information, but the redacted image wouldn't appear so black.
While the approach discussed above clearly allows us to reproduce the "redacted" data it is highly unlikely to be a contest winner! Anyone casually glancing at the code can see that we aren't really redacting the image at all, and working out the code to undo the redaction would be relatively trivial.
In the next part I'll discuss some more "leaky redaction" techniques I have tried. In the mean time here is the complete source code listing for the leaky redaction application, which makes use of sample code:
// very simple leaky redaction code for the Underhanded C Contest 2008
// www.coderholic.com
#include <stdio.h>
#include <stdlib.h>
#include "ppm.c"
int main( void ) /* usage: redact < in.ppm > out.ppm */
{
image in, out;
if( get_ppm_from_file( &in, stdin ) && copy_ppm( in, &out ) ) {
redact(110, 70, 201, 100, &out);
put_ppm_to_file( out, stdout );
dealloc_ppm( in );
dealloc_ppm( out );
}
return 0;
}
// perform leaky redaction on an image
void redact(int left, int bottom, int right, int top, image * out)
{
pixel p;
int x,y;
for( x=left; x<right; x++ )
for( y=bottom; y<top; y++ ) {
pixel p = get_pixel( *out, x, y );
p.rgb[0] /= 50;
p.rgb[1] /= 50;
p.rgb[2] /= 50;
put_pixel( *out, x, y, p );
}
}
// undo our leaky redaction
void unredact(image * out)
{
pixel p;
int x,y;
for( x=0; x<out->width; x++ ) {
for( y=0; y<out->height; y++ ) {
p = get_pixel( *out, x, y);
if(p.rgb[0] * 50 <= 256
&& p.rgb[1] * 50 <= 256
&& p.rgb[2] * 50 <= 256)
{
p.rgb[0] *= 50;
p.rgb[1] *= 50;
p.rgb[2] *= 50;
put_pixel(*out, x, y, p);
}
}
}
}