A Flag is Just a Symbol

• By Brad Conte, January 31, 2007
• Post Categories: Miscellaneous
People make associations with symbols. It’s kind of a peculiar trait, but they consistently do. Some people do it more than others, though, and seem to have an emotional need to make connections between a symbol and that which the symbol represents.

The thing, though, is that I wonder if I’m delinquent in this area because I don’t make strong symbolic associations that other people do.

Take, as my main point of interest, flags. Flags and the graphical symbols they bear were designed for the purpose of easy identification, usually from a distance. Images have no language barrier, and having a simple picture to represent you and the people you are associated with makes it easy to label people and places. Whether it’s old-style battles where flags would be carried, maps with flags on each country, or just a display of patriotism for your country, they’re good for communicating the simple concept “This flag represents the people X.”

That I understand.

What I don’t get is when people turn a symbol itself into a sacred image of whatever it represents.

Take religious idols, for example. Basically every religion has had some sort of idol system and usually those idols are sacred, having special rules like “do not touch” or “whenever you see it you must sacrifice to it”, or whatever. But, through the history of major religions, those idols were rarely (as far as I know) actual gods themselves. Rather, actual gods were said to have dwelt in the seas, the air, the sun, or really anywhere else. But although they weren’t gods, people would treat the idols as if they were. That rock over there is insignificant and the atoms that compose it uninteresting, but the atoms that compose that specific idol are sacred and should be treated different.

Back to flags. I don’t know about other countries, but here in America some people basically treat the American flag like an idol. It is not to touch the ground, it is to be fully raised initially even when flown at half-mast, it is not to be touched with a hand that has touched raw meat in the past 24 hours, or whatever. Rules, rules, rules, and rules some people worship. If you let a flag brush the ground and actually don’t really care about it, you’re disgracing their nation and you risk assault by a high caliber weapon. (Note that I’m not talking about people’s view of America itself, I’m just talking about their view of it’s flag.)

But all that is just about a symbol. A symbol that represents something else. And what I don’t get is how people can elevate a symbol to the position of, if not sometimes actually higher than, that which the symbol represents. That just makes no logical sense to me.

A symbol, by indisputable definition, is something that is not what it represents and it merely serves as a placeholder to be used when the thing itself would not suffice. For example, you can’t fly the country of America from a pole, at least not without some serious hydraulic work, but it would be easy to simply display a picture that represented the United States, thus a flag makes logical sense. But treating the flag as if it were sacred?

If a symbol is as sacred as what it represents, where does it end? If a symbol (in this case, a flag) is as sacred as that which it represents (America), is the symbol the original symbol (for example, a bumper sticker of a flag) just as sacred? If Symbol1 = Object, does Symbol2 = Symbol1 = Object? Is a bumper sticker just as important as a fifty-foot flag? Is a picture of a bumper sticker in a catalogue just as sacred as the nation of America itself?

A flag is a piece of cloth with a logo on it, and that logo just represents America. But it’s only a representation of America, America itself relies a grand total of nothing on the well-being of that flag. There are an innumerable number of flags around, all made of pretty cheap material, many not even made in America, all of which have no impact whatsoever on the operational status or well being of anything related to America.

If I see someone burning a flag to make a political statement, I don’t burst arteries, I’m just glad they’re taking out their anger in a way that doesn’t hurt anyone. They’re burning a symbol, a symbol that can be replaced for $7.99 USD at one of many stores within a 10 minute drive.

I think I understand why people make those symbolic connections, though. I’m not a psychologist, but I think it’s common knowledge that most people love having something physical over something that’s abstract. The United States is abstract in the sense of being huge in physical area, population, philosophical ideals, laws, customs, etc, but a flag is a small, physical, comprehensible object, and people like that better. It’s easier to comprehend and imagine a flag than it is 2,263,960,000 acres of land, 300,000,000 people, and all the civil, social, political, and technological complexities they have. People can look at a flag and be proud of it, but they can’t look at America and be proud of it, they have to just imagine it and be proud of it.

I suppose I do understand why people elevate symbols to the levels of that which they represent, I just think it’s stupid.

