You are on page 1of 159

STI College – Bacoor

ADAPTIVE DIGITAL STEGANOGRAPHY FOR TRUE-COLOR


BITMAPS

A Thesis Presented to
Systems Technology Institute
Bacoor

in Partial Fulfillment
of the Requirements for the Degree of
Bachelor of Science in Computer Science

by:

Gan, Mark David C.

Mr. Gerry A. Villanueva


Thesis Adviser

March 2003
STI College – Bacoor

ADVISER’S RECOMMENDATION SHEET

This Thesis entitled

Adaptive Digital Steganography for True-Color Bitmaps

by:

Gan, Mark David C.

and submitted in partial fulfillment of the requirements of the


Bachelor of Science in Computer Science degree has been examined
and is recommended for acceptance and approval

_________________________________
Mr. Gerry A. Villanueva
Thesis Adviser

March 2003
STI College – Bacoor

THESIS COORDINATOR AND DEAN’S


ACCEPTANCE SHEET

This Thesis entitled

Adaptive Digital Steganography for True-Color Bitmaps

after having been recommended and approved is hereby accepted


by the Information Technology Department
of Systems Technology Institute - Bacoor

_________________________________
Mr. Angelo Magdangal A. Maderal
Thesis Coordinator

_________________________________
Ms. Minerva R. Almalvez
Assistant Dean

March 2003
STI College – Bacoor

PANEL’S APPROVAL SHEET

This Thesis entitled

Adaptive Digital Steganography for True-Color Bitmaps

developed by:

Gan, Mark David C.

after having been presented is hereby approved


by the following members of the panel

_________________________________ _________________________________
Mr. Angelo Magdangal A. Maderal Mr. Ruben B. Muñoz
Panelist Panelist
March 2003 March 2003

_________________________________
Mr. Reynaldo P. Gozum
Lead Panelist
March 2003
TABLE OF CONTENTS

Title Page
Adviser’s Recommendation Sheet
Thesis Coordinator and Dean’s Acceptance Sheet
Panel’s Approval Sheet
List of Appendices
List of Tables
List of Figures
Acknowledgement
Abstract

1.0 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-1


1.1 Background of the Study . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-1
1.2 Statement of the Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4
1.3 Objectives of the Study . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-6
1.3.1 General Objective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-6
1.3.2 Specific Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-6
1.4 Significance of the Study . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-7
1.5 Scope and Limitation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-9
2.0 Methodology of the Study . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-1
3.0 Review of Related Literature and Studies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-1
4.0 Theoretical Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-1
4.1 Parameters of Information Hiding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-1
4.2 Least Significant Bit Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-4
4.3 Transform Embedding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-5
4.4 Masking and Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-6
4.5 Bit-plane Steganalysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-6
4.6 Statistical Attacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-8
4.7 Capacity Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-10
4.8 Minimum-Error Replacement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-13
4.9 Error Diffusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-14
4.10 Pseudorandom Number Generators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-16
4.11 Hash Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-17
5.0 Data Gathering Procedures and Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-1
6.0 Documentation of Current System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-1
6.1 EyeMage IIE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-1
6.2 Invisible Secrets 2002 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-2
6.3 Steganos File Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-5
6.4 The Third Eye . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-6
7.0 Requirement Analysis Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-1
7.1 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-1
7.2 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-1
7.3 Usability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-2
7.4 Functionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-2
8.0 System Design Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-1
8.1 Stegosystem Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-1
8.1.1 Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-2
8.1.2 Transmission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-5
8.1.3 Decoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-6
8.2 Stegosystem Pseudocode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-7
8.2.1 Capacity Evaluation Function . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-8
8.2.2 Minimum-Error Replacement Function . . . . . . . . . . . . . . . . . . . . 8-8
8.2.3 Error Diffusion Function . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-9
8.2.4 Encoding Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-9
8.2.5 Metadata Decoding Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-10
8.2.6 Data File Decoding Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-10
8.3 Image Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-11
9.0 Systems Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-1
9.1 Programming Considerations, Issues and Tools . . . . . . . . . . . . . . . . . . . . 9-1
9.2 System Requirement Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-2
9.3 Testing Activities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-4
9.4 Installation Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-12
10.0 Conclusion and Justification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-1
11.0 Recommendation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-1

Appendices
Bibliography
Curriculum Vitae
LIST OF APPENDICES

Appendix A. Information Hiding Terminology


Appendix B. Mathematical Notations
Appendix C. Project Schedule
Appendix D. Cover Images Used in Performance Testing
Appendix E. Stego Images With Severe Distortions
Appendix F. Chameleon Help File
Appendix G. Chameleon Source Code
LIST OF TABLES

Table 9-1. Cover-Images Used in Performance Testing . . . . . . . . . . . . . . . . . . . . . 9-5


Table 9-2. Test Results for Cover Image “abandon.bmp” . . . . . . . . . . . . . . . . . . . . 9-6
Table 9-3. Test Results for Cover Image “antelope.bmp” . . . . . . . . . . . . . . . . . . . . 9-6
Table 9-4. Test Results for Cover Image “badwater.bmp” . . . . . . . . . . . . . . . . . . . 9-7
Table 9-5. Test Results for Cover Image “death.bmp” . . . . . . . . . . . . . . . . . . . . . . 9-7
Table 9-6. Test Results for Cover Image “gardens.bmp” . . . . . . . . . . . . . . . . . . . . 9-7
Table 9-7. Test Results for Cover Image “kiss.bmp” . . . . . . . . . . . . . . . . . . . . . . . . 9-8
Table 9-8. Test Results for Cover Image “nap.bmp” . . . . . . . . . . . . . . . . . . . . . . . . 9-8
Table 9-9. Test Results for Cover Image “passing.bmp” . . . . . . . . . . . . . . . . . . . . . 9-8
Table 9-10. Test Results for Cover Image “race.bmp” . . . . . . . . . . . . . . . . . . . . . . . 9-9
Table 9-11. Test Results for Cover Image “rain.bmp” . . . . . . . . . . . . . . . . . . . . . . . . 9-9
Table 9-12. Test Results for Cover Image “ruins.bmp” . . . . . . . . . . . . . . . . . . . . . . . 9-9
Table 9-13. Test Results for Cover Image “storm.bmp” . . . . . . . . . . . . . . . . . . . . . . 9-10
Table 9-14. Test Results for Cover Image “style.bmp” . . . . . . . . . . . . . . . . . . . . . . . 9-10
Table 9-15. Test Results for Cover Image “subtle.bmp” . . . . . . . . . . . . . . . . . . . . . . 9-10
Table 9-16. Test Results for Cover Image “sunrise.bmp” . . . . . . . . . . . . . . . . . . . . . 9-11
LIST OF FIGURES

Figure 2-1. Software Engineering Paradigm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-1


Figure 4-1. Data-Hiding Problem Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-3
Figure 4-2. A Grayscale STI College Logo and its Bit-planes . . . . . . . . . . . . . . . . 4-7
Figure 4-3. Neighbors of a Pixel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-9
Figure 6-1. A Noise Image Created by EyeMage IIE . . . . . . . . . . . . . . . . . . . . . . 6-1
Figure 6-2. Screenshot of EyeMage IIE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-2
Figure 6-3. Screenshot of Invisible Secrets 2002 . . . . . . . . . . . . . . . . . . . . . . . . . . 6-4
Figure 6-4. Screenshot of Steganos File Manager . . . . . . . . . . . . . . . . . . . . . . . . . 6-5
Figure 6-5. Screenshot of The Third Eye . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-7
Figure 8-1. Framework of the Proposed Stegosystem . . . . . . . . . . . . . . . . . . . . . . 8-1
Figure 8-2. HIPO Chart of the Encoding Module . . . . . . . . . . . . . . . . . . . . . . . . . . 8-2
Figure 8-3. HIPO Chart of the Decoding Module . . . . . . . . . . . . . . . . . . . . . . . . . 8-6
Figure D-1. abandon.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-1
Figure D-2. antelope.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-2
Figure D-3. badwater.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-3
Figure D-4. death.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-4
Figure D-5. gardens.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-5
Figure D-6. kiss.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-6
Figure D-7. nap.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-7
Figure D-8. passing.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-8
Figure D-9. race.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-9
Figure D-10. rain.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-10
Figure D-11. ruins.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-11
Figure D-12. storm.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-12
Figure D-13. style.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-13
Figure D-14. subtle.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-14
Figure D-15. sunrise.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D-15
Figure E-1. e_abandon_data350k.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E-1
Figure E-2. e_gardens_data310k.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E-2
Figure E-3. e_rain_data170k.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E-3
Figure E-4. e_storm_data350k.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E-4
Figure E-5. e_style_data190k.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E-5
Figure E-6. e_sunrise_data360k.bmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . E-6
ACKNOWLEDGEMENT

First of all, the author would like to thank his thesis adviser, Mr. Gerry

Villanueva, and the thesis coordinator, Mr. Angelo Magdangal Maderal. Their continued

efforts in supervising the development of this thesis is truly appreciated.

The author would also like to express his appreciation for the well-needed support

and guidance extended by the faculty and staff of STI College Bacoor.

Sincere gratitude also goes to Mr. Conrado Vidal who provided valuable

assistance in the preparation of this paper.

The author also gives out thanks to his friends and classmates who have helped in

various ways for the benefit of this project.

Lastly, the author extends out heartfelt appreciation to his parents and relatives

who have contributed a great deal of moral and material support not only for the

completion of this project but more importantly for the physical, mental, and spiritual

well-being of the author. This project would not have been possible without them.
ABSTRACT

Steganography is the science of hiding the existence of information for the

purpose or covert communications. Unlike cryptography which conceals the content of a

message, steganography conceals the very existence of a message.

In the electronic world, one of the most appropriate “hosts” for steganography are

digital images. Digital photographs are a commonly shared, sent, and exchanged

throughout the Internet in the form of email attachments or web postings. However,

current steganographic software available on the market have poor support for

high-capacity image steganography. Even worse, some steganographic software actually

distort or degrade the appearance of cover images and therefore exposes the

steganographic transformation the image has undergone.

In this study, a new image steganography software was presented to answer the

need for a software that makes optimum use of hiding space in an image without creating

any visible distortions. Along with a highly secure method for randomized encoding,

techniques for adaptive encoding were incorporated with the design of the software.

These techniques include capacity evaluation, minimum-error replacement, and error

diffusion.

The test results of comparing the performance of the presented software with

popular and currently-available steganography software showed that the presented

software is a major improvement especially in terms of providing high capacities for

hidden data while preserving the quality and appearance of the image.
1.0 INTRODUCTION

1.1 Background of the Study

Cryptography has long been the cornerstone of information

security. With a history that can be traced back to the ancient Egyptians

some 4000 years ago, it still plays a crucial role in present-day diplomatic

and military services [MENE1996]. However, encryption of messages is

obviously useful only when there is an expected enemy that is monitoring

the channel of communications. Unfortunately, detection of encrypted

communications is likely to provoke an enemy to exert great efforts in

destroying the exposed signal. In an even worse scenario, an enemy may

have enough computing power to break the encryption and decipher the

message. In such situations, the secrecy of the message transmission can

be as vital as the secrecy of the message itself.

Such a case was introduced by G. J. Simmons in 1983 as the

Prisoners’ Problem [ANDE1998]. The problem is that of two prisoners

named Alice and Bob who want to devise an escape plan.

Communications between them pass through a warden named Willie, who

frustrates their plans by putting them into solitary confinement every time

an encrypted message is detected. To avoid detection, they must first find

a way to conceal not only the content of the message but also the message

transmission itself. The solution is an ancient craft called steganography.

Adaptive Digital Steganography for True-Color Bitmaps 1-1


Steganography is the art and science of hiding the existence of

information. The term originated from Greek words (steganoz and

grafein) that literally mean “covered writing” [HETZ2002]. The Greek

historian Herodotus recorded several accounts of steganography in the

ancient times [KAHN1996]. One of these stories was that of a man named

Histaieus who wanted to inform his allies when to revolt against the

Medes and the Persians. To avoid detection, the message was tattooed on

the shaved head of a trusted slave whose hair was later allowed to grow

before being dispatched to Persia. The message was successfully sent and

a victorious revolt soon followed.

Steganography played a key role in classical warfare and it

continued to do so even in modern times. In World War I, for example,

spies made extensive use of invisible inks in order for their mail to pass

through censorship bureaus [DAVE1995]. During World War II, microdot

technology allowed the Germans to photographically shrink documents

into the size of a printed period and avoid detection [KAHN1996]. At the

turn of the century, even the international terrorist leader Osama bin Laden

is believed be using steganography to “covertly distribute information to

his supporters and hide messages throughout the Internet” [SIEB2001].

Evidently, the practical use of steganography in covert communications

makes it one of the most significant subdisciplines in the field of

information hiding.

Adaptive Digital Steganography for True-Color Bitmaps 1-2


Although considered as a relative of cryptography, steganography

presents an entirely different perspective in protecting data. Cryptography

conceals the content of a message; steganography conceals the very

existence of a message [ANDE1998]. Encrypted text is quite prone to

detection, primarily due to its enigmatic or scrambled appearance. For

instance, practically any person who sees a piece of text written like

“HQFUBSWHG PHVVDJH” would suspect that it is an encrypted

message, since the text is obviously meaningless in its present form. On

the contrary, steganography avoids exposure by hiding information within

common and seemingly harmless media. Instead of merely obscuring the

appearance of information, the observer is provided with a convincing

illusion. As a result, the act of communication itself is kept secret.

The introduction of computers to the modern world has provided

various forms of digital media that can be exploited by steganography to

secretly host vital information. Modern approaches include the use of text

documents, digital pictures and even music files as carriers of hidden data.

For digital images, the most basic method for steganography is called least

significant bit encoding (LSB encoding). The simple and logical concept

behind this method makes it effective in concealing relatively large

volumes of data within a single image.

Unfortunately, the transformation-sensitive nature of

LSB-embedded data makes LSB encoding inapplicable to some image

formats, including popular standards like JPEG and GIF. As a result, most

Adaptive Digital Steganography for True-Color Bitmaps 1-3


researchers and developers focus their work on improving alternative

methods for image steganography; therefore leaving behind formats that

use LSB encoding like the standard Windows Bitmap (.bmp).

With the advent of these emerging steganographic technologies,

steganographic software applications are now becoming considerably

popular in the information security industry. Among the most popular and

highly acclaimed are Steganos File Manager, Invisible Secrets 2002,

EyeMage IIE and The Third Eye. All these four steganographic software

utilize safe hiding algorithms for standard Windows bitmaps. However,

most steganographic software available in the market are not always

suitable or sufficient for real-world applications of steganography because

of certain problems with respect to their design.

This study works on the problems of current steganographic

programs and presents a fully-operational software designed for real-world

application of steganography in covert communications and covert data

transfer.

1.2 Statement of the Problem

Generally, current steganographic software are adequate tools for

concealing information. However, most of the steganographic techniques

incorporated by these tools have certain weaknesses that may render the

software inapplicable in certain real-world situations that require the use

of steganography.

Adaptive Digital Steganography for True-Color Bitmaps 1-4


Basically, these weaknesses include the following:

· Inefficient use of hiding space for bitmap images.

Current steganographic software uses standard LSB


encoding for bitmap images, which means the number of bits
used for data hiding is the same (fixed) for every pixel. To
minimize the possibility of making visual distortions in the
resulting image, only the first LSB of each color component of
each pixel is used as hiding space. Considering the relatively
larger file size of uncompressed bitmaps, keeping the size of
the hiding space to a fixed minimum results in inefficiency.

· Tendency to produce distortions in the image.

To maximize hiding capacity, an alternative method is to


use more bits in a pixel instead of just the least significant bits.
As embedding is performed on more-significant bits,
distortions or noticeable marks tend to appear on the image.
Moreover, with original high-resolution digital photographs,
distortions can appear even when embedding is performed only
on the least significant bits.

· Insecure hiding schemes.

Some steganographic software utilize insecure techniques


such as comment insertion for JPEG (Joint Photographic
Experts Group) and PNG (Portable Network Graphics) image
formats. As the name suggests, the algorithm works by merely
inserting data as comments in the header of the image file.
Although this method allows a virtually unlimited size of data
to be hidden, this is obviously insecure. Since the data is not
encoded within the pixels of the image but rather as header
information, the hidden data is readily visible and extractable

Adaptive Digital Steganography for True-Color Bitmaps 1-5


in a file editor. Such hiding scheme hardly qualifies as real
steganography.

For a further discussion on the nature of these problems, the

concepts behind LSB encoding along with other topics on information

hiding are discussed in Chapter 4.

1.3 Objectives of the Study

1.3.1 General Objective

This study aims to develop a secure steganography

software that overcomes the weaknesses of current steganographic

software and that is suitable for real-world application in covert

communications before the end of the school year 2002-2003.

1.3.2 Specific Objectives

To accomplish this objective, this study aims to:

· Incorporate techniques that would eliminate the


possibility of creating human-perceptible distortions in
the image.

· Incorporate techniques that would maximize the use of


hiding space in the image.

· Incorporate techniques that encode the hidden data


within the pixels of the image in order to make them
more integrated with the image itself and not merely as
appended header information in the image file.

Adaptive Digital Steganography for True-Color Bitmaps 1-6


· Establish security that is reliable even when an enemy
has knowledge of how the steganographic algorithm
works, i.e., unconditional security.

1.4 Significance of the Study

As a relative of cryptography in the spycraft family, steganography

is undeniably significant in the espionage industry. However, its use is

certainly not limited to illegal or malicious purposes. Steganography can

also be used to defeat espionage by concealing and securing the

transmission of sensitive information. Around the world, there are

growing concerns regarding diplomatic, industrial and even domestic

espionage. Nowadays, such attacks may come from a wide variety of

organizations that range from government intelligence agencies to

international terrorist networks.

In the fifth of July 2000, for instance, the European Parliament

decided to investigate claims that a global interception system, presumably

codenamed ECHELON, is “being used for purposes of industrial

espionage” under the control of the US National Security Agency (NSA)

and associate countries [SCHM2001]. Although no substantial evidence

proved that it has actually been used to gather competitive intelligence in

favor of American business firms, it was concluded that the satellite-based

interception system undoubtedly exists and is operational.

During the same year, the US Federal Bureau of Investigation

(FBI) also stirred up human rights issues with its Carnivore software

Adaptive Digital Steganography for True-Color Bitmaps 1-7


[MCCU2000]. Like its reported predecessors, Carnivore is capable of

intercepting Web and email traffic as part of investigations on suspected

felons. The online article “How Carnivore Works” explains that the

software uses a technology called packet sniffing, which is a common

technology used by network administrators to monitor network traffic

[TYSO2001]. The unfortunate availability of this technology leads to

serious security concerns regarding Internet traffic.

Government intelligence agencies also have rising concerns

regarding the communications capabilities of extremist factions. Even

before the heightened security concerns brought about by the September

11, 2001 terrorist attack on the World Trade Center, Muslim extremist

groups that are linked to the attacks were already reported to be using

“Internet bulletin boards carrying pornographic and sports information” as

hosts for innocuous-looking pictures encoded with terrorist guerilla plots

[PLEM2001]. Clearly, such exploitations of Internet media pose a threat to

society and are unacceptable.

This paper provides useful information regarding both established

and experimental steganographic techniques. These techniques provide

formidable security for data transmission over public channels such as the

Internet. Companies and various institutions can also integrate

steganographic technology as a primary layer to their existing security

protocols. For example, those which use cryptography as their only

security layer may incorporate steganography as an additional first line of

Adaptive Digital Steganography for True-Color Bitmaps 1-8


defense next to encryption. This way, transmitted messages need to be

detected, extracted and deciphered before its contents can be compromised

to unauthorized personnel.

In addition, understanding the concepts behind digital

steganography can help Web-based companies to develop precautionary

measures to protect their websites or message boards from being used as

hosts for covert criminal transactions such as terrorist plots. Similar

protocols may also be employed by business firms to prevent disloyal

employees from using steganography in secretly passing sensitive

information to rival companies through the company’s own website.

1.5 Scope and Limitation

This study centers its work on the application of digital image

steganography in covert communications. The techniques presented in this

study are not suitable for other areas of information hiding since different

applications focus on different features, as explained in Chapter 4.

Focusing on communications, the primary concerns of the proposed

steganographic software are imperceptibility and hiding capacity.

This study also limits its work on true-color bitmaps. True-color

bitmaps represent pixels as a combination of three 8-bit values

corresponding to the red, green, and blue color components of a pixel.

Despite of its relatively large file size as compared to grayscale images,

the true-color format offers a wider range of distinct colors. More colors in

Adaptive Digital Steganography for True-Color Bitmaps 1-9


an image’s palette means less difference in color tone between each pair of

close colors. This allows for higher levels of modification to be made in

each pixel before the human eye is capable of noticing the changes in

color.

It is important to note that the presented algorithms are

inapplicable to image formats that use lossy compression. Lossy

compression refers to the type of compression wherein “some data is

deliberately discarded to achieve massive reductions in the size of the

compressed file” [PFAF1995]. An example of which is the Discrete

Cosine Transform (DCT) of the popular JPEG image format. This

transformation smoothens the random textures of an image, the same areas

of texture in which embedding is most appropriate. Such transformations

can therefore destroy the data embedded within an image.

Furthermore, although such transformations remove details that are

typically imperceptible to the human eye, repeated processing will

eventually result in a highly degraded image quality. On the other hand,

bitmaps that utilize lossless compression store color values in exact detail.

This means that unlike in JPEG images, bitmaps remain exactly the same

regardless of how many times they are saved or copied.

Adaptive Digital Steganography for True-Color Bitmaps 1-10


2.0 METHODOLOGY

As an outline for the software development section of this study, the

author followed the generic software engineering paradigm presented by

Pressman [PRES1992]. However, Pressman’s generic paradigm is an outline for

company-based software systems. In contrast, the application software developed

in this study is not designed for any specific organization or individual. Its main

purpose is to demonstrate the proposed stegosystem and to test it effectiveness.

With this in mind, the generic paradigm was modified to suit the needs of the

project. The five phases of this modified paradigm is presented in Figure 2-1.

The analysis phase is concerned with defining the scope and functions of

the software being developed. In this phase, the specific attributes that need to be

incorporated to the stegosystem are assessed. Then follows the design phase,

where concepts and techniques are put together to form an abstract model of the

Analysis

Design

Coding

Testing

Enhancement

Figure 2-1.
Software Engineering Paradigm

Adaptive Digital Steganography for True-Color Bitmaps 2-1


proposed stegosystem. In the coding phase, the model conceptualized in the

design phase is translated to computer code by construction of a software

prototype. After construction, next is the testing phase where the effectiveness of

the design is evaluated. Finally, in the enhancement phase, additional

optimizations or corrections are made to the algorithm as necessary.

Supplementary software features are also added in this phase, yielding a fully

engineered version of the application software.

It is important to note that since the software is not a company-based

software system, adaptive maintenance is inapplicable. The software is designed

for a specific use, not for a specific user. It is generic and does not need to adapt

to a specific organization or individual.

Furthermore, requirement analysis is very limited. No company-related

data gathering operations, like interviews and surveys, are needed in this study.

The requirements defined for the proposed stegosystem are based entirely on the

concepts of information hiding and of other fields in computer science.

Adaptive Digital Steganography for True-Color Bitmaps 2-2


3.0 REVIEW OF RELATED LITERATURE AND STUDIES

Over the past few years, a growing interest in the field of information

hiding started to arise. In May of 1996, the “First International Workshop on

Information Hiding” was held in Cambridge, UK. From then on, several areas of

the new field, like steganography and digital watermarking, started to get

attention from the research community. INSPEC reported that by 1998, the

number of publications on digital watermarking alone increased to 103 from

merely 2 back in 1992 [PETI1999].

Following the trend, different research institutions published reports and

journal articles that advertised the developing field. The Institute of Electrical and

Electronics Engineers (IEEE) published many of these articles, especially those in

the area of steganography. Neil Johnson and Sushil Jajodia’s article in the IEEE’s

magazine Computer provided a good primer for understanding steganography

[JOHN1998]. The article discussed basic techniques for image steganography and

evaluated a few steganographic software. Ross Anderson and Fabien Petitcolas

discussed the limitations of steganography in a special issue of the IEEE Journal

of Selected Areas in Communications [ANDE1998]. Petitcolas and Anderson,

along with Markus Kuhn, also wrote a summary of different areas of information

hiding and discussed several practical applications in the July 1999 issue of

Proceedings of the IEEE [PETI1999].

In 1996, Walter Bender et al. wrote a comprehensive article entitled

“Techniques for Data Hiding” for the IBM Systems Journal [BEND1996]. This

renowned publication discussed watermarking techniques for digital images such

Adaptive Digital Steganography for True-Color Bitmaps 3-1


as Texture Block Coding and the robust Patchwork algorithm. For digital audio,

the article also discussed low-bit coding, phase coding, echo data hiding, and

Direct Sequence Spread Spectrum (DSSS) encoding.

Bender et al. also explained semantic and syntactic methods for data

hiding in text. Syntactic methods manipulate punctuations such as commas in

order to encode a series of bits. Semantic methods, on the other hand, encode data

by replacing certain words with synonyms, where each synonym corresponds to a

certain binary value. Perhaps the simplest text-based steganographic techniques

presented in the article are the open space methods, otherwise known as white

space steganography. Bender presented such methods that encode data bits by

modulating the number of spaces between each pair of words. A simple approach

to such methods is to encode 0’s as single spaces and 1’s as double spaces.

A more efficient white space method is Matthew Kwan’s SNOW

algorithm, which stands for “Steganographic Nature of Whitespace”

[KWAN2001]. Unlike Bender’s example, SNOW encodes a set of three bits as a

set of spaces whose length is equal to the decimal value of the set of bits. Each set

of spaces is terminated with a tab character, which is also a white space. This

ensures that for each column of white spaces, exactly three bits of data are stored.

For example, the binary value 111 (decimal number 7) is encoded as a

combination of seven spaces and a tab. The binary value 011 (decimal number 3)

on the other hand, is encoded as a combination of three spaces and a tab.

Furthermore, these sets of white spaces are placed only at the end of every line of

text so as not to affect the appearance of the text.

Adaptive Digital Steganography for True-Color Bitmaps 3-2


Bender’s article was later followed by the equally comprehensive

“Applications for Data Hiding” in 2000 [BEND2000]. This next article, also

written by Bender, discussed several applications of information hiding such as

anti-counterfeiting, tamper detection, and copyright marking.

Well noted for his works on digital watermarking, Bender also supervised

the Master’s degree thesis of Fernando Paiz entitled “Tartan Threads: A Method

for the Real-time Recognition of Secure Documents in Ink Jet Printers”

[PAIZ1999]. This impressive thesis for the Massachusetts Institute of Technology

(MIT) presented a robust watermarking technology that can be used to prevent

inkjet printers from printing copyrighted documents and even monetary bills.

Such technologies are truly valuable in fighting forgery and counterfeiting.

Recognizing its significance in covert communications, the US Military

also conducted studies on steganography. One of which was the project lead by

Lisa Marvel on Spread Spectrum Image Steganography (SSIS), which was

sponsored by the US Army Research Laboratory [MARV1999]. SSIS adopted

concepts from spread spectrum communications to maximize embedding capacity

and imperceptibility. The Air Force Research Laboratory, on the other hand,

sponsored the work of Jiri Fridrich et al. on steganalysis techniques for detecting

LSB encoding in color images [FRID2000]. The Office of Naval Research also

supported steganographic studies. Under the Naval Research Laboratory,

Moskowitz et al. wrote the article “A New Paradigm Hidden in Steganography”.

The article explained how the concepts of information theory are inapplicable in

steganography, unlike in the case of cryptography [MOSK2000].

Adaptive Digital Steganography for True-Color Bitmaps 3-3


With the emergence of several studies on various steganographic

techniques, some researchers moved on to the study of steganalysis, i.e., the

process of detecting and defeating steganography. In 2002, Jessica Fridrich and

Miroslav Goljan wrote a paper entitled “Practical Steganalysis of Digital Images”

[FRID2002]. The paper is a compilation of current approaches to steganalysis and

included discussions on both visual attacks and statistical attacks. Visual attacks

rely on a human observer to “look for suspicious artifacts using simple visual

inspection”. The paper pointed out that despite the simplicity of visual attacks, “it

may be impossible to distinguish noisy images or highly textured images from

stego images using this technique”.

Statistical tests, the other hand, look for discrepancies in certain expected

properties of an image. Neils Provos and Peter Honeyman explains that “some

tests are independent of the data format and just measure the entropy of the

redundant data” [PROV2001a]. This means that images with hidden data are

expected to have “higher entropy” than those without. Images without hidden

data, for example, tend to have an LSB plane that is correlated to 1 or 0. Jiri

Fridrich’s paper on steganalysis for the Air Force Research Laboratory discusses

a technique that is based on evaluating the relative frequencies of close color pairs

[FRID2000].

With respect to statistical attacks, Neils Provos wrote a paper entitled

“Defending Against Statistical Steganalysis” which discusses certain

countermeasures that could help prevent the detection of hidden information.

These approaches “included preserving correlations to one and entropy measured

Adaptive Digital Steganography for True-Color Bitmaps 3-4


by the Maurer test” [PROV2001]. These concepts were incorporated in Provos’

image steganography software called OutGuess which uses the JPEG format.

Another software designed to defeat statistical steganalysis is Andreas

Wesfeld’s software named F5 [WEST2001]. F5 uses a technique called matrix

encoding in order to maximize hiding capacity in JPEG images. As a result, F5

uses an average of 13% of the image file size, which means it is as space-efficient

as the standard fixed-size LSB encoding in lossless true-color bitmaps.

In 2002 however, Jessica Fridrich et al. wrote a paper entitled “Attacking

the OutGuess” which explains how stego images created with OutGuess, F5, and

other JPEG-based steganography software can be reliably detected and identified

[FRID2002a]. The results presented in the paper was verified by Provos himself

by developing a software called Stegdetect based on the presented steganalysis

techniques. The reliability of the techniques presented were acknowledged by

Provos in the OutGuess website, where Stegdetect is available for download

[PROV2002].

Other relevant publications on steganography are cited in Petitcolas and

Anderson’s “Information Hiding: An Annotated Bibliography” [ANDE1999].

This bibliography written for the Computer Laboratory of the University of

Cambridge is an excellent resource guide on practically every area of information

hiding.

Adaptive Digital Steganography for True-Color Bitmaps 3-5


4.0 THEORETICAL FRAMEWORK

4.1 Parameters of Information Hiding

Depending on the application, different methods for information

hiding are inherently focused on different features or parameters. The

basic parameters of information hiding systems are imperceptibility,

hiding capacity, and robustness.

Imperceptibility, or perceptual transparency, is obviously an

inherent goal of every information hiding system. In order to conceal the

existence of hidden information, it is important that the embedding

process does not produce perceptible distortions to the cover-medium.

Bender et al. related this concept to the magician’s trick of misdirection,

which allows “something to be hidden while it remains in plain sight”

[BEND1996].

An extension to imperceptibility is undetectability. Instead of

exploiting the weaknesses of human perceptive capabilities, as in the case

of imperceptibility, undetectability focuses on defending steganography

against computer-based steganalysis by preserving certain statistical

characteristics of the cover-medium. Undetectability is therefore

concerned with the stego-medium’s consistency with the statistical

characteristics of the original cover-medium [FRID1998].

Hiding capacity, which is also referred to as embedding capacity,

bit-rate, and payload, was defined by Eugene Lin and Edward Delp as

Adaptive Digital Steganography for True-Color Bitmaps 4-1


“the size of information that can be hidden relative to the size of the

cover” [LIN1999]. They further explained that a higher capacity rate

reduces the need for using larger cover-files. This in turn enhances

portability and transmission speed, which are both high priorities in covert

communications. Digital watermarking systems, on the other hand, embed

only small volumes of data like copyright information and thus capacity is

of minimal importance in such applications [BEND1996].

Robustness is the resistance against attempts to destroy the

embedded data by means of modifying the stego-medium. Bender et al.

stated that sources of such modifications range “from intentional and

intelligent attempts of removal to anticipated manipulations”

[BEND1996]. In image processing, these “anticipated manipulations”

include the inevitable consequences of certain image transformations. A

good example of which is the downgrading of image quality in the JPEG

format, as explained in Chapter 1.

Beyond accidental or intentional destruction of embedded data, an

even greater threat is tampering. An example of such malicious attack is a

pirate’s attempt to alter embedded copyright information. As with music

files, copyrighted images are common targets of piracy. Robustness and

tamper resistance are therefore primary concerns of digital watermarking

systems [LIN1999].

Marvel et al. stated that capacity and robustness is impossible to

maximize at the same time while adhering to high imperceptibility rates

Adaptive Digital Steganography for True-Color Bitmaps 4-2


[MARV1999]. In an article for the IBM Systems Journal, Bender et al.

introduced this trade-off between capacity and robustness as the

data-hiding problem space [BEND1996]. The article explains that to

achieve robustness, redundant encoding of the embedded data on the

cover-medium must be performed, which in turn sacrifices capacity.

Figure 4-1 is based on Fridrich’s diagram for the data-hiding problem

space, which depicts the mutually competitive nature of these parameters

[FRID1998].

As the triangular shape of the diagram shows, the three opposing

parameters cannot be maximized all at the same time. In the case of covert

communications, for example, working on the midpoint between

imperceptibility and hiding capacity provides optimum balance between

the two parameters but at the expense of completely compromising

robustness. On the other hand, digital watermarking systems sacrifice

capacity in favor of robustness, as is required by the application.

Imperceptibility

Digital
Steganography Watermarking

Hiding Capacity Robustness

Figure 4-1.
Data-Hiding Problem Space

Adaptive Digital Steganography for True-Color Bitmaps 4-3


4.2 Least Significant Bit Encoding

The concept behind LSB encoding is to replace the least

significant bit (LSB) of each pixel in an image with the bits of the data to

be embedded [LIN1999]. In a grayscale image, for example, each pixel is

represented by an 8-bit value that corresponds to the pixel’s intensity. The

lower the value, the closer the pixel is to the color black. Since the least

significant bit has a place value of 1, modifying it would result in a

maximum difference of only 1. Because the human eye is not capable of

distinguishing minute changes in color, such modifications would

normally be imperceptible.

In true-color bitmaps, the three colors of light (red, green, and

blue) are combined in varying intensities to define the color of each pixel.

Each color component is represented by an 8-bit value that corresponds to

the component’s intensity, ranging from 0 to 255. Since there are three

LSB’s in each pixel, the hiding capacity in terms of bits is three times the

total number of pixels in the cover image. In a 300x300 bitmap, for

example, the hiding capacity is 270,000 bits (33,750 bytes).

In cases that require large volumes of data to be hidden,

embedding can be performed even up to the second or third LSB of each

color component of a pixel. However, using the more significant portions

of a color component will certainly cause drastic changes in the image.

These changes may exist in the form undesirable marks and artifacts or as

distortions in the contour of smooth areas in an image.

Adaptive Digital Steganography for True-Color Bitmaps 4-4


LSB encoding, therefore, deals with two basic problems:

· If capacity is maximized, modifications become evident and


secrecy is compromised.

· If imperceptibility is maximized, lower volumes of data can be


hidden.

Furthermore, embedding in images with areas of very smooth

textures or solid patterns, such as computer-drawn images and graphs, is

likely to create visible distortions even if only the first LSB’s are

modified.

4.3 Transform Embedding

Because of the loss of data caused by the transformations

employed by many image file formats, standard LSB encoding is

inapplicable to many images. In such cases, instead of manipulating the

pixels or the spatial domain of an image, the coefficients of the transform

domain of a processed image is used [LIN1999]. The JPEG format, for

example, uses a lossy compression algorithm called the Discrete Cosine

Transform (DCT). The LSBs of the coefficients of this transform can then

be used as hiding space for data bits.

Although transform embedding techniques are typically more

robust as compared with standard LSB encoding, they also typically offer

less hiding capacity [LIN1999]. Furthermore, since such techniques are

format-dependent and embed data after the transformations have been

Adaptive Digital Steganography for True-Color Bitmaps 4-5


made, the embedding process may alter certain statistical properties of the

image that are common or unique to that particular image format. This

makes transform embedding techniques susceptible to detection or

steganalysis. Considering this, such techniques are ideal only for

applications like copyright marking and authentication.

4.4 Masking and Filtering

Another alternative method for data hiding in digital images are

masking and filtering techniques. Such techniques hide data by “marking

an image in a manner similar to paper watermarks”, thus they are designed

for application in digital watermarking [JOHN1998].

Digital watermarking techniques are more robust than traditional

steganographic techniques since watermarks are more integrated into the

image. The Patchwork watermarking algorithm, for example, embeds data

by manipulating the brightness or luminance of certain pairs of points in

an image [BEND1996].

4.5 Bit-plane Steganalysis

A bit-plane is the plane formed by the bits of the same bit position

in each pixel. Figure 4-2 shows a grayscale image of the STI College logo

along with its eight bit-planes. Black areas in the bit-planes represent a bit

value of 0 while white areas represent 1. Figure 4-2b is the most

significant bit-plane of the original image depicted as Figure 4-2a. Figure

Adaptive Digital Steganography for True-Color Bitmaps 4-6


