Codeer met priemgetallen

In oktober 1999 bracht een groep onder leiding van de toen 16-jarige Noor Jon Lech Johansen het DeCSS- programma uit om de Content Scramble System (CSS)-beveiliging voor dvd-weergave te omzeilen. CSS gebruikte 40-bits encryptie, waarvan de sleutels werden verspreid onder gelicentieerde fabrikanten, om dvd-weergave te beperken. Omdat de verspreiding van de code onder de Amerikaanse DMCA viel en wettelijk verboden was, zochten activisten naar manieren om de code te vermommen als een wiskundige entiteit.


Phil Carmody construeerde vervolgens een priemgetal dat, na gzip-decompressie in binaire vorm geïnterpreteerd, de volledige broncode van DeCSS bevat. De kern van het DeCSS-algoritme kan in TypeScript als volgt worden geïmplementeerd, waarbij de bitbewerkingen rechtstreeks de sectorontsleutelingslogica weergeven.:

function CSSdescramble(sec: Uint8Array, key: Uint8Array): void {
    let t1: number, t2: number, t3: number, t4: number, t5: number, t6: number;
    const end = 0x800;

    t1 = (key[0] ^ sec[0x54]) | 0x100;
    t2 = key[1] ^ sec[0x55];

    const keyView = new DataView(key.buffer, key.byteOffset);
    const secView = new DataView(sec.buffer, sec.byteOffset);

    t3 = (keyView.getUint32(2, true) ^ secView.getUint32(0x56, true)) >>> 0;
    t4 = t3 & 7;
    t3 = (t3 * 2 + 8 - t4) >>> 0;

    let offset = 0x80;
    t5 = 0;

    while (offset < end) {
        t4 = CSStab2[t2] ^ CSStab3[t1];
        t2 = t1 >>> 1;
        t1 = ((t1 & 1) << 8) ^ t4;
        t4 = CSStab5[t4];
        t6 = (((((((t3 >>> 3) ^ t3) >>> 1) ^ t3) >>> 8) ^ t3) >>> 5) & 0xff;
        t3 = (((t3 << 8) >>> 0) | t6) >>> 0;
        t6 = CSStab4[t6];
        t5 += t6 + t4;

        sec[offset] = CSStab1[sec[offset]] ^ (t5 & 0xff);
        t5 >>>= 8;
        offset++;
    }
}

Het principe achter het priemgetal is om de volledige broncode te interpreteren als één enkel, solide geheel getal. Omdat geen enkel bestand ooit een priemgetal is, wordt het getal kunstmatig aangevuld met extra bytes (padding). Deze padding wordt in een lus verhoogd totdat een primaliteitstest, zoals de Miller-Rabin-test, bevestigt dat het getal priem is. De volgende generator gebruikt de hierboven beschreven DeCSS-code en zoekt naar een overeenkomstige representatie als een priemgetal.:

import { isPrime } from 'crypto-utils-lib'; // Hypothetical library for primality testing

async function generateIllegalPrime(code: string): Promise<bigint | null> {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(code);

    let hexBase = Array.from(bytes)
        .map(b => b.toString(16).padStart(2, '0'))
        .join('');

    // Start bei 1, da 0x00 immer gerade und damit keine Primzahl ist
    for (let i = 1; i < 256; i++) {
        const candidateHex = hexBase + i.toString(16).padStart(2, '0');
        const candidateInt = BigInt('0x' + candidateHex);

        if (await isPrime(candidateInt)) {
            return candidateInt;
        }
    }
    return null;
}

const source = `void CSSdescramble(unsigned char *sec, unsigned char *key) { ... }`;
generateIllegalPrime(source).then(p => console.log(p));

De priemgetaltruc was nooit onderwerp van een aparte rechtszaak, en dat was ook niet nodig. Hoewel Carmody's oorspronkelijke priemgetal 1401 cijfers telde, was het te klein voor de top van de lijsten met de grootste priemgetallen van die tijd. Later creëerde hij een versie met 1905 cijfers, kunstmatig opgeblazen met null-bytes, waarmee hij de tiende plaats in de ECPP-ranglijst behaalde. Dit succes toonde aan dat het onmogelijk was om zuivere wiskunde te censureren, aangezien het getal zijn plaats op de lijst uitsluitend verdiende op basis van zijn wiskundige eigenschappen.

Terug