메인 콘텐츠로 건너뛰기

13년 무결점 깨진 Libsodium, 이번 취약점 진짜 얼마나 위험할까?

암호 라이브러리 하면 OpenSSL, Bouncy Castle 같은 이름이 먼저 떠오르지만, 실제로 많은 서비스와 앱에서 조용히 일하는 라이브러리가 있습니다. 바로 “쉽게 쓰는 암호 라이브러리”를 표방하는 Libsodium입니다.

이 Libsodium이 무려 13년 동안 CVE 한 번 없이 버텨온 걸로 유명한데, 드디어(?) 취약점이 하나 보고됐습니다. 그런데 내용이 꽤 수학적이고, 코드는 로우레벨이고, 대부분의 글은 너무 기술적으로만 설명되어 있죠.

이 글에서는 개발자 눈높이에서 다음을 정리합니다.

  • Libsodium 취약점이 실제로 어떤 문제인지

  • 어떤 프로젝트가 영향을 받는지, 대부분은 왜 “안 무서운지”

  • Edwards25519, 부그룹, Ristretto255 같은 어려운 말들을 최대한 쉽게 풀어서

  • 지금 당장 개발자가 무엇을 해야 하는지 체크리스트로 정리

“우리 서비스 Libsodium 쓰는데, 지금 당장 패닉 모드인가?”라는 질문을 갖고 있다면, 이 글 하나로 정리해보세요.


Libsodium은 어떤 라이브러리이고, 왜 이번 취약점이 주목받나

Libsodium은 NaCl을 기반으로 만들어진 현대적인 암호 라이브러리입니다. C로 구현됐고, C/C++뿐 아니라 다양한 언어 바인딩을 통해 폭넓게 쓰이고 있죠.1 목적은 단순합니다. “암호 기술은 복잡하니, 개발자는 그냥 고수준 API만 불러 쓰게 해주자.”

그래서 보통 Libsodium을 쓸 때는 이런 식의 고수준 함수만 사용합니다.

  • crypto_sign_* 계열로 서명·검증

  • crypto_secretbox_* 로 대칭키 암호

  • crypto_pwhash_* 로 패스워드 해시

어떤 곡선이냐, 어떤 모드냐, 이런 건 대부분 신경 쓸 필요가 없습니다. 그런 설계 덕분에 Libsodium은 13년 동안 CVE가 한 번도 없었다는 놀라운 트랙 레코드를 유지했습니다.2

그런데 2025년 12월 30일, 프로젝트 유지 관리자가 직접 “Edwards25519 관련 낮은 수준 함수에서 취약점이 있었다”고 공개했습니다.2
보안 성과가 워낙 좋았던 라이브러리라, 이 한 건이 더 크게 보이는 면도 있습니다.

하지만 포인트는 이겁니다.

  • 이번 취약점은 “로우레벨 함수 하나”에 집중된 버그

  • 일반적인 사용 패턴, 특히 crypto_sign_* 같은 고수준 API는 영향 없음

  • 커스텀 암호 스킴을 구현하는 소수 사용자에게만 실질적 리스크

그래서 “헤드라인만 보고 Libsodium 버리자”는 식의 반응은 과합니다. 대신, 내가 Libsodium을 어떻게 쓰고 있는지를 점검하는 게 훨씬 현실적인 대응입니다.


이번 Libsodium 취약점, 정확히 어디에서 어떻게 터졌나

문제가 된 함수 이름부터 살펴보면 이렇습니다.

crypto_core_ed25519_is_valid_point()

이름만 봐도 감이 오죠. “Ed25519 곡선 위에 있는 유효한 점인지 검사하는 함수”입니다.2 이 함수는 고수준 API 내부에서 쓰이는 게 아니라, 로우레벨 API 중 하나입니다. 곧:

  • Ed25519 위에서 직접 연산하며 커스텀 프로토콜을 만드는

  • 비교적 소수의, 꽤 암호에 익숙한 개발자들이 쓰는 함수

문제는 이 함수가 “검사해야 할 걸 덜 검사해서”, 일부 잘못된 점을 유효한 점으로 착각하던 버그였습니다.