(b) (c) (d) (e)

(a)

(f) (g) (h) (i)

Figure 4-2.
A Grayscale STI College Logo and its Bit-planes

4-2i, on the other hand, is the least significant bit-plane of the original

image.

Yeuan-Kwen Lee and Ling-Hwei Chen made two important

observations regarding bit-planes that are relevant to information hiding

[LEE1999]. The first observation is that areas appearing as random texture

in a more significant bit-plane will also appear as random texture in less

significant bit-planes. The second observation is that randomness in the

texture of a specific area increases gradually from the most significant

bit-plane to the least significant bit-plane. These observations are evident

in Figure 4-2.

Random textures in a bit-plane are produced by transitions of

0-to-1 or 1-to-0 in the values of adjacent bits in a bit-plane. Considering

the observations on bit-planes, Lee and Chen concluded that transition

Adaptive Digital Steganography for True-Color Bitmaps 4-7


density is higher in less significant bit-planes compared to that of more

significant bit-planes [LEE1999].

Embedding in the more significant bits of an image is likely to

increase the transition densities of these bit-planes. The supposedly

gradual increase in transition density from more significant bit-planes to

less significant bit-planes would consequently be changed. Considering

this phenomenon, an attacker can therefore detect the presence of

embedded data by analyzing the transition densities of the bit-planes of an

image.

However, it is important to note that like most techniques for

steganalysis, bit-plane steganalysis is essentially based on statistical

observations and assumptions of distinct properties of the cover-medium.

The results of such methods for detection are not always reliable as they

may sometimes miss detecting hidden data or falsely identify a plain

image as a host for steganography. Moreover, Lee and Chen’s paper does

not provide details as to how bit-plane steganalysis may be automated

with the use of algorithms or software. Bit-plane steganalysis therefore

remains a visual attack and thus require a human observer to evaluate the

bit planes.

4.6 Statistical Attacks

Unlike visual attacks, statistical attacks are steganalytic methods

that can be automated through software. Statistical attacks operate by

Adaptive Digital Steganography for True-Color Bitmaps 4-8


detecting discrepancies in certain expected properties of an image or

image format. Lossy-compressed image formats, like JPEG for example,

tend to have distinct statistical properties because of the transformations

involved. Jessica Fridrich and Miroslav Goljan’s paper on practical

steganalysis explains that after a JPEG image is embedded with data, “the

cover image will become incompatible with the JPEG format in the sense

that it may be possible to prove that a particular 8x8 block of pixels could

not have been produced by JPEG decompression” [FRID2002]. The JPEG

compatibility test can therefore “potentially detect messages as short as

one bit”. Such distinct properties therefore make JPEG images very

vulnerable to attacks.

On the other hand, lossless-compressed bitmaps do not undergo

transformations and are therefore unlikely to have distinct properties, since

any combination of pixels in any area of the image is possible. However,

Jiri Fridrich et al. wrote a paper entitled “Steganalysis of LSB Encoding in

Color Images” that describes a steganalysis technique that is expected to

detect statistical discrepancies even in lossless-compressed true-color

bitmaps [FRID2000]. This technique called the RQP method (Raw Quick

Pair method) “is based on analyzing close pairs of colors created by LSB

embedding” [FRID2002].

Fridrich et al. states that data embedding tends to increase the

number of close colors in an image’s palette [FRID2000]. If an image

already has been embedded with hidden data, the ratio between the

Adaptive Digital Steganography for True-Color Bitmaps 4-9


number of all pairs of close colors and the number of all color pairs will

no longer increase if LSB encoding of random data is again performed on

the image.

A pair of colors is considered to be “close” if the difference

between the red-green-blue values of one color and the red-green-blue

values of the other color is less than or equal to 1. This expression can be

expressed as:

(|R1 – R2| £ 1) and (|G1 – G2| £ 1) and (|B1 – B2| £ 1)

This is expression is also equivalent to:

(R1 – R2)2 + (G1 – G2)2 + (B1 – B2)2 £ 3

The RQP method is said to work “reasonably well as long as the

number of unique colors in the cover image is less than 30% of the

number of pixels” [FRID2002].

4.7 Capacity Evaluation

Instead of embedding on a fixed number of bits in every pixel, the

size of the hiding space in each pixel must be dependent on the color

variation of the adjacent pixels. This prevents the embedding process from

making drastic modifications in the smooth areas of an image, therefore

minimizing human-perceptible distortions. Such adaptive selection of

hiding space also protects the stego image from bit-plane steganalysis and

Adaptive Digital Steganography for True-Color Bitmaps 4-10


B C D
(x-1,y-1) (x,y-1) (x+1,y-1)

A P E
(x-1,y) (x,y) (x+1,y)

H G F
(x-1,y+1) (x,y+1) (x+1,y+1)

Figure 4-3.
Neighbors of a Pixel

other visual attacks since the significant bits of each pixel remain

unchanged.

Lee and Chen presented a simple method for evaluating the hiding

capacity of a pixel in a grayscale image [LEE1999]. For a particular pixel

P, the first step is to get the gray level variation in its top-left adjacent

pixels A, B, C, and D. The schematic layout of these pixels is depicted in

Figure 4-3. The gray level variation is defined as the difference between

the maximum and the minimum gray values among the four pixels. The

formula for the gray level variation V can be written as:

V = max {A, B, C, D} – min {A, B, C, D}

According to Lee and Chen, the number of bits that can be

modified in pixel P is the minimum number of bits needed to store the

Adaptive Digital Steganography for True-Color Bitmaps 4-11


binary value of V minus 1. Mathematically, this can be expressed simply

as:

K = ë log2 V û

It is important to note that with this technique, embedding can only

be performed in a top-to-bottom left-to-right orientation. Only the four

top-left adjacent pixels are considered in the evaluation because the

embedding function has already passed through these pixels. The other

four pixels on the bottom-right are still to undergo the embedding process,

which means their values may still change.

Lee and Chen also noted a distinct characteristic of the human

visual system (HVS) that is crucial to capacity evaluation. They stated that

for the human eye, “the greater the gray-scale is, the more change of the

gray-scale could be tolerated” [LEE2000]. Simply put, this means that the

closer a pixel is to the color white, the more tolerant it is to modifications.

Considering this, an upper boundary for the capacity of a pixel can be set

based on its intensity. Lee and Chen gives the following condition:

if P > 191 then U = 5, else U = 4

A threshold of 5 is set for U because the more significant bits of

the pixels must not be allowed to change so that the upper boundary may

still be calculated accurately in the decoding process. The succeeding

Adaptive Digital Steganography for True-Color Bitmaps 4-12


topic will explain why the constants 191, 5, and 4 were chosen for the

condition for U.

Although not mentioned in Lee and Chen’s paper, such a technique

is, in theory, also applicable for true-color images. One possible

interpretation of the original algorithm is to use the capacity evaluation

function independently for each of the three color channels of a pixel.

Instead of evaluating grayscale values, the intensity of each color

component of a pixel may be considered. This approach will be

experimented in this study.

4.8 Minimum-Error Replacement

In order to minimize the changes made to a pixel as a result of

embedding, minimum-error replacement (MER) will also be incorporated

in the proposed stegosystem. The idea behind MER is to adjust the bit that

is immediately succeeding the modified LSB’s of a particular color value

in such a way that the change caused by the embedding operation is

minimal.

For example, if a binary number 1000 (decimal number 8) is

changed to 1111 (decimal number 15) because its three LSB’s were

replaced with embedded data, the difference from the original number is 7.

This difference in the original value of a color component is called the

embedding error. By adjusting the fourth bit from a value of 1 to a value

of 0, the binary number now becomes 0111 (decimal number 7) and the

Adaptive Digital Steganography for True-Color Bitmaps 4-13


embedding error is reduced to 1 while at the same time preserving the

value of the three embedded bits.

For every K number of LSB’s used for embedding in a particular

color value, the maximum embedding error for that color value is 2K–1, or

the maximum value for a set of K bits. Since MER adjusts the bit next to

the modified LSB’s, the embedding error is restricted to a maximum value

of 2(K–1) [LEE1999].

Going back to the calculation of the upper boundary in capacity

evaluation, the constants 191, 5, and 4 were chosen with consideration to

how MER works. A threshold of 5 was selected since embedding five bits

into an 8-bit value (a byte) using MER would mean that the sixth LSB

may also change. Since the only remaining bits that are protected from

modification are the two most significant bits (MSB), the value of a byte

when only these two bits are set to 1 is 192, i.e., 27 + 26. Whatever the

value of the six LSBs, the value of the byte will always be greater than

191 as long as both of the two MSBs are set to 1.

4.9 Error Diffusion

Since the capacity-evaluation technique presented by Lee and

Chen analyzes only the four top-left adjacent pixels, distortions in the

contour of certain areas or shapes in an image can still be made. For an

image to adapt to the changes in color caused by embedding, an error

diffusion technique must also be employed.

Adaptive Digital Steganography for True-Color Bitmaps 4-14


Lee and Chen presented an error diffusion technique called

Improved Gray-Scale Compensation (IGSC), which makes up for the

embedding error in the grayscale value of a pixel by spreading that error

evenly across the adjacent pixels [LEE2000]. This is done by adding ¼ of

the embedding error to the intensity or grayscale value of each of the four

bottom-right adjacent pixels. These pixels are depicted in Figure 4-3 as

pixels E, F, G, and H.

In simpler terms, when a pixel’s intensity increases, the intensities

of the four adjacent pixels on its bottom-right sides are decreased. Lee and

Chen did not discuss exactly how such an operation helps in preventing

distortions in the image. Nevertheless, it is conceivable that when a pixel’s

intensity increases, the capacity evaluation function is likely to allocate

higher capacities for the succeeding pixels than what it would have

originally allocated if the intensity of the current pixel had not increased,

and vice versa. This is because an increase or decrease in the intensity of

the current pixel affects the capacity evaluation for the succeeding pixels

that have not been processed yet. IGSC therefore compensates for the

change by maintaining balance between the intensities of adjacent pixels.

Moreover, performing such correcting operations allow the image to

preserve the average color intensity of the image as well as possible

correlations in the image’s bit-planes.

Although IGSC was presented as a technique for grayscale images,

Lee and Chen stated that it was based on an error-diffusion technique used

Adaptive Digital Steganography for True-Color Bitmaps 4-15


when converting true-color images to 8-bit color formats [LEE2000]. It

may therefore be assumed that the concept behind IGSC is applicable to

color images.

4.10 Pseudorandom Number Generators

According to Menezes et al., the “security of many cryptographic

systems depends upon the generation of unpredictable quantities”

[MENE1996]. In digital cryptography, this is particularly true in the sense

that every computer-based cryptosystem utilizes what is generally known

as a pseudorandom number generator (PRNG). A PRNG is a device or

algorithm that outputs a seemingly-random sequence of numbers based on

a given numerical value called the seed. Unlike real random number

generators (RNG), PRNGs are deterministic, which means a particular

seed will generate the exact same sequence of numbers every time it is

used.

Before the use of computer-based PRNGs in cryptography, data is

encrypted with a keystream as long as the unencrypted data in order to

eliminate any detectable patterns in encryption process. With PRNGs,

instead of requiring the user to remember an extremely long keystream,

encryption algorithms can use as a keystream the long sequence of

numerical values generated by a PRNG that is seeded by the numeric

equivalent of a given password or encryption key. This way, encryption

keys can be relatively short while still maintaining high security.

Adaptive Digital Steganography for True-Color Bitmaps 4-16


The same concept for key security can be used in steganography.

PRNGs can be used in steganography in randomizing the pattern of

embedding. With PRNGs, data bits may be scattered pseudorandomly

across the cover-medium. This makes the embedded data extremely

difficult, if not impossible, to extract without knowledge of the seed used

by the PRNG. In such a setup, the seed of the PRNG can be the hash value

of a user-given stego key.

4.11 Hash Functions

Like PRNGs, hash functions “play a fundamental role in modern

cryptography” [MENE1996]. Hash functions transform input values of

varying length or range into a fixed-length bit stream. Unlike

cryptographic functions, these functions are not reversible. Once a value

has been hashed, information about its original value has already been

lost.

This unique feature of hash functions makes them ideal for

password verification operations. For example, if a password-protected

operating system stores a list of valid passwords within the system for

login verification, a potential attacker or hacker may eventually find a way

to access the contents of such a list and break into the system.

A solution to this problem is to store the hash values of the

passwords instead of the original values. During login, entered passwords

are verified by calculating their hash values and comparing them with the

Adaptive Digital Steganography for True-Color Bitmaps 4-17


hash values stored in the system. This way, even if a hacker gains access

to the password list, the only way to know the actual passwords is to

calculate the hash value every possible character combination within the

maximum length for passwords and find the ones that matches the hash

values in the list. This would be an extremely exhaustive operation for the

attacker.

The same concept can be used in steganography. For password

verification, a hash value of the original password may be embedded in an

image along with the hidden data bits.

Adaptive Digital Steganography for True-Color Bitmaps 4-18


5.0 DATA GATHERING PROCEDURES AND OUTPUTS

The software being developed in this study is not a company-based system

but rather a general-purpose security software for use in covert communications.

Because of this, data gathering for this study is focused on the modern researches

and developments in the field of information hiding, particularly in

steganography. No interviews or surveys on companies and company personnel

are conducted during the course of this study, as they are not necessary.

The primary information resource used in this study is the Internet. As it is

with most subjects, the Internet is evidently the best source for up-to-date and

detailed information regarding steganographic research. Several research papers,

technical reports, and journal articles gathered from the Internet provided the

technical information required for the designing and development of this study’s

proposed steganography software.

Most of the papers referenced during the course of this study were

acquired from the CiteSeer Scientific Literature Digital Library, a comprehensive

archive of scientific documents sponsored by the NEC Research Institute.

CiteSeer currently indexes over 500,000 research documents on the web and

allows copies of these documents to be downloaded in PostScript and PDF

formats.

Copies of the IBM Systems Journal downloaded from the IBM Research

website were also referenced in this study. The two issues of this journal

referenced in this study provided useful background information on data hiding

Adaptive Digital Steganography for True-Color Bitmaps 5-1


techniques. News articles referenced in this paper were acquired from Wired

News, TechTV.com, and CNN.com.

Other Internet searches were done in AlltheWeb, a “public search engine

and technology showcase” from Fast Search & Transfer, Inc. [FAST2002].

Originally set up as a test site for new and experimental search features,

AlltheWeb grew into a fast and comprehensive search engine ideal for students

and researchers. At present, it “indexes over 2.1 billion web pages, 118 million

multimedia files, 132 million FTP files, two million MP3s, 15 million PDF files

and supports 49 languages”.

Adaptive Digital Steganography for True-Color Bitmaps 5-2


6.0 DOCUMENTATION OF CURRENT SYSTEM

6.1 EyeMage IIE

EyeMage IIE (In Image Encryption) is a free steganography

software from Proporta Ltd. It supports data hiding in Windows bitmaps

only but allows data to be embedded in more significant bit planes, not

just on the LSBs.

The unique feature of EyeMage is the ability to create a custom

noise image in which a selected data file may be embedded. However, as

the name suggests, noise images are made up of random colors and form

no meaningful picture. Because of this, using noise images as cover

images would hardly qualify as valid steganography since the media is

obviously cryptic and does not provide a convincing illusion. Figure 6-1

shows a sample of such an image created by EyeMage.

Figure 6-1.
A Noise Image Created by EyeMage IIE

Adaptive Digital Steganography for True-Color Bitmaps 6-1


Figure 6-2.
Screenshot of EyeMage IIE

According to the included documentation, EyeMage also features

built-in encryption and compression capabilities. It also uses a technique

called password mangling which processes the user-given password with a

hash function repeatedly several times before it is actually used in the

encoding process. The user interface of EyeMage is quite simple and is

relatively easy to use. Figure 6-2 shows a screenshot of EyeMage.

6.2 Invisible Secrets 2002

Invisible Secrets 2002 is a commercial steganography software

from NeoByte Solutions [NEOB2002]. Version 3.2 supports

steganography in five different file formats:

Adaptive Digital Steganography for True-Color Bitmaps 6-2


· Windows Bitmap (.bmp)

· JPEG File Interchange Format (.jpg)

· Portable Network Graphics (.png)

· Wave sound files (.wav)

· HTML documents (.html)

For Windows bitmaps, Invisible Secrets uses standard LSB

encoding to avoid creating distortions on the stego image. In the case of

JPEG and PNG images, however, a technique referred to as comment

insertion is used. As the name suggests, the hidden data file is encoded as

comment data in the header of the image. Although this provides an

unlimited hiding space and does not make any changes to the image itself,

such a technique is highly insecure. Since the data bits are not embedded

as integral parts of the image, the hidden data is readily extractable by

potential attackers. Moreover, inserting large files would greatly increase

the size of the stego image and may attract suspicion since JPEG and PNG

images often have very small file sizes.

Invisible Secrets may be considered as a general-purpose

“information security suite” because it can also be used exclusively for file

encryption or file shredding. The included encryption algorithms are

Blowfish, Twofish, RC4, Cast128, GOST, Rijndael (AES), Diamond 2, and

Sapphire II.

Invisible Secrets features a wizard-style user interface that makes it

very easy to use as compared with other software. Figure 6-3 shows a

Adaptive Digital Steganography for True-Color Bitmaps 6-3


Figure 6-3.
Screenshot of Invisible Secrets 2002

screenshot of this user interface. It has been observed in this study that

such interface designs are very effective in enhancing the usability of

steganographic software.

Invisible Secrets is designed and tested to run under the Windows

95, Windows 98, Windows 2000, Windows ME, Windows NT, and

Windows XP operating systems.

The NeoByte Solutions website does not provide any information

regarding the minimum system requirements of Invisible Secrets 2002.

Adaptive Digital Steganography for True-Color Bitmaps 6-4


Nevertheless, it is has been tested to run reasonably fast even on slow

computers during the course of this study.

6.3 Steganos File Manager

The Steganos File Manager is a steganography program

distributed as a part of the Steganos Security Suite, which includes several

security features such as file shredding, file encryption, disk encryption,

and Internet tracks erasing [STEG2002].

Although one of the most popular steganography software on the

Internet, Steganos supports embedding on standard Windows bitmaps

only. The encryption algorithms included with Steganos is Rijndael and

Blowfish.

Figure 6-4.
Screenshot of Steganos File Manager

Adaptive Digital Steganography for True-Color Bitmaps 6-5


The user interface of the Steganos File Manager is quite similar to

that of the WinZip file compression software and is not as easy to use as

other steganographic software. A screenshot of this user interface is shown

in Figure 6-4.

The minimum system requirements of Steganos listed on its Help

file are as follows:

· Pentium processor

· 32 MB RAM

· 9 MB hard drive space

· screen resolution of 640x480 pixels at 256 colors.

· mouse or other pointing devices (since it does not provide full


keyboard support)

6.4 The Third Eye

The Third Eye is a freeware steganography program developed by

Satya Kiran [KIRA2002]. Version 1.0 supports steganography in three

image formats:

· Windows Bitmap (.bmp)

· Graphics Interchange Format (.gif)

· PC Paintbrush Format (.pcx)

The Third Eye also uses standard LSB encoding like Steganos and

Invisible Secrets. The user’s manual defines the following minimum

system requirements:

Adaptive Digital Steganography for True-Color Bitmaps 6-6


· Intel 80386 processor

· Windows operating system

· 1.5 MB free hard disk space.

The Third Eye features a Multiple Document Interface (MDI) that

is also quite easy to use since very few controls and menu options are on

the main window. Figure 6-5 shows a screenshot of this user interface.

Figure 6-5.
Screenshot of The Third Eye

Adaptive Digital Steganography for True-Color Bitmaps 6-7


The Third Eye does not include any encryption or compression

capabilities. It does however include a feature for binary comparison

between the pixels of two images.

Adaptive Digital Steganography for True-Color Bitmaps 6-8


7.0 REQUIREMENTS ANALYSIS SPECIFICATION

This study is focused on developing a steganography software that is

suitable in real-world application for covert communication or covert data

transmission. In view of the software’s intended function, certain points should be

considered in designing the software.

7.1 Performance

· The steganographic process should not create distortions or artifacts in


the image which may expose the existence of hidden data.

· The steganographic algorithm should support high capacities for


embedded data without sacrificing imperceptibility.

· The software should be streamlined and compact.

· The software should be reasonably fast.

· The software should incorporate file compression to further increase


hiding capacity.

7.2 Security

· The software should provide password protection.

· The steganographic algorithm should generate a randomized pattern


for embedding.

· The software should incorporate file encryption to further enhance


data protection.

Adaptive Digital Steganography for True-Color Bitmaps 7-1


7.3 Usability

· The user interface should be intuitive or easy to learn.

· The user interface should be able to guide the user step-by-step


throughout each steganographic process.

· The user interface should provide full keyboard support.

· The user interface should be fairly easy-to-use with the mouse.

7.4 Functionality

· The software should provide a means for viewing the final appearance
of processed stego-image.

· The software should provide a means for opening the extracted data
file from within the software itself.

· The software should display a progress indicator during processing.

Adaptive Digital Steganography for True-Color Bitmaps 7-2


8.0 SYSTEM DESIGN SPECIFICATION

8.1 Stegosystem Model

The framework of the proposed stegosystem is based on the

generic model presented by Birgit Pfitzmann [PFIT1996]. The block

diagram of this framework is depicted in Figure 8-1.

Cover
Image

Data File Encoding Stego Key Stego Key Decoding Data File
Module Module

Stego Stego
Transmission Channel
Image Image

Figure 8-1.
Framework of the Proposed Stegosystem

A complete steganographic transaction essentially consists of three

separate processes: encoding, transmission, and decoding. Encoding

consists of all the tasks performed in embedding hidden data in an image.

Transmission refers to the transfer of the stego image from a sender to a

recipient. Decoding involves the extraction of the hidden data from the

stego image.

Adaptive Digital Steganography for True-Color Bitmaps 8-1


8.1.1 Encoding

The encoding module takes in exactly three inputs (data

file, cover image, and stego key) and produces a single image (the

stego image) as the output of the entire process. As with some

other steganography software, the proposed software incorporates

compression and encryption to further enhance an already secure

algorithm. Unlike others, however, the proposed software utilizes a

rather complex variation of LSB encoding. The Hierarchical

Input-Process-Output (HIPO) chart shown in Figure 8-2 illustrates

Encoding
1.0

Input Process Output


1.1 1.2 1.3

Data File Cover Stego Key Stego


Image Image
1.1.1 1.1.3
1.1.2 1.3.1

Compress Encrypt Perform


Data File Data File Embedding
1.2.1 1.2.2 1.2.3

Randomize Capacity MER Error Encode


Embedding Evaluation Diffusion Metadata
1.2.3.3
1.2.3.1 1.2.3.2 1.2.3.4 1.2.3.5

Figure 8-2.
Hierarchical Input-Process-Output (HIPO) Chart of the Encoding Module

Adaptive Digital Steganography for True-Color Bitmaps 8-2


this multipart process.

Before the actual embedding of the data bits, the 128-bit

MD5 hash-value of the user-given stego key is used to seed a

PRNG. During embedding, the numbers generated by this PRNG

determine the color channels on which each set of data bits is to be

embedded. This, in effect, randomizes the otherwise sequential

pattern of embedding and therefore protects the hidden data from

unauthorized extraction even after an attacker gains knowledge of

the hidden data’s existence.

The same PRNG mentioned above is also used to assign the

pseudorandom address of a bit stream of metadata that is also

embedded within the image. This metadata bit stream is composed

of five segments of information arranged in the following order:

1. 20-byte string representing the SHA-1 hash value of the


user-given stego key.

2. 255-byte string representing the filename of the hidden


data file.

3. 8-byte value representing the modify date and time that


the hidden data file was created or last modified.

4. 4-byte integer representing the size of the data file in


terms of bytes.

5. 16-byte string representing the MD5 checksum of the


hidden data file.

Adaptive Digital Steganography for True-Color Bitmaps 8-3


The SHA-1 hash value of the stego key is included in the

metadata in order to support password verification in the decoding

process. The MD5 checksum, on the other hand, is used for data

integrity verification.

The algorithms for capacity evaluation, minimum-error

replacement (MER), and error diffusion described in Chapter 4 are

incorporated in the embedding process to maximize hiding

capacity and minimize distortions in the image. However, since

true-color images have three color channels and each one is being

evaluated separately, one color component of a pixel may increase

while another decreases. In such cases, the increase in total

embedding error may result to visible distortions. To compensate

for this, the original formula for gray level variation is replaced

with a formula for color intensity variation based on the texture

formed by pairs of adjacent pixels on the top and left sides of the

pixel being evaluated. This new formula may be expressed in the

form:

V = round [(|C–A| + |A–B| +|B–C| +|C–D|) / 4]

Although not explicitly stated in their paper, it is

understandable that Lee and Chen’s capacity evaluation function

calculates a pixel’s hiding capacity based on the range of color

intensities of surrounding pixels. By considering only the

Adaptive Digital Steganography for True-Color Bitmaps 8-4


difference between the maximum and minimum color intensities,

the actual texture of the area being evaluated is not put into

consideration. In contrast, the formula presented in this paper

calculates hiding capacity based on the texture of the top-left sides

of a pixel. As a result, the new capacity evaluation function now

provides a more sensitive and more accurate estimate of a pixel’s

tolerance to modifications.

8.1.2 Transmission

As this is digital steganography, the transmission channel

must also be digital in nature. This may be in the form of the

Internet, a local area network (LAN), a disk, and other digital

media. In the case of the Internet, the stego image can be posted on

a web page or sent as an email attachment. Steganographic

transactions have long been suspected to take place in Internet

bulletin boards and other public web sites. The advantage of using

such media is the fact that web pages have no specified recipients

unlike emails. This makes it virtually impossible to track down the

intended recipient of the hidden message.

It is important to note that the proposed software does not

cover this part of the steganographic transaction. Since the general

objective of steganography is to make communication or file

transfer seem innocuous, common or traditional tools for data

Adaptive Digital Steganography for True-Color Bitmaps 8-5


transfer such as popular web browsers must be used to enhance

that innocuous effect. Using the same steganography software for

file transfer is quite impractical.

8.1.3 Decoding

After transmission, the stego image is now ready for

decoding at the receiving end. The decoding module uses the stego

image and the stego key for input and performs a reverse operation

of the encoding process. This reversed process is illustrated in

Decoding
1.0

Input Process Output


1.1 1.2 1.3

Stego Stego Key Data File


Image
1.1.2 1.3.1
1.1.1

Perform Decrypt Decompress


Extraction Data File Data File
1.2.1 1.2.2 1.2.3

Extract Verify Capacity Extract


Metadata Stego Key Evaluation Data Bits
1.2.1.1 1.2.1.2 1.2.1.3 1.2.1.4.

Figure 8-3.
Hierarchical Input-Process-Output (HIPO) Chart of the Decoding Module

Adaptive Digital Steganography for True-Color Bitmaps 8-6


Figure 8-3.

At the beginning of extraction, the Metadata is extracted

first in order to determine the data file size and verify the stego key

entered by the recipient. Capacity evaluation is still required in

order to determine how many bits are embedded in each pixel.

MER and error diffusion, on the other hand, is no longer required

since they are only functions for minimizing distortions during

embedding. If the stego key entered is correct, the data file will

properly extracted as final output. It is important to note, however,

that the original cover image cannot be regenerated out of the stego

image. That original information was already lost during

embedding.

8.2 Stegosystem Pseudocode

The following are abstract codes for the major components of the

proposed stegosystem. All functions are written in a format patterned on

the Visual Basic programming language.

It is important to note that the following pseudocodes depict only

the essential logic and fundamental structure of the actual program code.

These pseudocodes do not include variable declarations, input validation,

bounds checking, error handling, and other auxiliary code.

Adaptive Digital Steganography for True-Color Bitmaps 8-7


8.2.1 Capacity Evaluation Function

Function ComputeCapacity()

Dif1 = Abs(PixelC – PixelA)


Dif2 = Abs(PixelA – PixelB)
Dif3 = Abs(PixelD – PixelC)
Dif4 = Abs(PixelC – PixelD)

V = Round((Dif1 + Dif2 + Dif3 + Dif4) / 4)

K = Int(Log(V) / Log(2))

If PixelP > 191 Then


U = 5
Else
U = 4
End If

If K < U Then
Capacity = K
Else
Capacity = U
End If

End Function

8.2.2 Minimum-Error Replacement Function

Function PerformMER()

BitMask = Not ((2 ^ (Capacity + 1)) - 1)

Value1 = (PixelP And BitMask) Or Bits


Error1 = Value1 - PixelP

Value2 = Value1 Or (2 ^ Capacity)


Error2 = Value2 - PixelP

If Abs(Error1) < Abs(Error2) Then


PixelP = Value1
EmbeddingError = Error1
Else
PixelP = Value2
EmbeddingError = Error2
End If

End Function

Adaptive Digital Steganography for True-Color Bitmaps 8-8


8.2.3 Error Diffusion Function

Function DiffuseError()

ErrorFraction = EmbeddingError / 4

PixelE = PixelE – ErrorFraction


PixelF = PixelF – ErrorFraction
PixelG = PixelG – ErrorFraction
PixelH = PixelH – ErrorFraction

End Function

8.2.4 Encoding Function

Function Encode()

InitializePRNGWith(StegoKeyMD5Hash)

MetadataAddress = GetRandomNumber
CurrentAddress = 0

DataFileCounter = 0

Do Until AllPixelsEncoded

If CurrentAddress = MetadataAddress Then


GetBitsFrom(Metadata)
Else
If DataFileCounter < DataFileSize Then
GetBitsFrom(DataFile)
DataFileCounter = DataFileCounter + 1
Else
GetRandomBits
End If
End If

ComputeCapacity
PerformMER
DiffuseError

SelectRandomAddress

Loop

End Function

Adaptive Digital Steganography for True-Color Bitmaps 8-9


8.2.5 Metadata Decoding Function

Function DecodeMetadata()

InitializePRNGWith(StegoKeyMD5Hash)

MetadataAddress = GetRandomNumber
CurrentAddress = 0

MetadataCounter = 0

Do While MetadataCounter < MetadataSize

If CurrentAddress = MetadataAddress Then

ComputeCapacity
Extracted = PixelP And ((2 ^ Capacity) - 1)

AppendToMetadata(Extracted)
DataFileCounter = MetadataCounter + 1

SelectNextAddress

End If

Loop

End Function

8.2.6 Data File Decoding Function

Function DecodeDataFile()

InitializePRNGWith(StegoKeyMD5Hash)

MetadataAddress = GetRandomNumber
CurrentAddress = 0

DataFileCounter = 0

Do While DataFileCounter < DataFileSize

If CurrentAddress <> MetadataAddress Then

ComputeCapacity

Extracted = PixelP And ((2 ^ Capacity) - 1)

AppendToDataFile(Extracted)

Adaptive Digital Steganography for True-Color Bitmaps 8-10


DataFileCounter = DataFileCounter + 1

SelectRandomAddress

End If

Loop

End Function

8.3 Image Formats

The algorithm used by the proposed software requires cover

images and stego images to be in the true-color format, i.e., composed of

red, green, and blue color channels. This allows for a randomized pattern

of embedding in three separate color channels. In essence, the presented

algorithm is applicable to other multiple-channel formats, such as the

32-bit CMYK (cyan-magenta-yellow-black) image standard. Nevertheless,

this study remains focused on 24-bit formats since 32-bit formats are

rarely used and generate even larger file sizes.

Furthermore, the stego image must also be saved in a lossless

image format so as not to lose any of the embedded data bits. This

automatically eliminates the popular JPEG and GIF images from the list of

supported stego image formats.

The proposed software, however, supports the five comparatively

popular image formats listed below.

Adaptive Digital Steganography for True-Color Bitmaps 8-11


· BMP (Windows Bitmap)

The standard uncompressed 24-bit image format for the


Microsoft Windows operating system. BMP files use an
extension name of “.bmp”.

· PNG (Portable Network Graphics)

An image format originally designed as a replacement for


GIF. It uses a variation of the LZ77 compression algorithm,
which makes it the most lightweight standard image format
that does not use lossy compression. PNGs use an extension
name of “.png”.

· PPM (Portable Pixelmap)

The 24-bit implementation of the PNM image standard


defined by Jef Poskanzer. PPM files are uncompressed and use
an extension name of “.ppm”.

· TARGA (Truevision Advanced Raster Graphics Adapter)

A widely-used bitmap format developed by Truevision


Incorporated. It supports alpha channels and typically uses RLE
compression. TARGA files use an extension name of “.tga”

· TIFF (Tagged Image File Format)

One of the most complex standard image formats.


Designed to support more than 70 types of tags, it is also
compatible with multiple image compression algorithms.
Without tags, TIFFs are quite smaller than Windows bitmaps.
TIFF files use and extension name of “.tiff” or “.tif”.

Using lossless image formats also increases the security of the

steganographic algorithm. Unlike algorithms that use JPEG and GIF, the

Adaptive Digital Steganography for True-Color Bitmaps 8-12


presented algorithm is not format dependent and is applicable to all bitmap

formats that do not apply transformations on the image. This means that

the encoding process does not leave any distinct signature on the created

stego image.

JPEG images, for example, have a certain characteristic structure

because of the Discrete Cosine Transform (DCT) that they undergo.

Because of this lossy transformation, embedding on JPEG images can only

be performed after it has undergone DCT. Embedding therefore, distorts

the characteristic structure of the JPEG image. Fridrich and Goljan explain

that when a JPEG image is embedded with data, “the cover image will

become (with high probability) incompatible with the JPEG format”

[FRID2002]. It is obviously quite suspicious and peculiar for a JPEG

image to be incompatible with the JPEG format. Such irony may therefore

be used as a proof that embedding has taken place.

In contrast, images that do not undergo any lossy transformation

do not have distinct characteristic structures since every color pattern and

every bit arrangement is valid and possible. Therefore, any statistical

assumption on the expected characteristics of an image for use in

steganalysis does not always apply.

Adaptive Digital Steganography for True-Color Bitmaps 8-13


9.0 SYSTEMS IMPLEMENTATION

With respect to the adaptive nature of the algorithms incorporated in the

presented steganography software, the software was named “Chameleon”, after

the species of reptiles that have the ability to adapt the color of their skin with

their surroundings. From hereon, the software developed in this study will

continually be referred to as Chameleon.

9.1 Programming Considerations, Issues and Tools

To achieve rapid and flexible development, Microsoft Visual Basic

6.0 was used in building Chameleon. Visual Basic’s graphical integrated

development environment (IDE) provides ways for easier development of

ergonomic user interfaces. This, in effect, allowed the programming task

to be more focused on the internal workings of the software and not on

development of a working graphical interface.

Being concerned with image steganography, the first requirement

in the development of Chameleon is a means for manipulating images.

Unfortunately, Visual Basic provides very little support for image

processing. Furthermore, Visual Basic is only capable of opening images

saved in the Windows bitmap, JPEG and GIF formats.

To overcome these obstacles, the open-source graphics library

FreeImage written by Floris van den Berg was used for opening and

saving images. FreeImage is freely downloadable and distributable as a

C++-compiled DLL (dynamic link library) file. To utilize the FreeImage

Adaptive Digital Steganography for True-Color Bitmaps 9-1


library in Visual Basic, a special Visual Basic wrapper class was written

for Chameleon. This wrapper class also made use or several Windows API

functions since FreeImage loads images into memory as device

independent bitmaps (DIB). In order to manipulate the contents of a DIB,

it must be converted into a device-dependent bitmap (DDB) that is

formatted as an array of red, green, and blue color components of each

pixel.

The open-source ActiveX control EzCryptoAPI written by Antonio

Ramirez Cobos is also used in encrypting data files with the very fast RC4

stream cipher. EzCryptoAPI also provided the MD5 and SHA-1 hash

functions required by the steganographic modules of the software. To

support data compression, the ZlibTool control of Mark Nelson is also

used. ZlibTool is a freeware ActiveX control based on the open-source

ZLib compression library.

A file wiping (also known as “file shredding”) feature is also

included in Chameleon. Wiping a file means permanently destroying its

contents before deleting it. Normally, when a file is deleted, it is simply

removed from the disk’s file system but its contents are left intact. This

allows file recovery programs to “undelete” the file. For this reason,

Chameleon features a file wipe option to allow users to wipe confidential

files such as secret messages hidden with Chameleon. Wiping original

data files when they are not needed in the computer further increases the

security provided by steganography software.

Adaptive Digital Steganography for True-Color Bitmaps 9-2


9.2 System Requirement Specification

Chameleon was designed, built, and tested on a slow Intel

Pentium-II-powered computer running Microsoft Windows ME. This

means that Chameleon will execute perfectly even on reasonably old

machines. However, since Chameleon does perform a rather exhaustive

analysis of the image during embedding, it is advisable to use faster

computers on images with very high resolutions.

Below is a listing of the estimated minimum computer setup for

Chameleon:

· 233 MHz processor

· 64 MB RAM

· A video card that supports 1024x768 True-Color display

· 14-inch color monitor

· Microsoft Windows operating system

Chameleon would perform reasonably fast enough in such a setup.

However, for faster embedding in extremely large images, faster

