Python Challenge - Level 19

Problem

The page title is please! and the HTML source contains an email message from [email protected] containing a base64-encoded attachment named indian.wav.

Inspecting the map of India and the title hints at byte ordering: endianness (Indian ↔ Endian).

Solution

The WAV audio file has reversed byte order (big-endian vs little-endian for 16-bit PCM samples). Swapping every pair of adjacent bytes (bytes 2k and 2k + 1) fixes the audio stream.

When played, the corrected audio clearly speaks: "Sorry!". Visiting sorry.html leads to: "what? 'sorry'? it's not you, it's the other idiot." The next page is therefore idiot2.html.

Python

import base64
import email
import wave

# Read MIME email and extract audio payload
with open("email.txt", "r") as f:
    msg = email.message_from_file(f)

for part in msg.walk():
    if part.get_content_type() == "audio/x-wav":
        audio_data = part.get_payload(decode=True)
        with open("indian.wav", "wb") as w:
            w.write(audio_data)

# Read frames and swap byte order (16-bit samples = 2 bytes per sample)
with wave.open("indian.wav", "rb") as w_in:
    params = w_in.getparams()
    frames = bytearray(w_in.readframes(w_in.getnframes()))

# Swap adjacent bytes
for i in range(0, len(frames), 2):
    frames[i], frames[i + 1] = frames[i + 1], frames[i]

with wave.open("fixed.wav", "wb") as w_out:
    w_out.setparams(params)
    w_out.writeframes(frames)

Go

package main

import (
	"encoding/binary"
	"io"
	"os"
)

func main() {
	data, err := os.ReadFile("indian.wav")
	if err != nil {
		panic(err)
	}

	// WAV header is 44 bytes; audio PCM data follows
	header := data[:44]
	pcm := make([]byte, len(data[44:]))
	copy(pcm, data[44:])

	// Swap byte pairs (16-bit little-endian <-> big-endian)
	for i := 0; i < len(pcm)-1; i += 2 {
		pcm[i], pcm[i+1] = pcm[i+1], pcm[i]
	}

	out, err := os.Create("fixed.wav")
	if err != nil {
		panic(err)
	}
	defer out.Close()

	out.Write(header)
	out.Write(pcm)
}

Rust

use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut data = fs::read("indian.wav")?;

    // In a standard canonical WAV, PCM audio data starts after the 44-byte header
    if data.len() > 44 {
        let pcm = &mut data[44..];
        for chunk in pcm.chunks_exact_mut(2) {
            chunk.swap(0, 1);
        }
    }

    fs::write("fixed.wav", &data)?;
    println!("Audio fixed: plays 'Sorry!'");
    Ok(())
}

Language Comparison

Feature Python Go Rust
WAV / Audio Parsing Standard library wave module parses headers and samples No stdlib audio package; manual header offset or go-audio/wav No stdlib audio package; hound crate or manual header parsing
Byte Swapping Mutable bytearray indexing frames[i], frames[i+1] = frames[i+1], frames[i] pcm[i], pcm[i+1] = pcm[i+1], pcm[i] on byte slices chunk.swap(0, 1) on chunks_exact_mut(2) iterator
MIME Email Decoding email package in stdlib automatically parses multipart payloads net/mail in stdlib parses headers; MIME parts parsed via mime/multipart mailparse crate

Key insight: Rust's chunks_exact_mut(2) iterator method provides a safe, idiomatic, bounds-check-optimized way to swap pairs of bytes without manual index management. Python's built-in wave module simplifies WAV metadata inspection, while Go's slice manipulation allows direct manipulation of the PCM payload.

Next Level

The audio says "Sorry", which directs to sorry.html, leading to:

http://www.pythonchallenge.com/pc/hex/idiot2.html

Loading...