조금 더 구체적으로 보면:

  1. Edwards25519는 하나의 큰 그룹만 있는 게 아니라, 여러 “부그룹(subgroup)”으로 나뉩니다.2
    특히 우리가 서명 등에서 사용하는 건 거대한 “주 그룹(main subgroup)”입니다.

  2. 이 함수의 의도는 “주 그룹에 속하지 않는 점은 걸러내자”였습니다.
    작게는 순서 1, 2, 4, 8 같은 작은 부그룹의 점, 더 복잡하게는 혼합 순서(2L, 4L, 8L) 부그룹 점도 막아야 하죠.2

  3. Libsodium은 이를 위해 “이 점의 순서를 검사”하는 전략을 썼습니다.

    • 그룹의 크기 L로 점을 곱하면, 주 그룹에 속한 점은 모두 항등점(0,1)으로 갑니다.

    • 내부 표현에서는 X, Y, Z 세 좌표로 점을 표현하고, 항등점은 X=0, Y=Z인 형태로 나타납니다.2

  4. 그런데 코드가 항등점인지 확인할 때, X=0만 확인하고 Y=Z는 체크하지 않았습니다.
    결과적으로 “X는 0이지만 Y와 Z가 다른 이상한 점”이 통과하는 상황이 가능해졌습니다.2

실제로, 임의의 정상 점 Q에 “순서 2인 점 (0, -1)”을 더해 만든 Q+(0,-1) 같은 점이 검사를 통과할 수 있었던 것으로 알려졌습니다.2 이것은 주 그룹이 아닌 점인데도 “유효”하다고 판단된 셈이죠.

정리하면 버그의 본질은 단 한 줄입니다.

  • 원래는 X=0만 체크

  • 사실 항등점 확인에는 X=0Y=Z 두 조건이 필요

  • 이 중 하나를 빼먹어서 “잘못된 점들이 구멍으로 새어 들어감”

암호 쪽에서 늘 강조하는 “체크를 하나라도 빼먹지 말 것”이 실제 코드에서 그대로 사고로 이어진 케이스입니다.


수정보완 내용: 코드 레벨로 보면 얼마나 간단했나

재미있는 건, 이 취약점의 수정 자체는 매우 단순했다는 점입니다.2

기존 코드(개념적으로 표현):

// 예전 코드 (요지)
return fe25519_iszero(pl.X);

수정된 코드(개념적으로 표현):

// 새 코드 (요지)
fe25519_sub(t, pl.Y, pl.Z);
return fe25519_iszero(pl.X) & fe25519_iszero(t);

이제는 항등점 판별을 이렇게 합니다.

  • X 좌표가 0인지 확인

  • Y와 Z의 차이가 0인지, 즉 Y=Z인지 확인

단 두 줄이지만, 이 차이가 “부그룹 점을 통과시키느냐, 막느냐”를 결정합니다.

이 패치가 적용된 버전은 다음과 같이 정리할 수 있습니다.

  • 취약한 버전: Libsodium 1.0.20 이하, 그리고 2025년 12월 30일 이전에 릴리스된 모든 Libsodium 패키지2

  • 수정된 버전: 2025년 12월 30일 이후 릴리스된 모든 stable 패키지에 수정 반영2

공식 배포 형태(소스 tarball, Visual Studio/MingW 바이너리, NuGet 패키지, rust libsodium-sys-stable, libsodium.js, swift-sodium용 xcframework 등)에도 모두 패치가 포함됐습니다.2

즉, 패키지 관리자를 통해 최신 stable Libsodium을 설치했다면, 이미 이 취약점은 해결된 상태라고 봐도 무방합니다.


실제로 얼마나 위험한가: 고수준 API vs 커스텀 스킴

이쯤 되면 핵심 질문은 하나로 압축됩니다.

“내 서비스가 이 취약점의 영향을 받는가?”

영향 여부는 딱 세 가지 조건으로 좁힐 수 있습니다.2

  1. Libsodium 버전이 1.0.20 이하(또는 2025-12-30 이전 릴리스)인가?

  2. crypto_core_ed25519_is_valid_point()직접 호출해서, 외부에서 들어오는 점(공개키 등)을 검증하고 있나?

  3. Edwards25519 위에서 직접 산술 연산을 수행하는 커스텀 암호 스킴을 구현했나?

이 세 가지에 모두 “예”라고 답하는 경우만, 실질적인 위험이 있습니다.