processors are required.

Concerning cover-images, it is advisable to use original photos

taken from digital cameras. Using private and original photos instead of

widely-available images posted on the Internet or stored in commercial

photo CDs prevents potential attackers from comparing the stego-images

to their original unprocessed copies.

Adaptive Digital Steganography for True-Color Bitmaps 9-3


9.3 Testing Activities

To test the performance of the proposed software, the efficiency of

Chameleon in terms of hiding capacity was compared to those of the four

popular steganography software described in Chapter 6.

In preparation for the tests, 50 test data files containing

pseudorandomly-generated bits were created with program written in

Visual Basic. The sizes of the data files range from 10 kilobytes to 500

kilobytes, in 10-kilobyte intervals.

The seed value used for Visual Basic’s built-in PRNG is the

hexadecimal value F0F0F0F0 (decimal number 4,042,322,160). The bits

written on the data files were random enough in such a way that none of

the data files can be compressed by standard compression algorithms,

even at maximum setting. This, in effect, provided a more accurate

measurement of the efficiency of each software’s embedding algorithm

since Steganos File Manager and The Third Eye does not include a data

compression feature like the ones integrated with Chameleon, Invisible

Secrets and EyeMage.

The 15 cover images used in the tests were downloaded from

fredmiranda.com, the online gallery of digital photographer Fred Miranda.

Table 9-1 is a list of these digital photographs. The actual photos are

shown in Appendix D.

Adaptive Digital Steganography for True-Color Bitmaps 9-4


Table 9-1.
Cover Images Used in Performance Testing

Filename Dimensions Size of LSB Plane File Size


abandon.bmp 750x494 pixels 138,937.50 bytes 1,087 KB

antelope.bmp 367x550 pixels 75,693.75 bytes 594 KB

badwater.bmp 700x461 pixels 121,012.50 bytes 946 KB

death.bmp 466x700 pixels 122,325.00 bytes 958 KB

gardens.bmp 700x466 pixels 122,325.00 bytes 956 KB

kiss.bmp 368x550 pixels 75,900.00 bytes 594 KB

nap.bmp 550x368 pixels 75,900.00 bytes 594 KB

passing.bmp 550x368 pixels 75,900.00 bytes 594 KB

race.bmp 700x459 pixels 120,487.50 bytes 942 KB

rain.bmp 337x550 pixels 69,506.25 bytes 544 KB

ruins.bmp 700x529 pixels 138,862.50 bytes 1,085 KB

storm.bmp 495x750 pixels 139,218.75 bytes 1,090 KB

style.bmp 367x550 pixels 79,693.75 bytes 594 KB

subtle.bmp 550x367 pixels 75,693.75 bytes 593 KB

sunrise.bmp 750x506 pixels 142,312.50 bytes 1,113 KB

All tests were conducted on a desktop PC with the following

specifications:

· Intel Pentium II 233 MHz processor

· 64 MB RAM

· Trident 3D Image 9750 video adapter

· 17-inch color monitor

· Microsoft Windows Millennium Edition operating system

Adaptive Digital Steganography for True-Color Bitmaps 9-5


The succeeding tables show the test results for each cover image

under Chameleon, EyeMage IIE, Invisible Secrets 2002, Steganos File

Manager, and The Third Eye.

Table 9-2.
Test Results for Cover Image “abandon.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 28.59 sec 227,810 bytes 220 KB -

EyeMage IIE 5.35 sec 366,733 bytes 350 KB severe distortions

Invisible Secrets 2002 4.01 sec 138,937 bytes 130 KB -

Steganos File Manager 4.82 sec - 130 KB -

The Third Eye 1.31 sec 111,228 bytes 100 KB -

Table 9-3.
Test Results for Cover Image “antelope.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 17.42 sec 123,054 bytes 120 KB -

EyeMage IIE 2.95 sec 198,304 bytes 190 KB -

Invisible Secrets 2002 2.46 sec 75,693 bytes 70 KB -

Steganos File Manager 2.82 sec - 70 KB -

The Third Eye 0.83 sec 60,699 bytes 50 KB -

Adaptive Digital Steganography for True-Color Bitmaps 9-6


Table 9-4.
Test Results for Cover Image “badwater.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 31.53 sec 288,503 bytes 280 KB -

EyeMage IIE 5.37 sec 318,604 bytes 310 KB slight distortions

Invisible Secrets 2002 3.27 sec 121,012 bytes 110 KB -

Steganos File Manager 3.84 sec - 110 KB -

The Third Eye 1.03 sec 96,789 bytes 90 KB failed to extract data

Table 9-5.
Test Results for Cover Image “death.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 35.78 sec 366,935 bytes 350 KB -

EyeMage IIE 4.81 sec 322,570 bytes 310 KB -

Invisible Secrets 2002 3.41 sec 122,325 bytes 110 KB -

Steganos File Manager 2.83 sec - 110 KB -

The Third Eye 1.08 sec 97,979 bytes 90 KB failed to extract data

Table 9-6.
Test Results for Cover Image “gardens.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 19.89 sec 94,789 bytes 90 KB -

EyeMage IIE 5.04 sec 322,104 bytes 310 KB severe distortions

Invisible Secrets 2002 3.49 sec 122,325 bytes 110 KB -

Steganos File Manager 3.10 sec - 110 KB -

The Third Eye 1.01 sec 97,839 bytes 90 KB -

Adaptive Digital Steganography for True-Color Bitmaps 9-7


Table 9-7.
Test Results for Cover Image “kiss.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 16.34 sec 95,824 bytes 90 KB -

EyeMage IIE 2.96 sec 198,304 bytes 190 KB slight distortions

Invisible Secrets 2002 2.53 sec 75,900 bytes 70 KB -

Steganos File Manager 3.03 sec - 70 KB -

The Third Eye 0.83 sec 60,699 bytes 50 KB -

Table 9-8.
Test Results for Cover Image “nap.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 20.58 sec 208,810 bytes 200 KB -

EyeMage IIE 2.91 sec 198,549 bytes 190 KB slight distortions

Invisible Secrets 2002 2.59 sec 75,900 bytes 70 KB -

Steganos File Manager 3.15 sec - 70 KB -

The Third Eye 0.63 sec 60,773 bytes 50 KB -

Table 9-9.
Test Results for Cover Image “passing.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 17.14 sec 143,050 bytes 130 KB -

EyeMage IIE 3.11 sec 198,549 bytes 190 KB slight distortions

Invisible Secrets 2002 2.79 sec 75,900 bytes 70 KB -

Steganos File Manager 2.98 sec - 70 KB -

The Third Eye 0.72 sec 60,773 bytes 50 KB -

Adaptive Digital Steganography for True-Color Bitmaps 9-8


Table 9-10.
Test Results for Cover Image “race.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 31.71 sec 302,416 bytes 290 KB -

EyeMage IIE 4.29 sec 317,204 bytes 300 KB slight distortions

Invisible Secrets 2002 3.29 sec 120,487 bytes 110 KB -

Steganos File Manager 4.17 sec - 110 KB -

The Third Eye 1.07 sec 96,369 bytes 90 KB -

Table 9-11.
Test Results for Cover Image “rain.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 10.85 sec 60,671 bytes 50 KB -

EyeMage IIE 2.79 sec 181,437 bytes 170 KB severe distortions

Invisible Secrets 2002 2.13 sec 69,506 bytes 60 KB -

Steganos File Manager 2.81 sec - 60 KB -

The Third Eye 0.86 sec 55,639 bytes 50 KB -

Table 9-12.
Test Results for Cover Image “ruins.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 34.06 sec 348,720 bytes 340 KB -

EyeMage IIE 6.21 sec 366,204 bytes 350 KB slight distortions

Invisible Secrets 2002 4.03 sec 138,862 bytes 130 KB -

Steganos File Manager 5.66 sec - 130 KB -

The Third Eye 1.16 sec 111,069 bytes 100 KB failed to extract data

Adaptive Digital Steganography for True-Color Bitmaps 9-9


Table 9-13.
Test Results for Cover Image “storm.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 18.02 sec 110,852 bytes 100 KB -

EyeMage IIE 5.90 sec 367,904 bytes 350 KB highly severe distortions

Invisible Secrets 2002 4.06 sec 139,218 bytes 130 KB -

Steganos File Manager 4.93 sec - 130 KB -

The Third Eye 1.65 sec 111,579 bytes 100 KB failed to extract data

Table 9-14.
Test Results for Cover Image “style.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 11.19 sec 75,534 bytes 70 KB -

EyeMage IIE 3.07 sec 198,304 bytes 190 KB highly severe distortions

Invisible Secrets 2002 2.52 sec 79,693 bytes 70 KB -

Steganos File Manager 3.03 sec - 70 KB -

The Third Eye 0.71 sec 60,699 bytes 50 KB -

Table 9-15.
Test Results for Cover Image “subtle.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 15.06 sec 108,221 bytes 100 KB -

EyeMage IIE 3.10 sec 197,998 bytes 190 KB slight distortions

Invisible Secrets 2002 2.59 sec 75,693 bytes 70 KB -

Steganos File Manager 2.96 sec - 70 KB -

The Third Eye 0.79 sec 60,608 bytes 50 KB -

Adaptive Digital Steganography for True-Color Bitmaps 9-10


Table 9-16.
Test Results for Cover Image “sunrise.bmp”

Processing Reported Largest File


Software Errors
Time Capacity Hidden
Chameleon 12.64 sec 35,328 bytes 30 KB -

EyeMage IIE 5.46 sec 375,741 bytes 360 KB highly severe distortions

Invisible Secrets 2002 4.12 sec 142,312 bytes 130 KB -

Steganos File Manager 3.98 sec - 130 KB -

The Third Eye 1.34 sec 113,931 bytes 100 KB -

In all of the encoding tests, the password used was “test”. After

each encoding operation on an image, the created stego image was then

viewed to check for distortions or any visible differences from the cover

image. Finally, extraction is performed to verify that the data file has been

properly embedded and that no corruption of the data file occurred.

During extraction tests, four cases of extraction failures were

recorded on The Third Eye. In these four cases, The Third Eye displayed

error messages stating that no data is hidden within the stego images. The

messages were, of course, incorrect. This leads to the conclusion that

regardless of the fact that The Third Eye performed the fastest in all tests,

it is simply unreliable. No other software resulted in extraction failures.

Except for the tests on “death.bmp” and “nap.bmp”, EyeMage used

the largest hiding capacity for all cover images. However, as the results

show, EyeMage produced significant distortions on almost all images. In

three cases, the distortions were even highly severe.

Adaptive Digital Steganography for True-Color Bitmaps 9-11


With Chameleon, on the other hand, absolutely no distortions were

created on all images, even in images where it used the largest hiding

capacities. This proves that using more bits for embedding requires careful

analysis of the image. Invisible Secrets and Steganos File Manager also

did not produce any visible distortions on the images since both software

used only the first LSB plane of each image for embedding.

All results show that Chameleon is highly reliable in allocating the

maximum possible size of hiding space without making any visible

changes to an image.

9.4 Installation Process

The Chameleon Image Steganography installation package is very

compact and easy to install. The installation package was created with

Setup Factory 6.0 and is a single 3.41 MB self-extracting setup file. The

user interface of the setup program created by Setup Factory is very easy

to use.

Except for the Visual Basic runtime files, there are only seven

program files required by Chameleon, as listed below.

· Chameleon.exe (Chameleon main program file)

· FreeImage.dll (FreeImage Graphics Library)

· ZlibTool.ocx (ZlibTool ActiveX Control)

· EzCryptoApi.ocx (EZCryptoAPI ActiveX Control)

Adaptive Digital Steganography for True-Color Bitmaps 9-12


· MSCOMCTL.OCX (Windows Common Controls ActiveX
Control)

· COMDLG32.OCX (Common Dialog ActiveX Control)

· HHCTRL.OCX (Microsoft Help ActiveX Control)

Chameleon does not require any specialized training for a user to

be able to operate it. It features a very intuitive wizard-style user interface

that guides the user step-by-step along each steganographic task.

Command buttons in the interface are accentuated with descriptive 3D

icons to help the user easily understand the function of each button.

Moreover, a context-sensitive help system provides quick assistance for

first-time users by displaying the appropriate help topic at the press of the

“F1” key or the “More Help” button.

A separate program named Chameleon Decoder was also

constructed. The program is a smaller and more streamlined version of the

original software that can only perform decoding operations.

Adaptive Digital Steganography for True-Color Bitmaps 9-13


10.0 CONCLUSION AND JUSTIFICATION

In the course of this study, all the major problems of current

steganography software listed in Chapter 1 have been solved. These problems and

their corresponding solutions are described below.

· Inefficient use of hiding space.

To make optimum use of hiding space, a special capacity


evaluation function was incorporated in the steganographic algorithm.
The capacity evaluation function used analyzes the capacity of each
pixel based on the texture formed by the varying color intensities of its
surrounding pixels.

· Tendency to produce distortions in the image.

To minimize distortions, techniques for minimum-error


replacement (MER) and error diffusion were incorporated in the
encoding process. Changes in color values are minimized and error
values are spread across surrounding pixels to compensate for such
changes.

· Insecure hiding schemes.

Pseudorandom number generators and hash functions were used to


embed the data in an unfixed non-sequential pattern based on the
user-given stego-key. Moreover, the data bits are embedded on the
image pixels themselves to make them integrated with the image.

Other improvements included in the developed steganographic software

include file encryption, file compression, file wiping, password verification, data

integrity verification, and support for five standard bitmap formats.

Adaptive Digital Steganography for True-Color Bitmaps 10-1


All these incorporated solutions and improvements make the developed

software more suitable for real-world covert communications and covert data

transmission than currently available steganographic software in the market.

Adaptive Digital Steganography for True-Color Bitmaps 10-2


11.0 RECOMMENDATION

The steganographic techniques presented in this study were found to be

very effective in making imperceptible modifications to images even at high

bit-rates. Nevertheless, these techniques are susceptible to image modifications

and are therefore inapplicable to other fields of information hiding such as digital

watermarking. Modifying the techniques into a robust algorithm for watermarking

applications would be a great challenge for other researchers.

In such a shift of applications, researchers may consider working on other

techniques such as those presented by Yeuan-Kuen Lee and Ling-Hwei Chen in

their paper “Object-Based Image Steganography Using Affine Transformation”

[LEE2002]. In this paper, the authors focused their work on the robustness of the

hidden data and worked on a data hiding technique based on transformations

applied to specific objects in an image.

On the subject of undetectability, further research on the concept of

Gaussian noise may prove to be beneficial for future steganographic systems. In

the embedding process, for example, steganographic systems may exploit the fact

that Gaussian noise is considered to be a natural occurrence in certain cameras

[FRID2002].

Regarding Chameleon, it is recommended that it be used for

communications purposes only, since Chameleon is designed only for such

applications. The software would certainly not surpass the performance of

commercially-available watermarking software.

Adaptive Digital Steganography for True-Color Bitmaps 11-1


As it is with all image steganography software, the recommended

cover-images or carriers are original photos taken from digital cameras. Also the

ideal mode of transmission is through web postings on public bulletin boards.

This generally prevents the recipient from being traced by potential attackers

monitoring the channel of communications. Nevertheless, sending stego-images

as seemingly-innocuous email attachments is still relatively secure.

Adaptive Digital Steganography for True-Color Bitmaps 11-2


A. INFORMATION HIDING TERMINOLOGY

This paper conforms to the standard information hiding terminology that

was agreed upon in the First International Workshop on Information Hiding

[PFIT1996]. The author defines these terms as follows:

cover medium
Also referred to as host or carrier, it is the input medium of the embedding
process that will host the embedded data. In image steganography, this
medium is called the cover-image.

embedded data
The input data hidden within the cover-medium.

embedding
The process of hiding data within a cover-medium. It may also be referred to
as encoding.

extraction
The process of retrieving the embedded data from a stego-medium. It may
also be referred to as decoding.

steganalysis
A deliberate and systematic attempt to detect the existence of hidden data in a
cover-medium through statistical or computer-based examinations. Broadly, it
is an attempt to defeat a stegosystem.

stego medium
The output medium of the embedding process that hosts the embedded data.
In image steganography, this medium is called the stego-image.

Adaptive Digital Steganography for True-Color Bitmaps A-1


stego key
The security key used in the embedding process, which is required in order to
successfully extract the embedded data from the stego-medium. It is the
equivalent of an encryption key in cryptography.

stegosystem
A complete design for the implementation of steganography, which defines
all the stages involved in the steganographic process as well as their
underlying concepts and techniques.

Adaptive Digital Steganography for True-Color Bitmaps A-2


B. MATHEMATICAL NOTATIONS

This paper made use of certain mathematical notations in presenting

formulas and algebraic expressions. These notations are defined as follows:

|x|
The absolute value of x.

ëxû
The highest integer less than or equal to x.

xy
The power of x raised to the exponent y.

logb x
The logarithm of x to the base b.

max {x, y, z}
The highest number between x, y, and z.

min {x, y, z}
The lowest number between x, y, and z.

round (x)
The value of x rounded to the nearest integer.

Adaptive Digital Steganography for True-Color Bitmaps B-1


C. PROJECT SCHEDULE AND WORK ASSIGNMENT

Activities Jun Jul Aug Sep Oct Nov Dec Jan


Analysis

Requirements Analysis

Design

Algorithm Design

Interface Design

Coding

Prototype

Main Program

Help System

Testing

Error Testing

Performance Testing

Enhancement

Speed Optimization

Interface Enhancement

Adaptive Digital Steganography for True-Color Bitmaps C-1


D. COVER IMAGES USED IN PERFORMANCE TESTING

Figure D-1.
abandon.bmp

“Abandoned”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-1


Figure D-2.
antelope.bmp

“Antelope”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-2


Figure D-3.
badwater.bmp

“Badwater”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-3


Figure D-4.
death.bmp

“Death Valley”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-4


Figure D-5.
gardens.bmp

“Descanso Gardens”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-5


Figure D-6.
kiss.bmp

“French Kiss”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-6


Figure D-7.
nap.bmp

“Nap”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-7


Figure D-8.
passing.bmp

“Passing By”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-8


Figure D-9.
race.bmp

“Racetrack”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-9


Figure D-10.
rain.bmp

“Rain”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-10


Figure D-11.
ruins.bmp

“Old Ruins”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-11


Figure D-12.
storm.bmp

“After the Storm”


Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-12


Figure D-13.
style.bmp

“Style”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-13


Figure D-14.
subtle.bmp

“Subtle Light”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-14


Figure D-15.
sunrise.bmp

“Desert Sunrise”
Copyright © 2002 Fred Miranda

Adaptive Digital Steganography for True-Color Bitmaps D-15


E. STEGO IMAGES WITH SEVERE DISTORTIONS

Figure E-1.
e_abandon_data350k.bmp

Stego Image of “abandon.bmp” containing a 350 KB Data File embedded


by EyeMage IIE

Adaptive Digital Steganography for True-Color Bitmaps E-1


Figure E-2.
e_gardens_data310k.bmp

Stego Image of “gardens.bmp” containing a 310 KB Data File embedded


by EyeMage IIE

Adaptive Digital Steganography for True-Color Bitmaps E-2


Figure E-3.
e_rain_data170k.bmp

Stego Image of “rain.bmp” containing a 170 KB Data File embedded by


EyeMage IIE

Adaptive Digital Steganography for True-Color Bitmaps E-3


Figure E-4.
e_storm_data350k.bmp

Stego Image of “storm.bmp” containing a 350 KB Data File embedded by


EyeMage IIE

Adaptive Digital Steganography for True-Color Bitmaps E-4


Figure E-5.
e_style_data190k.bmp

Stego Image of “style.bmp” containing a 190 KB Data File embedded by


EyeMage IIE

Adaptive Digital Steganography for True-Color Bitmaps E-5


Figure E-6.
e_sunrise_data360k.bmp

Stego Image of “sunrise.bmp” containing a 360 KB Data File embedded


by EyeMage IIE

Adaptive Digital Steganography for True-Color Bitmaps E-6


F. CHAMELEON HELP FILE

About Steganography
Steganography refers to the art and science of hiding the existence of information.

The idea behind steganography is to hide information within coventional objects in


order to allow covert transmission of messages and other forms of information.
Classical examples of this include invisible inks and microdots, which were
extensively used by spies in hiding secret messages within conventional letters and
newspapers during World War II.

The advantage of steganography over standard cryptography is that encryption only


hides the meaning of information whereas steganography hides the existence of the
information itself. Obviously, information that cannot be seen is better protected than
information that cannot be understood.

In computer-based steganography, one of the most suitable forms of media are


digital images. Digital images are constantly being uploaded, downloaded, shared,
and transmitted over the Internet and through other digital channels of
communications. This characteristic of digital images makes them appropriate hosts
for steganography.

A digital picture can be used as a cover image or "carrier" by embedding the data
bits of a file or message across the pixels of the picture. Accordingly, the resulting
image wherein secret information is embedded is called a stego image.

Information hiding in images is usually performed by replacing the least-


significant-bit (LSB) of each of the three color components (red, green, blue) of a
pixel with data bits. The idea behind this is that the human eye is not capable of
distinguishing very minimal changes in color, such as those created by replacing the
LSBs of an image.

However, since only the very least significant bits are used, only a small capacity for
hidden information is available. In some images, using more bits in the color values of
pixels still doesn't cause visible changes and thus hiding capacity can be increased.
Some images, on the other hand, are visibly degraded or even distorted if more bits
are changed. In order to obtain optimum hiding capacities, a more space-efficient
technique must be used.

About Chameleon
Chameleon is an image steganography software for true-color (24-bit) digital images.

It was developed by Mark David Gan as part of his Computer Science Thesis at the
Systems Technology Institute for the school year of 2002-2003.

Adaptive Digital Steganography for True-Color Bitmaps F-1


Features
Chameleon provides a more space-efficient solution to image steganography by using
adaptive steganographic algorithms that analyze the optimum capacity of an
image for hidden data. These algorithms are sensitive to the texture of every area in
an image, thereby preventing Chameleon from degrading or distorting whatever
image is used.

Chameleon is also a highly-secure steganography software. It includes a password


verification feature and uses the user-given password to randomize the data hiding
sequence. Without the correct password, access to the hidden data is impossible even
if an attacker has detailed knowledge of the steganographic algorithms used by
Chameleon.

Chameleon also features integrated encryption and compression algorithms to


further enhance security and performance. Furthermore, a file wipe feature (also
known as "file shredding") is also included to allow users to permanently destroy files
that contain secret information. Secret message files extracted from stego images, for
example, may be wiped off the disk after the contents have been read by the
recipient.

Supported File Formats


Chameleon can hide any type of file within an image and allows processed stego
images to be converted into any true-color image format that do not use lossy
compression or undergo image transformations.

Chameleon can save images in five standard image formats:

· Windows Bitmap (*.bmp)


· Portable Network Graphics (*.png)
· Tagged Image File Format (*.tif)
· TARGA (*.tga)
· Portable Pixelmap (*.ppm)

In addition to these formats, Chameleon can also open images stored in the following
formats:

· JPEG (*.jpg)
· Kodak PhotoCD (*.pcd)
· PC Paintbrush (*.pcx)
· Adobe Photoshop (*.psd)

Main Window
At start-up, Chameleon displays the Main Window which offers the user four basic
options:

Adaptive Digital Steganography for True-Color Bitmaps F-2


· Hide
(shortcut key: Alt+H)
Starts up a hiding task and opens the first page of the Hide Wizard.

· Extract
(shortcut key: Alt+E)
Starts up an extraction task and opens the first page of the Extract
Wizard.

· Wipe
(shortcut key: Alt+W)
Wipes a file selected by the user from the Wipe Dialog.

· Help
(shortcut key: F1)
Opens up this help file.

Hide Wizard
The Hide Wizard is designed to help the user perform hiding tasks quickly and
easily. It guides the user step-by-step throughout the entire operation and features a
context-sensitive help system that provides useful information for first-time users.

The four pages comprising this wizard is discussed below.

Page 1: Select Data File


In this page, the user is asked to specify the data file to be hidden within an image.
Only existing files may be specified in this page.

Adaptive Digital Steganography for True-Color Bitmaps F-3


Only existing files may be specified in this page.

Whenever asked to specify a file, the user may either type the complete address of a
file in the File Path box or press the Open button (shown below) to select a file
from a dialog window.

Before continuing to the next page, the selected file may first be previewed by
clicking the Preview button (shown below). In previewing the file, Chameleon
opens the file in the application program associated to it. Text files, for example,
would normally be opened in "Notepad".

Page 2: Select Cover Image


In this page, the user is asked to specify the image to use as cover for the data file. A
copy of the selected image file will contain the actual hidden data and not the original
image file itself, thus the original cover image will remain the same. Only existing
image files may be specified in this page.

Adaptive Digital Steganography for True-Color Bitmaps F-4


The Preview button in this page displays the selected image in the center of a blank
screen. Chameleon generates image previews by itself and no external programs are
used.

Page 3: Enter Password


In this page, the user is asked to specify the password to use for restricting access to
the hidden data file. Without the correct password, extraction of the hidden data file
would be impossible since the password defines the random pattern of encoding used
in the hiding task.

To ensure that the desired password is specified correctly, the user is asked to re-
enter the same password in the Password Confirmation box.

Adaptive Digital Steganography for True-Color Bitmaps F-5


enter the same password in the Password Confirmation box.

Page 4: Encode Stego Image


In the last page, the user is provided with a summary of the selected input files to
allow the user to verify that the selected files are correct before initiating the actual
encoding. Pressing the Next button then signals the encoding process to start.

During encoding, a progress bar is displayed to indicate how much of the stego image
has already been processed.

After encoding, a dialog window is displayed to ask the user for the filename and
image format to use in saving the processed stego image.

Adaptive Digital Steganography for True-Color Bitmaps F-6


image format to use in saving the processed stego image.

Finally, a report of the encoding results is displayed. From here, the user may preview
a comparison of the original cover image and the processed stego image by pressing
the Preview button.

The user may also save the stego image multiple times in different filenames and
image formats by pressing the Save button (shown below) which opens up again
the previously-discussed dialog window.

Adaptive Digital Steganography for True-Color Bitmaps F-7


Pressing the Close button closes the wizard and opens up the Main Window.

Extract Wizard
The Extract Wizard is designed to help the user perform extraction tasks quickly
and easily. It guides the user step-by-step throughout the entire operation and
features a context-sensitive help system that provides useful information for first-time
users.

The three pages comprising this wizard is discussed below.

Page 1: Select Stego Image


In this page, the user is asked to specify the stego image from which to extract a
hidden data file. Only existing image files may be specified in this page.

Whenever asked to specify a file, the user may either type the complete address of a
file in the File Path box or press the Open button (shown below) to select a file
from a dialog window.

Before continuing to the next page, the selected image may first be previewed by
clicking the Preview button (shown below). In previewing the image, Chameleon
displays the selected image in the center of a blank screen. Chameleon generates
image previews by itself and no external programs are used.

Adaptive Digital Steganography for True-Color Bitmaps F-8


Page 2: Enter Password
In this page, the user is asked to specify the password to use for extracting the
hidden data file.

Pressing the Next button initiates password verification. The wizard will continually
ask for the password until the correct one is given or when the Cancel button is
pressed.

Adaptive Digital Steganography for True-Color Bitmaps F-9


It is important to note that there is no way of identifying a real stego image. If the
image selected in the previous page does not contain a data file hidden with
Chameleon, password verification will continually fail. In such cases, it is even
possible for password verification to succeed but only meaningless data will be
extracted since no data file is actually hidden inside the image.

Page 3: Decode Data File


In the last page, the user is provided with information about the hidden data file to
allow the user to verify that the correct stego image has been selected. Pressing the
Next button then signals the decoding process to start.

During decoding, a progress bar is displayed to indicate how much of the data file has
already been processed.

Adaptive Digital Steganography for True-Color Bitmaps F-10


After decoding, a dialog window is displayed to ask the user for the filename to use in
saving the extracted data file.

Finally, a report of the decoding results is displayed. From here, the user may preview
the extracted data file by pressing the Preview button. In previewing the file,
Chameleon opens the file in the application program associated to it. Text files, for
example, would normally be opened in "Notepad". For this reason, previewing is only
possibly after the data file has been saved by the user.

Adaptive Digital Steganography for True-Color Bitmaps F-11


The user may also save the data file multiple times in different filenames by pressing
the Save button (shown below) which opens up again the previously-discussed
dialog window.

Pressing the Close button closes the wizard and opens up the Main Window.

Wipe Dialog
The Wipe Dialog asks the user to select a file to be wiped off the disk.

Wiping a file means permanently destroying the contents of a file and then deleting
it from the disk. This prevents a file from ever being recovered from the disk after
deletion. Such a feature is particularly useful in cases wherein a file containing secret
information needs to be permanently removed from the computer without leaving any
trace of its existence.

To wipe a file, Chameleon begins by renaming the file so as not to leave any trace of
what the file contains. Next, Chameleon overwrites the file with a bit pattern of
alternating 0's and 1's. Then, the file is overwritten again but this time with a bit
pattern of alternating 1's and 0's. Finally, the file is overwritten with 0's and then
deleted from the disk.

Adaptive Digital Steganography for True-Color Bitmaps F-12


Security Tips
Chameleon is essentially designed to make it easy for the user to perform
steganographic tasks without having to worry about a lot of things.

Nevertheless, there are still certain steps that a user can take to further improve
security and reliability:

· Use actual photos with complex textures instead of simple computer-


generated images. Complex or highly-detailed images have higher
hiding capacities than those with basic or solid textures.

· Use original photos taken from digital cameras and avoid scanned
images. Scanned images are usually of low quality and may already
appear degraded.

· Use unique passwords and avoid using dates or other personal


information.

· After hiding a data file in an image, wipe the original cover image to
prevent attackers from comparing the original cover image with the
created stego image.

· After hiding a data file in an image, wipe the original data file from
the computer to prevent unauthorized users from accessing its
contents.

· After reading an extracted data file from an image, wipe the


extracted data file from the computer to prevent unauthorized users
from accessing its contents.

Adaptive Digital Steganography for True-Color Bitmaps F-13


G. CHAMELEON SOURCE CODE

'------------------------------------------------------------------------------'
' ' End Sub
' Chameleon Image Steganography v1.2 '
' '
' Cover Image Selection Form ' Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
' [frmCoverImage] '
' ' If Shift = vbCtrlMask Then
'------------------------------------------------------------------------------'
' ' Select Case KeyCode
' Copyright (C) 2003 Mark David Gan ' Case vbKeyO: btnBrowse.Press
' ' Case vbKeyP: btnView.Press
'------------------------------------------------------------------------------' End Select

ElseIf KeyCode = vbKeyF1 Then


Option Explicit
btnHelp.Press

'------------------------------------------------------------------------------' End If
' Public Procedures '
'------------------------------------------------------------------------------' End Sub

Public Sub ResetControls() Private Sub txtPath_Change()


lblFileSize(1).Caption = vbNullString
lblFileDate(1).Caption = vbNullString If Screen.ActiveControl Is txtPath Then
txtPath.Text = vbNullString lblFileSize(1).Caption = vbNullString
End Sub lblFileDate(1).Caption = vbNullString
End If

'------------------------------------------------------------------------------' End Sub


' Event Handlers '
'------------------------------------------------------------------------------'
Private Sub txtPath_GotFocus()

Private Sub btnBack_Click() With txtPath


frmDataFile.Show If .Tag <> "MouseDown" Then
frmDataFile.SetFocus .SelStart = 0
End Sub .SelLength = Len(.Text)
End If
End With
Private Sub btnBrowse_Click()
End Sub
If Len(txtPath.Text) > 0 Then
dlgBrowse.InitDir = txtPath.Text
If FileExists(txtPath.Text) Then dlgBrowse.FileName = txtPath.Text Private Sub txtPath_KeyDown(KeyCode As Integer, Shift As Integer)
End If If KeyCode = vbKeyReturn Then btnNext.SetFocus
End Sub
On Error Resume Next
dlgBrowse.ShowOpen
Private Sub txtPath_LostFocus()
If Err.Number = 0 Then txtPath.Text = GetAbsolutePath(Trim$(txtPath.Text))
txtPath.Text = dlgBrowse.FileName lblFileSize(1).Caption = GetFileSize(txtPath.Text)
Call txtPath_LostFocus lblFileDate(1).Caption = GetFileDateTime(txtPath.Text)
End If End Sub

txtPath.SetFocus
Private Sub txtPath_MouseDown(Button As Integer, Shift As Integer, _
End Sub X As Single, Y As Single)
txtPath.Tag = "MouseDown"
End Sub
Private Sub btnCancel_Click()
frmMainMenu.Show
frmMainMenu.SetFocus Private Sub txtPath_MouseUp(Button As Integer, Shift As Integer, _
End Sub X As Single, Y As Single)
txtPath.Tag = ""
End Sub
Private Sub btnHelp_Click()
DisplayHelpFile "hide_wizard.html#Page2"
End Sub Private Sub txtPath_Validate(Cancel As Boolean)

If Len(txtPath.Text) = 0 Then
Private Sub btnNext_Click() MsgBox "No file has been specified." & vbCrLf & _
"Please specify an existing file.", vbExclamation
On Error Resume Next Cancel = True
Me.ValidateControls ElseIf Not FileExists(txtPath.Text) Then
MsgBox "The specified file cannot be found." & vbCrLf & _
If ActiveControl Is btnNext Then "Please specify an existing file.", vbExclamation
frmPassword1.Show Cancel = True
frmPassword1.SetFocus End If
End If
End Sub
End Sub

Private Sub btnView_Click()

On Error Resume Next


Me.ValidateControls '------------------------------------------------------------------------------'
' '
If ActiveControl Is btnView Then ' Chameleon Image Steganography v1.2 '
If Not frmView.DisplayByFilename(, txtPath.Text) Then ' '
MsgBox "The specified file cannot be opened as an image." & vbCrLf & _ ' Data File Selection Form '
"Please select a valid image file.", vbExclamation ' [frmDataFile] '
End If ' '
End If '------------------------------------------------------------------------------'
' '
End Sub ' Copyright (C) 2003 Mark David Gan '
' '
'------------------------------------------------------------------------------'
Private Sub Form_Activate()
On Error Resume Next
txtPath.SetFocus Option Explicit
End Sub

'------------------------------------------------------------------------------'
Private Sub Form_Deactivate() ' Public Procedures '
If Screen.ActiveForm.MDIChild Then Me.Hide '------------------------------------------------------------------------------'
End Sub

Public Sub ResetControls()


Private Sub Form_Load() lblFileSize(1).Caption = vbNullString
lblFileDate(1).Caption = vbNullString
Set imgPageIcon(1).Picture = imgPageIcon(0).Picture txtPath.Text = vbNullString
SetMargins txtPath, 1 End Sub
dlgBrowse.Filter = "(All supported image formats)|" & _
"*.bmp;*.png;*.tif;*.tiff;*.tga;*.ppm;" & _ '------------------------------------------------------------------------------'
"*.jpg;*.jpeg;*.pcx;*.psd;*.ras|" & _ ' Event Handlers '
"Adobe Photoshop (*.psd)|*.psd|" & _ '------------------------------------------------------------------------------'
"JPEG File Interchange Format (*.jpg)" & _
"|*.jpg;*.jpeg|" & _
"PC Paintbrush (*.pcx)|*.pcx|" & _ Private Sub btnBack_Click()
"Portable Network Graphics (*.png)|*.png|" & _ frmMainMenu.Show
"Portable Pixelmap (*.ppm)|*.ppm|" & _ frmMainMenu.SetFocus
"Tagged Image File Format (*.tif)|*.tif;*.tiff|" & _ End Sub
"TARGA Bitmap (*.tga)|*.tga|" & _
"Sun Rasterfile (*.ras)|*.ras|" & _
"Windows Bitmap (*.bmp)|*.bmp|" Private Sub btnBrowse_Click()
dlgBrowse.FilterIndex = 1
dlgBrowse.Flags = cdlOFNHideReadOnly + cdlOFNLongNames + _ If Len(txtPath.Text) > 0 Then
cdlOFNPathMustExist + cdlOFNFileMustExist dlgBrowse.InitDir = txtPath.Text
dlgBrowse.InitDir = GetPrimaryDrive If FileExists(txtPath.Text) Then dlgBrowse.FileName = txtPath.Text

Adaptive Digital Steganography for True-Color Bitmaps G-1


End If "Please specify an existing file.", vbExclamation
Cancel = True
On Error Resume Next ElseIf Not FileExists(txtPath.Text) Then
dlgBrowse.ShowOpen MsgBox "The specified file cannot be found." & vbCrLf & _
"Please specify an existing file.", vbExclamation
If Err.Number = 0 Then Cancel = True
txtPath.Text = dlgBrowse.FileName End If
Call txtPath_LostFocus
End If End Sub

txtPath.SetFocus

End Sub

Private Sub btnCancel_Click() '------------------------------------------------------------------------------'


