AI 에이전트와 계약에 의한 설계가 프로덕션 전에 크립토 버그를 포착하는 방법
AI 에이전트는 보안 시스템 개발의 판도를 바꾸고 있습니다. 수동으로 코드와 테스트를 작성하는 대신 형식 계약에 기반한 구현을 생성하죠. 이는 Design by Contract가 실패했던 주요 원인인 이중 작업을 없애줍니다. 하드웨어 TRNG와 PKI를 사용하는 프로젝트에서 일반 단위 테스트로는 놓쳤을 두 개의 치명적 취약점이 바로 계약 테스트를 통해 포착되었습니다.
테스트가 암호화학의 논리적 오류를 놓치는 이유
테스트는 프로그래머가 생각한 것만 확인합니다. RSA의 패딩 검증이나 DRBG에 입력하기 전에 엔트로피 품질을 확인할 생각을 못 했다면—테스트는 스스로 작성되지 않죠. 바로 그래서 OpenBSD의 27년 된 버그와 FFmpeg의 16년 된 취약점이 수백만 건의 자동 검사에서 빠져나갔습니다. 컴파일러와 정적 분석기는 논리적 오류 앞에서는 무력합니다: 잘못된 암호화 모드 선택, 인증서 폐지 확인 생략, 구식 표준 사용—이 모든 게 그들의 레이더를 피해갑니다.
핵심 문제: 테스트는 구현에 반응할 뿐 의도를 확인하지 않습니다. 계약은 코드 작성 전에 의도를 포착합니다. 시스템이 반드시 해야 할 일(후조건), 금지된 것(불변식), 호출 조건(전조건)을 경계를 설정하죠. 이는 단순 문서가 아닙니다—실행 가능한 명세입니다.
계약 접근법의 차별점은 다음과 같습니다:
- 형식성: PRE/POST/INV를 주석이 아닌 기계 판독 가능 형태로 작성.
- 조기 탐지: 계약 위반은 프로덕션에서가 아닌 즉시 실패.
- 보증 중심: "어떻게 작동하나"가 아닌 "무엇이 보증되나"에 초점.
- 진실의 단일 원천: 개발 중 계약은 변경되지 않음; 요구사항 변경 시에만 업데이트.
AI 에이전트가 작업의 후반부를 처리하는 방식
Design by Contract는 주류에서 이중 작업량 때문에 실패했습니다: 먼저 계약 작성, 코드 작성, 테스트 작성. 마감 압박 속에서 계약이 가장 먼저 희생됐죠. 오늘날 AI 에이전트가 구현과 테스트 생성을 맡아 인간은 계약만 작성합니다. 이는 경제성을 바꿉니다: 계약 한 줄이 코드와 테스트 수백 줄을 대체하죠.
프로세스는 다음과 같습니다:
- 인간이 불변식 작성:
padding == RSA-PSS | RSA-OAEP; PKCS#1 v1.5 == FORBIDDEN. - 에이전트가 허용 패딩만 사용하는 CryptoEngine 모듈 생성.
- 동시에 에이전트가 PKCS#1 v1.5 사용 시 예외를 기대하는 계약 테스트 생성.
- 테스트 실패 시—에이전트가 계약 건드리지 않고 구현 수정.
- 인간은 10줄 계약만 검토, 1000줄 코드 아님.
장점:
- 속도: 전체 스택 임베디드 프로젝트에 개월 대신 11일 적극 작업.
- 신뢰성: 계약이 초점; 코드보다 오류 발견 쉬움.
- 확장성: 한 사람이 코더, 테스터, 아키텍트 역할 에이전트 관리.
실제 사례: 하드웨어 TRNG와 계약 테스트를 사용한 PKI
pki-on-box 프로젝트는 다섯 모듈 포함: STM32G431 (하드웨어 TRNG), Python 데몬 (NIST SP 800-90A 기준 DRBG), CryptoEngine (키 생성), KeyStorage (AES-256-GCM), CA 서비스 (X.509 서명). 각 모듈 인터페이스에 형식 계약 있음. 배포 전에 두 치명적 취약점 발견:
- 잘못된 패딩: 구현이 RSA-PSS 대신 PKCS#1 v1.5 우연히 사용. Bleichenbacher 공격으로 패딩 오라클 통해 평문 복구 가능—계약 테스트 즉시 실패.
- 잘못된 AES 모드: GCM 대신 ECB 선택. 계약이 인증 암호화 요구—테스트 다시 실패.
프로젝트 지표:
- 131 commits
- 62 contract-tests + 15 HW-tests
- 3 MCU boards (STM32G474, G431, H750)
- Target platform: RK3328 ARM64
- AI cost: 1780₽ for 30 sessions
- Open repository: github.com/vasilievsv/hw.pki-on-box
인터페이스의 계약: 치명적 오류가 발생하는 곳
논리적 오류는 모듈 경계에서 발생합니다. DRBG가 바이트 출력—CryptoEngine가 사용법 알아야. 계약 없인 누군가 StackOverflow 예제에서 패딩 고름. 프로젝트의 두 핵심 계약:
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 == FORBIDDEN
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
패딩에 대한 계약 테스트:
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 must rabotat
pub.verify(sig, data, padding.PSS(...))
# PKCS1v15 must slomatsya
with pytest.raises(Exception):
pub.verify(sig, data, padding.PKCS1v15(), hashes.SHA256())
이 테스트는 기능 확인이 아닙니다—불변식 준수 확인. 패딩 변경 시 테스트 실패, 서명이 "기술적으로 작동"해도.
주요 교훈
- 계약 > 테스트: 테스트는 구현 확인; 계약은 의도 확인. 논리적 오류는 형식 보증으로만 포착.
- AI가 이중 작업 제거: 에이전트가 계약에서 코드와 테스트 생성; 인간은 명세에 집중.
- 경계의 치명적 오류: 패딩, 암호화 모드, 폐지 확인—모듈 인터페이스 불변식으로 제어.
- 오픈 검증: 하드웨어 TRNG와 계약 테스트 프로젝트 오픈 저장소로 감사 가능.
- 시간 경제성: 역할 분담과 자동 생성 덕에 전체 스택 임베디드 시스템 11일 만에 완성—개월 대신.
— Editorial Team
아직 댓글이 없습니다.