I guess I was born without whatever gland that’s responsible for that type of emotion because I have never made a big deal out of symbols. They’re just… symbols. I’d be ticked if you attacked America, but I really don’t care if you burn our flag. One down, fifteen million to go. Big deal. It’s the same thing as yelling “**** America”. Your complaint has been duly noted. I probably knew that you hated America before I saw you burn a flag, I still know that you hate America. You’ve done nothing more than communicate your hatred for America, and the odds are pretty good that I don’t care about your opinion to anyway.

Flag burning is stupid. When you burn a flag, all you do is communicate that you hate the nation (or organization) that flag represents. But there are many ways that you can communicate that idea, most of which are more efficient and don’t make you look quite so stupid. Burning a flag is just a overly-passionate person assigning unwarranted emotional attachment to a flag… which sounds familiar.

But in the end, regardless of the logical sense an emotional connection to a symbol may or may not make, people have the right to do it. If you want to make a flag sacred, you can. But, similarly, if you want to burn a flag you can do that too. Both acts are stupid in my opinion, but you’re free to do both. All I really ask is that you try your best to keep your illogical, raging emotions to yourself. Not only do I not care, you’re probably wasting time and effort from doing something productive.

Blowfish – C

• By Brad Conte, August 8, 2006
• Post Categories: My Code
Algorithm
This is an implementation of the Blowfish block cipher.

There are two steps to the cipher. First, five sets of tables are initialized using the user’s key and the blowfish encryption algorithm itself (making the algorithm recursive). Second, the data is encrypted using the permutated tables initialized previously.

Code Documentation
  • void key_schedule(uchar user_key[], BLOWFISH_KEY *keystruct, int len)
    This generates an encryption key from a user-supplied key.

    • uchar user_key[]
      This is the user-supplied key.
    • BLOWFISH_KEY *keystruct
      This is the key structure that will be used to encrypt data later in the encryption functions.
    • int len
      This is the length, in bytes, of the key in the first parameter. It may be any value up to 448.


  • blowfish_encrypt(uchar in[], uchar out[], BLOWFISH_KEY *keystruct)
    blowfish_decrypt(uchar in[], uchar out[], BLOWFISH_KEY *keystruct)
    These functions encrypt and decrypt data, accordingly, using a Blowfish key structure.

    • uchar in[]
      This is the data to be encrypted, for the blowfish_encrypt() function, and the data to be decrypted for the blowfish_decrypt() function.
    • uchar out[]
      This is where to store the output encrypted data, for the blowfish_encrypt() function, and the output decrypted data for the blowfish_decrypt() function.
    • BLOWFISH_KEY *keystruct
      This is the key structure that is generated by the key_schedule() function (above). It is the same for both encrypted and decryption.
Code Usage
  1. Create the arrays to hold both input and output data for the encryption and/or decryption functions and a BLOWFISH_KEY structure.
  2. Call the key_schedule() function with the key, the BLOWFISH_KEY structure, and the length of the key in bytes.
  3. To encrypt data, call the blowfish_encrypt() function passing the array with the plaintext, the array to hold the output ciphertext, and the key structure.
  4. Do decrypt data, call the blowfish_decrypt() function passing the array with the ciphertext, the array to hold the output plaintext, and the key structure.
Code
Source Code
Sample Driver Program

Notes
In this implementation, all the initial P-Box and S-Box constants are stored in static memory location and copied to temporary memory locations for use in the key-initialization step. This is because the S-Box and P-Box values will be altered during the key initialization, so if the implementor wishes to encrypt data using multiple keys in the same session, then the key initialization function must be called more than once. Each time it is called it must start with the same constant values, but these values are altered during the key initialization. Since the P/S-Boxes are crafted uniquely for each encryption key, using a single universal array to store those values would allow multiple keys to be used sequentially, but it would prevent the developer from using multiple keys at the same time. Thus the blowfish key is represented as a structure that houses both the P-Box and S-Boxes. Using structures allows the developer to create and manage as many keys as desired by creating one structure per key.

The slight drawback to this method is that copying all the initial data introduces a minor performance hit when calling the key schedule, and using multiple memory locations boosts the amount of memory necessary (every Blowfish key requires just over 1KB of memory). However, on modern PCs, the memory performance hit is completely negligible. Assuming the developer only needs to use one Blowfish key, this code could be optimized to just use the permanent S/P-Boxes. These factors are only of practical concern for extremely computationally-weak machines (very low-end PCs, specialized hardware).