frmMainMenu.Show ' '
frmMainMenu.SetFocus ' Chameleon Image Steganography v1.2 '
End Sub ' '
' Decoding Process Form '
' [frmDecode] '
Private Sub btnHelp_Click() ' '
DisplayHelpFile "hide_wizard.html" '------------------------------------------------------------------------------'
End Sub ' '
' Copyright (C) 2003 Mark David Gan '
' '
Private Sub btnNext_Click() '------------------------------------------------------------------------------'
On Error Resume Next
Me.ValidateControls Option Explicit
If ActiveControl Is btnNext Then
frmCoverImage.Show '------------------------------------------------------------------------------'
frmCoverImage.SetFocus ' Private Variables '
End If '------------------------------------------------------------------------------'
End Sub
'[ user-selected input file ]'
Private m_StegoImagePath As String
Private Sub btnView_Click()
On Error Resume Next '[ temporary files ]'
Me.ValidateControls Private m_TemporaryFilePath As String
If ActiveControl Is btnView Then OpenFile txtPath.Text Private m_TemporaryDataFilePath As String
End Sub
'[ user-selected output file ]'
Private m_DataFilePath As String
Private Sub Form_Activate()
On Error Resume Next '[ user password ]'
txtPath.SetFocus Private m_Password As String
End Sub Private m_PasswordHashMD5 As String

'[ cancel process flag ]'


Private Sub Form_Deactivate() Private m_Cancel As Boolean
If Screen.ActiveForm.MDIChild Then Me.Hide
End Sub
'------------------------------------------------------------------------------'
' Private Procedures '
Private Sub Form_Load() '------------------------------------------------------------------------------'
Set imgPageIcon(1).Picture = imgPageIcon(0).Picture
SetMargins txtPath, 1 Private Function PerformDecompression() As Boolean
dlgBrowse.Filter = "(All files)|*.*|" lblStatus(0).Caption = "Decompressing data file..."
dlgBrowse.FilterIndex = 1 lblStatus(1).Caption = vbNullString
dlgBrowse.Flags = cdlOFNHideReadOnly + cdlOFNLongNames + _ prgStatus.Value = 0
cdlOFNPathMustExist + cdlOFNFileMustExist
dlgBrowse.InitDir = GetPrimaryDrive On Error GoTo ZlibError
With frmMainMenu.ZlibDecompressor
End Sub .Level = Standard
.InputFile = m_TemporaryFilePath
.OutputFile = m_TemporaryDataFilePath
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) .Decompress
End With
If Shift = vbCtrlMask Then
ZlibError:
Select Case KeyCode If UCase(frmMainMenu.ZlibDecompressor.Status) = "SUCCESS" Then
Case vbKeyO: btnBrowse.Press PerformDecompression = True
Case vbKeyP: btnView.Press Else
End Select PerformDecompression = False
End If
ElseIf KeyCode = vbKeyF1 Then
End Function
btnHelp.Press

End If Private Sub PerformDecryption()


End Sub lblStatus(0).Caption = "Decrypting data file..."
lblStatus(1).Caption = vbNullString
prgStatus.Value = 0
Private Sub txtPath_Change()
'--------------------------------------------------------------------------'
If Screen.ActiveControl Is txtPath Then ' '
lblFileSize(1).Caption = vbNullString ' Special Note: '
lblFileDate(1).Caption = vbNullString ' For some reason, the last hash function executed by EzCryptoApi '
End If ' affects the succeeding encryption/decryption operation. Because of '
' this, it must be made sure that last hash function called before '
End Sub ' an decryption operation is the same as the last hash function called '
' before its corresponding encryption operation. '
' '
Private Sub txtPath_GotFocus() '--------------------------------------------------------------------------'
GetHashValue m_Password, SHA
With txtPath
If .Tag <> "MouseDown" Then On Error Resume Next
.SelStart = 0
.SelLength = Len(.Text) With frmMainMenu.EzCrypto
End If .EncryptionAlgorithm = RC4
End With .Speed = [1KB]
.Password = m_Password
End Sub .DecryptFile m_TemporaryFilePath
End With
Private Sub txtPath_KeyDown(KeyCode As Integer, Shift As Integer) End Sub
If KeyCode = vbKeyReturn Then btnNext.SetFocus
End Sub
Private Function PerformExtraction() As Boolean
Private Sub txtPath_LostFocus() lblStatus(0).Caption = "Extracting data file..."
txtPath.Text = GetAbsolutePath(Trim$(txtPath.Text)) lblStatus(1).Caption = vbNullString
lblFileSize(1).Caption = GetFileSize(txtPath.Text) prgStatus.Value = 0
lblFileDate(1).Caption = GetFileDateTime(txtPath.Text)
End Sub With frmMainMenu.StegoDecoder
If .Decode(m_PasswordHashMD5) Then
.SaveDataFile m_TemporaryFilePath
Private Sub txtPath_MouseDown(Button As Integer, Shift As Integer, _ PerformExtraction = True
X As Single, Y As Single) Else
txtPath.Tag = "MouseDown" PerformExtraction = False
End Sub End If

End With
Private Sub txtPath_MouseUp(Button As Integer, Shift As Integer, _
X As Single, Y As Single) End Function
txtPath.Tag = ""
End Sub
'------------------------------------------------------------------------------'
' Event Handlers '
Private Sub txtPath_Validate(Cancel As Boolean) '------------------------------------------------------------------------------'
If Len(txtPath.Text) = 0 Then
MsgBox "No file has been specified." & vbCrLf & _ Private Sub btnBack_Click()

Adaptive Digital Steganography for True-Color Bitmaps G-2


frmPassword2.Show End If
frmPassword2.SetFocus
End Sub btnClose.SetFocus

End Sub
Private Sub btnCancel_Click()

If Not btnNext.Visible Then Private Sub btnSave_Click()


If MsgBox("Do you wish to cancel the current task?", _
vbQuestion + vbYesNo) = vbYes Then On Error Resume Next
m_Cancel = True dlgBrowse.ShowSave
frmMainMenu.ZlibDecompressor.Abort
frmMainMenu.StegoDecoder.Abort If Err.Number = 0 Then
frmMainMenu.Show m_DataFilePath = dlgBrowse.FileName
frmMainMenu.SetFocus FileCopy m_TemporaryDataFilePath, m_DataFilePath
End If SetFileDate m_DataFilePath, frmMainMenu.StegoDecoder.DataFileDate
Else btnView.SetFocus
frmMainMenu.Show End If
frmMainMenu.SetFocus
End If End Sub

End Sub
Private Sub btnView_Click()
If Len(m_DataFilePath) = 0 Then
Private Sub btnClose_Click() MsgBox "The extracted data file has not been saved yet." & vbCrLf & _
"Please save the data file first.", _
If fraSave.Visible Then vbExclamation
If Len(m_DataFilePath) = 0 Then btnSave.SetFocus
If MsgBox("Would you like to save the extracted data file first?", _ Else
vbQuestion + vbYesNo) = vbYes Then OpenFile m_DataFilePath
btnSave.Press End If
End If End Sub
End If
End If
Private Sub Form_Activate()
frmMainMenu.Show
frmMainMenu.SetFocus m_Cancel = False
m_StegoImagePath = frmStegoImage.txtPath.Text
End Sub m_TemporaryFilePath = GenerateTempFile
m_TemporaryDataFilePath = GenerateTempFile
m_DataFilePath = vbNullString
Private Sub btnHelp_Click()
DisplayHelpFile "extract_wizard.html#Page3" lblDataFileName1(1).Caption = frmMainMenu.StegoDecoder.DataFileName
End Sub lblDataFileName2(1).Caption = lblDataFileName1(1).Caption
lblDataFileDate(1).Caption = FormatDate(frmMainMenu.StegoDecoder.DataFileDate)

Private Sub btnNext_Click() CompactCaptionWithEllipses lblDataFileName1(1)


CompactCaptionWithEllipses lblDataFileName2(1)
Dim Extracted As Boolean
Dim Msg As String m_Password = frmPassword2.txtPassword.Text
m_PasswordHashMD5 = GetHashValue(m_Password, MD5)
m_Cancel = False
dlgBrowse.FileName = frmMainMenu.StegoDecoder.DataFileName
fraStatus.Visible = True
btnNext.Visible = False If Not ActiveControl Is btnNext Then btnNext.SetFocus
btnBack.Visible = False
btnCancel.SetFocus End Sub
lblHelp(0).Visible = False
lblHelp(1).Visible = True
Private Sub Form_Deactivate()
'[ prepare timer ]'
Dim Tmr As RealTimer If Screen.ActiveForm.MDIChild Then
Set Tmr = New RealTimer
Me.Hide
Extracted = PerformExtraction
'[ reset controls ]'
'[ perform tasks ]' fraStatus.Visible = False
If Extracted Then fraProperties(0).Visible = True
fraProperties(1).Visible = False
If m_Cancel Then Exit Sub fraHelp.Visible = True
fraSave.Visible = False
'[ verify checksum ]' fraView.Visible = False
If frmMainMenu.StegoDecoder.DataFileChecksum = _
GetHashValueOfFile(m_TemporaryFilePath, MD5) Then lblStatus(0).Caption = lblStatus(0).Tag
lblStatus(1).Caption = vbNullString
Msg = vbNullString lblDataFileName1(1).Caption = vbNullString
lblDataFileName2(1).Caption = vbNullString
Else lblDataFileDate(1).Caption = vbNullString
lblDataFileSize(1).Caption = vbNullString
Msg = "The extracted data has an invalid checksum and is " & _ lblHelp(0).Visible = True
"possibly corrupted." & vbCrLf & _ lblHelp(1).Visible = False
"Do you still want to continue the decoding operation?"
prgStatus.Min = 0
If MsgBox(Msg, vbQuestion + vbYesNo) = vbNo Then prgStatus.Max = 100
Extracted = False prgStatus.Value = 0
GoTo PostProcessing
End If btnNext.Visible = True
btnBack.Visible = True
End If btnCancel.Visible = True
btnClose.Visible = False
PerformDecryption
If m_Cancel Then Exit Sub '[ cleanup temporary files ]'
WipeFile m_TemporaryFilePath, False
PerformDecompression WipeFile m_TemporaryDataFilePath, False
If m_Cancel Then Exit Sub
End If
End If
End Sub
PostProcessing:

'[ display elapsed time ]' Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Tmr.Mark
lblStatus(1).Caption = "Processing Time: " & Tmr.ElapsedTimeInMinutes If Shift = vbCtrlMask Then

prgStatus.Value = prgStatus.Max Select Case KeyCode


fraProperties(1).Visible = True Case vbKeyS: btnSave.Press
fraProperties(0).Visible = False Case vbKeyP: btnView.Press
fraHelp.Visible = False End Select
btnCancel.Visible = False
btnClose.Visible = True ElseIf KeyCode = vbKeyF1 Then
btnClose.Refresh
btnHelp.Press
If m_Cancel Then Exit Sub
End If
If Extracted Then
End Sub
'[ indicate completion ]'
lblStatus(0).Caption = "Decoding Complete."
lblDataFileSize(1).Caption = FormatSize(FileLen(m_TemporaryDataFilePath)) Private Sub Form_Load()

fraSave.Visible = True Set imgPageIcon(1).Picture = imgPageIcon(0).Picture


fraView.Visible = True
btnSave.Press dlgBrowse.Filter = "(All files)|*.*|"
dlgBrowse.FilterIndex = 1
Else dlgBrowse.Flags = cdlOFNHideReadOnly + cdlOFNLongNames + _
cdlOFNPathMustExist + cdlOFNOverwritePrompt
'[ indicate failure ]' dlgBrowse.InitDir = GetPrimaryDrive
lblStatus(0).Caption = "Decoding Failed."
lblDataFileName2(1).Caption = vbNullString End Sub
lblDataFileSize(1).Caption = vbNullString

If Msg = vbNullString Then Private Sub Form_Unload(Cancel As Integer)


MsgBox "The selected image does not contain valid hidden data." & _ WipeFile m_TemporaryFilePath, False
vbCrLf & "Decoding cannot be completed.", vbExclamation WipeFile m_TemporaryDataFilePath, False
Else End Sub
MsgBox "The selected image is possibly corrupted." & _
vbCrLf & "Decoding has been canceled.", vbExclamation
End If

Adaptive Digital Steganography for True-Color Bitmaps G-3


End Sub

'------------------------------------------------------------------------------'
' ' '------------------------------------------------------------------------------'
' Chameleon Image Steganography v1.2 ' ' Event Handlers '
' ' '------------------------------------------------------------------------------'
' Encoding Process Form '
' [frmEncode] '
' ' Private Sub btnBack_Click()
'------------------------------------------------------------------------------' frmPassword1.Show
' ' frmPassword1.SetFocus
' Copyright (C) 2003 Mark David Gan ' End Sub
' '
'------------------------------------------------------------------------------'
Private Sub btnCancel_Click()

Option Explicit If Not btnNext.Visible Then


If MsgBox("Do you wish to cancel the current task?", _
vbQuestion + vbYesNo) = vbYes Then
'------------------------------------------------------------------------------' m_Cancel = True
' Private Variables ' frmMainMenu.ZlibCompressor.Abort
'------------------------------------------------------------------------------' frmMainMenu.StegoEncoder.Abort
frmMainMenu.Show
frmMainMenu.SetFocus
'[ user-selected input files ]' End If
Private m_CoverImagePath As String Else
Private m_DataFilePath As String frmMainMenu.Show
frmMainMenu.SetFocus
'[ temporary file ]' End If
Private m_TemporaryFilePath As String
End Sub
'[ user-selected output file ]'
Private m_StegoImagePath As String
Private Sub btnClose_Click()
'[ user password ]'
Private m_Password As String If fraSave.Visible Then
Private m_PasswordHashMD5 As String If Len(m_StegoImagePath) = 0 Then
Private m_PasswordHashSHA As String If MsgBox("Would you like to save the created stego image first?", _
vbQuestion + vbYesNo) = vbYes Then
'[ cancel process flag ]' btnSave.Press
Private m_Cancel As Boolean End If
End If
End If
'------------------------------------------------------------------------------'
' Private Procedures ' frmMainMenu.Show
'------------------------------------------------------------------------------' frmMainMenu.SetFocus

End Sub
Private Function PerformCompression() As Boolean

lblStatus(0).Caption = "Compressing data file..." Private Sub btnHelp_Click()


lblStatus(1).Caption = vbNullString DisplayHelpFile "hide_wizard.html#Page4"
prgStatus.Value = 0 End Sub

On Error GoTo ZlibError


With frmMainMenu.ZlibCompressor Private Sub btnNext_Click()
.Level = Standard
.InputFile = m_DataFilePath Dim Completed As Boolean
.OutputFile = m_TemporaryFilePath
.Compress m_Cancel = False
End With
fraStatus.Visible = True
ZlibError: btnNext.Visible = False
If UCase(frmMainMenu.ZlibCompressor.Status) = "SUCCESS" Then btnBack.Visible = False
PerformCompression = True lblHelp(0).Visible = False
Else lblHelp(1).Visible = True
PerformCompression = False
End If '[ prepare timer ]'
Dim Tmr As RealTimer
End Function Set Tmr = New RealTimer

PerformCompression
Private Function PerformEmbedding() If m_Cancel Then Exit Sub

lblStatus(0).Caption = "Hiding data file..." PerformEncryption


lblStatus(1).Caption = vbNullString If m_Cancel Then Exit Sub
prgStatus.Value = 0
Completed = PerformEmbedding
PerformEmbedding = False If m_Cancel Then Exit Sub

With frmMainMenu.StegoEncoder '[ display elapsed time ]'


Tmr.Mark
If .LoadDataFile(m_TemporaryFilePath, _ lblStatus(1).Caption = "Processing Time: " & Tmr.ElapsedTimeInMinutes
GetPathFileName(m_DataFilePath), _
FileDateTime(m_DataFilePath), _ fraProperties(1).Visible = True
GetHashValueOfFile(m_TemporaryFilePath, MD5)) Then fraProperties(0).Visible = False
fraHelp.Visible = False
If .LoadCoverImage(m_CoverImagePath) Then btnCancel.Visible = False
PerformEmbedding = .Encode(m_PasswordHashMD5, m_PasswordHashSHA) btnClose.Visible = True
lblDataSize(1).Caption = FormatSize(.DataFileSize) btnClose.Refresh
lblCapacity(1).Caption = FormatSize(.ImageCapacity)
Else If Completed Then
m_Cancel = True
MsgBox "The selected cover image cannot be loaded." & vbCrLf & _ '[ indicate completion ]'
"Please select a valid image file.", vbInformation lblStatus(0).Caption = "Encoding Complete."
frmCoverImage.Show fraSave.Visible = True
frmCoverImage.SetFocus fraView.Visible = True
End If btnSave.Press
btnClose.SetFocus
Else
m_Cancel = True Else
MsgBox "The selected data file cannot be loaded." & vbCrLf & _
"Please select a valid data file.", vbInformation '[ indicate failure ]'
frmDataFile.Show lblStatus(0).Caption = "Encoding Failed."
frmDataFile.SetFocus
End If Dim Res As VbMsgBoxResult
Res = MsgBox("There is not enough space on the selected image." & vbCrLf & _
End With "Would you like to select another cover image?", _
vbQuestion + vbYesNo)
End Function
If Res = vbYes Then
frmCoverImage.Show
Private Sub PerformEncryption() frmCoverImage.SetFocus
Else
lblStatus(0).Caption = "Encrypting data file..." MsgBox "Encoding Canceled.", vbExclamation
lblStatus(1).Caption = vbNullString btnClose.SetFocus
prgStatus.Value = 0 End If

'--------------------------------------------------------------------------' End If
' '
' Special Note: ' End Sub
' For some reason, the last hash function executed by EzCryptoApi '
' affects the succeeding encryption/decryption operation. Because of '
' this, it must be made sure that last hash function called before ' Private Sub btnSave_Click()
' a decryption operation is the same as the last hash function called '
' before its corresponding encryption operation. ' On Error Resume Next
' ' dlgBrowse.ShowSave
'--------------------------------------------------------------------------'
GetHashValue m_Password, SHA If Err.Number = 0 Then

On Error Resume Next '[ set stego image file format ]'
Dim ImageFormat As FREE_IMAGE_FORMAT
With frmMainMenu.EzCrypto Select Case dlgBrowse.FilterIndex
.EncryptionAlgorithm = RC4 Case 1: ImageFormat = FIF_BMP
.Speed = [1KB] Case 2: ImageFormat = FIF_PNG
.Password = m_Password Case 3: ImageFormat = FIF_PPMRAW
.EncryptFile m_TemporaryFilePath Case 4: ImageFormat = FIF_TIFF
End With Case 5: ImageFormat = FIF_TARGA
End Select

Adaptive Digital Steganography for True-Color Bitmaps G-4


' '
'[ save stego image ]' '------------------------------------------------------------------------------'
m_StegoImagePath = dlgBrowse.FileName
frmMainMenu.StegoEncoder.SaveStegoImage m_StegoImagePath, ImageFormat
btnView.SetFocus Option Explicit

End If
'------------------------------------------------------------------------------'
End Sub ' Windows API Function Declarations '
'------------------------------------------------------------------------------'

Private Sub btnView_Click()


With frmMainMenu.StegoEncoder Private Declare Function ReleaseCapture Lib "user32" () As Long
If Not frmView.DisplayByDIB(.CoverImageDIB, .StegoImageDIB) Then
MsgBox "The images cannot be displayed." & _ Private Declare Function SetCapture Lib "user32" (ByVal hWnd As Long) As Long
"The encoding process may have failed.", vbExclamation
End If
End With '------------------------------------------------------------------------------'
End Sub ' Public Variables '
'------------------------------------------------------------------------------'

Private Sub Form_Activate()


'[ stegosystem objects ]'
m_Cancel = False Public WithEvents StegoEncoder As StegosystemEncoder
m_DataFilePath = frmDataFile.txtPath.Text Public WithEvents StegoDecoder As StegosystemDecoder
m_CoverImagePath = frmCoverImage.txtPath.Text
m_TemporaryFilePath = GenerateTempFile
m_StegoImagePath = vbNullString '------------------------------------------------------------------------------'
' Event Handlers '
lblDataFile(1).Caption = m_DataFilePath '------------------------------------------------------------------------------'
lblCoverImage(1).Caption = m_CoverImagePath

CompactCaptionWithEllipses lblDataFile(1) Private Sub btnExit_Click()


CompactCaptionWithEllipses lblCoverImage(1) Unload frmMDI
End Sub
m_Password = frmPassword1.txtPassword(0).Text
m_PasswordHashMD5 = GetHashValue(m_Password, MD5)
m_PasswordHashSHA = GetHashValue(m_Password, SHA) Private Sub btnExtract_Click()
CurrentTask = TASK_DECODE
If Not ActiveControl Is btnNext Then btnNext.SetFocus frmStegoImage.Show
frmStegoImage.SetFocus
End Sub End Sub

Private Sub Form_Deactivate() Private Sub btnHelp_Click()


DisplayHelpFile "index.html"
If Screen.ActiveForm.MDIChild Then End Sub

Me.Hide
Private Sub btnHide_Click()
'[ reset controls ]' CurrentTask = TASK_ENCODE
fraStatus.Visible = False frmDataFile.Show
fraProperties(0).Visible = True frmDataFile.SetFocus
fraProperties(1).Visible = False End Sub
fraHelp.Visible = True
fraSave.Visible = False
fraView.Visible = False Private Sub btnWipe_Click()

lblStatus(0).Caption = vbNullString Dim Msg As String


lblStatus(1).Caption = vbNullString
lblDataFile(1).Caption = vbNullString On Error Resume Next
lblCoverImage(1).Caption = vbNullString dlgBrowse.ShowOpen
lblDataSize(1).Caption = vbNullString
lblCapacity(1).Caption = vbNullString Msg = "A file can no longer be recovered after being wiped." & vbCrLf & _
lblHelp(0).Visible = True "Are you sure you wish to permanently remove the following file?" & _
lblHelp(1).Visible = False vbCrLf & vbCrLf & _
dlgBrowse.FileName
prgStatus.Min = 0
prgStatus.Max = 100 If Err.Number = 0 Then
prgStatus.Value = 0 If MsgBox(Msg, vbQuestion + vbYesNo) = vbYes Then
If WipeFile(dlgBrowse.FileName, True) Then
btnNext.Visible = True MsgBox "The selected file has been successfully wiped."
btnBack.Visible = True Else
btnCancel.Visible = True MsgBox "The selected file cannot be wiped."
btnClose.Visible = False End If
End If
'[ cleanup temporary files ]' End If
WipeFile m_TemporaryFilePath, False
End Sub
End If

End Sub Private Sub EzCrypto_DecryptionFileStatus(ByVal lBytesProcessed As Long, _


ByVal lTotalBytes As Long)
With frmDecode
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) .prgStatus.Value = (lBytesProcessed * 100) \ lTotalBytes
.lblStatus(1).Caption = .prgStatus.Value & "% complete"
If Shift = vbCtrlMask Then End With
End Sub
Select Case KeyCode
Case vbKeyS: btnSave.Press
Case vbKeyP: btnView.Press Private Sub EzCrypto_EncryptionFileStatus(ByVal lBytesProcessed As Long, _
End Select ByVal lTotalBytes As Long)
With frmEncode
ElseIf KeyCode = vbKeyF1 Then .prgStatus.Value = (lBytesProcessed * 100) \ lTotalBytes
.lblStatus(1).Caption = .prgStatus.Value & "% complete"
btnHelp.Press End With
End Sub
End If

End Sub Private Sub Form_Activate()


CurrentTask = TASK_NONE
frmMDI.ResetChildFormControls
Private Sub Form_Load() End Sub

Set imgPageIcon(1).Picture = imgPageIcon(0).Picture


Private Sub Form_Deactivate()
dlgBrowse.Filter = "Windows Bitmap (*.bmp)|*.bmp|" & _ If Screen.ActiveForm.MDIChild Then Me.Hide
"Portable Network Graphics (*.png)|*.png|" & _ End Sub
"Portable Pixelmap (*.ppm)|*.ppm|" & _
"Tagged Image File Format (*.tif)|*.tif;*.tiff|" & _
"TARGA Bitmap (*.tga)|*.tga|" Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
dlgBrowse.FilterIndex = 1 If KeyCode = vbKeyF1 Then btnHelp.Press
dlgBrowse.Flags = cdlOFNHideReadOnly + cdlOFNLongNames + _ End Sub
cdlOFNPathMustExist + cdlOFNOverwritePrompt
dlgBrowse.InitDir = GetPrimaryDrive
Private Sub Form_Load()
End Sub
Set picHeader.Picture = imgTitle.Picture

Private Sub Form_Unload(Cancel As Integer) dlgBrowse.InitDir = GetPrimaryDrive


WipeFile m_TemporaryFilePath, False dlgBrowse.Filter = "(All files)|*.*|"
End Sub dlgBrowse.Flags = cdlOFNHideReadOnly + cdlOFNLongNames + _
cdlOFNPathMustExist + cdlOFNFileMustExist

Set StegoEncoder = New StegosystemEncoder


Set StegoDecoder = New StegosystemDecoder

Me.Show

'------------------------------------------------------------------------------' End Sub


' '
' Chameleon Image Steganography v1.2 '
' ' Private Sub Form_Unload(Cancel As Integer)
' Main Menu Form ' Set StegoEncoder = Nothing
' [frmMainMenu] ' Set StegoDecoder = Nothing
' ' End Sub
'------------------------------------------------------------------------------'
' '
' Copyright (C) 2003 Mark David Gan ' Private Sub picHeader_LostFocus()

Adaptive Digital Steganography for True-Color Bitmaps G-5


If picHeader.Picture <> imgTitle.Picture Then ) As Long
Set picHeader.Picture = imgTitle.Picture
End If
End Sub '------------------------------------------------------------------------------'
' Public Procedures '
'------------------------------------------------------------------------------'
Private Sub picHeader_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Set picHeader.Picture = imgAuthor.Picture Public Sub FormatWindow()
End Sub
Dim Res As Long
Dim Ctr As Long
Private Sub picHeader_MouseUp(Button As Integer, Shift As Integer, _
X As Single, Y As Single) '[ remove maximize button from mdi form and disable resizing ]'
If picHeader.Picture <> imgTitle.Picture Then Res = GetWindowLong(Me.hWnd, GWL_STYLE)
Set picHeader.Picture = imgTitle.Picture SetWindowLong Me.hWnd, GWL_STYLE, Res And Not (WS_MAXIMIZEBOX + WS_THICKFRAME)
End If
End Sub '[ remove maximize menu item from system menu ]'
Res = GetSystemMenu(Me.hWnd, 0)
RemoveMenu Res, SC_MAXIMIZE, MF_BYCOMMAND
Private Sub StegoDecoder_DataFileProgress(ByVal Processed As Long, _ DrawMenuBar Me.hWnd
ByVal Total As Long)
With frmDecode End Sub
.prgStatus.Value = (Processed * 100) \ Total
.lblStatus(1).Caption = .prgStatus.Value & "% complete"
End With Public Sub ResetChildFormControls()
End Sub On Error Resume Next
Dim Frm As Form
For Each Frm In VB.Forms
Private Sub StegoDecoder_MetadataProgress(ByVal Processed As Long, _ If Frm.MDIChild Then Frm.ResetControls
ByVal Total As Long) Next Frm
With frmPassword2 End Sub
.prgStatus.Value = (Processed * 100) \ Total
.lblStatus(1).Caption = .prgStatus.Value & "% complete"
End With '------------------------------------------------------------------------------'
End Sub ' Event Handlers '
'------------------------------------------------------------------------------'

Private Sub StegoEncoder_Progress(ByVal Processed As Long, ByVal Total As Long)


With frmEncode Private Sub MDIForm_Load()
.prgStatus.Value = (Processed * 100) \ Total
.lblStatus(1).Caption = .prgStatus.Value & "% complete" '[ check for other instances of chameleon in memory ]'
End With If App.PrevInstance Then
End Sub MsgBox "Another instance of Chameleon is already open." & vbCrLf & _
"Only one instance of Chameleon may be opened.", vbCritical
End
Private Sub ZlibCompressor_Progress(ByVal percent_complete As Integer) End If
With frmEncode
.prgStatus.Value = percent_complete FormatWindow
.lblStatus(1).Caption = percent_complete & "% complete" Load frmView
End With
End Sub End Sub

Private Sub ZlibDecompressor_Progress(ByVal percent_complete As Integer) Private Sub MDIForm_QueryUnload(Cancel As Integer, UnloadMode As Integer)
With frmDecode
.prgStatus.Value = percent_complete If (UnloadMode = vbAppTaskManager) Or (UnloadMode = vbFormControlMenu) Then
.lblStatus(1).Caption = percent_complete & "% complete" If Not frmMDI.ActiveForm Is frmMainMenu Then
End With
End Sub If MsgBox("Do you wish to cancel the current task and exit Chameleon?", _
vbQuestion + vbYesNo) = vbNo Then
Cancel = True
Exit Sub
End If

End If
'------------------------------------------------------------------------------' End If
' '
' Chameleon Image Steganography v1.2 ' Cancel = False
' '
' Multiple Document Interface (MDI) Form ' '[ hide mdi form ]'
' [frmMDI] ' frmMDI.WindowState = vbMinimized
' ' frmMDI.Hide
'------------------------------------------------------------------------------'
' ' CloseHelpFiles
' Copyright (C) 2003 Mark David Gan '
' ' Unload frmView
'------------------------------------------------------------------------------' Unload frmMDI

End Sub
Option Explicit

'------------------------------------------------------------------------------'
' Windows User Interface Constants '
'------------------------------------------------------------------------------'
'------------------------------------------------------------------------------'
' '
Private Const MF_BYCOMMAND = &H0& ' Chameleon Image Steganography v1.2 '
Private Const MF_BYPOSITION = &H400& ' '
' Password Specification Form '
Private Const SC_SIZE = &HF000& ' [frmPassword1] '
Private Const SC_MOVE = &HF010& ' '
Private Const SC_MINIMIZE = &HF020& '------------------------------------------------------------------------------'
Private Const SC_MAXIMIZE = &HF030& ' '
' Copyright (C) 2003 Mark David Gan '
Private Const WS_CAPTION = &HC00000 ' '
Private Const WS_MAXIMIZEBOX = &H10000 '------------------------------------------------------------------------------'
Private Const WS_MINIMIZEBOX = &H20000
Private Const WS_SYSMENU = &H80000
Private Const WS_THICKFRAME = &H40000 Option Explicit

Private Const GWL_STYLE = -16


'------------------------------------------------------------------------------'
' Public Procedures '
'------------------------------------------------------------------------------' '------------------------------------------------------------------------------'
' Windows User Interface Function Declarations '
'------------------------------------------------------------------------------'
Public Sub ResetControls()
txtPassword(0).Text = vbNullString
Private Declare Function GetSystemMenu _ txtPassword(1).Text = vbNullString
Lib "user32" ( _ End Sub
ByVal hWnd As Long, _
ByVal bRevert As Long _
) As Long '------------------------------------------------------------------------------'
' Event Handlers '
Private Declare Function RemoveMenu _ '------------------------------------------------------------------------------'
Lib "user32" ( _
ByVal hMenu As Long, _
ByVal nPosition As Long, _ Private Sub btnBack_Click()
ByVal wFlags As Long _ frmCoverImage.Show
) As Long frmCoverImage.SetFocus
End Sub
Private Declare Function DrawMenuBar _
Lib "user32" ( _
ByVal hWnd As Long _ Private Sub btnCancel_Click()
) As Long frmMainMenu.Show
frmMainMenu.SetFocus
Private Declare Function SetWindowLong _ End Sub
Lib "user32" Alias "SetWindowLongA" ( _
ByVal hWnd As Long, _
ByVal nIndex As Long, _ Private Sub btnHelp_Click()
ByVal dwNewLong As Long _ DisplayHelpFile "hide_wizard.html#Page3"
) As Long End Sub

Private Declare Function GetWindowLong _


Lib "user32" Alias "GetWindowLongA" ( _ Private Sub btnNext_Click()
ByVal hWnd As Long, _
ByVal nIndex As Long _ On Error Resume Next

Adaptive Digital Steganography for True-Color Bitmaps G-6


Me.ValidateControls Private Sub PerformVerification()

If ActiveControl Is btnNext Then Dim PasswordHashMD5 As String


frmEncode.Show Dim PasswordHashSHA As String
frmEncode.SetFocus
End If With frmMainMenu.StegoDecoder

End Sub fraPage.Enabled = False

If .LoadStegoImage(m_StegoImagePath) Then
Private Sub Form_Activate()
On Error Resume Next PasswordHashMD5 = GetHashValue(txtPassword.Text, MD5)
txtPassword(0).SetFocus PasswordHashSHA = GetHashValue(txtPassword.Text, SHA)
End Sub
lblStatus(0).Caption = "Verifying password..."
fraStatus.Visible = True
Private Sub Form_Deactivate()
If Screen.ActiveForm.MDIChild Then Me.Hide .DecodeMetadata PasswordHashMD5
End Sub
lblStatus(0).Caption = vbNullString
lblStatus(1).Caption = vbNullString
Private Sub Form_Load()
Set imgPageIcon(1).Picture = imgPageIcon(0).Picture If .StoredPassword = PasswordHashSHA Then
SetMargins txtPassword(0), 1 If m_Cancel Then Exit Sub
SetMargins txtPassword(1), 1 frmDecode.Show
End Sub frmDecode.SetFocus
Else
If m_Cancel Then Exit Sub
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) lblStatus(0).Caption = "Invalid Password."
If KeyCode = vbKeyF1 Then btnHelp.Press MsgBox "The specified password is invalid." & vbCrLf & _
End Sub "Please specify the correct password.", vbExclamation
fraPage.Enabled = True
txtPassword.SetFocus
Private Sub txtPassword_GotFocus(Index As Integer) End If

With txtPassword(Index) Else


If .Tag <> "MouseDown" Then
.SelStart = 0 MsgBox "The selected image does not contain valid hidden data." & _
.SelLength = Len(.Text) vbCrLf & "Please select a valid stego image.", vbExclamation
End If
End With frmStegoImage.Show
frmStegoImage.SetFocus
End Sub
End If

Private Sub txtPassword_KeyDown(Index As Integer, KeyCode As Integer, _ End With


Shift As Integer)
End Sub
If KeyCode = vbKeyReturn Then
Select Case Index
Case 0: txtPassword(1).SetFocus '------------------------------------------------------------------------------'
Case 1: btnNext.SetFocus ' Event Handlers '
End Select '------------------------------------------------------------------------------'
End If

End Sub Private Sub btnBack_Click()


frmStegoImage.Show
frmStegoImage.SetFocus
Private Sub txtPassword_MouseDown(Index As Integer, Button As Integer, _ End Sub
Shift As Integer, _
X As Single, Y As Single)
txtPassword(Index).Tag = "MouseDown" Private Sub btnCancel_Click()
End Sub
If Not btnNext.Visible Then
If MsgBox("Do you wish to cancel the current task?", _
Private Sub txtPassword_MouseUp(Index As Integer, Button As Integer, _ vbQuestion + vbYesNo) = vbYes Then
Shift As Integer, _ m_Cancel = True
X As Single, Y As Single) frmMainMenu.StegoDecoder.Abort
txtPassword(Index).Tag = "" frmMainMenu.Show
End Sub frmMainMenu.SetFocus
End If
Else
Private Sub txtPassword_Validate(Index As Integer, Cancel As Boolean) frmMainMenu.Show
frmMainMenu.SetFocus
If Len(txtPassword(0).Text) = 0 Then End If
MsgBox "No password has been specified." & vbCrLf & _
"Please specify a password.", vbExclamation End Sub
Cancel = True
ElseIf Len(txtPassword(1).Text) = 0 Then
MsgBox "The password has not been confirmed." & vbCrLf & _ Private Sub btnHelp_Click()
"Please confirm the password.", vbExclamation DisplayHelpFile "extract_wizard.html#Page2"
Cancel = True End Sub
ElseIf txtPassword(0).Text <> txtPassword(1).Text Then
MsgBox "The two passwords specified are different." & vbCrLf & _
"Please confirm the password carefully.", vbExclamation Private Sub btnNext_Click()
Cancel = True
End If On Error Resume Next
Me.ValidateControls
End Sub
If ActiveControl Is btnNext Then PerformVerification

End Sub

Private Sub Form_Activate()


'------------------------------------------------------------------------------'
' ' m_Cancel = False
' Chameleon Image Steganography v1.2 ' m_StegoImagePath = frmStegoImage.txtPath.Text
' '
' Password Verification Form ' On Error Resume Next
' [frmPassword2] ' txtPassword.SetFocus
' '
'------------------------------------------------------------------------------' End Sub
' '
' Copyright (C) 2003 Mark David Gan '
' ' Private Sub Form_Deactivate()
'------------------------------------------------------------------------------'
If Screen.ActiveForm.MDIChild Then

Option Explicit Me.Hide

'[ reset controls ]'


'------------------------------------------------------------------------------' fraPage.Enabled = True
' Private Variables ' fraStatus.Visible = False
'------------------------------------------------------------------------------' lblStatus(0).Caption = vbNullString
lblStatus(1).Caption = vbNullString
prgStatus.Min = 0
'[ user-selected input file ]' prgStatus.Max = 100
Private m_StegoImagePath As String prgStatus.Value = 0

'[ cancel process flag ]' End If


Private m_Cancel As Boolean
End Sub

