일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 애플 달팽이
- 분산 신원
- Tendermint
- rust 소개
- Config server
- 주말농장
- rust
- 카디날
- Feign
- 반복문
- MSA
- RSA
- rust 강좌
- PKI
- for
- 체리새우
- 조건문
- 치비
- MSSQL
- 가재
- 무화과
- did
- 물생활
- 쌈채소
- 분산 식별자
- 기본문법
- Python 강좌
- 텐더민트
- 구피
- golang 강좌
- Today
- Total
comnic's Dev&Life
[Rust 예제] 기본적인 PKI(Public Key Infrastructure) 구현 본문
기본적인 PKI(Public Key Infrastructure) 구현
Rust에서 PKI(Public Key Infrastructure)를 구현하기 위해 가장 많이 사용되는 암호화 알고리즘 중 하나는 RSA(Rivest–Shamir–Adleman)입니다. RSA는 대표적인 공개키 알고리즘으로, 안전한 키 교환과 전자 서명을 위해 사용됩니다.
Rust를 공부하는 입장으로 먼저 RSA를 직접 구현해 보고,
이후 rsa 라이브러리를 사용해서 구현해 보겠습니다.
1. 키 생성
RSA는 공개키와 비밀키로 이루어져 있습니다. 키는 두 개의 소수인 p와 q를 생성하고, n = pq로 계산됩니다. 그리고 양의 정수 e와 d를 선택하여 다음의 조건을 만족하는 공개키 (e, n)과 비밀키 (d, n)를 생성합니다.
- e와 (p-1)(q-1)이 서로소여야 합니다.
- (ed - 1)은 (p-1)(q-1)로 나누어 떨어져야 합니다.
Rust에서는 다양한 큰 정수 처리 라이브러리를 활용할 수 있습니다. 여기서는 num-bigint 라이브러리를 사용합니다.
use num_bigint::{BigUint, ToBigUint};
fn generate_keys() -> ((BigUint, BigUint), (BigUint, BigUint)) {
// 소수 p와 q 생성
let p = BigUint::from(61u64);
let q = BigUint::from(53u64);
// n 계산
let n = &p * &q;
// (p-1)(q-1) 계산
let phi = (&p - 1u64) * (&q - 1u64);
// e 선택 (일반적으로 65537 사용)
let e = BigUint::from(65537u64);
// d 계산
let d = e.modpow(&BigUint::one(), &phi);
((e.clone(), n.clone()), (d, n))
}
2. 암호화와 복호화
RSA에서는 공개키로 암호화하고 비밀키로 복호화합니다. 메시지 m에 대해 암호문 c는 다음과 같이 계산됩니다.
비밀키로 복호화할 때는 다음과 같이 계산됩니다.
fn encrypt(m: &BigUint, public_key: &(BigUint, BigUint)) -> BigUint {
let (e, n) = public_key;
m.modpow(e, n)
}
fn decrypt(c: &BigUint, private_key: &(BigUint, BigUint)) -> BigUint {
let (d, n) = private_key;
c.modpow(d, n)
}
3. 서명 생성과 검증
RSA는 전자 서명에도 사용됩니다. 서명 생성자는 개인 키로 메시지에 대한 서명을 생성하고, 서명 검증자는 공개 키로 받은 서명의 유효성을 확인합니다.
fn sign(m: &BigUint, private_key: &(BigUint, BigUint)) -> BigUint {
let (d, n) = private_key;
m.modpow(d, n)
}
fn verify(signature: &BigUint, m: &BigUint, public_key: &(BigUint, BigUint)) -> bool {
let (e, n) = public_key;
let decrypted = signature.modpow(e, n);
decrypted == *m
}
4. RSA 라이브러리를 사용한 구현
먼저, rsa 라이브러리를 사용하여 RSA 알고리즘을 구현합니다. 이 라이브러리는 RSA 키 생성, 서명, 검증 등을 편리하게 다룰 수 있도록 도와줍니다.
먼저 cargo.toml에 사용할 라이브러리를 추가한다.
# Cargo.toml에 의존성 추가
[dependencies]
rsa = "0.9.6"
num-bigint = "0.4.4"
cargo add를 사용해 아래와 같이 추가해도 된다.
cargo add rsa
cargo add num-bigint
다음은 RSA를 사용한 PKI 구현의 예제 코드입니다
use rsa::{RSAPrivateKey, RSAPublicKey, PaddingScheme};
use num_bigint::BigUint;
use rand::rngs::OsRng;
fn main() {
// 1. 키 생성
let private_key = RSAPrivateKey::new(&mut OsRng, 2048).expect("Failed to generate a private key");
let public_key = RSAPublicKey::from(&private_key);
// 2. 서명 생성
let message = "Hello, PKI!";
let signature = sign(message.as_bytes(), &private_key);
// 3. 검증
let is_valid = verify(message.as_bytes(), &signature, &public_key);
// 결과 출력
if is_valid {
println!("Signature is valid.");
} else {
println!("Signature is not valid.");
}
}
// 서명 생성 함수
fn sign(message: &[u8], private_key: &RSAPrivateKey) -> Vec<u8> {
let mut signer = rsa::Signer::new(rsa::PKCS1_PSS_SHA256, &private_key).expect("Failed to create signer");
signer.update(message);
signer.finalize().expect("Failed to finalize signature").to_vec()
}
// 검증 함수
fn verify(message: &[u8], signature: &[u8], public_key: &RSAPublicKey) -> bool {
let mut verifier = rsa::Verifier::new(rsa::PKCS1_PSS_SHA256, &public_key).expect("Failed to create verifier");
verifier.update(message);
verifier.verify(signature)
}
이 코드에서 rsa::PKCS1_PSS_SHA256는 서명 및 검증에 사용되는 패딩 및 해시 알고리즘을 나타냅니다. 이 예제에서는 SHA-256 해시와 PSS 패딩을 사용하였습니다.
'Rust' 카테고리의 다른 글
[PKI 예제] RSA로 서명하고 검증하기 (0) | 2023.12.12 |
---|---|
[Rust] 14. 비동기 프로그래밍과 async/await (0) | 2023.12.09 |
[Rust] 13. 안전한 코드와 unsafe 키워드 (0) | 2023.12.09 |
[Rust] 12. 테스트와 에러 핸들링 (0) | 2023.12.09 |
[Rust] 11. 병행성(Concurrency)과 동시성(Parallelism) (0) | 2023.12.09 |