Cryptanalysis of the Blowfish algorithm itself to date has yielded but a few minor flaws, placing Blowfish as one of the best 64-bit block ciphers in existence. However, 64-bit block ciphers are known to leak information about the plaintext and should not be used if possible. So although no reasonable attacks exist against Blowfish itself, its 64-bit block size make it less than undesirable in the modern cryptographic world.

Base 64 – C

• By Brad Conte, July 26, 2006
• Post Categories: My Code
Algorithm
This is an implementation of Base64 encoding.

Base64 is an encoding scheme that allows binary data to be represented as text. It accepts a bit string of any length, splits it up into chucks of 6 bits, and replaces each chunk with its corresponding value from the list of characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ When the input is not an even multiple of 6 bits, the character ‘=’ is appended to the output as padding as needed.

Since the input has 8 bits of significant data and the output has 6 significant bits of data (there are 26=64 characters in the array above), the input to output ratio is very close to 3:4.

Code Documentation
  • void base64_encode(unsigned char in[], unsigned char out[], int len)
    This encodes raw data to Base64.
    • unsigned char in[]
      This contains the data to be encoded.
    • unsigned char out[]
      This will contains the output. The array should be larger than the input by a scale of 4:3, with a two character buffer.
    • int len
      This is the length, in bytes, of the input.
    • int newline_flag
      This is a flag, which can be set to true or false, to indicate whether or not the function should insert a newline in the base64 output every 76 characters. The technical specification for Base64 calls for this value, but this was based on technical standards/difficulties of the past and isn’t always desirable. By setting it to a non-zero value, a newline character will be added every 76 output characters (to wrap it in a rough rectangle shape), if it is set to 0 then the output will be one long string.
  • base64_decode(unsigned char in[], unsigned char out[], int len)
    This function decodes Base64 code into its original form.
    • unsigned char in[]
      This contains the Base64 data to be decoded.
    • unsigned char out[]
      This is the output array, it should be at least 3/4 the length of the input data, with an extra character of buffer.
    • int len
      This is the length of the input Base64 data.
    • Note: There is no need to include a newline flag for the decoding function, as it automatically parses out newline characters.
Code Usage
  1. First create/allocate two arrays to contain your original and encoded data.
  2. Determine the length of the data you wish to encode. Pass the input data, the array to contain the output, and the length of the data as arguments to the base64_encode() function.
  3. When you wish to decode the data, use the base64_decode() function. It works the same way, except the data gets decoded.
Code
• Source Code
• Sample Driver Program

Notes
This is the traditional base64 encoding scheme. The “Internet Base64″, in order to be URL friendly, replaces the last two characters of the substitution string, “+” and “/”, with “*” and “-”, respectively.

• Thanks to Christoph Otto for fixing a NULL termination bug (7-26-06). •

AES – C

• By Brad Conte, July 25, 2006
• Post Categories: My Code
Algorithm
This is an implementation of the AES block cipher in 128, 192, and 256 bit modes, where the bit size corresponds to the key length. The algorithm encrypts plaintext in block sizes of 128 bits.

Code Documentation
  • KeySchedule(unsigned char key[], unsigned int w[])
    This function takes the generated key (128, 192, or 256 bits in length) and generates a key schedule to use in encryption.
    • unsigned char key[]
      Must contain 16, 24, or 32 bytes of data to be used as the key.
    • unsigned int w[]
      Must be 60 32-bit integers in size. This will be the outputted key schedule.
    • int keysize
      Must be the size of the key in bits, limited to the values 128, 192, or 256.
  • aes_encrypt(unsigned char in, unsigned char out, unsigned int key[], int keysize)
    aes_decrypt(unsigned char in, unsigned char out, unsigned int key[], int keysize)
    These functions encrypt and decrypt data, respectively.
    • unsigned char in[]
      The plaintext to be encrypted. The array must be 16 bytes in size.
    • unsigned char out[]
      The output ciphertext. The array must be 16 bytes in size.
    • unsigned int key[]
      The “w” array key schedule from the KeySchedule() function.
    • int keysize
      Ensure it’s the same value as the “keysize” value in KeySchedule() function.