'------------------------------------------------------------------------------'
' Public Procedures ' Private Sub Form_Load()
'------------------------------------------------------------------------------' Set imgPageIcon(1).Picture = imgPageIcon(0).Picture
SetMargins txtPassword, 1
End Sub
Public Sub ResetControls()
txtPassword.Text = vbNullString
End Sub Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyF1 Then btnHelp.Press
End Sub
'------------------------------------------------------------------------------'
' Private Procedures '
'------------------------------------------------------------------------------' Private Sub txtPassword_GotFocus()

With txtPassword

Adaptive Digital Steganography for True-Color Bitmaps G-7


If .Tag <> "MouseDown" Then
.SelStart = 0 Private Sub Form_Activate()
.SelLength = Len(.Text) On Error Resume Next
End If txtPath.SetFocus
End With End Sub

End Sub
Private Sub Form_Deactivate()
If Screen.ActiveForm.MDIChild Then Me.Hide
Private Sub txtPassword_KeyDown(KeyCode As Integer, Shift As Integer) End Sub
If KeyCode = vbKeyReturn Then btnNext.SetFocus
End Sub
Private Sub Form_Load()

Private Sub txtPassword_MouseDown(Button As Integer, Shift As Integer, _ Set imgPageIcon(1).Picture = imgPageIcon(0).Picture


X As Single, Y As Single) SetMargins txtPath, 1
txtPassword.Tag = "MouseDown"
End Sub dlgBrowse.Filter = "(All supported image formats)|" & _
"*.bmp;*.png;*.tif;*.tiff;*.tga;*.ppm|" & _
"Windows Bitmap (*.bmp)|*.bmp|" & _
Private Sub txtPassword_MouseUp(Button As Integer, Shift As Integer, _ "Portable Network Graphics (*.png)|*.png|" & _
X As Single, Y As Single) "Portable Pixelmap (*.ppm)|*.ppm|" & _
txtPassword.Tag = "" "Tagged Image File Format (*.tif)|*.tif;*.tiff|" & _
End Sub "TARGA Bitmap (*.tga)|*.tga|"
dlgBrowse.FilterIndex = 1
dlgBrowse.Flags = cdlOFNHideReadOnly + cdlOFNLongNames + _
Private Sub txtPassword_Validate(Cancel As Boolean) cdlOFNPathMustExist + cdlOFNFileMustExist
dlgBrowse.InitDir = GetPrimaryDrive
If Len(txtPassword.Text) = 0 Then
MsgBox "No password has been specified." & vbCrLf & _ End Sub
"Please specify a password.", vbExclamation
Cancel = True
End If Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

End Sub If Shift = vbCtrlMask Then

Select Case KeyCode


Case vbKeyO: btnBrowse.Press
Case vbKeyP: btnView.Press
End Select

'------------------------------------------------------------------------------' ElseIf KeyCode = vbKeyF1 Then


' '
' Chameleon Image Steganography v1.2 ' btnHelp.Press
' '
' Stego Image Selection Form ' End If
' [frmStegoImage] '
' ' End Sub
'------------------------------------------------------------------------------'
' '
' Copyright (C) 2003 Mark David Gan ' Private Sub txtPath_Change()
' '
'------------------------------------------------------------------------------' If Screen.ActiveControl Is txtPath Then
lblFileSize(1).Caption = vbNullString
lblFileDate(1).Caption = vbNullString
Option Explicit End If

End Sub
'------------------------------------------------------------------------------'
' Public Procedures '
'------------------------------------------------------------------------------' Private Sub txtPath_GotFocus()

With txtPath
Public Sub ResetControls() If .Tag <> "MouseDown" Then
lblFileSize(1).Caption = vbNullString .SelStart = 0
lblFileDate(1).Caption = vbNullString .SelLength = Len(.Text)
txtPath.Text = vbNullString End If
End Sub End With

End Sub
'------------------------------------------------------------------------------'
' Form Event Handlers '
'------------------------------------------------------------------------------' Private Sub txtPath_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyReturn Then btnNext.SetFocus
End Sub
Private Sub btnBack_Click()
frmMainMenu.Show
frmMainMenu.SetFocus Private Sub txtPath_LostFocus()
End Sub txtPath.Text = GetAbsolutePath(Trim$(txtPath.Text))
lblFileSize(1).Caption = GetFileSize(txtPath.Text)
lblFileDate(1).Caption = GetFileDateTime(txtPath.Text)
Private Sub btnBrowse_Click() End Sub

If Len(txtPath.Text) > 0 Then


dlgBrowse.InitDir = txtPath.Text Private Sub txtPath_MouseDown(Button As Integer, Shift As Integer, _
If FileExists(txtPath.Text) Then dlgBrowse.FileName = txtPath.Text X As Single, Y As Single)
End If txtPath.Tag = "MouseDown"
End Sub
On Error Resume Next
dlgBrowse.ShowOpen
Private Sub txtPath_MouseUp(Button As Integer, Shift As Integer, _
If Err.Number = 0 Then X As Single, Y As Single)
txtPath.Text = dlgBrowse.FileName txtPath.Tag = ""
Call txtPath_LostFocus End Sub
End If

txtPath.SetFocus Private Sub txtPath_Validate(Cancel As Boolean)

End Sub If Len(txtPath.Text) = 0 Then


MsgBox "No file has been specified." & vbCrLf & _
"Please specify an existing file.", vbExclamation
Private Sub btnCancel_Click() Cancel = True
frmMainMenu.Show ElseIf Not FileExists(txtPath.Text) Then
frmMainMenu.SetFocus MsgBox "The specified file cannot be found." & vbCrLf & _
End Sub "Please specify an existing file.", vbExclamation
Cancel = True
End If
Private Sub btnHelp_Click()
DisplayHelpFile "extract_wizard.html" End Sub
End Sub

Private Sub btnNext_Click()

On Error Resume Next


Me.ValidateControls '------------------------------------------------------------------------------'
' '
If ActiveControl Is btnNext Then ' Chameleon Image Steganography v1.2 '
frmPassword2.Show ' '
frmPassword2.SetFocus ' Image Preview Form '
End If ' [frmView] '
' '
End Sub '------------------------------------------------------------------------------'
' '
' Copyright (C) 2003 Mark David Gan '
Private Sub btnView_Click() ' '
'------------------------------------------------------------------------------'
On Error Resume Next
Me.ValidateControls
Option Explicit
If ActiveControl Is btnView Then
If Not frmView.DisplayByFilename(, txtPath.Text) Then
MsgBox "The specified image cannot be loaded." & vbCrLf & _ '------------------------------------------------------------------------------'
"Please select a valid image.", vbExclamation ' Private Variables '
End If '------------------------------------------------------------------------------'
End If

End Sub '[ freeimage wrapper object ]'


Private Imager As FreeImageWrapper

Adaptive Digital Steganography for True-Color Bitmaps G-8


If picCoverImage(0).Visible Then
'[ image dib handles ]' Call picCoverImage_MouseDown(1, vbLeftButton, 0, 0, 0)
Private m_CoverImageDIB As Long Call picCoverImage_MouseMove(1, vbLeftButton, 0, 10, 0)
Private m_StegoImageDIB As Long Else
Private m_DIBsTemporary As Boolean Call picStegoImage_MouseDown(1, vbLeftButton, 0, 0, 0)
Call picStegoImage_MouseMove(1, vbLeftButton, 0, 10, 0)
'[ number of images to display ]' End If
Private m_ImageCount As Long
Case vbKeyDown:
'[ mouse down coordinate ]' If picCoverImage(0).Visible Then
Private m_MouseX As Long Call picCoverImage_MouseDown(1, vbLeftButton, 0, 0, 0)
Private m_MouseY As Long Call picCoverImage_MouseMove(1, vbLeftButton, 0, 0, -10)
Else
'[ size difference between image and container ]' Call picStegoImage_MouseDown(1, vbLeftButton, 0, 0, 0)
Private m_DifX As Long Call picStegoImage_MouseMove(1, vbLeftButton, 0, 0, -10)
Private m_DifY As Long End If

Case vbKeyUp:
'------------------------------------------------------------------------------' If picCoverImage(0).Visible Then
' Public Procedures ' Call picCoverImage_MouseDown(1, vbLeftButton, 0, 0, 0)
'------------------------------------------------------------------------------' Call picCoverImage_MouseMove(1, vbLeftButton, 0, 0, 10)
Else
Call picStegoImage_MouseDown(1, vbLeftButton, 0, 0, 0)
Public Function DisplayByDIB( _ Call picStegoImage_MouseMove(1, vbLeftButton, 0, 0, 10)
Optional ByVal CoverImage As Long = 0, _ End If
Optional ByVal StegoImage As Long = 0 _
) As Boolean Case vbKeyEscape:
Call mnuClose_Click
DisplayByDIB = False
Case 93:
m_ImageCount = 0 Call Form_MouseDown(vbRightButton, 0, 0, 0)
m_CoverImageDIB = CoverImage
m_StegoImageDIB = StegoImage End Select
m_DIBsTemporary = False
End Sub
If PaintImage(picCoverImage(1)) Then m_ImageCount = m_ImageCount + 1
If PaintImage(picStegoImage(1)) Then m_ImageCount = m_ImageCount + 1
Private Sub Form_Load()
If m_ImageCount > 0 Then Set Imager = New FreeImageWrapper
Call Form_Resize End Sub
Me.Show
DisplayByDIB = True
End If Private Sub Form_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
End Function If Button = vbRightButton Then
PopupMenu mnuView
End If
Public Function DisplayByFilename( _ End Sub
Optional ByVal CoverImage As String = vbNullString, _
Optional ByVal StegoImage As String = vbNullString _
) As Boolean Private Sub Form_Resize()

DisplayByFilename = False Dim W As Long


Dim H As Long
m_ImageCount = 0 Dim L As Long
m_CoverImageDIB = Imager.LoadDIB(CoverImage) Dim T As Long
m_StegoImageDIB = Imager.LoadDIB(StegoImage)
m_DIBsTemporary = True Select Case m_ImageCount

If PaintImage(picCoverImage(1)) Then m_ImageCount = m_ImageCount + 1 Case 1:


If PaintImage(picStegoImage(1)) Then m_ImageCount = m_ImageCount + 1 W = Me.ScaleWidth
H = Me.ScaleHeight
If m_ImageCount > 0 Then If m_CoverImageDIB <> 0 Then
Call Form_Resize m_DifX = W - picCoverImage(1).Width
Me.Show m_DifY = H - picCoverImage(1).Height
DisplayByFilename = True picCoverImage(0).Move 0, 0
End If picCoverImage(0).Width = W
picCoverImage(0).Height = H
End Function Else
m_DifX = W - picStegoImage(1).Width
m_DifY = H - picStegoImage(1).Height
'------------------------------------------------------------------------------' picStegoImage(0).Move 0, 0
' Private Procedures ' picStegoImage(0).Width = W
'------------------------------------------------------------------------------' picStegoImage(0).Height = H
End If

Private Function PaintImage(ByRef Picture1 As PictureBox) As Boolean Case 2:


W = Me.ScaleWidth \ 2
Dim hDIB As Long H = Me.ScaleHeight
m_DifX = W - picCoverImage(1).Width
Select Case Picture1.Name m_DifY = H - picCoverImage(1).Height
Case picCoverImage(1).Name: hDIB = m_CoverImageDIB picCoverImage(0).Move 0, 0
Case picStegoImage(1).Name: hDIB = m_StegoImageDIB picCoverImage(0).Width = W - 1
End Select picCoverImage(0).Height = H
picStegoImage(0).Move W + 1, 0
If hDIB <> 0 Then picStegoImage(0).Width = W - 1
picStegoImage(0).Height = H
Picture1.Width = Imager.GetWidth(hDIB)
Picture1.Height = Imager.GetHeight(hDIB) End Select

If Imager.PaintDIB(hDIB, Picture1.hDC) Then L = m_DifX \ 2


PaintImage = True T = m_DifY \ 2
Select Case Picture1.Name
Case picCoverImage(1).Name: picCoverImage(0).Visible = True If m_CoverImageDIB <> 0 Then
Case picStegoImage(1).Name: picStegoImage(0).Visible = True With picCoverImage(1)
End Select If L < 0 Then
Else .Left = 0
PaintImage = False .MousePointer = vbSizeAll
End If Else
.Left = L
End If .MousePointer = vbDefault
End If
End Function If T < 0 Then
.top = 0
.MousePointer = vbSizeAll
'------------------------------------------------------------------------------' Else
' Event Handlers ' .top = T
'------------------------------------------------------------------------------' End If
End With
End If
Private Sub Form_Deactivate()
If m_StegoImageDIB <> 0 Then
Me.Hide With picStegoImage(1)
picCoverImage(0).Visible = False If L < 0 Then
picStegoImage(0).Visible = False .Left = 0
.MousePointer = vbSizeAll
If m_DIBsTemporary Then Else
On Error Resume Next .Left = L
Imager.UnloadDIB m_CoverImageDIB .MousePointer = vbDefault
Imager.UnloadDIB m_StegoImageDIB End If
End If If T < 0 Then
.top = 0
End Sub .MousePointer = vbSizeAll
Else
.top = T
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) End If
End With
Select Case KeyCode End If

Case vbKeyRight: End Sub


If picCoverImage(0).Visible Then
Call picCoverImage_MouseDown(1, vbLeftButton, 0, 0, 0)
Call picCoverImage_MouseMove(1, vbLeftButton, 0, -10, 0) Private Sub Form_Unload(Cancel As Integer)
Else Set Imager = Nothing
Call picStegoImage_MouseDown(1, vbLeftButton, 0, 0, 0) End Sub
Call picStegoImage_MouseMove(1, vbLeftButton, 0, -10, 0)
End If
Private Sub mnuClose_Click()
Case vbKeyLeft: Me.Hide

Adaptive Digital Steganography for True-Color Bitmaps G-9


End Sub
'------------------------------------------------------------------------------'
' Windows API Structure Data Types '
Private Sub picCoverImage_MouseDown(Index As Integer, Button As Integer, _ '------------------------------------------------------------------------------'
Shift As Integer, X As Single, Y As Single)
If Button = vbLeftButton Then
m_MouseX = X Public Type RECT
m_MouseY = Y Left As Long
ElseIf Button = vbRightButton Then top As Long
PopupMenu mnuView Right As Long
End If Bottom As Long
End Sub End Type

Private Sub picStegoImage_MouseDown(Index As Integer, Button As Integer, _ '------------------------------------------------------------------------------'


Shift As Integer, X As Single, Y As Single) ' Windows API Constants '
If Button = vbLeftButton Then '------------------------------------------------------------------------------'
m_MouseX = X
m_MouseY = Y
ElseIf Button = vbRightButton Then '[ constants for setting textbox margins with "SendMessageLong" function ]'
PopupMenu mnuView Private Const EC_LEFTMARGIN As Long = &H1
End If Private Const EC_RIGHTMARGIN As Long = &H2
End Sub Private Const EM_SETMARGINS As Long = &HD3

'[ constants for "DrawText" function "uFormat" parameter ]'


Private Sub picCoverImage_MouseMove(Index As Integer, Button As Integer, _ Private Const DT_CALCRECT As Long = &H400
Shift As Integer, X As Single, Y As Single) Private Const DT_END_ELLIPSIS As Long = &H8000
Private Const DT_MODIFYSTRING As Long = &H10000
If (Index = 1) Then Private Const DT_NOPREFIX As Long = &H800
If (Button = vbLeftButton) Then Private Const DT_PATH_ELLIPSIS As Long = &H4000
Private Const DT_WORD_ELLIPSIS As Long = &H40000
Dim X2 As Long
Dim Y2 As Long '[ constants for "ShellExecute" function return values ]'
X2 = picCoverImage(1).Left Private Const SE_ERR_ACCESSDENIED As Long = 5
Y2 = picCoverImage(1).top Private Const SE_ERR_ASSOCINCOMPLETE As Long = 27
Private Const SE_ERR_DDEBUSY As Long = 30
If (m_DifX < 0) Then Private Const SE_ERR_DDEFAIL As Long = 29
X2 = X2 + (X - m_MouseX) Private Const SE_ERR_DDETIMEOUT As Long = 28
If X2 > 0 Then Private Const SE_ERR_DLLNOTFOUND As Long = 32
X2 = 0 Private Const SE_ERR_FNF As Long = 2
ElseIf X2 < m_DifX Then Private Const SE_ERR_NOASSOC As Long = 31
X2 = m_DifX Private Const SE_ERR_OOM As Long = 8
End If Private Const SE_ERR_PNF As Long = 3
End If Private Const SE_ERR_SHARE As Long = 26
Private Const ERROR_BAD_FORMAT As Long = 11&
If (m_DifY < 0) Then
Y2 = Y2 + (Y - m_MouseY) '[ constants for "ShellExecute" function "nShowCmd" parameter ]'
If Y2 > 0 Then Private Const SW_SHOW As Long = 5
Y2 = 0 Private Const SW_SHOWDEFAULT As Long = 10
ElseIf Y2 < m_DifY Then Private Const SW_SHOWMAXIMIZED As Long = 3
Y2 = m_DifY Private Const SW_SHOWMINIMIZED As Long = 2
End If Private Const SW_SHOWMINNOACTIVE As Long = 7
End If Private Const SW_SHOWNA As Long = 8
Private Const SW_SHOWNOACTIVATE As Long = 4
If (X2 <> picCoverImage(1).Left) Or (Y2 <> picCoverImage(1).top) Then Private Const SW_SHOWNORMAL As Long = 1
picCoverImage(1).Move X2, Y2
If picStegoImage(0).Visible Then picStegoImage(1).Move X2, Y2 '------------------------------------------------------------------------------'
Me.Refresh ' HTML Help Constants '
End If '------------------------------------------------------------------------------'

End If
End If Public Const HH_DISPLAY_TOPIC As Long = &H0
Public Const HH_SET_WIN_TYPE As Long = &H4
End Sub Public Const HH_GET_WIN_TYPE As Long = &H5
Public Const HH_GET_WIN_HANDLE As Long = &H6
Public Const HH_DISPLAY_TEXT_POPUP As Long = &HE
Private Sub picStegoImage_MouseMove(Index As Integer, Button As Integer, _ Public Const HH_HELP_CONTEXT As Long = &HF
Shift As Integer, X As Single, Y As Single) Public Const HH_TP_HELP_CONTEXTMENU As Long = &H10
Public Const HH_TP_HELP_WM_HELP As Long = &H11
If (Index = 1) Then Public Const HH_CLOSE_ALL As Long = &H12
If (Button = vbLeftButton) Then

Dim X2 As Long '------------------------------------------------------------------------------'


Dim Y2 As Long ' Windows API Function Declarations '
X2 = picStegoImage(1).Left '------------------------------------------------------------------------------'
Y2 = picStegoImage(1).top

If (m_DifX < 0) Then Private Declare Function DestroyWindow _


X2 = X2 + (X - m_MouseX) Lib "user32" (ByVal hWnd As Long) As Long
If X2 > 0 Then
X2 = 0 Private Declare Function DrawText _
ElseIf X2 < m_DifX Then Lib "user32" Alias "DrawTextA" ( _
X2 = m_DifX ByVal hDC As Long, _
End If ByVal lpString As String, _
End If ByVal nCount As Long, _
lpRect As RECT, _
If (m_DifY < 0) Then ByVal uFormat As Long _
Y2 = Y2 + (Y - m_MouseY) ) As Long
If Y2 > 0 Then
Y2 = 0 Private Declare Function GetDesktopWindow Lib "user32" () As Long
ElseIf Y2 < m_DifY Then
Y2 = m_DifY Private Declare Function SendMessageLong _
End If Lib "user32" Alias "SendMessageA" ( _
End If ByVal hWnd As Long, _
ByVal wMsg As Long, _
If (X2 <> picStegoImage(1).Left) Or (Y2 <> picStegoImage(1).top) Then ByVal wParam As Long, _
picStegoImage(1).Move X2, Y2 ByVal lParam As Long _
If picCoverImage(0).Visible Then picCoverImage(1).Move X2, Y2 ) As Long
Me.Refresh
End If Private Declare Function ShellExecute _
Lib "shell32.dll" Alias "ShellExecuteA" ( _
End If ByVal hWnd As Long, _
End If ByVal lpOperation As String, _
ByVal lpFile As String, _
End Sub ByVal lpParameters As String, _
ByVal lpDirectory As String, _
ByVal nShowCmd As Long _
) As Long

'------------------------------------------------------------------------------'
'------------------------------------------------------------------------------' ' HTML Help Function Declarations '
' ' '------------------------------------------------------------------------------'
' Chameleon Image Steganography v1.2 '
' '
' Miscellaneous Application Procedures Module ' Private Declare Function HtmlHelp _
' [modApplication] ' Lib "hhctrl.ocx" Alias "HtmlHelpA" ( _
' ' ByVal hwndCaller As Long, _
'------------------------------------------------------------------------------' ByVal pszFile As String, _
' ' ByVal uCommand As Long, _
' Copyright (C) 2003 Mark David Gan ' ByVal dwData As Long _
' ' ) As Long
'------------------------------------------------------------------------------'
'------------------------------------------------------------------------------'
Option Explicit ' Public Variables '
'------------------------------------------------------------------------------'

'------------------------------------------------------------------------------'
' Public Enumerated Data Types ' Public CurrentTask As appTaskConstants
'------------------------------------------------------------------------------'
'------------------------------------------------------------------------------'
Public Enum appTaskConstants ' Public Procedures '
TASK_NONE = 0 '------------------------------------------------------------------------------'
TASK_ENCODE = 1
TASK_DECODE = 2
End Enum Public Sub CloseHelpFiles()
Call HtmlHelp(0, "", HH_CLOSE_ALL, 0)

Adaptive Digital Steganography for True-Color Bitmaps G-10


End Sub '------------------------------------------------------------------------------'
' Windows API Constants '
'------------------------------------------------------------------------------'
Public Sub CompactCaptionWithEllipses(Label1 As Control)

Dim Cap As String '[ constants for "SetWindowLong" function "nIndex" parameter ]'
Dim RC As RECT Private Const GWL_WNDPROC As Long = (-4)

With Label1 '[ constants for "TRACTMOUSEEVENTTYPE" structure "dwFlags" member ]'
Private Const TME_HOVER As Long = &H1
'[ compute boundary ]' Private Const TME_LEAVE As Long = &H2
RC.Right = frmView.ScaleX(.Width, vbTwips, vbPixels) Private Const TME_QUERY As Long = &H40000000
RC.Bottom = frmView.ScaleY(.Height, vbTwips, vbPixels) Private Const TME_CANCEL As Long = &H80000000

Cap = .Caption '[ window messages ]'


Set frmMainMenu.Font = Label1.Font Private Const WM_LBUTTONDBLCLK As Long = &H203
Private Const WM_LBUTTONDOWN As Long = &H201
'[ use ellipses to compact the caption ]' Private Const WM_LBUTTONUP As Long = &H202
Call DrawText(frmMainMenu.hDC, Cap, -1, RC, _ Private Const WM_MOUSEACTIVATE As Long = &H21
DT_CALCRECT + DT_MODIFYSTRING + DT_NOPREFIX + _ Private Const WM_MOUSEHOVER As Long = &H2A1
DT_PATH_ELLIPSIS) Private Const WM_MOUSELEAVE As Long = &H2A3
Private Const WM_MOUSEMOVE As Long = &H200
If .Caption = Cap Then Private Const WM_MOUSEWHEEL As Long = &H20A
.ToolTipText = vbNullString
Else
'[ set the tooltip to the original caption and display new caption ]' '------------------------------------------------------------------------------'
.ToolTipText = .Caption ' Public Structure Data Types '
.Caption = Cap '------------------------------------------------------------------------------'
End If

End With Private Type TRACKMOUSEEVENTTYPE


cbSize As Long
End Sub dwFlags As Long
hwndTrack As Long
dwHoverTime As Long
Public Sub DisplayHelpFile(ByVal TopicFile As String) End Type
Call HtmlHelp(GetDesktopWindow, App.Path & "\Chameleon.chm::/" & TopicFile & _
">default", HH_DISPLAY_TOPIC, 0)
End Sub '------------------------------------------------------------------------------'
' Windows API Function Declarations '
'------------------------------------------------------------------------------'
Public Function FormatDate(ByVal DateTime As Date) As String
FormatDate = Format$(DateTime, "mmmm d, yyyy" & vbCrLf & "dddd" & vbCrLf & _
"h:Nn AMPM") Private Declare Function CallWindowProc _
End Function Lib "user32" Alias "CallWindowProcA" ( _
ByVal lpPrevWndFunc As Long, _
ByVal hWnd As Long, _
Public Function FormatSize(ByVal Bytes As Long) As String ByVal Msg As Long, _
FormatSize = Format$(Bytes, "#,##0") & IIf(Bytes = 1, " byte", " bytes") ByVal wParam As Long, _
End Function ByVal lParam As Long _
) As Long

Public Function GetHashValue(ByVal Data As String, _ Private Declare Function SetWindowLong _


ByVal Algorithm As EC_HASH_ALG_ID) As String Lib "user32" Alias "SetWindowLongA" ( _
With frmMainMenu.EzCrypto ByVal hWnd As Long, _
.HashAlgorithm = Algorithm ByVal nIndex As Long, _
.CreateHash ByVal dwNewLong As Long _
.HashDigestData Data ) As Long
GetHashValue = .GetDigestedData(EC_HF_ASCII)
.DestroyHash Private Declare Function TrackMouseEvent _
End With Lib "user32" ( _
End Function lpEventTrack As TRACKMOUSEEVENTTYPE _
) As Long

Public Function GetHashValueOfFile(ByVal FileName As String, _


ByVal Algorithm As EC_HASH_ALG_ID) As String
With frmMainMenu.EzCrypto '------------------------------------------------------------------------------'
.HashAlgorithm = Algorithm ' Private Variables '
.CreateHash '------------------------------------------------------------------------------'
.HashDigestFile FileName
GetHashValueOfFile = .GetDigestedData(EC_HF_ASCII)
.DestroyHash Private m_ButtonCollection As Collection
End With
End Function
'------------------------------------------------------------------------------'
' Public Procedures '
Public Function OpenFile(ByVal FileName As String) As Boolean '------------------------------------------------------------------------------'

Dim RV As Long
Public Function NewWndProc(ByVal hWnd As Long, ByVal uMsg As Long, _
On Error Resume Next ByVal wParam As Long, ByVal lParam As Long) As Long
OpenFile = (ShellExecute(0, "", FileName, "", "", SW_SHOW) > 32)
Dim CButton1 As CustomButton
If Not OpenFile Then
On Error Resume Next
RV = ShellExecute(0, "open", FileName, "", "", SW_SHOW)
If Not m_ButtonCollection Is Nothing Then
If RV > 32 Then
Set CButton1 = m_ButtonCollection.Item("hWnd: " & hWnd)
OpenFile = True
'[ test for mouse leave event ]'
Else If CButton1.Enabled Then
Select Case uMsg
OpenFile = False
Case WM_MOUSELEAVE:
Select Case RV CButton1.State = cbtnStateNormal
Case SE_ERR_NOASSOC, SE_ERR_ASSOCINCOMPLETE: CButton1.RaiseMouseLeaveEvent
MsgBox "The file " & FileName & " cannot be opened." & vbCrLf & _
"The file may not be associated with any application.", _ End Select
vbExclamation End If
Case Else:
MsgBox "The file " & FileName & " cannot be opened." & vbCrLf & _ '[ call original window procedure ]'
"An error occured while accessing the file.", vbExclamation NewWndProc = CallWindowProc(CButton1.OldWndProc, hWnd, uMsg, wParam, lParam)
End Select
End If
End If
End Function
End If

End Function Public Sub StartSubclassingButton(ByVal CButton1 As CustomButton)

If CButton1.OldWndProc = 0 Then
Public Sub SetMargins(ByRef Text1 As TextBox, ByVal Margin As Long)
SendMessageLong Text1.hWnd, EM_SETMARGINS, EC_LEFTMARGIN, Margin '[ create button collection ] '
SendMessageLong Text1.hWnd, EM_SETMARGINS, EC_RIGHTMARGIN, Margin * &H10000 If m_ButtonCollection Is Nothing Then
End Sub Set m_ButtonCollection = New Collection
End If

'[ subclass button ]'


m_ButtonCollection.Add CButton1, "hWnd: " & CButton1.hWnd
CButton1.OldWndProc = SetWindowLong(CButton1.hWnd, GWL_WNDPROC, _
AddressOf NewWndProc)
'------------------------------------------------------------------------------'
' ' End If
' Chameleon Image Steganography v1.2 '
' ' End Sub
' Custom Button Subclassing Module '
' [modCustomButton] '
' ' Public Sub StopSubclassingButton(ByVal CButton1 As CustomButton)
'------------------------------------------------------------------------------'
' ' '[ reconnect button to its original window procedure ]'
' Copyright (C) 2003 Mark David Gan ' If CButton1.OldWndProc <> 0 Then
' ' SetWindowLong CButton1.hWnd, GWL_WNDPROC, CButton1.OldWndProc
'------------------------------------------------------------------------------' CButton1.OldWndProc = 0
m_ButtonCollection.Remove "hWnd: " & CButton1.hWnd
End If
Option Explicit
End Sub

Adaptive Digital Steganography for True-Color Bitmaps G-11


Private Declare Function SetFileTime _
Public Sub TrackMouseLeaveEvent(ByVal CButton1 As CustomButton) Lib "kernel32" ( _
ByVal hFile As Long, _
Dim TMEvent As TRACKMOUSEEVENTTYPE ByVal lpCreationTime As Long, _
ByRef lpLastAccessTime As FILETIME, _
With TMEvent ByRef lpLastWriteTime As FILETIME _
.cbSize = Len(TMEvent) ) As Long
.hwndTrack = CButton1.hWnd
.dwFlags = TME_LEAVE Private Declare Function SystemTimeToFileTime _
End With Lib "kernel32" ( _
lpSystemTime As SYSTEMTIME, _
TrackMouseEvent TMEvent lpFileTime As FILETIME _
) As Long
End Sub
Private Declare Function WriteFile _
Lib "kernel32.dll" ( _
ByVal iFileHandler As Long, _
ByRef lpBuffer As Any, _
ByVal nNumberOfBytesToWrite As Long, _
ByRef lpNumberOfBytesWritten As Long, _
'------------------------------------------------------------------------------' ByVal lpOverlapped As Long _
' ' ) As Long
' Chameleon Image Steganography v1.2 '
' '
' File System Operations Module ' '------------------------------------------------------------------------------'
' [modFileSystem] ' ' Public Procedures '
' ' '------------------------------------------------------------------------------'
'------------------------------------------------------------------------------'
' '
' Copyright (C) 2003 Mark David Gan ' Public Sub CreateFolder(ByVal Path As String)
' '
'------------------------------------------------------------------------------' Dim FSO As Object
Set FSO = CreateObject("Scripting.FileSystemObject")

Option Explicit If Len(FSO.GetParentFolderName(Path)) > 0 Then


CreateFolder FSO.GetParentFolderName(Path)
End If
'------------------------------------------------------------------------------'
' Windows API Structure Data Types ' On Error Resume Next
'------------------------------------------------------------------------------' MkDir Path

End Sub
'[ 64-bit time structure ]'
Private Type FILETIME
dwLowDateTime As Long Public Function FileExists(ByVal Path As String) As Boolean
dwHighDateTime As Long Dim FSO As Object
End Type Set FSO = CreateObject("Scripting.FileSystemObject")
FileExists = FSO.FileExists(Path)
'[ multiple-field time structure ]' End Function
Private Type SYSTEMTIME
wYear As Integer
wMonth As Integer Public Function FolderExists(ByVal Path As String) As Boolean
wDayOfWeek As Integer Dim FSO As Object
wDay As Integer Set FSO = CreateObject("Scripting.FileSystemObject")
wHour As Integer FolderExists = FSO.FolderExists(Path)
wMinute As Integer End Function
wSecond As Integer
wMilliseconds As Integer
End Type Public Function GenerateTempFile() As String

Dim FSO As Object


'------------------------------------------------------------------------------' Set FSO = CreateObject("Scripting.FileSystemObject")
' Windows API Constants '
'------------------------------------------------------------------------------' '[ set current drive to that of the windows folder ]'
ChDir Left$(FSO.GetSpecialFolder(GSF_WINDOWSFOLDER), 2) & "\"

'[ constants for "CreateFile" function "dwDesiredAccess" parameter ]' '[ get path of temporary folder ]'
Private Const GENERIC_READ As Long = &H80000000 GenerateTempFile = FSO.GetSpecialFolder(GSF_TEMPORARYFOLDER) & "\" & _
Private Const GENERIC_WRITE As Long = &H40000000 UCase$(FSO.GetTempName)

'[ constants for "CreateFile" function "dwShareMode" parameter ]' End Function
Private Const FILE_SHARE_READ As Long = &H1
Private Const FILE_SHARE_WRITE As Long = &H2
Public Function GetAbsolutePath(ByVal Path As String) As String
'[ constants for "CreateFile" function "dwCreateDisposition" parameter ]'
Private Const CREATE_ALWAYS As Long = 2 If Len(Path) = 0 Then
Private Const CREATE_NEW As Long = 1 GetAbsolutePath = ""
Private Const OPEN_ALWAYS As Long = 4 Exit Function
Private Const OPEN_EXISTING As Long = 3 End If
Private Const TRUNCATE_EXISTING As Long = 5
Dim FSO As Object
'[ constants for "CreateFile" function "dwFlagsAndAttributes" parameter ]' Set FSO = CreateObject("Scripting.FileSystemObject")
Private Const FILE_ATTRIBUTE_ARCHIVE As Long = &H20
Private Const FILE_ATTRIBUTE_HIDDEN As Long = &H2 '[ replace illegal characters ]'
Private Const FILE_ATTRIBUTE_NORMAL As Long = &H80 Path = Replace$(Path, ">", "")
Private Const FILE_ATTRIBUTE_READONLY As Long = &H1 Path = Replace$(Path, "<", "")
Private Const FILE_ATTRIBUTE_SYSTEM As Long = &H4 Path = Replace$(Path, "*", "")
Private Const FILE_FLAG_DELETE_ON_CLOSE As Long = &H4000000 Path = Replace$(Path, "?", "")
Private Const FILE_FLAG_NO_BUFFERING As Long = &H20000000 Path = Replace$(Path, "|", "")
Private Const FILE_FLAG_OVERLAPPED As Long = &H40000000 Path = Replace$(Path, Chr(34), "")
Private Const FILE_FLAG_POSIX_SEMANTICS As Long = &H1000000
Private Const FILE_FLAG_RANDOM_ACCESS As Long = &H10000000 '[ ensure that the colon character is in place ]'
Private Const FILE_FLAG_SEQUENTIAL_SCAN As Long = &H8000000 If InStr(1, Path, ":") = 2 Then
Private Const FILE_FLAG_WRITE_THROUGH As Long = &H80000000 Path = Left$(Path, 2) & Replace$(Path, ":", "", 3)
Else
'[ constants for "SetFilePointer" function "dwMoveMethod" parameter ]' Path = Replace$(Path, ":", "")
Private Const FILE_BEGIN As Long = 0 End If
Private Const FILE_CURRENT As Long = 1
Private Const FILE_END As Long = 2 '[ set current drive to that of the windows folder ]'
ChDir Left$(FSO.GetSpecialFolder(GSF_WINDOWSFOLDER), 2) & "\"

'------------------------------------------------------------------------------' GetAbsolutePath = FSO.GetAbsolutePathName(Path)


' FileSystemObject Constants '
'------------------------------------------------------------------------------' End Function

'[ constants for "GetSpecialFolder" function "folderspec" parameter ]' Public Function GetFileDateTime(ByVal FileName As String) As String
Private Const GSF_WINDOWSFOLDER As Long = 0
Private Const GSF_SYSTEMFOLDER As Long = 1 If FileExists(FileName) Then
Private Const GSF_TEMPORARYFOLDER As Long = 2 GetFileDateTime = FormatDate(FileDateTime(FileName))
Else
GetFileDateTime = vbNullString
'------------------------------------------------------------------------------' End If
' Windows API Function Declarations '
'------------------------------------------------------------------------------' End Function

Private Declare Function CloseHandle _ Public Function GetFileSize(ByVal FileName As String) As String
Lib "kernel32.dll" (ByVal hObject As Long) As Long
If FileExists(FileName) Then
Private Declare Function CreateFile _ GetFileSize = FormatSize(FileLen(FileName))
Lib "kernel32.dll" Alias "CreateFileA" ( _ Else
ByVal lpFileName As String, _ GetFileSize = vbNullString
ByVal dwDesiredAccess As Long, _ End If
ByVal dwShareMode As Long, _
ByVal lpSecurityAttributes As Long, _ End Function
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long _ Public Function GetPathFileName(ByVal Path As String) As String
) As Long Dim FSO As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
Private Declare Function SetFilePointer _ GetPathFileName = FSO.GetFileName(Path)
Lib "kernel32.dll" ( _ End Function
ByVal iFileHandler As Long, _
ByVal lDistanceToMove As Long, _
ByRef lpDistanceToMoveHigh As Long, _ Public Function GetPathFolderName(ByVal Path As String) As String
ByVal dwMoveMethod As Long _ Dim FSO As Object
) As Long Set FSO = CreateObject("Scripting.FileSystemObject")
GetPathFolderName = FSO.GetParentFolderName(Path)

