DEV Community

Khalif AL Mahmud
Khalif AL Mahmud

Posted on

Python Cryptography Basics: Building ASCII & Alphabet Tables from Scratch

When I first started digging into cryptography, I realized something quickly — before you can understand ciphers, encryption, or any real crypto concept, you need a solid grip on how computers actually represent characters. Numbers, binary, hex — it all starts there.

So I wrote two small Python programs that build these tables from scratch. Sounds simple, but honestly it clicked a lot of things into place for me. Let me walk you through both.


What We're Building

Program 1 — A table of uppercase letters (A–Z) with their decimal values (0–25), plus an arithmetic operation that adds 3 to each value.

Program 2 — A full ASCII table (characters 0–127) showing each character in Binary, Octal, Decimal, and Hexadecimal.


Program 1: Uppercase Alphabet Table with Arithmetic

The Problem

Map every uppercase letter A–Z to a number (A=0, B=1, ... Z=25), display the original table, then add 3 to every value and display an updated table.

This is actually the foundation of the Caesar cipher — shifting letters by a fixed number. That "add 3" operation? That's exactly what Caesar did.

The Code

print("Original Table:")
print("Letter\tDecimal")

letters = []
values = []

# A-Z Loop
for i in range(26):
    letter = chr(65 + i)   # ASCII of A = 65
    value = i
    letters.append(letter)
    values.append(value)
    print(f"{letter}\t{value}")

print("\nAfter Adding 3:")
print("Letter\tNew Value")

for i in range(26):
    new_value = values[i] + 3
    print(f"{letters[i]}\t{new_value}")
Enter fullscreen mode Exit fullscreen mode

Step-by-Step Breakdown

1. chr(65 + i) — How we get letters from numbers

In Python, chr() converts an integer to its ASCII character. Since A has ASCII value 65, chr(65) gives 'A', chr(66) gives 'B', and so on up to chr(90) which is 'Z'.

print(chr(65))  # Output: A
print(chr(90))  # Output: Z
Enter fullscreen mode Exit fullscreen mode

2. Storing letters and values in lists

We build two parallel lists — letters and values — so we can loop over them separately for the updated table.

3. Adding 3 to each value

new_value = values[i] + 3
Enter fullscreen mode Exit fullscreen mode

This shifts every letter's number by 3. In cryptography terms, this is a Caesar cipher with shift=3. A (0) becomes 3, B (1) becomes 4, and so on.

4. Tab-separated output with \t

Using \t gives clean columnar output in the terminal without needing any external libraries.

Screenshot

How to Run

python alphabet_table.py
Enter fullscreen mode Exit fullscreen mode

Expected Output (partial)

Original Table:
Letter  Decimal
A       0
B       1
C       2
...
Z       25

After Adding 3:
Letter  New Value
A       3
B       4
C       5
...
Enter fullscreen mode Exit fullscreen mode

Program 2: Full ASCII Table — Binary, Octal, Decimal, Hex

The Problem

Print all 128 standard ASCII characters with their representations in four number systems: Binary, Octal, Decimal, and Hexadecimal — all in a clean tabular format.

The Code

print("Char\tDecimal\tBinary\t\tOctal\tHex")

for i in range(128):   # standard ASCII
    char    = chr(i)
    decimal = ord(char)
    binary  = bin(i)
    octal   = oct(i)
    hexa    = hex(i)

    print(f"{char}\t{decimal}\t{binary}\t{octal}\t{hexa}")
Enter fullscreen mode Exit fullscreen mode

Step-by-Step Breakdown

1. range(128) — Standard ASCII range

ASCII defines 128 characters (0–127). The first 32 are control characters (non-printable), the rest are printable symbols, digits, and letters.

2. chr(i) — Integer to character

Converts each number to its corresponding ASCII character.

3. ord(char) — Character back to integer

ord() is the reverse of chr(). It takes a character and returns its ASCII decimal value. Useful to verify the round-trip conversion.

print(ord('A'))   # 65
print(chr(65))    # A
Enter fullscreen mode Exit fullscreen mode

4. bin(), oct(), hex() — Python's built-in converters

Function What it does Example output
bin(i) Converts to binary string 0b1000001
oct(i) Converts to octal string 0o101
hex(i) Converts to hexadecimal string 0x41

Python automatically adds prefixes (0b, 0o, 0x) so you always know which base you're looking at.

5. f-string formatting with \t

The \t tabs keep all columns aligned in the terminal without needing format() or any padding library.

Screenshot

How to Run

python ascii_table.py
Enter fullscreen mode Exit fullscreen mode

Expected Output (partial)

Char    Decimal Binary          Octal   Hex
A       65      0b1000001       0o101   0x41
B       66      0b1000010       0o102   0x42
C       67      0b1000011       0o103   0x43
...
a       97      0b1100001       0o141   0x61
b       98      0b1100010       0o142   0x62
Enter fullscreen mode Exit fullscreen mode

How to Verify Your Output

For Program 1:

  • Check that A maps to 0 and Z maps to 25
  • After adding 3: A should show 3, Z should show 28
  • Total rows: exactly 26 in each table

For Program 2:

  • A → decimal 65, binary 0b1000001, octal 0o101, hex 0x41
  • a → decimal 97 (lowercase is always 32 more than uppercase)
  • Total rows: 128 (0–127)

Quick sanity check in Python:

# Verify a few values manually
print(bin(65))   # 0b1000001
print(oct(65))   # 0o101
print(hex(65))   # 0x41
print(ord('A'))  # 65
Enter fullscreen mode Exit fullscreen mode

What I Learned

Going through this exercise, a few things clicked that I hadn't fully internalized before:

  • Every character is just a number. The letter A and the number 65 are the same thing from the machine's perspective. Encryption at its core is just math on these numbers.

  • The Caesar cipher is literally just addition. Adding 3 to each letter's value and the cipher is done. Subtracting 3 decrypts it. That's it.

  • Number bases aren't scary. Binary, octal, hex — they're just different ways to write the same value. Python's bin(), oct(), and hex() make conversion trivial, but understanding why they exist (hardware efficiency, readability) matters more than memorizing conversions.

  • chr() and ord() are the gateway to text-based cryptography. Every classical cipher — Caesar, Vigenere, ROT13 — uses this same idea of converting text to numbers, operating on them, and converting back.


Common Mistakes

Mistake Why it happens Fix
chr(i) starting from 0 gives weird symbols ASCII 0–31 are control characters Start from range(32, 128) if you only want printable chars
Forgetting chr(65 + i) and using chr(i) directly Off-by-one thinking A = 65 in ASCII, not 0
Values after adding 3 going past Z (25→28) Letters only go 0–25 Use modulo: (value + 3) % 26 for wrapping
Binary output looking messy in columns Binary strings have variable length Use format(i, '08b') for fixed 8-bit width
ord() and chr() confused Their names aren't obvious ord = ordinal (number), chr = character

Conclusion

These two programs are small, but they sit right at the foundation of everything in cryptography. Before you can implement any cipher — even the simplest one — you need to understand how characters map to numbers and how those numbers can be represented in different bases.

If you're starting your cryptography journey, I'd recommend running both of these, playing with the shift value in Program 1 (try 13 for ROT13), and spending a few minutes reading the ASCII table output carefully. It makes a lot of later concepts much easier to grasp.

Top comments (0)