Code Usage
  1. Call the KeyExpantion() function with the encryption key you want to use, the key schedule array, and the number of bits in length of the key.
  2. To decrypt data, call the aes_encrypt() function with the input plaintext array, an array to hold the output ciphertext, and the size of the original key in bits (same as the value passed to the KeyExpantion() function).
  3. To decrypt data, call the aes_decrypt() function with the input ciphertext array, an array to hold the output plaintext, and the size of the original key in bits (same as the value passed to the KeyExpantion() function).
Code
• Source Code
• Sample Driver Program

Notes
This implementation is designed for little endian processors, but I think should work for big endian processors as well.

I’ve taken some steps towards optimizing it, (basic things like unrolling loops), but the implementation is fairly slow. I hope to be able to optimize it more in the future.

Also note that this is not a hardened implementation of AES. It has benchmarked to be fairly slow and has not been designed to be resistant to side-channel attacks. Optimizing it and attack-proofing it are on my to-do list.

There are a few extra functions included in this code, printstate() and print_rnd_key(), and print_arry(), that fall under the heading of “Debugging Functions”. These are not a part of the AES implementation and may be removed, they only exist to aid in debugging the code should the implementor seek to optimize it or tinker with it in any way. I used them excessively when originally implementing the code, and figured they might come in handy to someone else as well. They’re not complex, but useful.

SHA-256 – C

• By Brad Conte,
• Post Categories: My Code
Algorithm
This is an implementation of the SHA-256 hash algorithm.

Code Documentation
  • SHA256_CTX
    A MD5 structure that will hold all hash-related data and calculations as the hash is calculated.

  • SHA256_init(SHA256_CTX *ctx)
    Initializes the SHA256_CTX object.

  • SHA1_update(SHA256_CTX *ctx, unsigned char data[], int len)
    Once an object has been created and initialized, the data to be hashed must be added. Due to practical limitations, it may not be optimal (or possible) to add all the data to the SHA256 hash in one data chunk, so the function inputs, stores, and calculates data as it is received, allowing the data to be added in as many chunks as necessary.

    • unsigned char data[]
      This is the data to be added to the hash.
    • int len
      This is the length, in bytes, of the data in the “data” array.


  • SHA256_final(SHA256_CTX *ctx, unsigned char hash[])
    Finalize and output the hash.

    • unsigned char hash[]
      This is the array to store the output hash. It must be at least 16 bytes in size.
Code Usage
  1. Create an SHA256_CTX object.
  2. Initialize it with sha256_init().
  3. Read some/all of the data to hash into an array, calculate the size of the data, and add it to the hash with sha256_update().
  4. Repeat the previous step for all the data you want to hash.
  5. Finalize and output the hash with sha256_final().
Repeat steps (2) to (5) for as many hashes as you want to calculate.

Code
Source Code
Sample Driver Program

Notes
The 32-bit words (which in this case are unsigned integers) used in the code use little endian byte ordering. The SHA-256 specification uses the big endian byte order, so some byte-reversals are made when copying data into and out of integers in this code.

This algorithm can hash data of any length, although 264 bits (2,147,483,648 gigabytes) is the recommended limit.

This algorithm has not been implemented in an optimized manner. This algorithm has passed testing against numerous test vectors, including all official vectors.

(3)DES – C