Adaptive Digital Steganography for True-Color Bitmaps G-12


End Function pDst As Any, _
pSrc As Any, _
ByVal ByteLen As Long)
Public Function GetPrimaryDrive() As String
Dim FSO As Object
Set FSO = CreateObject("Scripting.FileSystemObject") '------------------------------------------------------------------------------'
GetPrimaryDrive = Left$(FSO.GetSpecialFolder(GSF_WINDOWSFOLDER), 2) & "\" ' Private Variables '
End Function '------------------------------------------------------------------------------'

Public Function SetFileDate(ByVal FileName As String, _ Private m_Stream() As Byte '[ bit stream array ]'
ByVal FileDate As Date) As Boolean Private m_Length As Long '[ bit stream length ]'

Dim STime As SYSTEMTIME


Dim FTime As FILETIME '------------------------------------------------------------------------------'
Dim hFile As Long ' Public Procedures '
'------------------------------------------------------------------------------'
'[ get data file date and time ]'
STime.wYear = Year(FileDate)
STime.wMonth = Month(FileDate) Public Sub Clear()
STime.wDay = Day(FileDate) Erase m_Stream
STime.wDayOfWeek = Weekday(FileDate) - 1 m_Length = 0
STime.wHour = Hour(FileDate) End Sub
STime.wMinute = Minute(FileDate)
STime.wSecond = Second(FileDate)
STime.wMilliseconds = 0 Public Function ExtractBits(ByVal BitCount As Long) As Long
SystemTimeToFileTime STime, FTime
If BitCount > 32 Then BitCount = 32
'[ set file attribute to normal ]'
On Error Resume Next If BitCount <= m_Length Then
SetAttr FileName, vbNormal
'[ decrement length ]'
'[ open source file ]' m_Length = m_Length - BitCount
hFile = CreateFile(FileName, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0)
ExtractBits = 0
'[ get file date and time ]'
If hFile <> -1 Then Dim Ctr As Long
SetFileTime hFile, 0, FTime, FTime For Ctr = 1 To BitCount
CloseHandle hFile
SetFileDate = True If Ctr < 32 Then
Else '[ add bit value ]'
SetFileDate = False If m_Stream(m_Length + Ctr) > 0 Then
End If ExtractBits = ExtractBits + Int(2 ^ (Ctr - 1))
End If
End Function Else
'[ if negative, compute two's complement ]'
If m_Stream(m_Length + Ctr) > 0 Then
Public Function WipeFile(ByVal FileName As String, ByVal Rename As Boolean) _ ExtractBits = (Not ExtractBits) + 1
As Boolean End If
End If
Dim FileName2 As String
Dim FileSize As Long Next Ctr
Dim hFile As Long
Dim Ctr As Long '[ resize stream ]'
Dim Pattern() As Byte If m_Length > 0 Then
Dim BytesWritten As Long ReDim Preserve m_Stream(1 To m_Length)
Else
On Error Resume Next Erase m_Stream
End If
'[ set file attribute to normal and retrieve file size ]'
SetAttr FileName, vbNormal End If
FileSize = FileLen(FileName)
End Function
'[ rename file and move to windows temporary folder ]'
If Rename Then
FileName2 = GenerateTempFile Public Function ExtractByte() As Byte
Kill FileName2
Name FileName As FileName2 If m_Length > 7 Then
Else
FileName2 = FileName '[ decrement length ]'
End If m_Length = m_Length - 8

On Error GoTo FileError '[ add bit values ]'


ExtractByte = 0
'[ open file with disk caching disabled ]' If m_Stream(m_Length + 1) > 0 Then ExtractByte = ExtractByte + 1
hFile = CreateFile(FileName2, GENERIC_WRITE, 0, 0, OPEN_EXISTING, _ If m_Stream(m_Length + 2) > 0 Then ExtractByte = ExtractByte + 2
FILE_FLAG_WRITE_THROUGH + FILE_FLAG_DELETE_ON_CLOSE + _ If m_Stream(m_Length + 3) > 0 Then ExtractByte = ExtractByte + 4
FILE_FLAG_SEQUENTIAL_SCAN, 0) If m_Stream(m_Length + 4) > 0 Then ExtractByte = ExtractByte + 8
If m_Stream(m_Length + 5) > 0 Then ExtractByte = ExtractByte + 16
'[ if file opened successfully, then wipe file ]' If m_Stream(m_Length + 6) > 0 Then ExtractByte = ExtractByte + 32
If hFile <> -1 Then If m_Stream(m_Length + 7) > 0 Then ExtractByte = ExtractByte + 64
If m_Stream(m_Length + 8) > 0 Then ExtractByte = ExtractByte + 128
ReDim Pattern(1 To FileSize, 1 To 3)
'[ resize stream ]'
'[ assign bit patterns ]' If m_Length > 0 Then
For Ctr = 1 To FileSize ReDim Preserve m_Stream(1 To m_Length)
Pattern(Ctr, 1) = &H55 '[ bit pattern 01010101 ]' Else
Pattern(Ctr, 2) = &HAA '[ bit pattern 10101010 ]' Erase m_Stream
Pattern(Ctr, 3) = &H0 '[ bit pattern 00000000 ]' End If
Next Ctr
End If
'[ write bit patterns to file ]'
For Ctr = 1 To 3 End Function
SetFilePointer hFile, 0, 0, FILE_BEGIN
WriteFile hFile, Pattern(1, Ctr), FileSize, BytesWritten, 0
Next Ctr Public Function ExtractString(ByVal CharCount As Long) As String
Dim Ctr As Long
'[ close and delete file ]' ExtractString = vbNullString
CloseHandle hFile For Ctr = 1 To CharCount
WipeFile = True ExtractString = ExtractString & Chr(ExtractByte)
Next Ctr
Exit Function End Function

End If
Public Sub InsertBitsAtEnd(ByVal Bits As Long, ByVal BitCount As Long)
FileError:
WipeFile = False If BitCount > 32 Then BitCount = 32

End Function '[ resize stream ]'


ReDim Preserve m_Stream(1 To (m_Length + BitCount))

'[ shift bits towards the top ]'


If m_Length > 0 Then
CopyMemory ByVal VarPtr(m_Stream(BitCount + 1)), _
ByVal VarPtr(m_Stream(1)), _
'------------------------------------------------------------------------------' m_Length
' ' End If
' Chameleon Image Steganography v1.2 '
' ' '[ insert bits in the stream ]'
' Bit Stream Class ' Dim Ctr As Long
' [BitStream] ' For Ctr = 1 To BitCount
' ' If Ctr < 32 Then
'------------------------------------------------------------------------------' If (Bits And Int(2 ^ (Ctr - 1))) > 0 Then
' ' m_Stream(Ctr) = 1
' Copyright (C) 2003 Mark David Gan ' Else
' ' m_Stream(Ctr) = 0
'------------------------------------------------------------------------------' End If
Else
If Bits < 0 Then
Option Explicit m_Stream(Ctr) = 1
Else
m_Stream(Ctr) = 0
'------------------------------------------------------------------------------' End If
' Windows API Function Declarations ' End If
'------------------------------------------------------------------------------' Next Ctr

'[ increment length ]'


Private Declare Sub CopyMemory _ m_Length = m_Length + BitCount
Lib "kernel32" Alias "RtlMoveMemory" ( _

Adaptive Digital Steganography for True-Color Bitmaps G-13


End Sub
'------------------------------------------------------------------------------'
' '
Public Sub InsertBitsAtTop(ByVal Bits As Long, ByVal BitCount As Long) ' Requires: FreeImage.dll '
' '
If BitCount > 32 Then BitCount = 32 ' The FreeImage Library (FreeImage.dll) is written by Floris van den Berg. '
' '
'[ resize stream ]' '------------------------------------------------------------------------------'
ReDim Preserve m_Stream(1 To (m_Length + BitCount))

'[ insert bits in the stream ]' Option Explicit


Dim Ctr As Long
For Ctr = 1 To BitCount
If Ctr < 32 Then '------------------------------------------------------------------------------'
If (Bits And Int(2 ^ (Ctr - 1))) > 0 Then ' Windows API Structure Data Types '
m_Stream(m_Length + Ctr) = 1 '------------------------------------------------------------------------------'
Else
m_Stream(m_Length + Ctr) = 0
End If '[ rgb color components ]'
Else Private Type RGBQUAD
If Bits < 0 Then rgbBlue As Byte
m_Stream(m_Length + Ctr) = 1 rgbGreen As Byte
Else rgbRed As Byte
m_Stream(m_Length + Ctr) = 0 rgbReserved As Byte
End If End Type
End If
Next Ctr '[ dib dimensions and color format ]'
Private Type BITMAPINFOHEADER
'[ increment length ]' biSize As Long
m_Length = m_Length + BitCount biWidth As Long
biHeight As Long
End Sub biPlanes As Integer
biBitCount As Integer
biCompression As Long
Public Sub InsertByteAtEnd(ByVal Bits As Byte) biSizeImage As Long
biXPelsPerMeter As Long
'[ resize stream ]' biYPelsPerMeter As Long
ReDim Preserve m_Stream(1 To (m_Length + 8)) biClrUsed As Long
biClrImportant As Long
'[ shift bits towards the top ]' End Type
If m_Length > 0 Then
CopyMemory ByVal VarPtr(m_Stream(9)), ByVal VarPtr(m_Stream(1)), m_Length '[ dib information ]'
End If Private Type BITMAPINFO
bmiHeader As BITMAPINFOHEADER
'[ insert bits in the stream ]' bmiColors() As RGBQUAD
m_Stream(8) = (Bits And &H80) \ &H80 End Type
m_Stream(7) = (Bits And &H40) \ &H40
m_Stream(6) = (Bits And &H20) \ &H20 '[ bitmap structure ]'
m_Stream(5) = (Bits And &H10) \ &H10 Private Type BITMAP
m_Stream(4) = (Bits And &H8) \ &H8 bmType As Long
m_Stream(3) = (Bits And &H4) \ &H4 bmWidth As Long
m_Stream(2) = (Bits And &H2) \ &H2 bmHeight As Long
m_Stream(1) = Bits And &H1 bmWidthBytes As Long
bmPlanes As Integer
'[ increment length ]' bmBitsPixel As Integer
m_Length = m_Length + 8 bmBits As Long
End Type
End Sub

'------------------------------------------------------------------------------'
Public Sub InsertByteAtTop(ByVal Bits As Byte) ' Windows API Constants '
'------------------------------------------------------------------------------'
'[ resize stream ]'
ReDim Preserve m_Stream(1 To (m_Length + 8))
'[ constant for "CreateDIBitmap" function "BitFlags" parameter ]'
'[ insert bits in the stream ]' Private Const CBM_INIT As Long = &H4
m_Stream(m_Length + 8) = (Bits And &H80) \ &H80
m_Stream(m_Length + 7) = (Bits And &H40) \ &H40 '[ color representation ]'
m_Stream(m_Length + 6) = (Bits And &H20) \ &H20 Private Const DIB_RGB_COLORS As Long = 0 '[ colors as rgb components ]'
m_Stream(m_Length + 5) = (Bits And &H10) \ &H10 Private Const DIB_PAL_COLORS As Long = 1 '[ colors as palette indexes ]'
m_Stream(m_Length + 4) = (Bits And &H8) \ &H8
m_Stream(m_Length + 3) = (Bits And &H4) \ &H4
m_Stream(m_Length + 2) = (Bits And &H2) \ &H2 '------------------------------------------------------------------------------'
m_Stream(m_Length + 1) = Bits And &H1 ' FreeImage Constants '
'------------------------------------------------------------------------------'
'[ increment length ]'
m_Length = m_Length + 8
'[ default load/save flags ]'
End Sub Private Const BMP_DEFAULT As Long = 0
Private Const CUT_DEFAULT As Long = 0
Private Const ICO_DEFAULT As Long = 0
Public Sub InsertStringAtEnd(ByVal Bits As String) Private Const IFF_DEFAULT As Long = 0
Dim Ctr As Long Private Const JPEG_DEFAULT As Long = 0
For Ctr = 1 To Len(Bits) Private Const KOALA_DEFAULT As Long = 0
InsertByteAtEnd Asc(Mid$(Bits, Ctr, 1)) Private Const LBM_DEFAULT As Long = 0
Next Ctr Private Const MNG_DEFAULT As Long = 0
End Sub Private Const PCD_DEFAULT As Long = 0
Private Const PCX_DEFAULT As Long = 0
Private Const PNG_DEFAULT As Long = 0
Public Sub InsertStringAtTop(ByVal Bits As String) Private Const PNM_DEFAULT As Long = 0
Dim Ctr As Long Private Const PSD_DEFAULT As Long = 0
For Ctr = Len(Bits) To 1 Step -1 Private Const RAS_DEFAULT As Long = 0
InsertByteAtTop Asc(Mid$(Bits, Ctr, 1)) Private Const TARGA_DEFAULT As Long = 0
Next Ctr Private Const TIFF_DEFAULT As Long = 0
End Sub Private Const WBMP_DEFAULT As Long = 0

'[ special load flags ]'


'------------------------------------------------------------------------------' Private Const ICO_FIRST As Long = 0
' Public Properties ' Private Const ICO_SECOND As Long = 0
'------------------------------------------------------------------------------' Private Const ICO_THIRD As Long = 0
Private Const JPEG_FAST As Long = 1
Private Const JPEG_ACCURATE As Long = 2
Public Property Get Length() As Long Private Const PCD_BASE As Long = 1 '[ PhotoCD, size 768 x 512 ]'
Length = m_Length Private Const PCD_BASEDIV4 As Long = 2 '[ PhotoCD, size 384 x 256 ]'
End Property Private Const PCD_BASEDIV16 As Long = 3 '[ PhotoCD, size 192 x 128 ]'
Private Const PNG_IGNOREGAMMA As Long = 1
Private Const TARGA_LOAD_RGB888 As Long = 1
'------------------------------------------------------------------------------'
' Event Handlers ' '[ special save flags ]'
'------------------------------------------------------------------------------' Private Const JPEG_QUALITYSUPERB As Long = &H80
Private Const JPEG_QUALITYGOOD As Long = &H100
Private Const JPEG_QUALITYNORMAL As Long = &H200
Private Sub Class_Initialize() Private Const JPEG_QUALITYAVERAGE As Long = &H400
Clear Private Const JPEG_QUALITYBAD As Long = &H800
End Sub Private Const PNM_SAVE_RAW As Long = 0
Private Const PNM_SAVE_ascii As Long = 1

Private Sub Class_Terminate()


Clear '------------------------------------------------------------------------------'
End Sub ' FreeImage Enumerated Data Types '
'------------------------------------------------------------------------------'

'[ image file format ]'


Public Enum FREE_IMAGE_FORMAT
FIF_UNKNOWN = -1 '[ unidentified bitmap type ]'
'------------------------------------------------------------------------------' FIF_BMP = 0 '[ windows or OS/2 bitmap file (*.bmp) ]'
' ' FIF_ICO = 1 '[ windows icon (*.ico) ]'
' Chameleon Image Steganography v1.2 ' FIF_JPEG = 2 '[ independent jpeg froup (*.jpg) ]'
' ' FIF_JNG = 3 '[ jpeg network graphics (*.jng) ]'
' FreeImage Library Wrapper Class ' FIF_KOALA = 4 '[ commodore 64 koala format (*.koa) ]'
' [FreeImageWrapper] ' FIF_IFF = 5 '[ amiga iff (*.iff, *.lbm) ]'
' ' FIF_MNG = 6 '[ multiple network graphics (*.mng) ]'
'------------------------------------------------------------------------------' FIF_PBM = 7 '[ portable bitmap (ascii) (*.pbm) ]'
' ' FIF_PBMRAW = 8 '[ portable bitmap (binary) (*.pbm) ]'
' Copyright (C) 2003 Mark David Gan ' FIF_PCD = 9 '[ kodak photocd (*.pcd) ]'
' ' FIF_PCX = 10 '[ pcx bitmap format (*.pcx) ]'
'------------------------------------------------------------------------------' FIF_PGM = 11 '[ portable graymap (ascii) (*.pgm) ]'
FIF_PGMRAW = 12 '[ portable graymap (binary) (*.pgm) ]'

Adaptive Digital Steganography for True-Color Bitmaps G-14


FIF_PNG = 13 '[ portable network Graphics (*.PNG) ]'
FIF_PPM = 14 '[ portable pixelmap (ascii) (*.PPM) ]' Private Declare Function FreeImage_GetBits _
FIF_PPMRAW = 15 '[ portable pixelmap (binary) (*.PPM) ]' Lib "FreeImage" Alias "_FreeImage_GetBits@4" ( _
FIF_RAS = 16 '[ sun rasterfile (*.ras) ]' ByVal hDIB As Long _
FIF_TARGA = 17 '[ targa files (*.tga) ]' ) As Long
FIF_TIFF = 18 '[ tagged image file format (*.tiff) ]'
FIF_WBMP = 19 '[ wireless bitmap (*.wbmp) ]' Private Declare Function FreeImage_GetBPP _
FIF_PSD = 20 '[ photoshop (*.psd) ]' Lib "FreeImage" Alias "_FreeImage_GetBPP@4" ( _
FIF_CUT = 21 '[ dr. halo (*.cut) ]' ByVal hDIB As Long _
End Enum ) As Long

Private Declare Function FreeImage_GetHeight _


'------------------------------------------------------------------------------' Lib "FreeImage" Alias "_FreeImage_GetHeight@4" ( _
' Windows API Function Declarations ' ByVal hDIB As Long _
'------------------------------------------------------------------------------' ) As Long

Private Declare Function FreeImage_GetInfo _


Private Declare Function CreateDIBitmap _ Lib "FreeImage" Alias "_FreeImage_GetInfo@4" ( _
Lib "gdi32" ( _ ByVal hDIB As Long _
ByVal hDC As Long, _ ) As Long
ByRef lpBITMAPINFOHEADER As Any, _
ByVal BitFlags As Long, _ Private Declare Function FreeImage_GetInfoHeader _
ByRef BmpBits As Any, _ Lib "FreeImage" Alias "_FreeImage_GetInfoHeader@4" ( _
ByRef lpBitmapInfo As Any, _ ByVal hDIB As Long _
ByVal fuUsage As Long _ ) As Long
) As Long
Private Declare Function FreeImage_GetPitch _
Private Declare Function DeleteObject _ Lib "FreeImage" Alias "_FreeImage_GetPitch@4" ( _
Lib "gdi32" (ByVal hObject As Long) As Boolean ByVal hDIB As Long _
) As Long
Private Declare Function GetBitmapBits _
Lib "gdi32" ( _ Private Declare Function FreeImage_GetWidth _
ByVal hBitmap As Long, _ Lib "FreeImage" Alias "_FreeImage_GetWidth@4" ( _
ByVal dwCount As Long, _ ByVal hDIB As Long _
BmpBits As Any _ ) As Long
) As Long

Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long '------------------------------------------------------------------------------'
' FreeImage Library Filetype Function Declarations '
Private Declare Function GetDesktopWindow Lib "user32" () As Long '------------------------------------------------------------------------------'

Private Declare Function GetDIBits _


Lib "gdi32" ( _ Private Declare Function FreeImage_GetFileType _
ByVal hDC As Long, _ Lib "FreeImage" Alias "_FreeImage_GetFileType@8" ( _
ByVal hBitmap As Long, _ ByVal FileName As String, _
ByVal StartingScanLine As Long, _ Optional ByVal size As Long = 16 _
ByVal ScanLineCount As Long, _ ) As FREE_IMAGE_FORMAT
ByRef lpBits As Any, _
ByRef lpBitmapInfo As Any, _ Private Declare Function FreeImage_GetFileTypeFromExt _
ByVal ColorUsage As Long _ Lib "FreeImage" Alias "_FreeImage_GetFileTypeFromExt@4" ( _
) As Long ByVal FileName As String _
) As FREE_IMAGE_FORMAT
Private Declare Function GetObject _
Lib "gdi32" Alias "GetObjectA" ( _ Private Declare Function FreeImage_GetFileTypeFromFormat _
ByVal hObject As Long, _ Lib "FreeImage" Alias "_FreeImage_GetFileTypeFromFormat@4" ( _
ByVal nCount As Long, _ ByVal FIF As FREE_IMAGE_FORMAT _
ByRef lpObject As Any _ ) As String
) As Long

Private Declare Function ReleaseDC _ '------------------------------------------------------------------------------'


Lib "user32" ( _ ' Public Procedures '
ByVal hWnd As Long, _ '------------------------------------------------------------------------------'
ByVal hDC As Long _
) As Long Public Function CreateBitmapFromDIB(ByVal hDIB As Long) As Long

Private Declare Function SetBitmapBits _ Dim BmpHead As Long


Lib "gdi32" ( _ Dim BmpInfo As Long
ByVal hBitmap As Long, _ Dim BmpBits As Long
ByVal dwCount As Long, _ Dim hDeskDC As Long
ByRef BmpBits As Any _ Dim hBmp As Long
) As Long
'[ get desktop dc ]'
Private Declare Function SetDIBitsToDevice _ hDeskDC = GetDC(GetDesktopWindow)
Lib "gdi32" ( _
ByVal Dest_hDC As Long, _ '[ get dib information ]'
ByVal Dest_X As Long, _ BmpHead = FreeImage_GetInfoHeader(hDIB)
ByVal Dest_Y As Long, _ BmpInfo = FreeImage_GetInfo(hDIB)
ByVal Src_Width As Long, _ BmpBits = FreeImage_GetBits(hDIB)
ByVal Src_Height As Long, _
ByVal Src_X As Long, _ '[ create screen-compatible bitmap based on dib ]'
ByVal Src_Y As Long, _ hBmp = CreateDIBitmap(hDeskDC, ByVal BmpHead, CBM_INIT, ByVal BmpBits, _
ByVal StartingScanLine As Long, _ ByVal BmpInfo, DIB_RGB_COLORS)
ByVal ScanLineCount As Long, _
ByRef BmpBits As Any, ByRef BmpInfo As Any, _ '[ return bitmap handle ]'
ByVal ColorUse As Long _ CreateBitmapFromDIB = hBmp
) As Long
'[ cleanup desktop dc ]'
ReleaseDC GetDesktopWindow, hDeskDC
'------------------------------------------------------------------------------'
' FreeImage Library General Function Declarations ' End Function
'------------------------------------------------------------------------------'

Public Function CreateDIBFromBitmap(ByVal hBmp As Long) As Long


Private Declare Sub FreeImage_DeInitialise _
Lib "FreeImage" Alias "_FreeImage_DeInitialise@0" () Dim BMP As BITMAP
Dim W As Long
Private Declare Sub FreeImage_Initialise _ Dim H As Long
Lib "FreeImage" Alias "_FreeImage_Initialise@4" ( _ Dim BPP As Long
Optional ByVal load_local_plugins_only As Boolean = False) Dim hDeskDC As Long
Dim hTmpDIB As Long
Dim BmpInfo As Long
'------------------------------------------------------------------------------' Dim BmpBits As Long
' FreeImage Library Bitmap Management Function Declarations ' Dim Res As Long
'------------------------------------------------------------------------------'
CreateDIBFromBitmap = 0

Private Declare Function FreeImage_Allocate _ '[ get bitmap information ]'


Lib "FreeImage" Alias "_FreeImage_Allocate@24" ( _ If GetObject(hBmp, Len(BMP), BMP) <> 0 Then
ByVal Width As Long, _
ByVal Height As Long, _ '[ get desktop dc ]'
ByVal BitsPerPixel As Long, _ W = BMP.bmWidth
Optional ByVal Red_Mask As Long = 0, _ H = BMP.bmHeight
Optional ByVal Green_Mask As Long = 0, _ BPP = 24
Optional ByVal Blue_Mask As Long = 0 _
) As Long '[ get desktop dc ]'
hDeskDC = GetDC(GetDesktopWindow)
Private Declare Function FreeImage_Load _
Lib "FreeImage" Alias "_FreeImage_Load@12" ( _ '[ allocate new dib ]'
ByVal FIF As FREE_IMAGE_FORMAT, _ hTmpDIB = FreeImage_Allocate(W, H, BPP)
ByVal FileName As String, _
Optional ByVal Flags As Long = 0 _ '[ get dib information ]'
) As Long BmpInfo = FreeImage_GetInfo(hTmpDIB)
BmpBits = FreeImage_GetBits(hTmpDIB)
Private Declare Function FreeImage_Save _
Lib "FreeImage" Alias "_FreeImage_Save@16" ( _ '[ set dib bits ]'
ByVal FIF As FREE_IMAGE_FORMAT, _ Res = GetDIBits(hDeskDC, hBmp, 0, H, ByVal BmpBits, ByVal BmpInfo, _
ByVal hDIB As Long, _ DIB_RGB_COLORS)
ByVal FileName As String, _
Optional ByVal Flags As Long = 0 _ If False Then
) As Boolean '[ cleanup dib ]'
FreeImage_Unload hTmpDIB
Private Declare Sub FreeImage_Unload _ Else
Lib "FreeImage" Alias "_FreeImage_Unload@4" (ByVal hDIB As Long) '[ return dib handle ]'
CreateDIBFromBitmap = hTmpDIB
End If
'------------------------------------------------------------------------------'
' FreeImage Library Bitmap Information Function Declarations ' '[ cleanup desktop dc ]'
'------------------------------------------------------------------------------' ReleaseDC GetDesktopWindow, hDeskDC

Adaptive Digital Steganography for True-Color Bitmaps G-15


End If '[ get bitmap structure ]'
GetObject hBmp, Len(BMP), BMP
End Function
'[ resize bitmap array ]'
ReDim Preserve PixelArray(0 To (BMP.bmWidthBytes \ BMP.bmWidth) - 1, _
Public Function DeleteBitmap(ByVal hBmp As Long) As Boolean 0 To BMP.bmWidth - 1, _
DeleteBitmap = DeleteObject(hBmp) 0 To BMP.bmHeight - 1) As Byte
End Function
'[ set bitmap bits from array ]'
SetBitmapBits hBmp, BMP.bmWidthBytes * BMP.bmHeight, _
Public Sub GetBitmapPixels(ByVal hBmp As Long, PixelArray() As Byte) PixelArray(0, 0, 0)

Dim BMP As BITMAP End Sub

'[ get bitmap structure ]'


GetObject hBmp, Len(BMP), BMP Public Sub UnloadDIB(hDIB As Long)
FreeImage_Unload hDIB
'[ resize bitmap array ]' End Sub
ReDim PixelArray(0 To (BMP.bmWidthBytes \ BMP.bmWidth) - 1, _
0 To BMP.bmWidth - 1, _
0 To BMP.bmHeight - 1) As Byte '------------------------------------------------------------------------------'
' Event Handlers '
'[ load bitmap bits to array ]' '------------------------------------------------------------------------------'
GetBitmapBits hBmp, BMP.bmWidthBytes * BMP.bmHeight, _
PixelArray(0, 0, 0)
Private Sub Class_Initialize()
End Sub ChDir App.Path
FreeImage_Initialise
End Sub
Public Function GetHeight(ByVal hDIB As Long) As Long
GetHeight = FreeImage_GetHeight(hDIB)
End Function Private Sub Class_Terminate()
FreeImage_DeInitialise
End Sub
Public Function GetWidth(ByVal hDIB As Long) As Long
GetWidth = FreeImage_GetWidth(hDIB)
End Function

Public Function GetFileType(ByVal FileName As String) As FREE_IMAGE_FORMAT


'------------------------------------------------------------------------------'
GetFileType = FreeImage_GetFileType(FileName) ' '
' Chameleon Image Steganography v1.2 '
If GetFileType = FIF_UNKNOWN Then ' '
GetFileType = FreeImage_GetFileTypeFromExt(FileName) ' High Frequency Timer Class '
End If ' [RealTimer] '
' '
End Function '------------------------------------------------------------------------------'
' '
' Copyright (C) 2003 Mark David Gan '
Public Function GetFileTypeString(ByVal FIF As FREE_IMAGE_FORMAT) As String ' '
GetFileTypeString = FreeImage_GetFileTypeFromFormat$(FIF) '------------------------------------------------------------------------------'
End Function

Option Explicit
Public Function LoadDIB(ByVal FileName As String, _
Optional ByRef FIF As Long) As Long
'------------------------------------------------------------------------------'
Dim Flg As Long ' Windows Timer Function Declarations '
'------------------------------------------------------------------------------'
'[ get format ]'
FIF = GetFileType(FileName)
Private Declare Function QueryPerformanceCounter _
'[ set load flags based on format ]' Lib "kernel32" (lpPerformanceCount As Currency) As Long
Select Case FIF
Case FIF_JPEG: Flg = JPEG_ACCURATE Private Declare Function QueryPerformanceFrequency _
Case FIF_PCD: Flg = PCD_BASE Lib "kernel32" (lpFrequency As Currency) As Long
Case FIF_PNG: Flg = PNG_IGNOREGAMMA
Case Else: Flg = 0
End Select '------------------------------------------------------------------------------'
' Private Variables '
'[ if format recognized, then load image ]' '------------------------------------------------------------------------------'
If FIF = FIF_UNKNOWN Then
LoadDIB = 0
Else Private m_Elapsed As Currency
LoadDIB = FreeImage_Load(FIF, FileName, Flg) Private m_Frequency As Currency
End If Private m_Start As Currency
Private m_Stop As Currency
End Function Private m_Supported As Boolean

Public Function PaintDIB(ByVal hDIB As Long, ByVal Dest_hDC As Long, _ '------------------------------------------------------------------------------'


Optional ByVal Dest_X As Long = 0, _ ' Public Properties '
Optional ByVal Dest_Y As Long = 0, _ '------------------------------------------------------------------------------'
Optional ByVal Src_Width As Long = -1, _
Optional ByVal Src_Height As Long = -1) As Boolean
Public Property Get CounterSupported() As Boolean
Dim W As Long CounterSupported = m_Supported
Dim H As Long End Property
Dim BmpBits As Long
Dim BmpInfo As Long
Dim Res As Long Public Property Get Frequency() As Currency
Frequency = m_Frequency
'[ get dimensions of dib ]' End Property
W = IIf(Src_Width > 0, Src_Width, FreeImage_GetWidth(hDIB))
H = IIf(Src_Height > 0, Src_Height, FreeImage_GetHeight(hDIB))
Public Property Get ElapsedTime() As Currency
'[ get memory address of dib bits ]' ElapsedTime = m_Elapsed
BmpBits = FreeImage_GetBits(hDIB) End Property
'[ get memory address of dib bitmap information ]'
BmpInfo = FreeImage_GetInfo(hDIB) Public Property Get ElapsedTimeInHours() As String
ElapsedTimeInHours = Format$((m_Elapsed \ 360000) Mod 100, "#00:") & _
'[ paint as bitmap ]' Format$((m_Elapsed \ 60000) Mod 60, "00:") & _
If (W > 0) And (H > 0) And (BmpBits) And (BmpInfo) Then Format$((m_Elapsed \ 1000) Mod 60, "00.") & _
Res = SetDIBitsToDevice(Dest_hDC, Dest_X, Dest_Y, W, H, 0, 0, 0, H, _ Format$(m_Elapsed Mod 1000, "000")
ByVal BmpBits, ByVal BmpInfo, DIB_RGB_COLORS) End Property
Else
Res = 0
End If Public Property Get ElapsedTimeInMinutes() As String
ElapsedTimeInMinutes = Format$((m_Elapsed \ 60000) Mod 100, "#00:") & _
PaintDIB = (Res <> 0) Format$((m_Elapsed \ 1000) Mod 60, "00.") & _
Format$(m_Elapsed Mod 1000, "000")
End Function End Property

Public Function SaveDIB(ByVal hDIB As Long, ByVal FileName As String, _ Public Property Get ElapsedTimeInSeconds() As String
ByVal FIF As FREE_IMAGE_FORMAT) As Long ElapsedTimeInSeconds = Format$((m_Elapsed \ 1000) Mod 100, "#00.") & _
Format$(m_Elapsed Mod 1000, "000")
Dim Flg As Long End Property
'[ set save flags ]'
Select Case FIF '------------------------------------------------------------------------------'
Case FIF_JPEG: Flg = JPEG_QUALITYSUPERB ' Public Procedures '
Case FIF_PBM: Flg = PNM_SAVE_RAW '------------------------------------------------------------------------------'
Case FIF_PGM: Flg = PNM_SAVE_RAW
Case FIF_PPM: Flg = PNM_SAVE_RAW
Case Else: Flg = 0 Public Sub Reset()
End Select QueryPerformanceCounter m_Start
End Sub
SaveDIB = FreeImage_Save(FIF, hDIB, FileName, Flg)

End Function Public Sub Mark()


QueryPerformanceCounter m_Stop
m_Elapsed = ((m_Stop - m_Start) / m_Frequency) * 1000
Public Sub SetBitmapPixels(ByVal hBmp As Long, PixelArray() As Byte) End Sub
Dim BMP As BITMAP
'------------------------------------------------------------------------------'

Adaptive Digital Steganography for True-Color Bitmaps G-16


' Event Handlers '
'------------------------------------------------------------------------------' '[ freeimage wrapper object ]'
Private Imager As FreeImageWrapper

Private Sub Class_Initialize() '[ dib handles ]'


m_Supported = QueryPerformanceFrequency(m_Frequency) Private m_StegoImageDIB As Long
QueryPerformanceCounter m_Start
End Sub '[ image properties ]'
Private m_ImageBits() As Byte
Private m_ImageWidth As Long
Private m_ImageHeight As Long
Private m_ImagePixels As Long

'[ data file properties ]'


'------------------------------------------------------------------------------' Private m_DataFileName As String
' ' Private m_DataFileDate As Date
' Chameleon Image Steganography v1.2 ' Private m_DataFileTime As FILETIME
' ' Private m_DataFileSize As Long
' Stegosystem Decoder Class ' Private m_DataFileChecksum As String
' [StegosystemDecoder] ' Private m_DataFileBits() As Byte
' '
'------------------------------------------------------------------------------' '[ password hash value stored with metadata ]'
' ' Private m_StoredPassword As String
' Copyright (C) 2003 Mark David Gan '
' ' '[ highest suitable address for metadata ]'
'------------------------------------------------------------------------------' Private m_MetadataMaxPosX As Long
Private m_MetadataMaxPosY As Long

'------------------------------------------------------------------------------' '[ starting address for metadata (color channel, horizontal, vertical) ]'
' ' Private m_MetadataPosC As Long
' Requires: FreeImageWrapper.cls ' Private m_MetadataPosX As Long
' FreeImage.dll ' Private m_MetadataPosY As Long
' '
'------------------------------------------------------------------------------' '[ current pixel position pointers (color channel, horizontal, vertical) ]'
Private m_PosC As Long
Private m_PosX(0 To 2) As Long
'------------------------------------------------------------------------------' Private m_PosY(0 To 2) As Long
' '
' Metadata Format: ' '[ abort process flag ]'
' Password SHA Hash Value - String - 20 Bytes ' Private m_Abort As Boolean
' Data File Name - String - 255 Bytes '
' Data File Date & Time - FILETIME - 8 Bytes '
' Data File Size - Long - 4 Bytes ' '------------------------------------------------------------------------------'
' Data File MD5 Checksum - String - 16 Bytes ' ' Public Properties '
' ' '------------------------------------------------------------------------------'
'------------------------------------------------------------------------------'
Public Property Get DataFileChecksum() As String
Option Explicit DataFileChecksum = m_DataFileChecksum
End Property

'------------------------------------------------------------------------------'
' Windows API Structure Data Types ' Public Property Get DataFileDate() As Date
'------------------------------------------------------------------------------' DataFileDate = m_DataFileDate
End Property

'[ 64-bit time structure ]'


Private Type FILETIME Public Property Get DataFileName() As String
dwLowDateTime As Long DataFileName = m_DataFileName
dwHighDateTime As Long End Property
End Type

'[ multiple-field time structure ]' Public Property Get DataFileSize() As Long
Private Type SYSTEMTIME DataFileSize = m_DataFileSize
wYear As Integer End Property
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer Public Property Get StegoImageDIB() As Long
wHour As Integer StegoImageDIB = m_StegoImageDIB
wMinute As Integer End Property
wSecond As Integer
wMilliseconds As Integer
End Type Public Property Get StoredPassword() As String
StoredPassword = m_StoredPassword
End Property
'------------------------------------------------------------------------------'
' Private Constants '
'------------------------------------------------------------------------------' '------------------------------------------------------------------------------'
' Private Properties '
'------------------------------------------------------------------------------'
'[ metadata bit length constants ]'
Private Const STOREDPASSWORD_BITS As Long = 160
Private Const FILENAME_BITS As Long = 2040 Private Property Get Pixel0() As Long
Private Const FILEDATEHIGH_BITS As Long = 32 '[ color value of current pixel ]'
Private Const FILEDATELOW_BITS As Long = 32 Pixel0 = m_ImageBits(m_PosC, m_PosX(m_PosC), m_PosY(m_PosC))
Private Const FILESIZE_BITS As Long = 32 End Property
Private Const FILECHECKSUM_BITS As Long = 128
Private Const METADATA_BITS As Long = STOREDPASSWORD_BITS + _
FILENAME_BITS + _ Private Property Get Pixel1() As Long
FILEDATEHIGH_BITS + _ '[ color value of middle-left pixel ]'
FILEDATELOW_BITS + _ Pixel1 = m_ImageBits(m_PosC, m_PosX(m_PosC) - 1, m_PosY(m_PosC))
FILESIZE_BITS + _ End Property
FILECHECKSUM_BITS

'[ metadata byte length constants ]' Private Property Get Pixel2() As Long
Private Const STOREDPASSWORD_BYTES As Long = 20 '[ color value of top-left pixel ]'
Private Const FILENAME_BYTES As Long = 255 Pixel2 = m_ImageBits(m_PosC, m_PosX(m_PosC) - 1, m_PosY(m_PosC) - 1)
Private Const FILEDATEHIGH_BYTES As Long = 4 End Property
Private Const FILEDATELOW_BYTES As Long = 4
Private Const FILESIZE_BYTES As Long = 4
Private Const FILECHECKSUM_BYTES As Long = 16 Private Property Get Pixel3() As Long
Private Const METADATA_BYTES As Long = STOREDPASSWORD_BYTES + _ '[ color value of top-middle pixel ]'
FILENAME_BYTES + _ Pixel3 = m_ImageBits(m_PosC, m_PosX(m_PosC), m_PosY(m_PosC) - 1)
FILEDATEHIGH_BYTES + _ End Property
FILEDATELOW_BYTES + _
FILESIZE_BYTES + _
FILECHECKSUM_BYTES Private Property Get Pixel4() As Long
'[ color value of top-right pixel ]'
'[ metadata progress report interval ]' Pixel4 = m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC) - 1)
Private Const METADATA_INTERVAL As Long = METADATA_BITS \ 100 End Property