반대로 다음과 같은 경우라면 안심해도 됩니다.

  • crypto_sign_* 고수준 API만 사용한다

    • 서명/검증, 키 생성 모두 이 라인으로만 처리

    • Libsodium 내부에서 자체적으로 안전한 점을 사용하므로 문제 없음2

  • crypto_sign_keypair, crypto_sign_seed_keypair로만 공개키를 생성한다

    • 이들이 만드는 키는 이미 올바른 주 그룹 상에 있도록 설계돼 있음2

  • Edwards25519 산술을 직접 만지지 않고, Ristretto255를 쓰고 있다

    • Ristretto는 애초에 이런 “부그룹(cofactor) 문제”를 없애기 위해 설계된 그룹입니다2

또한, 이번 버그가 “정보 유출” 같은 직접적인 공격 벡터로 바로 이어진 것은 아닙니다.
하지만 검증이 느슨해지면, 특정 공격 시나리오(예: 부그룹 관련 프로토콜 설계 오류, 키 재사용 문제 등)에서 보안 모델이 깨질 가능성은 존재합니다. 그게 바로 암호 라이브러리에서 이런 세밀한 점까지 따지는 이유입니다.

정리하면:

  • 대부분의 일반적인 Libsodium 사용자: 실질적 영향 거의 없음

  • 커스텀 프로토콜/스킴을 설계한 소수의 고급 사용자: 코드 리뷰 + 업그레이드 필수


Edwards25519 대신 Ristretto255를 쓰라는 의미, 실제로 뭘 바꾸라는 건가

취약점 공지에서 눈에 띄는 키워드 하나가 바로 “Ristretto255”입니다.2

프로젝트 측은 이렇게 권고합니다.

  • “커스텀 암호 스킴을 구현한다면, Edwards25519보다 Ristretto255를 사용하라.”

왜 그럴까요?

Edwards25519는 훌륭한 곡선이지만, 구조적으로 cofactor(부그룹 관련 요소)가 존재합니다. 이 때문에:

  • 점 검증을 제대로 하지 않으면,

  • 작은 부그룹이나 혼합 부그룹의 점이 프로토콜에 끼어들어

  • 서명, 키 교환, 익명성 보장 같은 곳에서 미묘한 취약점을 만들어낼 수 있습니다.

실제로 이번 버그도 “주 그룹에 있는지 확인하는 체크”가 미흡해서 생긴 문제였죠.

반면 Ristretto255는 같은 기본 필드를 사용하지만, “부그룹 관련 복잡성(cofactor 문제)”를 추상화해서 없앤 구조입니다.2

  • “디코딩이 성공하면 곧바로 안전한 점이다”

  • 추가적인 점 검증 로직 없이도 안전하게 쓸 수 있다

이게 얼마나 큰 차이냐면, 직접 스칼라 곱을 하고 점을 더하고 빼는 저수준 연산을 하는 사람 입장에서는, “검증 코드를 직접 관리할 필요가 없다는 것 자체가 보안 리스크를 크게 줄이는 효과”가 있습니다.

Libsodium에는 Ristretto255 지원이 2019년에 이미 추가되어 있습니다.2
따라서 앞으로:

  • 새로 커스텀 암호 스킴을 설계/구현해야 한다면

  • Edwards25519 로우레벨을 직접 만지는 대신

  • Ristretto255 관련 API를 사용하는 방향이 권장됩니다

정리하자면,

  • “곡선 자체가 나쁘다”가 아니라

  • “사람이 실수하기 쉬운 부분을 구조적으로 제거한 인터페이스를 쓰자”는 실용적인 조언입니다.


개발자를 위한 체크리스트와 실질적인 대응 전략

