Published on

Decrypting Kryptos K1 using Vigenère Cipher

Authors

Decrypting Kryptos K1 using Vigenère Cipher

Introduction

In 1990, artist Jim Sanborn unveiled Kryptos, a sculpture located at CIA headquarters in Langley, Virginia. It features an encrypted message split into four parts—of which only the first three have been solved. This post focuses on the first section, K1, which was decrypted in 1998 using a keyed Vigenère cipher.

This article walks through the process of implementing the same decryption approach in C#, showcasing the core cryptographic mechanics involved.

K1 Overview

To decrypt K1, two keywords are needed:

  • Tableau key: KRYPTOS
  • Vigenère key: PALIMPSEST

The ciphertext:

EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJYQTQUXQBQVYUVLLTREVJYQTMKYRDMFD

This section of Kryptos is encrypted using a modified Vigenère cipher, where the standard alphabet is replaced by a customized one based on the tableau key.

Constructing the Keyed Alphabet

The keyed alphabet is formed by prepending the tableau key (KRYPTOS) to the base alphabet (A–Z) and removing duplicates.

static string BuildKeyedAlphabet(string alphabet, string key)
{
    var seen = new HashSet<char>();
    var sb = new StringBuilder();

    foreach (char c in key.ToUpperInvariant())
        if (seen.Add(c))
            sb.Append(c);

    foreach (char c in alphabet)
        if (seen.Add(c))
            sb.Append(c);

    return sb.ToString();
}

Example input:

BuildKeyedAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "KRYPTOS");

Output:

KRYPTOSABDEFGHIJLMNQUVWXZ

Vigenère Cipher in C#

This cipher implementation applies the standard Vigenère shift, but against a custom alphabet. Only characters in the defined alphabet are processed.

public class VigenereCipher
{
    private readonly string _letters, _keyword;
    private readonly int _lettersLength, _keyLength;

    public VigenereCipher(string letters, string keyword)
    {
        if (string.IsNullOrWhiteSpace(letters) || string.IsNullOrWhiteSpace(keyword))
            throw new ArgumentException("Letters and keyword must be non‑empty.");

        if (letters.Distinct().Count() != letters.Length ||
            keyword.Any(c => !letters.Contains(c)))
            throw new ArgumentException("Invalid letters or keyword.");

        _letters = letters;
        _keyword = keyword;
        _lettersLength = letters.Length;
        _keyLength = keyword.Length;
    }

    public string Decrypt(string text) => Convert(text, decrypt: true);

    private string Convert(string text, bool decrypt)
    {
        var sb = new StringBuilder();
        int ki = 0;

        foreach (char c in text)
        {
            if (!_letters.Contains(c)) continue;
            int shift = _letters.IndexOf(_keyword[ki]);
            if (decrypt) shift = _lettersLength - shift;
            int pos = (_letters.IndexOf(c) + shift) % _lettersLength;
            sb.Append(_letters[pos]);
            ki = (ki + 1) % _keyLength;
        }

        return sb.ToString();
    }
}

Putting It All Together

Here's the full decryption routine using the components above.

static void Main(string[] args)
{
    const string baseAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const string tableauKey   = "KRYPTOS";
    const string vigKey       = "PALIMPSEST";
    const string k1Cipher     =
        "EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJYQTQUXQBQVYUVLLTREVJYQTMKYRDMFD";

    string keyedAlphabet = BuildKeyedAlphabet(baseAlphabet, tableauKey);
    var cipher = new VigenereCipher(keyedAlphabet, vigKey);
    string plaintext = cipher.Decrypt(k1Cipher);

    Console.WriteLine($"Keyed Alphabet: {keyedAlphabet}");
    Console.WriteLine($"Ciphertext:     {k1Cipher}");
    Console.WriteLine($"Plaintext:      {plaintext}");
}

Output

Keyed Alphabet: KRYPTOSABDEFGHIJLMNQUVWXZ
Ciphertext:     EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJYQTQUXQBQVYUVLLTREVJYQTMKYRDMFD
Plaintext:      BETWEENSUBTLESHADINGANDTHEABSENCEOFLIGHTLIESTHENUANCEOFIQLUSION

The decrypted message reads:

Between subtle shading and the absence of light lies the nuance of iqlusion.

Keyed Vigenère Tableau

Below is the full keyed Vigenère tableau used to decrypt K1. It’s built using the base alphabet A–Z with the key KRYPTOS prepended, duplicates removed. Each row is a shifted version of this keyed alphabet.

Keyed Vigenère Tableau

Beyond K1: K2, K3, and the Unsolved K4

While K1 used a keyed Vigenère cipher, the next sections shift both in tone and method:

  • K2 continues with a keyed Vigenère approach, but with different keys (ABSCISSA and KRYPTOS). It introduces grid references and coordinates—hinting at a physical location.
  • K3 deviates from Vigenère and is encrypted using a transposition cipher. Its plaintext references Howard Carter’s discovery of Tutankhamun’s tomb, suggesting themes of hidden knowledge and excavation.
  • K4, comprising only 97 characters, remains unsolved to this day. Sanborn has released small hints over the years, but its meaning and method remain elusive. The solution to K4 is often believed to require contextual or extralinguistic insight, beyond pure algorithmic decryption.

Kryptos, as a whole, is a layered cryptographic puzzle—a blend of classical ciphers and thematic symbolism designed to test even the most capable codebreakers.