'------------------------------------------------------------------------------' '------------------------------------------------------------------------------'
' Windows API Function Declarations ' ' Public Procedures '
'------------------------------------------------------------------------------' '------------------------------------------------------------------------------'

Private Declare Function FileTimeToSystemTime _ Public Function Abort()


Lib "kernel32" ( _ m_Abort = True
ByRef lpFileTime As FILETIME, _ End Function
ByRef lpSystemTime As SYSTEMTIME _
) As Long
Public Function Decode(ByVal PasswordHashMD5 As String) As Boolean
Private Declare Function GetInputState Lib "user32" () As Long
Dim hBmp As Long '[ temporary bitmap handle ]'
Dim Bits As Long '[ numeric value of bits extracted from pixel ]'
'------------------------------------------------------------------------------' Dim C As Long '[ pixel capacity ]'
' Public Events '
'------------------------------------------------------------------------------' Dim MetadataCtr As Long '[ number of extracted metadata bits ]'
Dim WriteCtr As Long '[ number of bits written on the data array ]'
Dim Interval As Long '[ progress event interval ]'
Public Event DataFileProgress(ByVal Processed As Long, ByVal Total As Long)
Public Event MetadataProgress(ByVal Processed As Long, ByVal Total As Long) Dim Buffer As BitStream '[ buffer for extracted bits ]'

'[ compute highest address in image where metadata can fit ]'
'------------------------------------------------------------------------------' m_MetadataMaxPosX = m_ImageWidth - METADATA_BITS
' Private Variables ' m_MetadataMaxPosY = m_ImageHeight - 1
'------------------------------------------------------------------------------'
Do While (m_MetadataMaxPosX < 0)

Adaptive Digital Steganography for True-Color Bitmaps G-17


m_MetadataMaxPosX = m_ImageWidth + m_MetadataMaxPosX Imager.GetBitmapPixels hBmp, m_ImageBits
m_MetadataMaxPosY = m_MetadataMaxPosY - 1
Loop '[ initialize prng with MD5 hash of password ]'
InitializePRNG PasswordHashMD5
'[ set progress event interval ]'
If m_DataFileSize < 200 Then '[ select starting address for the metadata bits ]'
Interval = 1 m_MetadataPosC = Int(Rnd * 3)
Else m_MetadataPosX = Int(Rnd * (m_MetadataMaxPosX + 1))
Interval = m_DataFileSize \ 100 m_MetadataPosY = Int(Rnd * (m_MetadataMaxPosY + 1))
End If
'[ initialize bit buffer ]'
'[ create temporary bitmap from the stego image dib ]' Set Buffer = New BitStream
hBmp = Imager.CreateBitmapFromDIB(m_StegoImageDIB)
'[ reset counters ]'
'[ copy bitmap bits to pixel array ]' MetadataCtr = 0
Imager.GetBitmapPixels hBmp, m_ImageBits
'[ set pixel position to starting address of metadata bits ]'
'[ initialize prng with MD5 hash of password ]' m_PosC = m_MetadataPosC
InitializePRNG PasswordHashMD5 m_PosX(m_PosC) = m_MetadataPosX
m_PosY(m_PosC) = m_MetadataPosY
'[ select starting address for the metadata bits ]'
m_MetadataPosC = Int(Rnd * 3) '[ extract metadata bits From the stego image ]'
m_MetadataPosX = Int(Rnd * (m_MetadataMaxPosX + 1)) Do While MetadataCtr < METADATA_BITS
m_MetadataPosY = Int(Rnd * (m_MetadataMaxPosY + 1))
If m_Abort Then
'[ initialize bit buffer ]' m_Abort = False
Set Buffer = New BitStream GoTo Cleanup
End If
'[ clear and resize data array ]'
ReDim m_DataFileBits(1 To m_DataFileSize) '[ get capacity ]'
PerformCapacityEvaluation C
'[ reset counters ]'
MetadataCtr = 0 If C > 0 Then
WriteCtr = 0
'[ store extracted metadata bits in the bit buffer ]'
ResetPixelPosition Bits = Pixel0 And ((2 ^ C) - 1)
Buffer.InsertBitsAtEnd Bits, C
'[ start extraction ]'
Do While WriteCtr < m_DataFileSize MetadataCtr = MetadataCtr + C
If MetadataCtr > METADATA_BITS Then MetadataCtr = METADATA_BITS
If m_Abort Then
m_Abort = False If (MetadataCtr Mod METADATA_INTERVAL) = 0 Then
GoTo Cleanup '[ report progress ]'
End If RaiseEvent MetadataProgress(MetadataCtr, METADATA_BITS)
DoEvents
'[ if no metadata is in the buffer ]' ElseIf GetInputState() Then
If MetadataCtr < 1 Then '[ allow other processes to execute ]'
DoEvents
'[ select a random color channel ]' End If
SelectPixelChannel
End If
'[ initialize countdown variable for metadata ]'
If (m_PosC = m_MetadataPosC) And _ SelectPixelCoordinate
(m_PosY(m_PosC) = m_MetadataPosY) And _
(m_PosX(m_PosC) = m_MetadataPosX) Then Loop
MetadataCtr = METADATA_BITS
End If '[ report completion ]'
If (MetadataCtr Mod METADATA_INTERVAL) > 0 Then
End If RaiseEvent MetadataProgress(MetadataCtr, METADATA_BITS)
End If
'[ get capacity ]'
PerformCapacityEvaluation C On Error Resume Next

If C > 0 Then '[ get information from metadata ]'


m_StoredPassword = Buffer.ExtractString(STOREDPASSWORD_BYTES)
'[ store extracted bits in the bit buffer ]' m_DataFileName = Trim$(Buffer.ExtractString(FILENAME_BYTES))
Bits = Pixel0 And ((2 ^ C) - 1) m_DataFileTime.dwHighDateTime = Buffer.ExtractBits(FILEDATEHIGH_BITS)
m_DataFileTime.dwLowDateTime = Buffer.ExtractBits(FILEDATELOW_BITS)
If MetadataCtr > 0 Then FileTimeToSystemTime m_DataFileTime, SysTime
MetadataCtr = MetadataCtr - C m_DataFileDate = DateSerial(SysTime.wYear, SysTime.wMonth, SysTime.wDay) + _
If MetadataCtr < 0 Then TimeSerial(SysTime.wHour, SysTime.wMinute, SysTime.wSecond)
C = Abs(MetadataCtr) m_DataFileSize = Buffer.ExtractBits(FILESIZE_BITS)
Buffer.InsertBitsAtEnd (Bits And ((2 ^ C) - 1)), C m_DataFileChecksum = Buffer.ExtractString(FILECHECKSUM_BYTES)
MetadataCtr = 0
End If Cleanup:
Else
Buffer.InsertBitsAtEnd Bits, C '[ cleanup temporary bitmap ]'
End If Imager.DeleteBitmap hBmp
Erase m_ImageBits
Do While Buffer.Length > 7
WriteCtr = WriteCtr + 1 End Sub
m_DataFileBits(WriteCtr) = CByte(Buffer.ExtractByte)
Loop
Public Function LoadStegoImage(ByVal FileName As String) As Boolean
End If
'[ create new dib for stego image ]'
SelectPixelCoordinate m_StegoImageDIB = Imager.LoadDIB(FileName)

If (WriteCtr Mod Interval) = 0 Then If m_StegoImageDIB = 0 Then


'[ signal progress ]' LoadStegoImage = False
RaiseEvent DataFileProgress(WriteCtr, m_DataFileSize) Else
DoEvents '[ get stego image dimensions ]'
ElseIf GetInputState() Then m_ImageWidth = Imager.GetWidth(m_StegoImageDIB)
'[ allow other processes to execute ]' m_ImageHeight = Imager.GetHeight(m_StegoImageDIB)
DoEvents m_ImagePixels = m_ImageWidth * m_ImageHeight * 3
End If LoadStegoImage = (m_ImagePixels > METADATA_BITS)
End If
Loop
End Function
'[ signal completion ]'
If (WriteCtr Mod Interval) > 0 Then
RaiseEvent DataFileProgress(WriteCtr, m_DataFileSize) Public Function SaveDataFile(ByVal FileName As String) As Boolean
End If
Dim FileIdx As Long
'[ return whether all bits have been extracted ]' On Error GoTo FileError
Decode = (WriteCtr >= m_DataFileSize)
'[ open data file ]'
Cleanup: FileIdx = FreeFile
Open FileName For Binary Access Write As FileIdx
'[ cleanup temporary bitmap ]'
Imager.DeleteBitmap hBmp '[ copy data file bits from data array ]'
Erase m_ImageBits Put FileIdx, , m_DataFileBits

End Function '[ close data file ]'


Close FileIdx

Public Sub DecodeMetadata(ByVal PasswordHashMD5 As String) SaveDataFile = True


Exit Function
Dim hBmp As Long '[ temporary bitmap handle ]'
Dim Bits As Long '[ numeric value of bits extracted from pixel ]' FileError:
Dim C As Long '[ pixel capacity ]' SaveDataFile = False
Dim Buffer As BitStream '[ buffer for extracted bits ]'
Dim SysTime As SYSTEMTIME '[ temporary variable for file date and time ]' End Function

Dim MetadataCtr As Long '[ number of extracted metadata bits ]'


'------------------------------------------------------------------------------'
'[ compute highest address in image where metadata can fit ]' ' Private Procedures '
m_MetadataMaxPosX = m_ImageWidth - METADATA_BITS '------------------------------------------------------------------------------'
m_MetadataMaxPosY = m_ImageHeight - 1

Do While (m_MetadataMaxPosX < 0) Private Sub InitializePRNG(ByVal Seed As String)


m_MetadataMaxPosX = m_ImageWidth + m_MetadataMaxPosX
m_MetadataMaxPosY = m_MetadataMaxPosY - 1 Dim Ctr As Long
Loop Dim Tmp As Single

'[ create temporary bitmap from the stego image dib ]' Rnd -1
hBmp = Imager.CreateBitmapFromDIB(m_StegoImageDIB) Randomize AscB(Left$(Seed, 1))

'[ copy bitmap bits to pixel array ]' For Ctr = 2 To Len(Seed)

Adaptive Digital Steganography for True-Color Bitmaps G-18


Tmp = Rnd
Rnd -1 '[ increment horizontal position ]'
Randomize Int(AscB(Mid$(Seed, Ctr, 1)) * Tmp) m_PosX(m_PosC) = m_PosX(m_PosC) + 1
Next Ctr
'[ increment vertical position ]'
End Sub If m_PosX(m_PosC) >= m_ImageWidth Then
m_PosX(m_PosC) = 0
m_PosY(m_PosC) = m_PosY(m_PosC) + 1
Private Sub PerformCapacityEvaluation(ByRef Capacity As Long) End If

'[ if current pixel is not at topmost row, then compute capacity ]' End Sub
If (m_PosY(m_PosC) > 0) Then

Dim Dif1 As Long '------------------------------------------------------------------------------'


Dim Dif2 As Long ' Event Handlers '
Dim Dif3 As Long '------------------------------------------------------------------------------'
Dim Dif4 As Long
Dim Avg As Long
Private Sub Class_Initialize()
'[ get difference of adjacent pairs formed by pixel1, pixel2, & pixel3 ]' Set Imager = New FreeImageWrapper
If m_PosX(m_PosC) > 0 Then m_StegoImageDIB = 0
Dif1 = Abs(Pixel3 - Pixel1) m_Abort = False
Dif2 = Abs(Pixel1 - Pixel2) End Sub
Dif3 = Abs(Pixel2 - Pixel3)
Else
Dif1 = 0 Private Sub Class_Terminate()
Dif2 = 0 On Error Resume Next
Dif3 = 0 Imager.UnloadDIB m_StegoImageDIB
End If Set Imager = Nothing
End Sub
'[ get difference of pixel3 and pixel4 ]'
If m_PosX(m_PosC) < (m_ImageWidth - 1) Then
Dif4 = Abs(Pixel3 - Pixel4)
Else
Dif4 = 0
End If
'------------------------------------------------------------------------------'
'[ compute average difference in color intensity ]' ' '
Avg = Round((Dif1 + Dif2 + Dif3 + Dif4) / 4) ' Chameleon Image Steganography v1.2 '
' '
'[ if c would not be equal to 0, compute hiding capacity of pixel ]' ' Stegosystem Encoder Class '
If Avg > 1 Then ' [StegosystemEncoder] '
' '
Dim C As Long '------------------------------------------------------------------------------'
Dim U As Long ' '
' Copyright (C) 2003 Mark David Gan '
'[ compute capacity (base-2 logarithm of average difference) ]' ' '
C = Int(Log(Avg) / Log(2)) '------------------------------------------------------------------------------'
If C > 4 Then
'------------------------------------------------------------------------------'
'[ compute upper boundary ]' ' '
If Pixel0 > 191 Then ' Requires: FreeImageWrapper.cls '
U = 5 ' FreeImage.dll '
Else ' '
U = 4 '------------------------------------------------------------------------------'
End If

'[ limit capacity by the upper boundary ]' '------------------------------------------------------------------------------'


If C < U Then ' '
Capacity = C ' Metadata Format: '
Else ' Password SHA Hash Value - String - 20 Bytes '
Capacity = U ' Data File Name - String - 255 Bytes '
End If ' Data File Date & Time - FILETIME - 8 Bytes '
' Data File Size - Long - 4 Bytes '
Else ' Data File MD5 Checksum - String - 16 Bytes '
' '
Capacity = C '------------------------------------------------------------------------------'
End If
Option Explicit
'[ if pixel in color channel of reserved area for metadata ]'
ElseIf m_PosC = m_MetadataPosC Then
'------------------------------------------------------------------------------'
If m_PosY(m_PosC) > m_MetadataMaxPosY Then ' Windows API Structure Data Types '
Capacity = 1 '------------------------------------------------------------------------------'
ElseIf (m_PosY(m_PosC) = m_MetadataMaxPosY) And _
(m_PosX(m_PosC) >= m_MetadataMaxPosX) Then
Capacity = 1 '[ 64-bit time structure ]'
Else Private Type FILETIME
Capacity = 0 dwLowDateTime As Long
End If dwHighDateTime As Long
End Type
Else
'[ multiple-field time structure ]'
Capacity = 0 Private Type SYSTEMTIME
wYear As Integer
End If wMonth As Integer
wDayOfWeek As Integer
'[ if current pixel is at topmost row ]' wDay As Integer
Else wHour As Integer
wMinute As Integer
'[ if pixel in color channel of reserved area for metadata ]' wSecond As Integer
If m_PosC = m_MetadataPosC Then wMilliseconds As Integer
End Type
If m_PosY(m_PosC) > m_MetadataMaxPosY Then
Capacity = 1
ElseIf (m_PosY(m_PosC) = m_MetadataMaxPosY) And _ '------------------------------------------------------------------------------'
(m_PosX(m_PosC) >= m_MetadataMaxPosX) Then ' Private Constants '
Capacity = 1 '------------------------------------------------------------------------------'
Else
Capacity = 0
End If '[ metadata bit length constants ]'
Private Const STOREDPASSWORD_BITS As Long = 160
Else Private Const FILENAME_BITS As Long = 2040
Private Const FILEDATEHIGH_BITS As Long = 32
Capacity = 0 Private Const FILEDATELOW_BITS As Long = 32
Private Const FILESIZE_BITS As Long = 32
End If Private Const FILECHECKSUM_BITS As Long = 128
Private Const METADATA_BITS As Long = STOREDPASSWORD_BITS + _
End If FILENAME_BITS + _
FILEDATEHIGH_BITS + _
End Sub FILEDATELOW_BITS + _
FILESIZE_BITS + _
FILECHECKSUM_BITS
Private Sub ResetPixelPosition()
m_PosC = 0
Erase m_PosX '------------------------------------------------------------------------------'
Erase m_PosY ' Windows API Function Declarations '
End Sub '------------------------------------------------------------------------------'

Private Sub SelectPixelChannel() Private Declare Function GetInputState Lib "user32" () As Long
'[ select random color channel ]' Private Declare Function SystemTimeToFileTime _
m_PosC = Int(Rnd * 3) Lib "kernel32" ( _
lpSystemTime As SYSTEMTIME, _
'[ if selected color channel is full, then select next ]' lpFileTime As FILETIME _
If m_PosY(m_PosC) >= m_ImageHeight Then ) As Long
m_PosC = (m_PosC + 1) Mod 3
If m_PosY(m_PosC) >= m_ImageHeight Then
m_PosC = (m_PosC + 1) Mod 3 '------------------------------------------------------------------------------'
End If ' Public Events '
End If '------------------------------------------------------------------------------'
End Sub
Public Event Progress(ByVal Processed As Long, ByVal Total As Long)
Private Sub SelectPixelCoordinate()

Adaptive Digital Steganography for True-Color Bitmaps G-19


'------------------------------------------------------------------------------' Private Property Get Pixel6() As Long
' Private Variables ' '[ color value of current bottom-right pixel ]'
'------------------------------------------------------------------------------' Pixel6 = m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC) + 1)
End Property

'[ freeimage wrapper object ]'


Private Imager As FreeImageWrapper Private Property Let Pixel6(New_Pixel6 As Long)
'[ color value of current bottom-right pixel ]'
'[ dib handles ]' If New_Pixel6 > 255 Then
Private m_CoverImageDIB As Long m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC) + 1) = 255
Private m_StegoImageDIB As Long ElseIf New_Pixel6 < 0 Then
m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC) + 1) = 0
'[ image properties ]' Else
Private m_ImageBits() As Byte m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC) + 1) = New_Pixel6
Private m_ImageWidth As Long End If
Private m_ImageHeight As Long End Property
Private m_ImagePixels As Long
Private m_ImageCapacity As Long
Private Property Get Pixel7() As Long
'[ data file properties ]' '[ color value of bottom-middle pixel ]'
Private m_DataFileName As String Pixel7 = m_ImageBits(m_PosC, m_PosX(m_PosC), m_PosY(m_PosC) + 1)
Private m_DataFileDate As Date End Property
Private m_DataFileTime As FILETIME
Private m_DataFileSize As Long
Private m_DataFileChecksum As String Private Property Let Pixel7(New_Pixel7 As Long)
Private m_DataFileBits() As Byte '[ color value of bottom-middle pixel ]'
If New_Pixel7 > 255 Then
'[ highest suitable address for metadata ]' m_ImageBits(m_PosC, m_PosX(m_PosC), m_PosY(m_PosC) + 1) = 255
Private m_MetadataMaxPosX As Long ElseIf New_Pixel7 < 0 Then
Private m_MetadataMaxPosY As Long m_ImageBits(m_PosC, m_PosX(m_PosC), m_PosY(m_PosC) + 1) = 0
Else
'[ starting address for metadata (color channel, horizontal, vertical) ]' m_ImageBits(m_PosC, m_PosX(m_PosC), m_PosY(m_PosC) + 1) = New_Pixel7
Private m_MetadataPosC As Long End If
Private m_MetadataPosX As Long End Property
Private m_MetadataPosY As Long

'[ current pixel position pointers (color channel, horizontal, vertical) ]' Private Property Get Pixel8() As Long
Private m_PosC As Long '[ color value of bottom-left pixel ]'
Private m_PosX(0 To 2) As Long Pixel8 = m_ImageBits(m_PosC, m_PosX(m_PosC) - 1, m_PosY(m_PosC) + 1)
Private m_PosY(0 To 2) As Long End Property

'[ abort process flag ]'


Private m_Abort As Boolean Private Property Let Pixel8(New_Pixel8 As Long)
'[ color value of bottom-left pixel ]'
If New_Pixel8 > 255 Then
'------------------------------------------------------------------------------' m_ImageBits(m_PosC, m_PosX(m_PosC) - 1, m_PosY(m_PosC) + 1) = 255
' Public Properties ' ElseIf New_Pixel8 < 0 Then
'------------------------------------------------------------------------------' m_ImageBits(m_PosC, m_PosX(m_PosC) - 1, m_PosY(m_PosC) + 1) = 0
Else
m_ImageBits(m_PosC, m_PosX(m_PosC) - 1, m_PosY(m_PosC) + 1) = New_Pixel8
Public Property Get CoverImageDIB() As Long End If
CoverImageDIB = m_CoverImageDIB End Property
End Property

'------------------------------------------------------------------------------'
Public Property Get DataFileDate() As Date ' Public Procedures '
DataFileDate = m_DataFileDate '------------------------------------------------------------------------------'
End Property

Public Function Abort()


Public Property Get DataFileName() As String m_Abort = True
DataFileName = m_DataFileName End Function
End Property

Public Function Encode(ByVal PasswordHashMD5 As String, _


Public Property Get DataFileSize() As Long ByVal PasswordHashSHA As String) As Boolean
DataFileSize = m_DataFileSize
End Property Dim hBmp As Long '[ temporary bitmap handle ]'
Dim Bits As Long '[ numeric value of bits to be embedded ]'
Dim C As Long '[ pixel capacity ]'
Public Property Get ImageCapacity() As Long Dim E As Long '[ embedding error ]'
ImageCapacity = m_ImageCapacity
End Property Dim MetadataCtr As Long '[ number of metadata bits in the buffer ]'
Dim ReadCtr As Long '[ number of bytes read from the data file ]'
Dim EmbedCtr As Long '[ number of bits embedded in the image ]'
Public Property Get StegoImageDIB() As Long Dim PixelCtr As Long '[ number of pixels processed ]'
StegoImageDIB = m_StegoImageDIB Dim Interval As Long '[ progress event interval ]'
End Property
Dim Buffer As BitStream '[ buffer for bits to be embedded ]'

'------------------------------------------------------------------------------' '[ compute highest address in image where metadata can fit ]'
' Private Properties ' m_MetadataMaxPosX = m_ImageWidth - METADATA_BITS
'------------------------------------------------------------------------------' m_MetadataMaxPosY = m_ImageHeight - 1

Do While (m_MetadataMaxPosX < 0)


Private Property Get Pixel0() As Long m_MetadataMaxPosX = m_ImageWidth + m_MetadataMaxPosX
'[ color value of current pixel ]' m_MetadataMaxPosY = m_MetadataMaxPosY - 1
Pixel0 = m_ImageBits(m_PosC, m_PosX(m_PosC), m_PosY(m_PosC)) Loop
End Property
'[ set progress event interval ]'
If m_ImagePixels < 200 Then
Private Property Let Pixel0(New_Pixel0 As Long) Interval = 1
'[ color value of current pixel ]' Else
m_ImageBits(m_PosC, m_PosX(m_PosC), m_PosY(m_PosC)) = New_Pixel0 Interval = m_ImagePixels \ 100
End Property End If

'[ create temporary bitmap from the cover image dib ]'
Private Property Get Pixel1() As Long hBmp = Imager.CreateBitmapFromDIB(m_CoverImageDIB)
'[ color value of middle-left pixel ]'
Pixel1 = m_ImageBits(m_PosC, m_PosX(m_PosC) - 1, m_PosY(m_PosC)) '[ copy bitmap bits to pixel array ]'
End Property Imager.GetBitmapPixels hBmp, m_ImageBits

'[ initialize prng with MD5 hash of password ]'


Private Property Get Pixel2() As Long InitializePRNG PasswordHashMD5
'[ color value of top-left pixel ]'
Pixel2 = m_ImageBits(m_PosC, m_PosX(m_PosC) - 1, m_PosY(m_PosC) - 1) '[ select starting address for the metadata bits ]'
End Property m_MetadataPosC = Int(Rnd * 3)
m_MetadataPosX = Int(Rnd * (m_MetadataMaxPosX + 1))
m_MetadataPosY = Int(Rnd * (m_MetadataMaxPosY + 1))
Private Property Get Pixel3() As Long
'[ color value of top-middle pixel ]' '[ initialize bit buffer ]'
Pixel3 = m_ImageBits(m_PosC, m_PosX(m_PosC), m_PosY(m_PosC) - 1) Set Buffer = New BitStream
End Property
'[ reset counters ]'
MetadataCtr = 0
Private Property Get Pixel4() As Long ReadCtr = 0
'[ color value of top-right pixel ]' EmbedCtr = 0
Pixel4 = m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC) - 1) PixelCtr = 0
End Property
ResetPixelPosition

Private Property Get Pixel5() As Long '[ start embedding ]'


'[ color value of middle-right pixel ]' For PixelCtr = 1 To m_ImagePixels
Pixel5 = m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC))
End Property If m_Abort Then
m_Abort = False
GoTo Cleanup
Private Property Let Pixel5(New_Pixel5 As Long) End If
'[ color value of middle-right pixel ]'
If New_Pixel5 > 255 Then '[ if no metadata is in the buffer ]'
m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC)) = 255 If MetadataCtr < 1 Then
ElseIf New_Pixel5 < 0 Then
m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC)) = 0 '[ select a random color channel ]'
Else SelectPixelChannel
m_ImageBits(m_PosC, m_PosX(m_PosC) + 1, m_PosY(m_PosC)) = New_Pixel5
End If '[ insert metadata bits at the start of the bit buffer ]'
End Property If (m_PosC = m_MetadataPosC) And _
(m_PosY(m_PosC) = m_MetadataPosY) And _
(m_PosX(m_PosC) = m_MetadataPosX) Then

Adaptive Digital Steganography for True-Color Bitmaps G-20


MetadataCtr = METADATA_BITS '[ copy data file bits to data array ]'
Buffer.InsertStringAtTop m_DataFileChecksum ReDim m_DataFileBits(1 To m_DataFileSize)
Buffer.InsertBitsAtTop m_DataFileSize, FILESIZE_BITS Get FileIdx, , m_DataFileBits
Buffer.InsertBitsAtTop m_DataFileTime.dwLowDateTime, FILEDATELOW_BITS
Buffer.InsertBitsAtTop m_DataFileTime.dwHighDateTime, FILEDATEHIGH_BITS '[ close data file ]'
Buffer.InsertStringAtTop m_DataFileName Close FileIdx
Buffer.InsertStringAtTop PasswordHashSHA
End If LoadDataFile = True
Exit Function
End If
FileError:
'[ get capacity ]' LoadDataFile = False
PerformCapacityEvaluation C
End Function
If C > 0 Then

If Buffer.Length < C Then Public Function SaveStegoImage(ByVal FileName As String, _


ByVal Format As FREE_IMAGE_FORMAT) As Boolean
If ReadCtr < m_DataFileSize Then SaveStegoImage = Imager.SaveDIB(m_StegoImageDIB, FileName, Format)
'[ insert data bits at the end of the bit buffer ]' End Function
ReadCtr = ReadCtr + 1
Buffer.InsertByteAtEnd m_DataFileBits(ReadCtr)
Else '------------------------------------------------------------------------------'
'[ insert random bits at the end of the bit buffer ]' ' Private Procedures '
Buffer.InsertByteAtEnd Int(Rnd * 256) '------------------------------------------------------------------------------'
End If

End If Private Sub InitializePRNG(ByVal Seed As String)

'[ select bits to embed ] ' Dim Ctr As Long


Bits = Buffer.ExtractBits(C) Dim Tmp As Single

'[ embed with minimum error ] ' Rnd -1


E = PerformMinimumErrorReplacement(Bits, C) Randomize AscB(Left$(Seed, 1))

'[ diffuse embedding error ] ' For Ctr = 2 To Len(Seed)


PerformErrorDiffusion E Tmp = Rnd
Rnd -1
'[ increment embedded bits counter ] ' Randomize Int(AscB(Mid$(Seed, Ctr, 1)) * Tmp)
EmbedCtr = EmbedCtr + C Next Ctr

'[ decrement metadata counter ] ' End Sub


If MetadataCtr > 0 Then MetadataCtr = MetadataCtr - C

End If Private Sub PerformCapacityEvaluation(ByRef Capacity As Long)

SelectPixelCoordinate '[ if current pixel is not at topmost row, then compute capacity ]'
If (m_PosY(m_PosC) > 0) Then
If (PixelCtr Mod Interval) = 0 Then
'[ report progress ]' Dim Dif1 As Long
RaiseEvent Progress(PixelCtr, m_ImagePixels) Dim Dif2 As Long
DoEvents Dim Dif3 As Long
ElseIf GetInputState() Then Dim Dif4 As Long
'[ allow other processes to execute ]' Dim Avg As Long
DoEvents
End If '[ get difference of adjacent pairs formed by pixel1, pixel2, & pixel3 ]'
If m_PosX(m_PosC) > 0 Then
Next PixelCtr Dif1 = Abs(Pixel3 - Pixel1)
Dif2 = Abs(Pixel1 - Pixel2)
'[ report completion ]' Dif3 = Abs(Pixel2 - Pixel3)
If (PixelCtr Mod Interval) > 0 Then Else
RaiseEvent Progress(PixelCtr, m_ImagePixels) Dif1 = 0
End If Dif2 = 0
Dif3 = 0
'[ update temporary bitmap with contents of pixel array ]' End If
Imager.SetBitmapPixels hBmp, m_ImageBits
'[ get difference of pixel3 and pixel4 ]'
'[ create stego dib from temporary bitmap ]' If m_PosX(m_PosC) < (m_ImageWidth - 1) Then
m_StegoImageDIB = Imager.CreateDIBFromBitmap(hBmp) Dif4 = Abs(Pixel3 - Pixel4)
Else
'[ compute net image capacity in bytes ]' Dif4 = 0
m_ImageCapacity = (EmbedCtr - METADATA_BITS) \ 8 End If

'[ return whether all data file bits have been embedded ]' '[ compute average difference in color intensity ]'
Encode = (m_ImageCapacity >= m_DataFileSize) Avg = Round((Dif1 + Dif2 + Dif3 + Dif4) / 4)

Cleanup: '[ if c would not be equal to 0, compute hiding capacity of pixel ]'
If Avg > 1 Then
'[ unload temporary bitmap ]'
Imager.DeleteBitmap hBmp Dim C As Long
Erase m_ImageBits Dim U As Long

End Function '[ compute capacity (base-2 logarithm of average difference) ]'
C = Int(Log(Avg) / Log(2))

Public Function LoadCoverImage(ByVal FileName As String) As Boolean If C > 4 Then

'[ create new dib for cover image ]' '[ compute upper boundary ]'
m_CoverImageDIB = Imager.LoadDIB(FileName) If Pixel0 > 191 Then
U = 5
If m_CoverImageDIB = 0 Then Else
LoadCoverImage = False U = 4
Else End If
'[ get cover image dimensions ]'
m_ImageWidth = Imager.GetWidth(m_CoverImageDIB) '[ limit capacity by the upper boundary ]'
m_ImageHeight = Imager.GetHeight(m_CoverImageDIB) If C < U Then
m_ImagePixels = m_ImageWidth * m_ImageHeight * 3 Capacity = C
LoadCoverImage = (m_ImagePixels > METADATA_BITS) Else
End If Capacity = U
End If
m_ImageCapacity = 0
Else
End Function
Capacity = C

Public Function LoadDataFile(ByVal FileName As String, _ End If


ByVal StoredFileName As String, _
ByVal StoredFileDate As Date, _ '[ if pixel in color channel of reserved area for metadata ]'
ByVal Checksum As String) ElseIf m_PosC = m_MetadataPosC Then

Dim FileIdx As Long If m_PosY(m_PosC) > m_MetadataMaxPosY Then


Dim SysTime As SYSTEMTIME Capacity = 1
ElseIf (m_PosY(m_PosC) = m_MetadataMaxPosY) And _
'[ get data file stored file name ]' (m_PosX(m_PosC) >= m_MetadataMaxPosX) Then
m_DataFileName = Format$(StoredFileName, "!" & String$(255, "@")) Capacity = 1
Else
'[ get data file date and time ]' Capacity = 0
m_DataFileDate = StoredFileDate End If
SysTime.wYear = Year(m_DataFileDate)
SysTime.wMonth = Month(m_DataFileDate) Else
SysTime.wDay = Day(m_DataFileDate)
SysTime.wDayOfWeek = Weekday(m_DataFileDate) - 1 Capacity = 0
SysTime.wHour = Hour(m_DataFileDate)
SysTime.wMinute = Minute(m_DataFileDate) End If
SysTime.wSecond = Second(m_DataFileDate)
SysTime.wMilliseconds = 0 '[ if current pixel is at topmost row ]'
SystemTimeToFileTime SysTime, m_DataFileTime Else

'[ get data file checksum ]' '[ if pixel in color channel of reserved area for metadata ]'
m_DataFileChecksum = Checksum If m_PosC = m_MetadataPosC Then

'[ open data file ]' If m_PosY(m_PosC) > m_MetadataMaxPosY Then


FileIdx = FreeFile Capacity = 1
On Error GoTo FileError ElseIf (m_PosY(m_PosC) = m_MetadataMaxPosY) And _
Open FileName For Binary Access Read As FileIdx (m_PosX(m_PosC) >= m_MetadataMaxPosX) Then
Capacity = 1
'[ get data file size ]' Else
m_DataFileSize = LOF(FileIdx) Capacity = 0
End If

Adaptive Digital Steganography for True-Color Bitmaps G-21


Else

Capacity = 0
'------------------------------------------------------------------------------'
End If ' '
' Chameleon Image Steganography v1.2 '
End If ' '
' Custom Button User Control '
End Sub ' [CustomButton] '
' '
'------------------------------------------------------------------------------'
Private Sub PerformErrorDiffusion(ByVal EmbeddingError As Long) ' '
' Copyright (C) 2003 Mark David Gan '
If EmbeddingError > 3 Then ' '
'------------------------------------------------------------------------------'
Dim E As Long

'[ get fraction of embedding error ]' '------------------------------------------------------------------------------'


E = EmbeddingError \ 4 ' '
' Requires: modCustomButton.bas '
'[ distribute embedding error among neighboring pixels ]' ' '
If m_PosY(m_PosC) < (m_ImageHeight - 1) Then '------------------------------------------------------------------------------'
If m_PosX(m_PosC) < (m_ImageWidth - 1) Then
Pixel5 = Pixel5 - E Option Explicit
Pixel6 = Pixel6 - E
End If
'------------------------------------------------------------------------------'
Pixel7 = Pixel7 - E ' Windows API Structure Data Types '
'------------------------------------------------------------------------------'
If m_PosX(m_PosC) > 0 Then
Pixel8 = Pixel8 - E
End If '[ pixel coordinates structure ]'
Private Type POINTAPI
ElseIf m_PosX(m_PosC) < (m_ImageWidth - 1) Then X As Long
Y As Long
Pixel5 = Pixel5 - E End Type
End If '[ rectangular coordinates structure ]'
Private Type RECT
End If Left As Long
top As Long
End Sub Right As Long
Bottom As Long
End Type
Private Function PerformMinimumErrorReplacement(ByVal Bits As Long, _
ByVal Capacity As Long) '[ font layout information ]'
Private Type TEXTMETRIC
Dim Mask As Long tmHeight As Long
Dim Value0 As Long tmAscent As Long
Dim Value1 As Long tmDescent As Long
Dim Value2 As Long tmInternalLeading As Long
Dim Error1 As Long tmExternalLeading As Long
Dim Error2 As Long tmAveCharWidth As Long
tmMaxCharWidth As Long
Value0 = Pixel0 tmWeight As Long
tmOverhang As Long
'[ compute new color value with rightmost Unreplaced bit set to 0 ]' tmDigitizedAspectX As Long
Mask = Not ((2 ^ (Capacity + 1)) - 1) tmDigitizedAspectY As Long
Value1 = (Value0 And Mask) Or Bits tmFirstChar As Byte
Error1 = Value1 - Value0 tmLastChar As Byte
tmDefaultChar As Byte
'[ compute new color value with rightmost Unreplaced bit set to 1 ]' tmBreakChar As Byte
Value2 = Value1 Or (2 ^ Capacity) tmItalic As Byte
Error2 = Value2 - Value0 tmUnderlined As Byte
tmStruckOut As Byte
'[ select color value with less embedding Error ]' tmPitchAndFamily As Byte
If Abs(Error1) < Abs(Error2) Then tmCharSet As Byte
Pixel0 = Value1 End Type
PerformMinimumErrorReplacement = Error1
Else
Pixel0 = Value2 '------------------------------------------------------------------------------'
PerformMinimumErrorReplacement = Error2 ' Public Enumerated Data Types '
End If '------------------------------------------------------------------------------'
End Function
'[ mask style enumeration ]'
Public Enum cbtnMaskStyleConstants
Private Sub ResetPixelPosition() cbtnMaskStyleNone = 0
m_PosC = 0 cbtnMaskStyleAuto = 1
Erase m_PosX cbtnMaskStyleCustom = 2
Erase m_PosY End Enum
End Sub