• By Brad Conte, July 10, 2006
• Post Categories: My Code
Algorithm
This is an implementation of the DES and 3 DES block ciphers. 3DES (is simply the DES algorithm iterated three times and sometimes refered to as Triple DES. This algorithm encrypts plaintext in block sizes of 8 bytes.

Code Documentation
For DES:
  • void key_schedule(unsigned char key[], unsigned char schedule[][6], unsigned int mode)
    This function generates a multi-dimensional key schedule from a user-supplied key, the key schedule will be used for encryption.

    • unsigned char key[]
      Must contain 8 bytes of data to be used as the key.
    • unsigned int schedule[][6]
      Must be 16 arrays of 6 bytes each. This will contain the final key output.
    • unsigned int mode
      This value should be set to appropriate the macro-defined ENCRYPT or DECRYPT value.


  • void des_crypt(unsigned char in[], unsigned char out[], unsigned char key[][6])
    This function both encrypts and decrypts text using the key schedule.

    • unsigned char in[]
      This contains the plaintext/ciphertext to be encrypted/decrypted. It must contain 8 bytes of data. Padding may be necessary if it is the last block of the plaintext.
    • unsigned char out[]
      This contains the encrypted/decrypted ciphertext/plaintext output. It must be 8 bytes in size.
    • unsigned int key[][6]
      The “schedule” array from the key_schedule() function.


For 3DES:
  • void three_des_key_schedule(unsigned char key[], unsigned char schedule[][16][6], unsigned int mode)

    • unsigned char key[]
      This array must contain 24 bytes of data to be used as the encryption key.
    • unsigned int schedule[][16][6]
      Must be 3 arrays each with 16 arrays of 6 bytes each.
    • unsigned int mode
      Set this equal to the macro-defined ENCRYPT or DECRYPT values.


  • three_des_crypt()
    function must be called, the same function both encrypts or decrypts the data.

    • unsigned char in[]
      Must contain 8 bytes of data to be encrypted/decrypted.
    • unsigned char out[]
      Must be 8 bytes in size to hold the encrypted/decrypted data.
    • unsigned int key[][16][6]
      The “schedule” array from three_key_schedule() function.




Code Usage
For DES:
  1. Generate an 8 byte key. Note that only the seven most significant bits of each byte will actually be used.
  2. Use the key_schedule() function to generate a key schedule from the eight byte key.
  3. Use the des_crypt() function to encrypt your plaintext in blocks of 8 bytes. (You will likely have to pad your last block of plaintext.) The output is the ciphertext.
  4. To decrypt the ciphertext, switch the “mode” argument for des_crypt() and pass said function the ciphertext as input.
For 3DES:
  1. Generate a 24 byte key. Note that only the seven most significant bits of each byte will actually be used.
  2. Use the three_des_key_schedule() function to expand the key into a key schedule.
  3. Use the three_des_crypt() function to encrypt your plaintext in blocks of 8 bytes. (You will likely have to pad your last block of plaintext.) The output is the ciphertext.
  4. To decrypt the ciphertext, switch the “mode” argument for three_des_crypt() and pass said function the ciphertext as input.
Code
Source Code
Sample Driver Program

Notes
This implementation adheres fully to the official DES specification and includes the Initial Permutation and Inverse Initial Permutation steps that are often neglected for convenience, as they serve no cryptographic purposes.

This is an amature implementation of DES. It has benchmarked to be fairly slow and has not been designed to be resistant to any sort of side-channel attacks. Hopefully I will optimize and attack-proof it in the future.

SHA-1 – C

• By Brad Conte, June 28, 2006
• Post Categories: My Code
Algorithm
This is an implementation of the SHA-1 hash algorithm.

Code Documentation
  • SHA1_CTX
    A MD5 structure that will hold all hash-related data and calculations as the hash is calculated.

  • SHA1_init(SHA1_CTX *ctx)
    Initializes the SHA1_CTX object.

  • SHA1_update(SHA1_CTX *ctx, unsigned char data[], int len)
    Once an object has been created and initialized, the data to be hashed must be added. Due to practical limitations, it may not be optimal (or possible) to add all the data to the SHA1 hash in one data chunk, so the function inputs, stores, and calculates data as it is received, allowing the data to be added in as many chunks as necessary.

    • unsigned char data[]
      This is the data to be added to the hash.
    • int len
      This is the length, in bytes, of the data in the “data” array.


  • SHA1_final(SHA1_CTX *ctx, unsigned char hash[])
    Finalize and output the hash.

    • unsigned char hash[]
      This is the array to store the output hash. It must be at least 16 bytes in size.
Code Usage
  1. Create an SHA1_CTX object.
  2. Initialize it with sha1_init().
  3. Read some/all of the data to hash into an array, calculate the size of the data, and add it to the hash with sha1_update().
  4. Repeat the previous step for all the data you want to hash.
  5. Finalize and output the hash with sha1_final().
Repeat steps (2) to (5) for as many hashes as you want to calculate.

Code
Source Code
Sample Driver Program

Notes
The 32-bit words (which in this case are unsigned integers) used in the code use little endian byte ordering. The SHA-1 specification uses the big endian byte order, so some byte-reversals are made when copying data into and out of integers in this code.

This algorithm has not been optimized, although some general attempts have been made to that effect. This algorithm has been tested against numerous test vectors (including all official ones) and passed the tests.

This algorithm can hash data of any length, although 264 bits (2,147,483,648 gigabytes) is the recommended limit.

It is worth noting that SHA-1 is no longer considered a perfectly secure hash algorithm. It is recommended that a hash algorithm such as Whirlpool or RIPE-MD, or even SHA-1 with double the number of standard rounds, be used in when security is critical.

MD5 – C

• By Brad Conte, June 21, 2006
• Post Categories: My Code
Algorithm
This is an implementation of the MD5 hash algorithm.

Code Documentation
  • MD5_CTX
    A MD5 structure that will hold all hash-related data and calculations as the hash is calculated.

  • md5_init(MD5_CTX *ctx)
    Initializes the MD5_CTX object.

  • md5_update(MD5_CTX *ctx, unsigned char data[], int len)
    Once an object has been created and initialized, the data to be hashed must be added. Due to practical limitations, it may not be optimal (or possible) to add all the data to the MD5 hash in one data chunk, so the function inputs, stores, and calculates data as it is received, allowing the data to be added in as many chunks as necessary.

    • unsigned char data[]
      This is the data to be added to the hash.
    • int len
      This is the length, in bytes, of the data in the “data” array.


  • md5_final(MD5_CTX *ctx, unsigned char hash[])
    Finalize and output the hash.

    • unsigned char hash[]
      This is the array to store the output hash. It must be at least 16 bytes in size.
Code Usage
  1. Create an MD5_CTX object.
  2. Initialize it with md5_init().
  3. Read some/all of the data to hash into an array, calculate the size of the data, and add it to the hash with md5_update().
  4. Repeat the previous step for all the data you want to hash.
  5. Finalize and output the hash with md5_final().
Repeat steps (2) to (5) for as many hashes as you want to calculate.

Code
Source Code
Sample Driver Program

Notes
The 32-bit words (which in this case are unsigned integers) used in the code assume little endian byte ordering. The MD5 specification uses the big endian byte order, so some byte-reversals are made when copying data into and out of integers in this code.

This algorithm has not actually been optimized, although some general attempts have been made to that effect. This algorithm has been tested against numerous test vectors (including all official ones) and has proved to be accurate.

This algorithm can hash data of any length, although 264 bits (2,147,483,648 gigabytes) is the recommended limit.

Note, that MD5 is no longer considered a reasonably secure hash algorithm. It is recommended that a hash algorithm such as Whirlpool, RIPEMD, or SHA1 (with double the number of standard rounds) be used rather than MD5.

MD2 – C

• By Brad Conte, June 20, 2006
• Post Categories: My Code
Algorithm
This is an implementation of the MD2 hash algorithm. This algorithm can hash data of any given length.

Code Documentation
  • MD2_CTX
    A MD2 object that will hold all hash-related data and calculations as the hash is calculated.

  • md2_init(MD2_CTX *ctx)
    Initialize the MD2_CTX object.

  • md2_update(MD2_CTX *ctx, unsigned char data[], int len)
    Once an object has been created and initialized, the data to be hashed must be added. Due to practical limitations, it may not be optimal (or possible) to add all the data to the MD2 hash in one data chunk, so the function inputs, stores, and calculates data as it is received, allowing the data to be added in as many chunks as necessary.

    • unsigned char data[]
      This is the data to be added to the hash.
    • int len
      This is the length, in bytes, of the data in the “data” array.


  • md2_final(MD2_CTX *ctx, unsigned char hash[])
    Finalize and output the hash.

    • unsigned char hash[]
      This is the array to store the output hash. It must be at least 16 bytes in size.
Code Usage
  1. Create an MD2_CTX object.
  2. Initialize it with md2_init().
  3. Read some/all of the data to hash into an array, calculate the size of the data, and add it to the hash with md2_update().
  4. Repeat the previous step for all the data you want to hash.
  5. Finalize and output the hash with md2_final().
Repeat steps (2) to (5) for as many hashes as you want to calculate.

Code
Source Code
Sample Driver Program

Notes
This implementation assumes little endian byte ordering (as the MD2 standard states it should). This algorithm not only has not been optimized, although some general attempts have been made to that effect. This implementation of MD2 has been tested against numerous test vectors (including all official ones) and has proved to be accurate.

Note that MD2 is not considered a secure hash algorithm. It is recommended that a hash algorithm such as Whirlpool or SHA-1 be used, or even MD5, as MD2 is grossly outdated.

How Not to Design a Campaign Billboard

• By Brad Conte, June 1, 2006
• Post Categories: Miscellaneous
I live in a rural California setting, situated in Congressional District #4. We are currently represented in the House of Representatives by Congressman John Doolittle, a guy who’s made a very solid political career for himself despite having the worst last name imaginable for a politician.

It’s five days (as of writing this) until the California primary elections are held, and, as always, campaign billboards and banners are out in full swing, offering information such as, “Dave Johnson: Values we trust” and “Joe Clark: Professionalism, Integrity, Good Hair,” and other vital voter information that the general public, come election day, will use to place an informed vote for the candidate who they have seen the most billboards for.

One such campaign banner caught my attention — not because of what it said, but rather because of what it failed to say. I’ve spotted this banner, pictured below, in a lot of places, one of which is by the main street near my house.

Billboard image from road


This photograph was taken from a car on the actual road, so that’s basically exactly what it looks like to a driver (at least, a driver who actually looks at it). At first glance, it looks like just another billboard that serves no purpose other than to display the candidate’s name (in this case, that of Congressman Doolittle’s) in big, bold letters, in an effort to boost the candidate’s name-recognition. It’s pathetic that the majority of political campaign boards are in this shallow vain, but it works. As a political candidate, simply getting your name as recognizable as possible by the public is a huge part of winning an election, and it appears that Congressman Doolittle understands this idea.

Here’s another picture of the same sign, this time a little bit closer and taken from the side of the road.

Billboard image from side of road


Again, it’s Congressman Dolittle’s name in big white letters contrasted against a solid black background. But this time the text above his name is more obvious. Let’s take a closer look at what it says.

Billboard image close up


Surprise — the banner is not for Congressman Dolittle after all. The text above his name reads, “How do you spell corruption?”, and it’s followed by “Congressman Doolittle”.

The sheer advertising stupidity being exhibited here leaves me in awe… Whoever sponsored this this campaign banner intended to approve the design of a billboard intended deface their opponent’s name, but actually managed to approve put his name in big, bold, white letters against a black background and the message defaming him in smallish, dark blue letters against a light blue background, creating an effect such that Doolittle’s name glares out broadly and clearly but the message against him basically blurs out and gets lost.

Close up, all of the board’s text is easily readable. But as you can see from the two previous photographs, the most critical part of the text isn’t so obvious to a driver. Scratch that, it isn’t obvious at all. I drove past that very sign for at least 3 weeks before I noticed what it actually said.

The average driver, judging from the driving habits I’ve seen, isn’t necessarily watching the road, much less scrutinizing every bit of political propaganda that they see. Your average driver is coming home from a long day of work, rushing to the store before it closes, trying to read poorly written directions, talking to a friend, thinking about the term paper they’re turning in that day, or trying to remember whether or not they remembered to close the garage door when they left the house. Whatever their situation, they are not interested in scrutinizing a hard-to-read by the road.

When it comes to boring roadside banners, making it such that the reader has to exert effort to get the message will lose you 90% of your audience. You have to make your message in-your-face obvious or it simply will not be read.

But even though the banner fails to get the desired message across, the true marvel of it is that it actually does its sponsor more harm than good. On average, the worst a poorly designed political billboard can do is not be readable, and thus not result in any net gain for the candidate sponsoring it. But this billboard actually scores negatively, because it not only fails to make its real message readable, but it blatantly looks like a billboard supporting the opponent. Doolittle’s name is in big letters, while the critical message against him is obscured. To the average passer-by, this looks like a blatanent ad for Doolittle.

So what lesson did we learn? Simple: If you have to create a visual advertisement, be sure to consider how and where your audience will see it. Make your message bloody obvious, and, above all else, do not leave any room for misinterpretation. Readers are much more likely to remember a name than a concept, so ensure that any information you provide about a name you’re trying to defame is more obvious than the name itself.

I wonder if Doolittle chuckles himself to sleep at night, thinking of the free advertising he got from his opponents… and this article.

« Older PostsNewer Posts »