Cryptography

Last modified: 2024-01-18

Cryptography

Cryptography is for secure communications. It uses a wide variety of techniques.

CyberChef Magic

CyberChef is a swiss army knife for cryptography.
Especially, "Magic" tool can process the given hashes automatically.
So it's recommended to use the "Magic" at first. It can be found on the left pane.


quipqiup

quipqiup is an online cryptogram solver. It can solve substitution ciphers often found in newspapers, including puzzles like cryptoquips and patristocrats.


OSINT

Before cracking, hashes might be revealed online so worth searching them with search engines.
Below are Google Dorks for this purpose. Note that hashes are surrounded with double-quotes.

"WVLY0mgH0RtUI"
"5d41402abc4b2a76b9719d911017c592"

Also we can use online tools to decrypt.


Identify the Cipher

Online Tools

CLIs

Manual Identification

The following cryptos mean "hello".

# Base32
NBSWY3DPEB3W64TMMQ======
# Base58
StV1DL6CwTryKyV
# Base64
aGVsbG8gd29ybGQ=

# Binary
01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111 01110010 01101100 01100100

# Decimal
104 101 108 108 111 32 119 111 114 108 100

# Hex
68 65 6c 6c 6f 20 77 6f 72 6c 64
68656c6c6f20776f726c64

# Morse Code
.... . .-.. .-.. ---
.-- --- .-. .-.. -..

# MD4
aa010fbc1d14c795d86ef98c95479d17
# MD5
5eb63bbbe01eeed093cb22bb8f5acdc3

# ROT13
uryyb jbeyq
# ROT47
96==@ H@C=5

# SHA1
2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
# SHA256
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
# SHA512
9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043

Binary Data Manual Operations

Using Python.

1. Change Hex to Base

import codecs

hex = "49276d206b6e6f"

b64 = codecs.encode(codecs.decode(hex, 'hex'), 'base64').decode()
print(b64)

2. XOR

  • Basic XOR

    hex1 = "1c0111001f010100061a024b53535009181c"
    hex2 = "686974207468652062756c6c277320657965"
    
    xored_hex = hex(int(hex1, 16) ^ int(hex2, 16))
    # Display without prefix '0x' by slicing [2:]
    print(xored_hex[2:])
    
  • Single-Byte XOR

    # Basic function
    def single_byte_xor(text: bytes, key: int) -> bytes:
        return bytes([b ^ key for b in text])
    
    # ---------------------------------------------------------------
        
    # Enctyption
    ciphertext = single_byte_xor(b"hello", 69)
    print(ciphertext)
    
    # Decryption
    ciphertext = single_byte_xor(b"- ))*", 69)
    print(ciphertext)
    
  • Crack Single-Byte XOR

    import random
    import string
    from collections import Counter
    from typing import Tuple
    
    def single_byte_xor(text: bytes, key: int) -> str:
        return bytes([b ^ key for b in text])
    
    def fitting_quotient(text: bytes) -> float:
        counter = Counter(text)
        dist_text = [
            (counter.get(ord(ch), 0) * 100) / len(text)
            for ch in occurence_english
        ]
            
        return sum([abs(a - b) for a, b in zip(dist_english, dist_text)]) / len(dist_text)
        
    def decipher(text: bytes) -> Tuple[bytes, int]:
        original_text, encryption_key, min_fq = None, None, None
        for k in range(256):
            # Generate the plaintext using encryption key 'k'
            _text = single_byte_xor(text, k)
            # Compute the fitting quotient for this decrypted plaintext
            fq = fitting_quotient(_text)
            # If the fitting quotient of this generated plaintext is less than the minimum seen till now 'min_fq' we update.
            if min_fq is None or fq < min_fq:
                encryption_key, original_text, min_fq = k, _text, fq
                
        # Return the text and key that has the minimum fitting quotient
        return original_text, encryption_key
        
        
    plaintext = b"Hello world"
    plaintext = plaintext.lower()
    
    key = 82
    
    ciphertext = single_byte_xor(plaintext, key)
    
    occurence_english = {
        'a': 8.2389258, 'b': 1.5051398, 'c': 2.8065007, 'd': 4.2904556,
        'e': 12.813865, 'f': 2.2476217, 'g': 2.0327458, 'h': 6.1476691,
        'i': 6.1476691, 'j': 0.1543474, 'k': 0.7787989, 'l': 4.0604477,
        'm': 2.4271893, 'n': 6.8084376, 'o': 7.5731132, 'p': 1.9459884,
        'q': 0.0958366, 'r': 6.0397268, 's': 6.3827211, 't': 9.1357551,
        'u': 2.7822893, 'v': 0.9866131, 'w': 2.3807842, 'x': 0.1513210,
        'y': 1.9913847, 'z': 0.0746517
    }
    
    dist_english = list(occurence_english.values())
    
    sentences = [
        b'His mind was blown that there was nothing in space except space itself.',
        b'I love bacon, beer, birds, and baboons.',
        b'With a single flip of the coin, his life changed forever.',
        b'The three-year-old girl ran down the beach as the kite flew behind her.',
    ]
    
    for sentence in sentences:
        sentence = sentence.lower()
        encryption_key = random.randint(10, 220)
        assert decipher(single_byte_xor(sentence, encryption_key)) == (sentence, encryption_key,)
        
        (_plaintext, _key) = decipher(single_byte_xor(sentence, encryption_key))
        print(_plaintext)
        print(_key)
        print("\n")
    

Crack Hashes

  1. Online Tools

  2. Cracking Tools

    First of all, you need to put the hash into the file like the following.

    echo -n '4bc9ae2b9236c2ad02d81491dcb51d5f' > hash.txt
    

    If you don't know which hash type it is, Example Hashes may help you.

    For brute forcing without wordlists in Hashcat, use the following command.

    hashcat -m <hash-mode> -a 3 '?a?a?a?a?a'
    

Wordlists for Cracking

Fetch Wordlists

Wordlistctl is a CLI that fetches, installs and searches wordlist archives from websites and torrent peers.

To fetch the wordlist, run as follow:

# -l: Wordlist
# -d: Decompress and remove archive
wordlistctl fetch -l dogs -d /usr/share/wordlists/misc/dogs.txt
wordlistctl fetch -l top_1000_usa_malenames_english -d /usr/share/wordlists/misc/top_1000_usa_malename_english.txt
wordlistctl fetch -l femalenames-usa-top1000 -d /usr/share/wordlists/usernames/femalenames-usa-top1000

Custom Wordlist

Below are some techniques to customize wordlists.

# Replace all 'c' with '$'
sed 's/c/$/g' origin.txt > new.txt

# Toggle the case of the second character
sed 's/\(.\)\(.\)\(.*\)/\1\U\2\E\3/g' origin.txt > new.txt

Encrypt Files

openssl enc -in /etc/passwd -out /tmp/passwd
openssl enc -in /tmp/passwd -out /etc/passwd

Useful Commands

  • Generate Random Strings

    # Hex encoded password
    openssl rand -hex 4