Web Development

How to Secure and Authenticate Images Using Watermarks

Cocoa applications use the NSImage class as the primary container for image data on MacOS X. This class supports most image formats such as JPEG, PNG and TIFF. It can load data from a local file or read it from a network session.

The class is hardware-agnostic — it can adapt its image data to suit the display device’s native resolution and color model. The class can also access the image pixels and alter them by code. It even comes with a number of useful transforms and effects.

But the NSImage class is unable to authenticate its image data. So in this article, we will learn how to give NSImage the ability to support watermarks. We will study how a watermark affects image quality, and how well it stands up to alterations.

The Challenge of Security

Today’s massive high-speed networks gave users the means to share their thoughts and ideas on a global basis. But they also allowed others to subvert those ideas, through either forgery or theft.

Consider the digital image for instance. Alice, a well-known and principled photojournalist, sends photos of a political rally to Bob, her news editor. She could post the images on a network service like PhotoBucket or e-mail them through her Gmail account. Bob can then retrieve and process the photos for the next news item.

Yet here comes Eve, who hacks into Alice’s network account. She alters the photos, either by blurring or deleting certain details. Then she replaces the originals with her altered copies. Both Bob and Alice remain unaware that the photos have been compromised.

Then there is Frank. He, too, hacks into Alice’s network account and copies her photos. He sells them to his news editor, assuring the latter that the photos are his. Not only is Alice robbed of the credit; she is also faced with the problem of proving her ownership.

Choices of Security

Now Alice has a couple ways to protect her work against such incursions. One way is to write copyright information to the photo’s metadata. Metadata is a reserved block of bytes that appears before or after the image proper. It is added by digital cameras and scanners, and used to hold information like color depth, model number, and pixel resolution.

But metadata is easy to forge, easy to remove. A skilled thief need only use the right image editor to alter or replace a photo’s metadata. Metadata also come in a wide range of competing formats. Some formats are unique to specific hardware vendors; others have limited data capacities. Furthermore, metadata are useless in measuring image use.

Another way to protect her work is to sign them with a watermark. Watermarks are personalized data embedded directly into the image. In short, they become part of the image itself. Any attempt to alter or remove a watermark is difficult without affecting the surrounding image. Plus, copying the image, or parts of it, also copies the watermark itself.

Some watermarks are visible to the naked eye (Figure 1).

[Click image to view at full size]

Figure 1.

The mark, which may be a company name or logo, or even the user’s own name, appears as a translucent distortion on top of the target image. Visible watermarks are quite easy to apply and verify. Their presence is often enough to deter casual theft. On the other hand, if the watermark has simple design, it can be easily forged. Or if the watermark is a complex one, it could obscure key image details

Other watermarks are not visible. In such cases, the mark itself is mixed into the image pixels. This makes it difficult to forge, especially without the original mark and image on hand. Specialized software is needed to apply and verify this type of watermark. Moreover, invisible watermarks can be vulnerable to certain image transforms and effects. It is common for some images to use both visible and invisible watermarks as a security measure.

Extension by Category

As stated earlier, the NSImage class is unable to apply a watermark to its image data. We could supply this ability by extending the class using a category. In Objective-C, a category is a collection of methods that supply a specific service. It attaches to the target class when an instance is created, and stays attached for the lifetime of that instance.

Categories have a number of advantages over other mechanisms like inheritance and protocols. Unlike inheritance, a category treats the class as an opaque construct. It can be compiled separately from the class, and it does not require prior knowledge of the class source. Unlike protocols, a category can be disabled without affecting the target class.

Category methods have access to all class properties, even private ones. If a category method and an instance method have the same name, the category method overrides the one from the instance. On the other hand, a category cannot add new properties to the target class.

An Objective-C class can attach to two or more categories. But a category can attach to only one class. This quirk allows categories avoid the same fragile base problems that plague multiple inheritance. Categories can be available on a per-application basis or globally. In the latter case, the categories are usually stored in a framework bundle.

Listing 1 shows how we declare the category StringHash. This category will attach a single method named digest(). Its @interface header names a target class, which is NSString. The category name is enclosed with '' and placed after the class name. Two header files are imported for this category: Cocoa.h, which holds the NSString class; and md5.h, which supplies the hash routines.

Listing 2 shows how we declare the next category ImageSign. This one will attach three methods to its target class NSImage. But it imports just the header file Cocoa.h, which holds just the target image. Notice all three methods have the same argument aMrk, of the same object type NSData.

The Watermark Algorithm

There are several ways to apply a watermark to the target image — one is with the LSB algorithm (LSB meaning "least significant bits"). This algorithm divides the watermark into its constituent bits. It then embeds the bits into the color bytes of each image pixel. The result is a subtle color shift, too subtle to be detected easily.

To demonstrate, assume the image uses a 24-bit RGB color model (Figure 2). The first image pixel has a teal green color (0x008080), while the first watermark byte is 0xDC. First, we divide the image pixel into its constituent bytes of red, green, and blue.

[Click image to view at full size]

Figure 2.

0x008080 => r:0x00, g:0x80, b:0x80

Then we divide the watermark byte into pairs of bits.

0xDC => 11 01 11 00

Next we embed each bit pair into bits 1 and 0 of each color byte. So the red byte (0x00) becomes 0x03, the green byte (0x80) becomes 0x81, and the blue byte (0x80) becomes 0x83. We then use these modified bytes to recolor the image pixel. The new pixel color, however, seems to be the same teal color (Figure 3).

[Click image to view at full size]

Figure 3.

Note also that there is still a bit pair left over from the watermark. This pair goes into the red byte of the next image pixel. The bit pairs for the green and blue bytes of that same pixel will then come from the next watermark byte. It takes three watermark bytes to cover four image pixels in succession. Afterwards, the first bit pair from the next watermark byte will go to red byte of the next image pixel.

Additionally, the aforementioned process reads the watermark bits in a little-endian direction, and it reads the color bytes big-endian. Bits 6 and 7 go into the red byte, bits 5 and 4 into green, and so on. But the same process can work with different endian directions. For instance, it could read the watermark bits big-endian, the color bytes little-endian. Provided the same endianess is observed when verifying the watermark, choosing which endian direction to use is pretty much a user preference.

The data size of an LSB watermark is limited by the size and color depth of the target image. Consider again a 24-bit RGB image of height H and width W. The maximum watermark size, in bytes, can be computed with the equation in Figure 4. So for an image 640 pixels wide and 480 pixels high (about 0.3 megapixels), the largest watermark it can have is about 225 kilobytes.

[Click image to view at full size]

Figure 4.

In practice, however, smaller marks are applied repeatedly on the same target image. This makes the marks harder to remove and it aids in estimating fair use.

Preparing the Watermark

For our example, we'll make a watermark in the form of human-readable text. We also will render the text into a hash digest for better security. The NSString class comes with its own hash routine. That routine, however, emits hashes as signed integers, which may be enough for indexing and comparison, but not for secure processes. So, we will use the StringHash category to allow NSString to use the MD5 hash routine.
Listing 3 shows how we define the digest() method in the StringHash category. The method begins by storing its string data into an NSData object (line 12). Note it encodes the string using UTF-8 characters.

Next, the method calls the MD5() function from the OpenSSL library (lines 15-16). It passes the raw byte stream from the NSData object, the stream size, and a nil. The MD5() function then returns the hash value as a 16-byte string.

Finally, the digest() method stores the hash value into a separate NSData object (line 20). And it returns that object to the calling routine.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!