'[ Button State Enumeration ]'


Private Sub SelectPixelChannel() Public Enum cbtnStateConstants
cbtnStateNormal = 0
'[ select random color channel ]' cbtnStateHover = 1
m_PosC = Int(Rnd * 3) cbtnStatePressed = 2
End Enum
'[ if selected color channel is full, then select next ]'
If m_PosY(m_PosC) >= m_ImageHeight Then
m_PosC = (m_PosC + 1) Mod 3 '------------------------------------------------------------------------------'
If m_PosY(m_PosC) >= m_ImageHeight Then ' Windows API Constants '
m_PosC = (m_PosC + 1) Mod 3 '------------------------------------------------------------------------------'
End If
End If
'[ constants for "DrawEdge" function "edge" parameter ]'
End Sub Private Const BDR_INNER As Long = &HC
Private Const BDR_OUTER As Long = &H3
Private Const BDR_RAISED As Long = &H5
Private Sub SelectPixelCoordinate() Private Const BDR_RAISEDINNER As Long = &H4
Private Const BDR_RAISEDOUTER As Long = &H1
'[ increment horizontal position ]' Private Const BDR_SUNKEN As Long = &HA
m_PosX(m_PosC) = m_PosX(m_PosC) + 1 Private Const BDR_SUNKENINNER As Long = &H8
Private Const BDR_SUNKENOUTER As Long = &H2
'[ if x exceeds width, then increment vertical position and reset x ]'
If m_PosX(m_PosC) >= m_ImageWidth Then '[ constants for "DrawEdge" function "edge" parameter ]'
m_PosX(m_PosC) = 0 Private Const EDGE_BUMP As Long = (BDR_RAISEDOUTER + BDR_SUNKENINNER)
m_PosY(m_PosC) = m_PosY(m_PosC) + 1 Private Const EDGE_ETCHED As Long = (BDR_SUNKENOUTER + BDR_RAISEDINNER)
End If Private Const EDGE_RAISED As Long = (BDR_RAISEDOUTER + BDR_RAISEDINNER)
Private Const EDGE_SUNKEN As Long = (BDR_SUNKENOUTER + BDR_SUNKENINNER)
End Sub
'[ constants for "DrawEdge" function "grfFlags" parameter ]'
Private Const BF_LEFT As Long = &H1
'------------------------------------------------------------------------------' Private Const BF_BOTTOM As Long = &H8
' Event Handlers ' Private Const BF_RIGHT As Long = &H4
'------------------------------------------------------------------------------' Private Const BF_TOP As Long = &H2
Private Const BF_RECT As Long = (BF_LEFT + BF_TOP + BF_RIGHT + BF_BOTTOM)
Private Sub Class_Initialize() '[ constants for "DrawStatePic" function "flags" parameter ]'
Set Imager = New FreeImageWrapper '[ constants for "DrawStateTxt" function "flags" parameter ]'
m_CoverImageDIB = 0 Private Const DSS_NORMAL As Long = &H0
m_StegoImageDIB = 0 Private Const DSS_DISABLED As Long = &H20
m_ImageCapacity = 0
m_DataFileSize = 0 '[ constants for "DrawStatePic" function "flags" parameter ]'
m_Abort = False '[ constants for "DrawStateTxt" function "flags" parameter ]'
End Sub Private Const DST_PREFIXTEXT As Long = &H2
Private Const DST_ICON As Long = &H3
Private Const DST_BITMAP As Long = &H4
Private Sub Class_Terminate()
On Error Resume Next '[ constants for "SetBkMode" function "nBkMode" parameter ]'
Imager.UnloadDIB m_CoverImageDIB Private Const BACKMODE_OPAQUE As Long = 0
Imager.UnloadDIB m_StegoImageDIB Private Const BACKMODE_TRANSPARENT As Long = 1
Set Imager = Nothing
End Sub
'------------------------------------------------------------------------------'
' Windows API Function Declarations '

Adaptive Digital Steganography for True-Color Bitmaps G-22


'------------------------------------------------------------------------------' Lib "gdi32" ( _
ByVal hDC As Long, _
ByVal X As Long, _
Private Declare Function BitBlt _ ByVal Y As Long, _
Lib "gdi32" ( _ ByVal crColor As Long _
ByVal hDestDC As Long, _ ) As Long
ByVal X As Long, _
ByVal Y As Long, _ Private Declare Function SetTextColor _
ByVal nWidth As Long, _ Lib "gdi32" ( _
ByVal nHeight As Long, _ ByVal hDC As Long, _
ByVal hSrcDC As Long, _ ByVal crColor As Long _
ByVal xSrc As Long, _ ) As Long
ByVal ySrc As Long, _
ByVal dwRop As Long _
) As Long '------------------------------------------------------------------------------'
' Public Events '
Private Declare Function CreateCompatibleBitmap _ '------------------------------------------------------------------------------'
Lib "gdi32" ( _
ByVal hDC As Long, _
ByVal nWidth As Long, _ Public Event Click()
ByVal nHeight As Long _ Public Event KeyDown(KeyCode As Integer, Shift As Integer)
) As Long Public Event KeyUp(KeyCode As Integer, Shift As Integer)
Public Event MouseDown(Button As Integer, Shift As Integer, X As Single, _
Private Declare Function CreateCompatibleDC _ Y As Single)
Lib "gdi32" (ByVal hDC As Long) As Long Public Event MouseHover()
Public Event MouseLeave()
Private Declare Function CreateFont _ Public Event MouseMove(Button As Integer, Shift As Integer, X As Single, _
Lib "gdi32" Alias "CreateFontA" ( _ Y As Single)
ByVal nHeight As Long, _ Public Event MouseUp(Button As Integer, Shift As Integer, X As Single, _
ByVal nWidth As Long, _ Y As Single)
ByVal nEscapement As Long, _
ByVal nOrientation As Long, _
ByVal fnWeight As Long, _ '------------------------------------------------------------------------------'
ByVal fdwItalic As Long, _ ' Private Variables '
ByVal fdwUnderline As Long, _ '------------------------------------------------------------------------------'
ByVal fdwStrikeOut As Long, _
ByVal fdwCharSet As Long, _
ByVal fdwOutputPrecision As Long, _ Private m_Alignment As AlignmentConstants
ByVal fdwClipPrecision As Long, _ Private m_Caption As String
ByVal fdwQuality As Long, _ Private m_GotFocus As Boolean
ByVal fdwPitchAndFamily As Long, _ Private m_MaskStyle As cbtnMaskStyleConstants
ByVal lpszFace As String _ Private m_OldWndProc As Long
) As Long Private m_Padding As Long
Private m_Picture As StdPicture
Private Declare Function CreateSolidBrush _ Private m_PictureOffset As Long
Lib "gdi32" (ByVal crColor As Long) As Long Private m_State As cbtnStateConstants

Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
'------------------------------------------------------------------------------'
Private Declare Function DeleteObject _ ' Public Properties '
Lib "gdi32" (ByVal hObject As Long) As Long '------------------------------------------------------------------------------'

Private Declare Function DrawEdge _


Lib "user32" ( _ Public Property Get AccessKeys() As String
ByVal hDC As Long, _ AccessKeys = UserControl.AccessKeys
ByRef qrc As RECT, _ End Property
ByVal edge As Long, _
ByVal grfFlags As Long _
) As Long Public Property Let AccessKeys(New_AccessKeys As String)
If UserControl.AccessKeys <> New_AccessKeys Then
Private Declare Function DrawFocusRect _ UserControl.AccessKeys = New_AccessKeys
Lib "user32" ( _ PropertyChanged "AccessKeys"
ByVal hDC As Long, _ PaintControl
lpRect As RECT _ End If
) As Long End Property

Private Declare Function DrawStatePic _


Lib "user32" Alias "DrawStateA" ( _ Public Property Get Alignment() As AlignmentConstants
ByVal hDC As Long, _ Alignment = m_Alignment
ByVal hBrush As Long, _ End Property
ByVal lpDrawStateProc As Long, _
ByVal lParam As Long, _
ByVal wParam As Long, _ Public Property Let Alignment(New_Alignment As AlignmentConstants)
ByVal X As Long, _ If m_Alignment <> New_Alignment Then
ByVal Y As Long, _ m_Alignment = New_Alignment
ByVal cx As Long, _ PropertyChanged "Alignment"
ByVal cy As Long, _ PaintControl
ByVal Flags As Long _ End If
) As Long End Property

Private Declare Function DrawStateTxt _


Lib "user32" Alias "DrawStateA" ( _ Public Property Get BackColor() As OLE_COLOR
ByVal hDC As Long, _ BackColor = UserControl.BackColor
ByVal hBrush As Long, _ End Property
ByVal lpDrawStateProc As Long, _
ByVal lString As String, _
ByVal wParam As Long, _ Public Property Let BackColor(New_BackColor As OLE_COLOR)
ByVal X As Long, _ If UserControl.BackColor <> New_BackColor Then
ByVal Y As Long, _ UserControl.BackColor = New_BackColor
ByVal cx As Long, _ PropertyChanged "BackColor"
ByVal cy As Long, _ PaintControl
ByVal Flags As Long _ End If
) As Long End Property

Private Declare Function FillRect _


Lib "user32" ( _ Public Property Get Caption() As String
ByVal hDC As Long, _ Caption = m_Caption
lpRect As RECT, _ End Property
ByVal hBrush As Long _
) As Long
Public Property Let Caption(New_Caption As String)
Private Declare Function GetPixel _ If m_Caption <> New_Caption Then
Lib "gdi32" ( _ m_Caption = New_Caption
ByVal hDC As Long, _ PropertyChanged "Caption"
ByVal X As Long, _ PaintControl
ByVal Y As Long _ End If
) As Long End Property

Private Declare Function GetTextMetrics _


Lib "gdi32" Alias "GetTextMetricsA" ( _ Public Property Get Enabled() As Boolean
ByVal hDC As Long, _ Enabled = UserControl.Enabled
lpMetrics As TEXTMETRIC _ End Property
) As Long

Private Declare Sub OleTranslateColor _ Public Property Let Enabled(New_Enabled As Boolean)


Lib "oleaut32.dll" ( _ If UserControl.Enabled <> New_Enabled Then
ByVal clr As Long, _ UserControl.Enabled = New_Enabled
ByVal hpal As Long, _ PropertyChanged "Enabled"
ByRef lpcolorref As Long) PaintControl
End If
Private Declare Function SelectObject _ End Property
Lib "gdi32" ( _
ByVal hDC As Long, _
ByVal hObject As Long _ Public Property Get Font() As StdFont
) As Long Set Font = UserControl.Font
End Property
Private Declare Function SetBkColor _
Lib "gdi32" ( _
ByVal hDC As Long, _ Public Property Set Font(New_Font As StdFont)
ByVal crColor As Long _ Set UserControl.Font = New_Font
) As Long PropertyChanged "Font"
PaintControl
Private Declare Function SetBkMode _ End Property
Lib "gdi32" ( _
ByVal hDC As Long, _
ByVal nBkMode As Long _ Public Property Get ForeColor() As OLE_COLOR
) As Long ForeColor = UserControl.ForeColor
End Property
Private Declare Function SetPixel _

Adaptive Digital Steganography for True-Color Bitmaps G-23


Public Property Let ForeColor(New_ForeColor As OLE_COLOR)
If UserControl.ForeColor <> New_ForeColor Then Friend Sub RaiseMouseLeaveEvent()
UserControl.ForeColor = New_ForeColor RaiseEvent MouseLeave
PropertyChanged "ForeColor" End Sub
PaintControl
End If
End Property '------------------------------------------------------------------------------'
' Private Procedures '
'------------------------------------------------------------------------------'
Public Property Get hWnd() As Long
hWnd = UserControl.hWnd
End Property Private Sub DrawBorder(ByVal hDC As Long, ByRef tRect As RECT)

Dim tRect2 As RECT


Public Property Get MaskColor() As OLE_COLOR tRect2.Left = tRect.Left + 1
MaskColor = UserControl.MaskColor tRect2.top = tRect.top + 1
End Property tRect2.Right = tRect.Right - 1
tRect2.Bottom = tRect.Bottom - 1

Public Property Let MaskColor(New_MaskColor As OLE_COLOR) Select Case m_State


If UserControl.MaskColor <> New_MaskColor Then Case cbtnStateNormal:
UserControl.MaskColor = New_MaskColor DrawEdge hDC, tRect, EDGE_ETCHED, BF_RECT
PropertyChanged "MaskColor" Case cbtnStateHover:
PaintControl DrawEdge hDC, tRect2, BDR_RAISEDINNER, BF_RECT
End If Case cbtnStatePressed:
End Property DrawEdge hDC, tRect2, BDR_SUNKENOUTER, BF_RECT
End Select

Public Property Get MaskStyle() As cbtnMaskStyleConstants End Sub


MaskStyle = m_MaskStyle
End Property
Private Sub DrawCaption(ByVal hDC As Long)

Public Property Let MaskStyle(New_MaskStyle As cbtnMaskStyleConstants) If Len(Trim$(m_Caption)) = 0 Then Exit Sub


If m_MaskStyle <> New_MaskStyle Then
m_MaskStyle = New_MaskStyle Dim CapStr As String
PropertyChanged "MaskStyle" Dim CapWidth As Long
PaintControl Dim X As Long
End If Dim Y As Long
End Property Dim Txt As TEXTMETRIC
Dim hNewFont As Long
Dim hOldFont As Long
Public Property Get Picture() As StdPicture
Set Picture = m_Picture '[ get caption width without mnemonic character ]'
End Property CapStr = Replace(m_Caption, "&&", Chr$(254))
CapStr = Replace(CapStr, "&", vbNullString)
CapStr = Replace(CapStr, Chr$(0), "&&")
Public Property Set Picture(New_Picture As StdPicture) CapWidth = TextWidth(CapStr)
Set m_Picture = New_Picture
PropertyChanged "Picture" '[ compute vertical position ]'
PaintControl Y = (UserControl.ScaleHeight - TextHeight(m_Caption)) \ 2
End Property
'[ compute horizontal position ]'
If m_Alignment = vbLeftJustify Then
Public Property Get Padding() As Long If m_Picture Is Nothing Then
Padding = m_Padding X = m_Padding
End Property Else
X = m_Padding + m_PictureOffset + _
ScaleX(m_Picture.Width, vbHimetric, vbPixels)
Public Property Let Padding(New_Padding As Long) End If
If m_Padding <> New_Padding Then ElseIf m_Alignment = vbRightJustify Then
m_Padding = New_Padding X = UserControl.ScaleWidth - CapWidth - m_Padding
PropertyChanged "Padding" ElseIf m_Alignment = vbCenter Then
PaintControl If m_Picture Is Nothing Then
End If X = (UserControl.ScaleWidth - CapWidth) \ 2
End Property Else
X = (UserControl.ScaleWidth - CapWidth + m_PictureOffset + _
ScaleX(m_Picture.Width, vbHimetric, vbPixels)) \ 2
Public Property Get PictureOffset() As Long End If
PictureOffset = m_PictureOffset End If
End Property
'[ adjust text position according to state ]'
If m_State = cbtnStatePressed Then
Public Property Let PictureOffset(New_PictureOffset As Long) X = X + 1
If m_PictureOffset <> New_PictureOffset Then Y = Y + 1
m_PictureOffset = New_PictureOffset End If
PropertyChanged "PictureOffset"
PaintControl '[ set font ]'
End If GetTextMetrics UserControl.hDC, Txt
End Property hNewFont = CreateFont(Txt.tmHeight, 0, 0, 0, Txt.tmWeight, Txt.tmItalic, _
Txt.tmUnderlined, Txt.tmStruckOut, 0, 0, 16, 0, 0, _
UserControl.Font.Name)
'------------------------------------------------------------------------------' hOldFont = SelectObject(ByVal hDC, hNewFont)
' Friend Properties '
'------------------------------------------------------------------------------' '[ set text color and background ]'
SetTextColor hDC, TranslateColor(UserControl.ForeColor)
SetBkMode hDC, BACKMODE_TRANSPARENT
Friend Property Get OldWndProc() As Long
OldWndProc = m_OldWndProc '[ paint Caption ]'
End Property If UserControl.Enabled Then
DrawStateTxt hDC, 0, 0, m_Caption, Len(m_Caption), X, Y, 0, 0, _
DST_PREFIXTEXT Or DSS_NORMAL
Friend Property Let OldWndProc(ByVal New_OldWndProc As Long) Else
m_OldWndProc = New_OldWndProc DrawStateTxt hDC, 0, 0, m_Caption, Len(m_Caption), X, Y, 0, 0, _
End Property DST_PREFIXTEXT Or DSS_DISABLED
End If

Friend Property Get State() As cbtnStateConstants '[ restore original font ]'
State = m_State SelectObject hDC, hOldFont
End Property DeleteObject hNewFont

End Sub
Friend Property Let State(ByVal New_State As cbtnStateConstants)
If m_State <> New_State Then
m_State = New_State Private Sub DrawFocusRectangle(ByVal hDC As Long, ByRef tRect As RECT)
PaintControl Dim tRect2 As RECT
End If tRect2.Left = tRect.Left + 3
End Property tRect2.top = tRect.top + 3
tRect2.Right = tRect.Right - 4
tRect2.Bottom = tRect.Bottom - 4
'------------------------------------------------------------------------------' SetTextColor hDC, vbBlack
' Public Procedures ' DrawFocusRect hDC, tRect2
'------------------------------------------------------------------------------' End Sub

Public Sub Press() Private Sub DrawPicture(ByVal hDC As Long)

On Error Resume Next If m_Picture Is Nothing Then Exit Sub

If Extender.Visible Then Dim CapStr As String


If UserControl.Enabled Then Dim CapWidth As Long
UserControl.SetFocus Dim offset As Long
DoEvents Dim X As Long
Call UserControl_Click Dim Y As Long
End If Dim PicWidth As Long
End If Dim PicHeight As Long
Dim hDCTmp As Long
End Sub Dim MaskClr As Long
Dim BackClr As Long
Dim Ctr1 As Long
Public Sub Refresh() Dim Ctr2 As Long
PaintControl
End Sub '[ get caption width and offset ]'
If Len(Trim$(m_Caption)) = 0 Then
CapWidth = 0
'------------------------------------------------------------------------------' offset = 0
' Friend Procedures ' Else
'------------------------------------------------------------------------------' '[ remove mnemonic characters from total width ]'

Adaptive Digital Steganography for True-Color Bitmaps G-24


CapStr = Replace(m_Caption, "&&", Chr$(254)) Call UserControl_Click
CapStr = Replace(CapStr, "&", vbNullString) End Sub
CapStr = Replace(CapStr, Chr$(0), "&&")
CapWidth = TextWidth(CapStr)
offset = m_PictureOffset Private Sub UserControl_AmbientChanged(PropertyName As String)
End If PaintControl
End Sub
'[ get picture dimensions ]'
PicWidth = UserControl.ScaleX(m_Picture.Width, vbHimetric, vbPixels)
PicHeight = UserControl.ScaleY(m_Picture.Height, vbHimetric, vbPixels) Private Sub UserControl_Click()
RaiseEvent Click
'[ compute vertical position ]' End Sub
Y = (UserControl.ScaleHeight - PicHeight) \ 2

'[ compute horizontal position ]' Private Sub UserControl_GotFocus()


If m_Alignment = vbLeftJustify Then m_GotFocus = True
X = m_Padding PaintControl
ElseIf m_Alignment = vbRightJustify Then End Sub
X = UserControl.ScaleWidth - m_Padding - CapWidth - PicWidth - offset
ElseIf m_Alignment = vbCenter Then
X = (UserControl.ScaleWidth - CapWidth - PicWidth - offset) \ 2 Private Sub UserControl_Hide()
End If modCustomButton.StopSubclassingButton Me
End Sub
'[ adjust picture position according to state ]'
If m_State = cbtnStatePressed Then Private Sub UserControl_Initialize()
X = X + 1 m_GotFocus = False
Y = Y + 1 m_State = cbtnStateNormal
End If m_OldWndProc = 0
End Sub
'[ if icon ]'
If m_Picture.Type = vbPicTypeIcon Then
Private Sub UserControl_InitProperties()
If UserControl.Enabled Then
DrawStatePic hDC, 0, 0, m_Picture.Handle, 0, X, Y, 0, 0, _ m_Alignment = vbCenter
DST_ICON Or DSS_NORMAL m_Caption = Replace(Extender.Name, UserControl.Name, "Button")
Else m_MaskStyle = cbtnMaskStyleAuto
DrawStatePic hDC, 0, 0, m_Picture.Handle, 0, X, Y, 0, 0, _ m_Padding = 10
DST_ICON Or DSS_DISABLED Set m_Picture = Nothing
End If m_PictureOffset = 10

'[ else if bitmap ]' UserControl.AccessKeys = vbNullString


Else UserControl.BackColor = vbButtonFace
UserControl.Enabled = True
'[ create temporary dc for picture ]' Set UserControl.Font = Ambient.Font
hDCTmp = CreateCompatibleDC(ByVal hDC) UserControl.ForeColor = vbButtonText
DeleteObject SelectObject(ByVal hDCTmp, m_Picture.Handle) UserControl.MaskColor = vbWhite

'[ if mask enabled ]' End Sub


If m_MaskStyle <> cbtnMaskStyleNone Then

'[ get mask color ]' Private Sub UserControl_KeyDown(KeyCode As Integer, Shift As Integer)
If m_MaskStyle = cbtnMaskStyleAuto Then
MaskClr = GetPixel(ByVal hDCTmp, 0, 0) If (KeyCode = vbKeyReturn) Then
Else '[ simulate click ]'
MaskClr = TranslateColor(UserControl.MaskColor) RaiseEvent Click
End If ElseIf (KeyCode = vbKeySpace) And (m_State <> cbtnStatePressed) Then
'[ simulate mouse down ]'
BackClr = TranslateColor(UserControl.BackColor) m_State = cbtnStatePressed
PaintControl
'[ clear transparent pixels of picture ]' ElseIf (KeyCode = vbKeyDown) Or (KeyCode = vbKeyRight) Then
For Ctr2 = 0 To PicHeight '[ select next control ]'
For Ctr1 = 0 To PicWidth SendKeys "{TAB}", True
If GetPixel(ByVal hDCTmp, Ctr1, Ctr2) = MaskClr Then ElseIf (KeyCode = vbKeyUp) Or (KeyCode = vbKeyLeft) Then
SetPixel hDCTmp, Ctr1, Ctr2, BackClr '[ select previous control ]'
End If SendKeys "+{TAB}", True
Next Ctr1 End If
Next Ctr2
RaiseEvent KeyDown(KeyCode, Shift)
End If
End Sub
'[ paint picture ]'
BitBlt hDC, X, Y, PicWidth, PicHeight, hDCTmp, 0, 0, vbSrcCopy
Private Sub UserControl_KeyUp(KeyCode As Integer, Shift As Integer)
'[ cleanup temporary dc ]'
DeleteDC hDCTmp If (KeyCode = vbKeySpace) And (m_State = cbtnStatePressed) Then
'[ simulate click ]'
End If m_State = cbtnStateNormal
PaintControl
End Sub RaiseEvent Click
End If

Private Sub PaintControl() RaiseEvent KeyUp(KeyCode, Shift)

Dim tRect As RECT End Sub


Dim hDC As Long
Dim hBmp As Long
Dim hBrush As Long Private Sub UserControl_LostFocus()
m_GotFocus = False
'[ compute control dimensions ]' PaintControl
tRect.Left = 0 End Sub
tRect.top = 0
tRect.Right = UserControl.ScaleWidth
tRect.Bottom = UserControl.ScaleHeight Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
'[ create back buffer ]'
hDC = CreateCompatibleDC(UserControl.hDC) If Button = vbLeftButton Then
hBmp = CreateCompatibleBitmap(UserControl.hDC, tRect.Right, tRect.Bottom) m_State = cbtnStatePressed
DeleteObject SelectObject(ByVal hDC, hBmp) PaintControl
End If
'[ fill back buffer with background color ]'
hBrush = CreateSolidBrush(TranslateColor(UserControl.BackColor)) RaiseEvent MouseDown(Button, Shift, X, Y)
FillRect hDC, tRect, hBrush
DeleteObject hBrush End Sub

'[ paint control on back buffer ]'


DrawPicture hDC Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, _
DrawCaption hDC X As Single, Y As Single)
DrawBorder hDC, tRect
If Ambient.UserMode Then
If m_GotFocus Then
DrawFocusRectangle hDC, tRect RaiseEvent MouseMove(Button, Shift, X, Y)
End If
If (m_State <> cbtnStateHover) And (Button <> vbLeftButton) Then
'[ copy back buffer contents to Control ]' modCustomButton.TrackMouseLeaveEvent Me
BitBlt UserControl.hDC, tRect.Left, tRect.top, tRect.Right, tRect.Bottom, _ m_State = cbtnStateHover
hDC, 0, 0, vbSrcCopy PaintControl
RaiseEvent MouseHover
'[ update display ]' End If
DoEvents
UserControl.Refresh End If

'[ cleanup temporary resources ]' End Sub


DeleteDC hDC
DeleteObject hBmp
Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, _
End Sub X As Single, Y As Single)
m_State = cbtnStateNormal
PaintControl
Private Function TranslateColor(OLEColor As OLE_COLOR) As Long RaiseEvent MouseUp(Button, Shift, X, Y)
OleTranslateColor OLEColor, UserControl.Palette, TranslateColor End Sub
End Function

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)


'------------------------------------------------------------------------------'
' Control Event Handlers ' With PropBag
'------------------------------------------------------------------------------'
m_Alignment = .ReadProperty("Alignment", vbCenter)
m_Caption = .ReadProperty("Caption", vbNullString)
Private Sub UserControl_AccessKeyPress(KeyAscii As Integer) m_MaskStyle = .ReadProperty("MaskStyle", cbtnMaskStyleAuto)

Adaptive Digital Steganography for True-Color Bitmaps G-25


m_Padding = .ReadProperty("Padding", 10)
Set m_Picture = .ReadProperty("Picture", Nothing)
m_PictureOffset = .ReadProperty("PictureOffset", 6)

UserControl.AccessKeys = .ReadProperty("AccessKeys", vbNullString)


UserControl.BackColor = .ReadProperty("BackColor", vbButtonFace)
UserControl.Enabled = .ReadProperty("Enabled", True)
Set UserControl.Font = .ReadProperty("Font", Ambient.Font)
UserControl.ForeColor = .ReadProperty("ForeColor", vbButtonText)
UserControl.MaskColor = .ReadProperty("MaskColor", vbWhite)

End With

End Sub

Private Sub UserControl_Resize()


PaintControl
End Sub

Private Sub UserControl_Show()


m_State = cbtnStateNormal
PaintControl
modCustomButton.StartSubclassingButton Me
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)


With PropBag
.WriteProperty "AccessKeys", UserControl.AccessKeys, vbNullString
.WriteProperty "Alignment", m_Alignment, vbCenter
.WriteProperty "BackColor", UserControl.BackColor, vbButtonFace
.WriteProperty "Caption", m_Caption, vbNullString
.WriteProperty "Enabled", UserControl.Enabled, True
.WriteProperty "Font", UserControl.Font, Ambient.Font
.WriteProperty "ForeColor", UserControl.ForeColor, vbButtonText
.WriteProperty "MaskColor", UserControl.MaskColor, vbWhite
.WriteProperty "MaskStyle", m_MaskStyle, cbtnMaskStyleAuto
.WriteProperty "Padding", m_Padding, 10
.WriteProperty "Picture", m_Picture, Nothing
.WriteProperty "PictureOffset", m_PictureOffset, 6
End With
End Sub

Adaptive Digital Steganography for True-Color Bitmaps G-26


BIBLIOGRAPHY

[ANDE1998] R J Anderson & F A P Petitcolas (1998). ‘On The Limits of


Steganography’, Special Issue on Copyright & Privacy Protection,
IEEE Journal of Selected Areas in Communications, 16(4), pp
474-482.

[ANDE1999] R J Anderson & F A P Petitcolas (1999). ‘Information Hiding: An


Annotated Bibliography’, Computer Laboratory, University of
Cambridge, UK.

[BEND1996] W Bender et al (1996). ‘Techniques for Data Hiding’, IBM Systems


Journal, 35(3&4), pp 313-336.

[BEND2000] W Bender et al (2000). ‘Applications for Data Hiding’, IBM Systems


Journal, 39(3&4), pp 547-568.

[DAVE1995] P Davern (1995). ‘Steganography: Its History and Its Application to


Computer Based Data Files’, Working Paper: CA-0795, School of
Computer Applications, Dublin City University.

[FAST2002] Fast Search & Transfer, Inc. (2002). ‘About Us’, AlltheWeb.
http://www.alltheweb.com/about/index.html .

[FRID1998] Jiri Fridrich (1998). Applications of Data Hiding in Digital Images,


Tutorial for the ISPACS’98 Conference in Melbourne, Australia.

[FRID2000] Jiri Fridrich, R Du & M Long (2000). ‘Steganalysis of LSB Encoding


in Color Images’, Air Force Research Laboratory, Air Force Material
Command, USAF.

[FRID2002] Jessica Fridrich & M Goljan (2002). ‘Practical Steganalysis of Digital


Images – State of the Art’, Air Force Research Laboratory, Air Force
Material Command, USAF.

[FRID2002a] Jessica Fridrich, M Goljan & D Hogea (2002). ‘Attacking the


OutGuess’, Air Force Research Laboratory, Air Force Material
Command, USAF.

[HETZ2002] S Hetzl (2002). ‘A Survey of Steganography’.

Adaptive Digital Steganography for True-Color Bitmaps Bibliography


[JOHN1998] N F Johnson & S Jajodia (1998). ‘Exploring Steganography: Seeing
the Unseen’, IEEE Computer, 31(2), pp 26-34.

[KAHN1996] D Kahn (1996). ‘The History of Steganography’, In: Information


Hiding: First International Workshop (R Anderson, ed), Lecture Notes
in Computer Science 1174, pp 1-5, Berlin: Springer-Verlag.

[KIRA2002] P S Kiran (2002). ‘Project Third Eye’, Webkclub.com.


http://www.webkclub.com/tte/.

[KWAN2001] M Kwan (2001). ‘How SNOW Works’, The SNOW Home Page.
http://www.darkside.com.au/snow/description.html .

[LEE1999] Y K Lee & L H Chen (1999). ‘An Adaptive Image Steganographic


Model Based on Minimum-Error LSB Replacement’, Department of
Computer and Information Science, National Chiao Tung University,
Taiwan, ROC.

[LEE2000] Y K Lee & L H Chen (2000). ‘High Capacity Image Steganographic


Model’, Department of Computer and Information Science, National
Chiao Tung University, Taiwan, ROC.

[LEE2002] Y K Lee & L H Chen (2002). ‘Object-Based Image Steganography


Using Affine Transformation’, Department of Computer and
Information Science, National Chiao Tung University, Taiwan, ROC.

[LIN1999] E Lin & E Delp (1999). ‘A Review of Data Hiding in Digital Images’,
Video and Image Processing Laboratory, School of Electrical and
Computer Engineering, Purdue University.

[MARV1999] L M Marvel, C G Boncelet Jr & C T Retter (1999). ‘Spread Spectrum


Image Steganography’, IEEE Transactions on Image Processing, 8(8),
pp 1075-1083.

[MCCU2000] D McCullagh (2000). ‘Carnivore to Continue Munching’, Wired


News. http://www.wired.com/news/print/0,1294,38618,00.html.

[MENE1996] A J Menezes, P C van Oorschot & S A Vanstone (1996). Handbook of


Applied Cryptography, Boca Raton: CRC Press.

Adaptive Digital Steganography for True-Color Bitmaps Bibliography


[MOSK2000] I S Moskowitz, G E Longdon & L W Chang (2000). ‘A New
Paradigm Hidden in Steganography’, Center for High Assurance
Computer Systems, Naval Research Laboratory, Washington DC.

[NEOB2002] NeoByte Solutions (2002). ‘Invisible Secrets 2002’, NeoByte Solutions


Website. http://www.neobytesolutions.com/invsecr/.

[PAIZ1999] F J Paiz (1999). ‘Tartan Threads: A Method for the Real-time Digital
Recognition of Secure Documents in Ink Jet Printers’, Department of
Electrical Engineering and Computer Science, MIT.

[PETI1999] F A P Petitcolas, R J Anderson & M G Kuhn (1999). ‘Information


Hiding–A Survey’, Proceedings of the IEEE, 87(7), pp 1062-1078.

[PFAF1995] B Pfaffenberger & D Wall (1995). Que’s Computer and Internet


Dictionary, 6th ed, Indianapolis: Que Corporation.

[PFIT1996] B Pfitzmann (1996). ‘Information Hiding Terminology’, In:


Information Hiding: First International Workshop (R Anderson, ed),
Lecture Notes in Computer Science 1174, pp 347-350, Berlin:
Springer-Verlag.

[PLEM2001] S Pleming (2001). ‘Muslim Extremists Utilize Web Encryption’,


TechTV. http://www.techtv.com/news/print/0,23102,3310112,00.html.

[PRES1992] R S Pressman (1992). Software Engineering: A Practitioner’s


Approach, 3rd ed, International ed, Singapore: McGraw-Hill.

[PROV2001] N Provos (2001). ‘Defending Against Statistical Steganalysis’, 10th


USENIX Security Symposium, Washington, DC.

[PROV2001a] N Provos & P Honeyman (2001). ‘Detecting Steganographic Content


on the Internet’, CITI Technical Report 01-11, Center for Information
Technology Integration, University of Michigan.

[PROV2002] N Provos (2002). OutGuess Website. http://www.outguess.org.

[SCHM2001] G Schmid (2001). Report on the Existence of a Global System for the
Interception of Private and Commercial Communications, Session
Document: A5-0264/2001-Par1, Temporary Committee on the
ECHELON Interception System, European Parliament.

Adaptive Digital Steganography for True-Color Bitmaps Bibliography


[SIEB2001] D Sieberg (2001). ‘Bin Laden exploits technology to suit his needs’,
CNN.com. http://www.cnn.com/2001/US/09/20/inv.terrorist.search/.

[STEG2002] Steganos GmbH (2002). ‘Steganos Security Suite 4’, Steganos GmbH
Home. http://www.steganos.com/en/sss/index.htm .

[TYSO2001] J Tyson (2001). ‘How Carnivore Works’, Howstuffworks.


http://www.howstuffworks.com/carnivore.htm/printable.

[WEST2001] Andreas Westfeld (2001). ‘F5–A Steganographic Algorithm’,


Presentation slides for the 4th Intenational Workshop on Information
Hiding, Technische Universität Dresden.

Adaptive Digital Steganography for True-Color Bitmaps Bibliography


791 G. Del Pilar Street, Home: (046) 431-0034
Caridad, Cavite City Mobile: (919) 635-6479
Philippines 4100 E-mail: markdavidgan@mail.com

Mark David C. Gan


Education 2001 up to present STI College Bacoor
Bachelor of Science in Computer Science
· Became the first Vice President for Internal Affairs of STI BITS (STI Bacoor
Information Technology Society) in 2001
· Computerized the 2002 Officer Elections of STI BITS
· Organized and facilitated the 2003 STI Bacoor Programming Competition
· Consistent Dean’s Honor List qualifier

1999–2001 STI College Bacoor


Associate in Computer Technology
· Graduated With Honors
· Student of the Year for the Batch of 2001
· Guaranteed Hire Program (GHP) qualifier
· Consistent Dean’s Honor List qualifier

Awards 2002

ACM Asia Programming Contest - Manila Site


· Twentieth Place

2002
STI “INTO Programming” - Senior Level
Computer Programming Contest
· Third Place in National Competition

2001

STI “Tagisan ng Talino” - Senior Level


Computer Quiz and Computer Programming Contest
· Third Place in National Competition

1999 and 2000


STI “Tagisan ng Talino” - Junior Level
Computer Quiz and Computer Programming Contest
· National Champion

Adaptive Digital Steganography for True-Color Bitmaps Curriculum Vitae

You might also like