Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как шифруется сертификат
Определение
Сертификат (X.509) — это документ, который подтверждает подлинность публичного ключа и содержит информацию о владельце. Сертификат подписан Certificate Authority (CA) — доверенной организацией.
Структура сертификата
X.509 Certificate
├── Тело сертификата (To Be Signed)
│ ├── Version
│ ├── Serial Number
│ ├── Signature Algorithm
│ ├── Issuer (кто выдал)
│ ├── Subject (для кого выдан)
│ ├── Public Key
│ ├── Validity Period (срок действия)
│ └── Extensions
│
└── Подпись (создана CA приватным ключом)
Как сертификат подписывается (не шифруется!)
Важно: сертификат не шифруется, а подписывается. Это разные операции!
Процесс подписи сертификата
1. Создание сертификата (public key + metadata)
↓
2. Хеширование содержимого (SHA-256)
Content Hash = SHA256(certificate_data)
↓
3. Шифрование хеша приватным ключом CA (RSA)
Digital Signature = RSA_Encrypt(Content Hash, CA_Private_Key)
↓
4. Добавление подписи в сертификат
↓
5. Отправка: Сертификат + Подпись (открытый текст!)
Алгоритмы шифрования подписи
RSA (Rivest-Shamir-Adleman)
Мост распространённый алгоритм для подписи сертификатов:
Процесс подписи:
1. Hash = SHA256(certificate_data)
2. Signature = RSA_Encrypt(Hash, CA_Private_Key) // 2048-4096 бит
Процесс проверки подписи:
1. Signature = RSA_Decrypt(Signature, CA_Public_Key)
2. Hash = SHA256(certificate_data)
3. Если Signature == Hash → подпись валидна
Длины ключей:
- 2048 бит — минимум (устаревает)
- 4096 бит — текущий стандарт
- 8192 бит — для высокой безопасности
// Проверка подписи RSA сертификата в Java
import java.security.*;
import java.security.cert.X509Certificate;
public class CertificateValidator {
public static boolean validateCertificateSignature(
X509Certificate cert,
PublicKey caPublicKey) throws Exception {
try {
// Verify использует публичный ключ CA
cert.verify(caPublicKey);
System.out.println("Certificate signature is valid!");
return true;
} catch (SignatureException e) {
System.out.println("Certificate signature is invalid!");
return false;
}
}
}
ECDSA (Elliptic Curve Digital Signature Algorithm)
Современный алгоритм, более эффективный чем RSA:
Процесс подписи:
1. Hash = SHA256(certificate_data)
2. Signature = ECDSA_Sign(Hash, CA_Private_Key) // 256-521 бит
(производит пару (r, s))
Процесс проверки подписи:
1. (r, s) = Signature
2. Hash = SHA256(certificate_data)
3. Если ECDSA_Verify(Hash, r, s, CA_Public_Key) → валидна
Преимущества ECDSA:
- Меньше размер ключей (256 бит = 2048 бит RSA)
- Быстрее вычисления
- Подходит для мобильных приложений
// Создание ECDSA подписи
import java.security.*;
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(256); // NIST P-256
KeyPair keyPair = keyGen.generateKeyPair();
// Подпись
Signature sig = Signature.getInstance("SHA256withECDSA");
sig.initSign(keyPair.getPrivate());
sig.update(certificate_data);
byte[] signature = sig.sign();
// Проверка подписи
Signature verifySignature = Signature.getInstance("SHA256withECDSA");
verifySignature.initVerify(keyPair.getPublic());
verifySignature.update(certificate_data);
boolean isValid = verifySignature.verify(signature);
SHA-256 (Хеширование)
Сертификат хешируется перед подписью:
import java.security.MessageDigest;
public class HashExample {
public static String hashCertificate(byte[] certificateData)
throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(certificateData);
// Преобразование в hex
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
}
// Output (для Google сертификата):
// 587c45eaaac0ec9ed8fc09b25ebb4b87d894eef6b0b9b8ea08fb8d00de2d87aa
Цепь доверия (Certificate Chain)
Когда браузер получает сертификат:
1. Получает сертификат сервера (например, google.com)
- Выдан: DigiCert
- Публичный ключ: xxxxxxxx
- Подпись: yyyyyyyy (подписано приватным ключом DigiCert)
2. Получает сертификат выдающего центра (DigiCert)
- Выдан: GlobalSign (root CA)
- Подпись: zzzzzzzz (подписано GlobalSign)
3. Получает root сертификат (GlobalSign)
- Самоподписанный (выдан сам себе)
- Уже есть в браузере в trusted roots
4. Проверяет цепь:
google.com сертификат ← DigiCert публичный ключ
DigiCert сертификат ← GlobalSign публичный ключ
GlobalSign сертификат ← trusted (встроен в браузер)
Если все подписи верны → доверять сайту
Алгоритмы до подписи
Дополнительные алгоритмы для подписи:
1. SHA-1 (устаревший, опасный)
- Длина: 160 бит
- Уязвимости известны
- Больше не используется для сертификатов
2. SHA-256 (текущий стандарт)
- Длина: 256 бит
- Безопасен
- Используется: RSA, ECDSA
3. SHA-384, SHA-512
- Еще надежнее
- Для критичных систем
Просмотр алгоритма сертификата
Через OpenSSL
# Просмотр сертификата
openssl x509 -in certificate.pem -text -noout
# Output:
# Signature Algorithm: sha256WithRSAEncryption
# Public-Key: (2048 bit)
# Issuer: C = US, O = Google Trust Services, CN = Google Internet Authority
Через Java
import java.security.cert.X509Certificate;
import java.io.FileInputStream;
import java.security.KeyStore;
public class CertificateInfo {
public static void printCertificateInfo(String certPath)
throws Exception {
FileInputStream fis = new FileInputStream(certPath);
java.security.cert.CertificateFactory cf =
java.security.cert.CertificateFactory.getInstance("X.509");
X509Certificate cert =
(X509Certificate) cf.generateCertificate(fis);
System.out.println("Subject: " + cert.getSubjectDN());
System.out.println("Issuer: " + cert.getIssuerDN());
System.out.println("Algorithm: " + cert.getSigAlgName());
// Output: Algorithm: SHA256withRSA
System.out.println("Public Key Algorithm: " +
cert.getPublicKey().getAlgorithm());
// Output: RSA
System.out.println("Valid from: " + cert.getNotBefore());
System.out.println("Valid until: " + cert.getNotAfter());
fis.close();
}
}
HTTPS процесс
1. Клиент подключается к серверу (порт 443)
Client Server
| |
|---- ClientHello ----------->
| |
|<--- ServerHello + Cert ------| (Сервер отправляет сертификат)
| |
|---- Клиент проверяет --------| (Проверяет подпись CA)
| cert (RSA с SHA-256) |
| |
|---- Certificate OK --------->| (Если подпись верна)
| |
|<--- TLS established ---------| (Шифрованное соединение)
Best Practices
-
Используй SHA-256 или выше:
// Хорошо Signature sig = Signature.getInstance("SHA256withRSA"); // Плохо (устаревший) Signature sig = Signature.getInstance("SHA1withRSA"); -
Используй ключи 2048+ бит:
# Проверить размер ключа openssl x509 -in cert.pem -text -noout | grep "Public-Key" -
Проверяй цепь доверия:
cert.verify(caPublicKey); // Проверяет подпись -
Используй ECDSA для новых приложений:
Signature sig = Signature.getInstance("SHA256withECDSA");
Вывод
Сертификат не шифруется, а подписывается приватным ключом Certificate Authority. Процесс:
- Содержимое сертификата хешируется (SHA-256)
- Хеш шифруется приватным ключом CA (RSA-2048/4096 или ECDSA)
- Результат (подпись) добавляется в сертификат
- При проверке браузер расшифровывает подпись публичным ключом CA и сравнивает с хешем
Текущие стандарты: SHA-256 с RSA-2048+ или ECDSA-256.