# Jak agenci AI i kontrakty Meyera wykrywają błędy kryptograficzne przed produkcją
Agenci AI zmieniają reguły gry w rozwoju bezpiecznych systemów: zamiast ręcznego pisania kodu i testów generują implementację na podstawie formalnych kontraktów. To eliminuje główną przyczynę porażki Design by Contract — podwójną pracę. W projekcie z sprzętowym TRNG i PKI dwie krytyczne luki zostały wykryte właśnie dzięki testom kontraktowym, których zwykłe testy jednostkowe by nie złapały.
Dlaczego testy nie wykrywają błędów logicznych w kryptografii
Testy sprawdzają tylko to, co programista przewidział. Jeśli nie wiedział o potrzebie weryfikacji paddingu w RSA czy jakości entropii przed podaniem do DRBG — test tego nie napisze. Dokładnie tak 27-letni błąd w OpenBSD i 16-letnia luka w FFmpeg przeszły przez miliony automatycznych sprawdzeń. Kompilatory i statyczne analizatory też są bezsilne wobec błędów logicznych: wybór niewłaściwego trybu szyfrowania, brak weryfikacji cofnięcia certyfikatu, użycie przestarzałych standardów — to wszystko pozostaje poza ich zasięgiem.
Kluczowy problem: testy reagują na implementację, a nie na intencję. Kontrakty natomiast utrwalają intencję przed napisaniem kodu. Określają granice: co system musi zrobić (postwarunki), co mu zabronione (inwarianty) i w jakich warunkach może być wywołany (przedwarunki). To nie tylko dokumentacja — to wykonywalna specyfikacja.
Oto co wyróżnia podejście kontraktowe:
- Formalność: PRE/POST/INV zapisywane w formie czytelnej dla maszyny, a nie w komentarzach.
- Wczesna weryfikacja: naruszenie kontraktu powoduje błąd od razu, a nie w produkcji.
- Skupienie na gwarancjach: zamiast „jak działa” — „co jest gwarantowane".
- Źródło prawdy: kontrakt nie zmienia się w trakcie rozwoju, modyfikuje się go tylko przy zmianie wymagań.
Jak agent AI przejmuje drugą połowę pracy
Design by Contract nie przyjął się w mainstreamie z powodu podwójnego obciążenia: najpierw kontrakt, potem kod, potem testy. Pod presją terminów kontrakty były pierwsze do wyrzucenia. Dziś agent AI bierze na siebie implementację i generowanie testów, pozostawiając człowiekowi tylko sformułowanie kontraktu. To zmienia ekonomię: jedna linia kontraktu zastępuje setki linii kodu i testów.
Proces wygląda następująco:
- Człowiek pisze inwariant:
padding == RSA-PSS | RSA-OAEP; PKCS#1 v1.5 == ZABRONIONE. - Agent generuje moduł CryptoEngine, który używa tylko dozwolonych paddingów.
- Równolegle agent tworzy test kontraktowy, który próbuje użyć PKCS#1 v1.5 i oczekuje wyjątku.
- Jeśli test pada — agent poprawia implementację, nie ruszając kontraktu.
- Człowiek weryfikuje tylko 10 linii kontraktu, a nie 1000 linii kodu.
Zalety:
- Szybkość: 11 dni aktywnej pracy nad projektem fullstack embedded zamiast miesięcy.
- Niezawodność: kontrakt to punkt skupienia, błędy w nim łatwiejsze do znalezienia niż w kodzie.
- Skalowalność: jedna osoba zarządza agentami w różnych rolach (koder, tester, architekt).
Prawdziwy przypadek: PKI ze sprzętowym TRNG i testami kontraktowymi
Projekt pki-on-box obejmuje pięć modułów: STM32G431 (sprzętowy TRNG), demon Python (DRBG wg NIST SP 800-90A), CryptoEngine (generacja kluczy), KeyStorage (AES-256-GCM), usługa CA (podpis X.509). Każdy moduł ma formalny kontrakt na styku. Dwie krytyczne luki znaleziono przed wdrożeniem:
- Niewłaściwy padding: implementacja przypadkowo użyła PKCS#1 v1.5 zamiast RSA-PSS. Atak Bleichenbachera pozwala odzyskać plaintext przez padding oracle — test kontraktowy natychmiast padł.
- Niewłaściwy tryb AES: zamiast GCM wybrano ECB. Kontrakt wymagał uwierzytelnionego szyfrowania — test znów padł.
Metryki projektu:
- 131 commitów
- 62 testy kontraktowe + 15 testów sprzętowych
- 3 płytki MCU (STM32G474, G431, H750)
- Platforma docelowa: RK3328 ARM64
- Koszt AI: 1780₽ za 30 sesji
- Otwarty repozytorium: github.com/vasilievsv/hw.pki-on-box
Kontrakty na styku modułów: tam rodzą się krytyczne błędy
Błędy logiczne powstają na granicach modułów. DRBG dostarcza bajty — CryptoEngine musi wiedzieć, jak ich użyć. Bez kontraktu ktoś wybierze padding z przykładu ze StackOverflow. Oto dwa kluczowe kontrakty z projektu:
contract: key_generation
PRE:
- DRBG.seeded == true
- algorithm ∈ {RSA-2048, ECDSA-P384}
POST:
- private_key.encrypted(AES-256-GCM)
- public_key = derive(private_key)
INV:
- padding == RSA-PSS | RSA-OAEP
- PKCS#1 v1.5 == ZABRONIONE
contract: certificate_issuance
PRE:
- issuer_ca.valid() && !revoked()
- csr.signature.verify() == true
POST:
- cert.serial.unique()
- cert.signature.verify(issuer_ca.public_key) == true
INV:
- root_ca.offline == true
- cert_chain.depth <= max_path_length
Test kontraktowy dla paddingu:
def test_rejects_pkcs1v15_padding(self, crypto):
priv, pub = crypto.generate_rsa_keypair(bits=2048)
data = b"invariant check"
sig = crypto.sign_data(priv, data)
# PSS musi działać
pub.verify(sig, data, padding.PSS(...))
# PKCS1v15 musi się wysypać
with pytest.raises(Exception):
pub.verify(sig, data, padding.PKCS1v15(), hashes.SHA256())
Test nie sprawdza funkcjonalności — sprawdza przestrzeganie inwarianta. Jeśli padding się zmieni — test padnie, nawet jeśli podpis technicznie „działa”.
Co najważniejsze
- Kontrakty > testy: testy weryfikują implementację, kontrakty — intencję. Błędy logiczne łapie się tylko przez formalne gwarancje.
- AI eliminuje podwójną pracę: agent generuje kod i testy z kontraktu, człowiek skupia się na specyfikacji.
- Krytyczne błędy na styku: padding, tryby szyfrowania, weryfikacja cofnięcia — wszystko kontrolowane inwariantami na granicach modułów.
- Otwarta weryfikacja: projekt ze sprzętowym TRNG i testami kontraktowymi dostępny w otwartym repozytorium do audytu.
- Ekonomia czasu: 11 dni na system fullstack embedded zamiast miesięcy — dzięki podziałowi ról i autogeneracji.
— Editorial Team
Brak komentarzy.