이제 “이걸 보고 실제로 뭘 해야 하나요?”에 답할 차례입니다.
Libsodium을 쓰고 있는 개발자라면, 아래 순서대로 점검해 보세요.

  1. Libsodium 버전 확인

    • 패키지 매니저(apt, yum, brew, vcpkg, NuGet 등)에서 설치 버전을 확인

    • 1.0.20 이하 혹은 2025-12-30 이전 빌드라면 업그레이드 계획 수립

    • 가능하면 “stable branch의 최신 패키지”로 올리는 것을 추천2

  2. 내 코드에서 로우레벨 Ed25519 함수 사용 여부 검색

    • crypto_core_ed25519_is_valid_point

    • crypto_core_ed25519_add, crypto_core_ed25519_sub

    • crypto_scalarmult_ed25519*_noclamp 변형 등

    이런 함수가 등장한다면, 커스텀 스킴을 구현하고 있을 가능성이 크니 코드 리뷰가 필요합니다.

  3. 외부 입력을 Ed25519 점으로 해석하는 로직이 있는지 확인

    • 네트워크에서 받은 바이트 배열을 crypto_core_ed25519_* 함수로 디코딩

    • 이때 crypto_core_ed25519_is_valid_point()로 검증만 믿고 있는 구조인지 점검

    만약 그렇다면, Libsodium 업그레이드를 최우선으로 진행해야 합니다.

  4. 당장 업그레이드가 어려운 경우, 애플리케이션 레벨 우회책 적용

    유지 관리자가 제시한 임시 함수 is_on_main_subgroup()을 그대로 혹은 조금 변형하여 사용할 수 있습니다.2
    이 함수는:

    • 그룹 순서 L-1로 스칼라 곱 → 항등점과의 관계를 이용해 주 그룹 여부를 확인

    • Libsodium 고수준 함수 위에서 동작하므로, 라이브러리 자체 패치를 못 하는 환경에서 쓸 수 있는 “플랜 B”

    물론 장기적으로는 라이브러리 자체 패치가 훨씬 안전합니다.

  5. 미래를 위한 설계 방향 재점검

    • 앞으로 새 프로토콜·스킴을 설계할 때는 Ristretto255 사용 고려

    • 고수준 API(crypto_sign_* 등)를 최대한 활용하고, 로우레벨 산술 함수 사용은 최소화

    • 꼭 로우레벨을 써야 한다면, 점 검증, 스칼라 검증 등 모든 체크 로직에 대해 명시적으로 테스트 코드와 리뷰 프로세스 마련

마지막으로, Libsodium은 사실상 한 명의 메인 유지 관리자가 이끌고 있는 프로젝트입니다.21
이런 라이브러리가 수년 동안 전 세계 서비스의 보안을 지켜온 만큼, 가능하다면 후원·기여 등을 통해 생태계 유지에 힘을 보태는 것도 장기적인 보안 투자라고 볼 수 있습니다.


시사점과 정리: “완벽한 라이브러리”는 없지만, 좋은 대응은 있다

이번 Libsodium 취약점 사건이 주는 메시지를 정리하면 세 가지입니다.

첫째, 완벽한 암호 라이브러리는 없다는 사실입니다.
13년간 CVE 0이던 프로젝트에도 결국 버그는 발견됐습니다. 중요한 건 “버그가 있느냐 없느냐”가 아니라, 발견됐을 때 투명하게 공개하고 빠르게 패치하고, 사용자가 그 정보를 바탕으로 현실적인 대응을 할 수 있느냐입니다.

둘째, 고수준 API를 쓰는 것이 곧 보안이다라는 설계 철학이 실제로 효과를 발휘했다는 점입니다.
이번 취약점은 높은 수준의 Libsodium 사용자 대부분에게 직접적인 위협이 되지 않았습니다. 이유는 간단합니다. 프로젝트가 애초에 “사람들이 로우레벨을 직접 건드리지 않게” 디자인됐기 때문입니다.

셋째, 커스텀 암호 스킴을 만든다는 것은 그만큼의 책임을 감수하는 일이라는 점입니다.
Edwards25519 위에서 직접 연산해 프로토콜을 짰다면, 라이브러리의 작은 검증 실수조차도 프로토콜 전체 보안 모델을 무너뜨릴 수 있습니다. 앞으로는 Ristretto255 같은 더 안전한 추상화 계층을 활용하거나, 가능하면 검증된 고수준 프로토콜을 재사용하는 것이 훨씬 현명한 선택입니다.

지금 당장 할 일은 어렵지 않습니다.

  • 버전 확인

  • 로우레벨 API 사용 여부 점검

  • 필요하면 업그레이드 또는 임시 우회책 적용

이 세 가지만 해도, 이번 Libsodium 취약점에 대해서는 “할 수 있는 만큼 잘 대응했다”고 말할 수 있을 것입니다.


참고

1libsodium – A modern, portable, easy to use crypto library.

2A vulnerability in libsodium

이 노트는 요약·비평·학습 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.