JavaRush /Java blogi /Random-UZ /Java kriptografiyasi arxitekturasi: Birinchi kirish
Viacheslav
Daraja

Java kriptografiyasi arxitekturasi: Birinchi kirish

Guruhda nashr etilgan
Ma'lumotlar almashinuvining xavfsizligi zamonaviy ilovalarning eng muhim xususiyatlaridan biridir. Qadim zamonlardan beri odamlar ayyor usullarni o'ylab topishgan, ular insoniyat rivojlanishi bilan butun kriptografiya faniga aylangan. Tabiiyki, Java chetda turmadi va ishlab chiquvchilarga Java Kriptografiya Arxitekturasini (JCA) taklif qildi. Ushbu sharh uning qanday ishlashi haqida birinchi fikrni berishi kerak.

Muqaddima

Men vaqtga sayohat qilishni taklif qilaman. Bizning oldimizda Qadimgi Rim. Va oldimizda Gay Yuliy Tsezar turibdi, u o'z qo'mondonlariga xabar yuboradi. Keling, ushbu xabarda nima borligini ko'rib chiqaylik:
Java kriptografiyasi arxitekturasi: Birinchi kirish - 2
Bu nimani anglatishi mumkin "ЕСКЕУГЬГМХИФЯ Е УЛП":? Keling, Java Online Compiler dasturini ochamiz, masalan: repl.it
class Main {
  public static void main(String[] args) {
    String code = "ЕСКЕУГЬГМХИФЯ Е УЛП";
    for (char symbol : code.toCharArray()) {
      if (symbol != ' ') {
        symbol = (char) (symbol - 3);
      }
      System.out.print(symbol);
    }
  }
}
Bizning oldimizda Sezar shifrining eng oddiy amalga oshirilishi. Qadimgi Rim tarixchisi Suetoniusning "O'n ikki Qaysarning hayoti" nomli asariga ko'ra, Sezar o'z sarkardalariga xabarlarni aynan shunday shifrlagan. Va bu Kriptografiya kabi narsadan foydalanishga oid eng qadimiy havolalardan biridir . "Kriptografiya" so'zi qadimgi yunoncha "yashirin" va "yozish" so'zlaridan kelib chiqqan, ya'ni. bu maxfiylik texnikasi haqidagi fan. Java kriptografiya uchun o'z yordamiga ega va u Java Kriptografiya Arxitekturasi (JCA) deb ataladi . Ta'rifni Oracle rasmiy hujjatlarida topish mumkin - " Java Kriptografiya Architecture (JCA) ". Men sizga JCA tufayli qanday imkoniyatlarga ega ekanligimizni ko'rib chiqishni taklif qilaman.
Java kriptografiyasi arxitekturasi: Birinchi kirish - 3

J.C.A.

Avval bilib olganimizdek, Java kriptografiya bilan ishlash uchun Java Kriptografiya Arxitekturasini (JCA) taklif qiladi. Ushbu arxitektura API (ya'ni, ma'lum interfeyslar to'plami) va provayderlarni (ularni amalga oshiradigan) o'z ichiga oladi:
Java kriptografiyasi arxitekturasi: Birinchi kirish - 4
Hujjatlarda aytilganidek, " Java platformasi bir qator o'rnatilgan provayderlarni o'z ichiga oladi ". Ya'ni, Java platformasi kerak bo'lganda kengaytirilishi mumkin bo'lgan o'rnatilgan provayderlar to'plamini taqdim etadi. Buni o'zingiz ko'rishingiz mumkin:
import java.security.Provider;
import java.security.Security;
class Main {
  public static void main(String[] args) {
    Provider[] providers = Security.getProviders();
    for (Provider p : providers) {
      System.out.println(p.getName());
    }
  }
}
Uchinchi tomon provayderini ro'yxatdan o'tkazish juda oson. Misol uchun: Security.addProvider(new BouncyCastleProvider()); Bu misol eng mashhur provayderlardan birini bog'laydi - BouncyCastle . Ammo ushbu sharhda biz uchinchi tomon kutubxonalarisiz faqat asosiy vositalardan foydalanamiz. Bizning asosiy hujjatimiz: " Java Kriptografiya Arxitekturasi (JCA) ". JCA qanday ishlashini tushunish, xuddi shu JCA faol qo'llaniladigan texnologiyalarni osonroq tushunishga yordam beradi. Masalan: HTTPS (qarang: " HTTPdan HTTPSga ").
Java kriptografiyasi arxitekturasi: Birinchi kirish - 5

MessageDigest

JCA hujjatlarida qayd etilgan birinchi narsa bu MessageDigest. Umuman olganda, rus tilidagi Dijest bir xil bo'ladi - dayjest "xulosa" ma'nosiga mos keladi. Ammo kriptografiyada dayjest xesh summasidir. Bundan tashqari, ingliz tilidagi Digestni dayjest sifatida ham tarjima qilish mumkinligini osongina eslashingiz mumkin. Batafsil ma'lumotni JCA hujjatlarida " MessageDigest " bo'limida topishingiz mumkin. Hujjatlarda aytilganidek, MessageDigest dayjest yoki xesh deb ataladigan qat'iy o'lchamdagi natijani yaratadi. Hashing bir tomonlama funktsiyadir, ya'ni. agar biz biror narsani xeshlagan bo'lsak, natijadan (ya'ni, xeshdan) biz asl manbani ololmaymiz. Ammo agar bir xil ob'ektlar xeshlangan bo'lsa (masalan, bir xil belgilar qatorlari), unda ularning xeshlari mos kelishi kerak. Hujjatlarda ta'kidlanganidek, bunday xesh ba'zida ma'lumotlarning "cheksum" yoki "raqamli barmoq izi" deb ham ataladi. Xeshlash turli xil algoritmlar yordamida amalga oshirilishi mumkin. Mavjud algoritmlarni " JDK 8 uchun Java Kriptografiya Arxitekturasi Standart Algoritm Nomi Hujjatlari " hujjatida ko'rish mumkin . Keling, xeshlashni bajaramiz va konsolga xeshni chop qilamiz:
import javax.xml.bind.DatatypeConverter;
import java.security.*;
public class Main {
  public static void main(String[] args) {
    try {
      MessageDigest digester = MessageDigest.getInstance("SHA-512");
      byte[] input = "Secret string".getBytes();
      byte[] digest = digester.digest(input);
      System.out.println(DatatypeConverter.printHexBinary(digest));
    } catch (NoSuchAlgorithmException e) {
      throw new IllegalStateException(e);
    }
  }
}
Hashing, masalan, parollarni saqlashda foydali bo'lishi mumkin. Kiritilgan parolning xeshini oldindan saqlangan xesh bilan tekshirish mumkin. Agar xeshlar mos kelsa, parol ham mos keladi. Yana xavfsizroq xeshlash uchun "tuz" deb nomlangan tushuncha ishlatiladi. Tuz SecureRandom klassi yordamida amalga oshirilishi mumkin . Digest usulini bajarishdan oldin, keling, "tuz" qo'shishni tavsiflaymiz:
byte[] salt = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(salt);
digester.update(salt);
Ammo hash bir tomonlama funktsiyadir. Ammo shifrlash va shifrni ochish imkoniyatiga ega bo'lishni istasangiz-chi?
Java kriptografiyasi arxitekturasi: Birinchi kirish - 6

Simmetrik kalit kriptografiyasi

Simmetrik shifrlash - shifrlash va shifrni ochish uchun bir xil kalitdan foydalanadigan shifrlash. Simmetrik shifrlashdan foydalanish uchun bizga kalit kerak. Uni olish uchun biz KeyGenerator dan foydalanamiz . Bundan tashqari, bizga shifrni ifodalovchi sinf kerak bo'ladi ( Cipher ). JCA hujjatlarida " Shifr ob'ektini yaratish " bo'limida aytilganidek , shifrni yaratish uchun siz faqat algoritmni emas, balki qatorda "o'zgartirish" ni ko'rsatishingiz kerak. Transformatsiya tavsifi quyidagicha ko'rinadi: "algorithm/mode/padding":
  • Algoritm : bu erda biz " Shifrlash (shifrlash) algoritmlari " ning standart nomlarini ko'rib chiqamiz . AES dan foydalanish tavsiya etiladi.
  • Tartib : shifrlash rejimi. Masalan: ECB yoki CBC (bu haqda biroz keyinroq gaplashamiz)
  • Indentation/Split : Har bir ma'lumot bloki alohida shifrlangan. Ushbu parametr 1 blok sifatida qancha ma'lumot hisoblanishini aniqlaydi.
Masalan, quyidagi transformatsiyani oling: "AES/ECB/PKCS5Padding". Ya'ni, shifrlash algoritmi - AES, shifrlash rejimi - ECB (elektron kod kitobining qisqartmasi), blok hajmi - PKCS5Padding. PKCS5Padding, bitta blokning hajmi 2 bayt (16 bit) ekanligini aytadi. Elektron kod kitobini shifrlash rejimi har bir blokning ketma-ket shifrlanishini o'z ichiga oladi:
Java kriptografiyasi arxitekturasi: Birinchi kirish - 7
Kodda shunday ko'rinishi mumkin:
import javax.xml.bind.DatatypeConverter;
import javax.crypto.*;
import java.security.Key;
public class Main {
  public static void main(String[] args) throws Exception {
    String text = "secret!!secret!!secret!!secret!!";
    // Generate new key
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    keygen.init(256);
    Key key = keygen.generateKey();
    // Encrypt with key
    String transformation = "AES/ECB/PKCS5Padding";
    Cipher cipher = Cipher.getInstance(transformation);
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] encrypted = cipher.doFinal(text.getBytes());
    System.out.println(DatatypeConverter.printHexBinary(encrypted));
    // Decrypt with key
    cipher.init(Cipher.DECRYPT_MODE, key);
    String result = new String(cipher.doFinal(encrypted));
    System.out.println(result);
  }
}
Agar biz ijro etsak, takrorlashni ko'rishni kutamiz, chunki biz 32 ta belgi belgiladik. Bu belgilar 16 bitli 2 blokdan iborat:
Java kriptografiyasi arxitekturasi: Birinchi kirish - 8
Bunday holatda takrorlashni oldini olish uchun siz boshqa rejimdan foydalanishingiz kerak - Cipher Block Chaining (CBC). Ushbu rejim Initialization Vector (IvParameterSpec klassi bilan ifodalanadi) tushunchasini taqdim etadi. Shuningdek, ushbu rejim tufayli oxirgi blokni yaratish natijasi keyingi blokni yaratish uchun ishlatiladi:
Java kriptografiyasi arxitekturasi: Birinchi kirish - 9
Endi buni kodda yozamiz:
import javax.xml.bind.DatatypeConverter;
import javax.crypto.*;
import java.security.*;
import javax.crypto.spec.IvParameterSpec;
public class Main {
  public static void main(String[] args) throws Exception {
    // Initialization Vector
    SecureRandom random = SecureRandom.getInstanceStrong();
    byte[] rnd = new byte[16];
    random.nextBytes(rnd);
    IvParameterSpec ivSpec = new IvParameterSpec(rnd);
    // Prepare key
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    keygen.init(256);
    Key key = keygen.generateKey();
    // CBC
    String text = "secret!!secret!!secret!!secret!!";
    String transformation = "AES/CBC/PKCS5Padding";
    Cipher cipher = Cipher.getInstance(transformation);
    cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
    byte[] enc = cipher.doFinal(text.getBytes());
    System.out.println(DatatypeConverter.printHexBinary(enc));
    // Decrypt
    cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
    String result = new String(cipher.doFinal(enc));
    System.out.println(result);
  }
}
Ko'rib turganimizdek, natijada biz takroriy shifr bloklarini ko'rmayapmiz. Shu sababli, ECB rejimi tavsiya etilmaydi, chunki takrorlashlarni ko'rish va bu bilimlardan shifrni ochish uchun foydalanish imkonini beradi. ECB va CBC haqida ko'proq ma'lumot olish uchun sizga materialni o'qishni maslahat beraman: “ Elektron kod kitobi rejimi ”. Ammo nosimmetrik shifrlashda aniq muammo bor - siz qandaydir tarzda kalitni shifrlagandan shifrlaganga o'tkazishingiz kerak. Va bu yo'lda bu kalitni ushlab turish mumkin va keyin ma'lumotlarni ushlab turish mumkin bo'ladi. Va assimetrik shifrlash bu muammoni hal qilish uchun mo'ljallangan.
Java kriptografiyasi arxitekturasi: Birinchi kirish - 10

Asimmetrik shifrlash

Assimetrik shifrlash yoki Ochiq kalitli kriptografiya shifrlash usuli bo'lib, bir juft kalitdan foydalanadi: shaxsiy kalit (hamma uchun sir saqlanadi) va ochiq kalit (omma uchun mavjud). Bu ajratish maxfiy kalitni xavfsiz saqlagan holda axborot almashuvchi tomonlar o'rtasida ochiq kalitni xavfsiz almashish uchun zarurdir. Kalitlar juftligini yaratishda KeyGenerator endi biz uchun yetarli emas; bizga KeyPairGenerator kerak . Keling, bir misolni ko'rib chiqaylik:
import javax.crypto.*;
import java.security.*;
public class Main {
  public static void main(String[] args) throws Exception {
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    generator.initialize(1024);
    KeyPair keyPair = generator.generateKeyPair();
    // Encrypt with PRIVATE KEY
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
    byte[] data = cipher.doFinal("Hello!".getBytes());
    // Decrypt with PUBLIC KEY
    cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
    byte[] result = cipher.doFinal(data);
    System.out.println(new String(result));
  }
}
Bu erda shuni tushunish kerakki, assimetrik shifrlashdan foydalanganda biz har doim bitta kalitni shifrlash uchun, ikkinchisini shifrlash uchun ishlatish uchun KeyPair-dan foydalanamiz. Lekin chunki Shifrlashning mohiyati shundan iboratki, uni faqat qabul qiluvchi shifrlashi mumkin, u ochiq kalit bilan shifrlangan va faqat shaxsiy kalit bilan shifrlangan.
Java kriptografiyasi arxitekturasi: Birinchi tanishuv - 11

Raqamli imzo

Yuqorida ko'rganimizdek, ochiq kalitni bilgan holda, siz ma'lumotlarni faqat shaxsiy kalit egasi shifrini ochishi uchun yuborishingiz mumkin. Ya'ni, assimetrik shifrlashning mohiyati shundaki, har kim shifrlaydi, lekin faqat biz o'qiymiz. Bundan tashqari, teskari protsedura mavjud - raqamli imzo, Imzo sinfi bilan ifodalanadi . Raqamli imzo quyidagi algoritmlardan foydalanishi mumkin: " Imzo algoritmlari ". JCA hujjatlari ushbu ikkitasini batafsil ko'rib chiqishni taklif qiladi: DSAwithMD5 va RSAwithMD5 DSA yoki RSA dan nima yaxshiroq va ularning farqi nimada bu yerda o'qishingiz mumkin: " Shifrlangan fayllarni uzatish uchun qaysi biri eng yaxshi ishlaydi - RSA yoki DSA? ". Yoki bu yerda muhokamalarni o'qing: " SSH autentifikatsiya kalitlari uchun RSA va DSA ". Shunday qilib, raqamli imzo. Bizga avvalgidek KeyPair va yangi Signature sinfi kerak bo'ladi. Agar siz hozirgacha onlayn kompilyatorlarda sinovdan o'tgan bo'lsangiz, unda quyidagi misol ular uchun biroz qiyin bo'lishi mumkin. Mening misolim faqat bu erda ishlaydi: rextester.com . Biz kerakli sinflarni import qilamiz:
import javax.crypto.*;
import java.security.*;
Shuningdek, biz asosiy usulni qayta yozamiz:
public static void main(String[] args) throws Exception {
    // Generate keys
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    SecureRandom random = SecureRandom.getInstanceStrong();
    generator.initialize(2048, random);
    KeyPair keyPair = generator.generateKeyPair();
    // Digital Signature
    Signature dsa = Signature.getInstance("SHA256withRSA");
    dsa.initSign(keyPair.getPrivate());
    // Update and sign the data
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
    byte[] data = cipher.doFinal("Hello!".getBytes());
    dsa.update(data);
    byte[] signature = dsa.sign();
    // Verify signature
    dsa.initVerify(keyPair.getPublic());
    dsa.update(data);
    boolean verifies = dsa.verify(signature);
    System.out.println("Signature is ok: " + verifies);
    // Decrypt if signature is correct
    if (verifies) {
      cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
      byte[] result = cipher.doFinal(data);
      System.out.println(new String(result));
    }
}
Raqamli imzo shunday ishlaydi. Raqamli imzo - qiziqarli mavzu. Men sizga ushbu mavzu bo'yicha hisobotni ko'rib chiqishni maslahat beraman:
Java kriptografiyasi arxitekturasi: Birinchi tanishuv - 12
Yuqorida biz tomonlar qanday ma'lumotlarni almashishini ko'rdik. JCA da taqdim etilgan ushbu o'zaro aloqa uchun standart interfeys mavjud emasmi? Ma'lum bo'lishicha, bor. Keling, buni ko'rib chiqaylik.
Java kriptografiyasi arxitekturasi: Birinchi tanishuv - 13

Asosiy kelishuv

Java kriptografiya arxitekturasi muhim vositani taqdim etadi - Kalit kelishuvi protokoldir. U KeyAgreement sinfi bilan ifodalanadi . JCA hujjatlarida ta'kidlanganidek, ushbu protokol bir nechta tomonlarga bir xil kriptografik kalitni tomonlar o'rtasida hech qanday maxfiy ma'lumot almashmasdan o'rnatish imkonini beradi. G'alati tuyuladimi? Keyin bir misolni ko'rib chiqaylik:
// 1. Одна из сторон (Алиса) генерирует пару ключей. Encoded публичный ключ отдаёт.
KeyPairGenerator generator = KeyPairGenerator.getInstance("DH");
KeyPair aliceKeyPair = generator.generateKeyPair();
byte[] alicePubKeyEncoded = aliceKeyPair.getPublic().getEncoded();

// 2. Другая сторона (например, Боб) получает открытый ключ Алисы
KeyFactory bobKeyFactory = KeyFactory.getInstance("DH");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(alicePubKeyEncoded);
PublicKey alicePubKey = bobKeyFactory.generatePublic(x509KeySpec);
// Параметры, которые использовала Алиса при генерации ключей
DHParameterSpec dhParamFromAlicePubKey = ((DHPublicKey)alicePubKey).getParams();
// Создаёт свою пару ключей. Отдаёт свой Encoded открытый ключ
KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
bobKpairGen.initialize(dhParamFromAlicePubKey);
KeyPair bobKeyPair = bobKpairGen.generateKeyPair();
byte[] bobPubKeyEncoded = bobKeyPair.getPublic().getEncoded();

Теперь, у Алисы есть открытый ключ Боба, а у Боба есть открытый ключ Алисы. What дальше?
Как сказано в documentации JCA, у нас есть инструмент KeyAgreement, https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#KeyAgreement который позволяет установить одинаковые ключи шифрования без необходимости обмениваться секретной информацией (т.е. без обмена private key). Соглашение выглядит следующим образом:
// 3. Соглашение по протоколу Диффи-Хеллмана (Diffie–Hellman, DH)
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKeyPair.getPrivate());
// Алиса на основе ключа боба и своего private key создаёт общий shared ключ
KeyFactory aliceKeyFactory = KeyFactory.getInstance("DH");
x509KeySpec = new X509EncodedKeySpec(bobPubKeyEncoded);
PublicKey bobPubKey = aliceKeyFactory.generatePublic(x509KeySpec);
aliceKeyAgree.doPhase(bobPubKey, true);
byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
SecretKeySpec aliceAesKey = new SecretKeySpec(aliceSharedSecret, 0, 16, "AES");
// Боб на основе ключа Алисы и своего private key создаёт общий shared ключ
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
bobKeyAgree.init(bobKeyPair.getPrivate());
bobKeyAgree.doPhase(alicePubKey, true);
byte[] bobSharedSecret = bobKeyAgree.generateSecret();
SecretKeySpec bobAesKey = new SecretKeySpec(bobSharedSecret, 0, 16, "AES");
// Общий ключ у Алисы и Боба одинаков
System.out.println("Shared keys are equals: " + Arrays.equals(aliceSharedSecret, bobSharedSecret));

Далее Боб и Алиса, используя общий ключ, про который больше никто не знает, обмениваются зашифрованными данными:
// 4. Боб шифрует сообщение для Алисы
Cipher bobCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
bobCipher.init(Cipher.ENCRYPT_MODE, bobAesKey);
byte[] ciphertext = bobCipher.doFinal("Hello, Alice!".getBytes());
// Передаёт Алисе параметры, с которыми выполнялась шифровка
byte[] encodedParamsFromBob = bobCipher.getParameters().getEncoded();

// 5. Алиса принимает сообщение и расшифровывает его
AlgorithmParameters aesParams = AlgorithmParameters.getInstance("AES");
aesParams.init(encodedParamsFromBob);
Cipher aliceCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aliceCipher.init(Cipher.DECRYPT_MODE, aliceAesKey, aesParams);
byte[] recovered = aliceCipher.doFinal(ciphertext);
System.out.println(new String(recovered));
Ushbu misol JCA hujjatlari misolidan olingan: " 2 Tomon o'rtasida Diffie-Hellman Key almashinuvi ". Assimetrik shifrlash Java kriptografiyasi arxitekturasida Kalit kelishuv protokoli yordamida taxminan shunday ko'rinadi. Asimmetrik shifrlash haqida ko'proq ma'lumot olish uchun tavsiya etilgan videolar:
Java kriptografiyasi arxitekturasi: Birinchi tanishuv - 14

Sertifikatlar

Xo'sh, shirinlik uchun bizda hali ham muhim bo'lmagan narsa bor - sertifikatlar. Odatda, sertifikatlar jdk-ga kiritilgan keytool yordam dasturi yordamida yaratiladi. Batafsil ma'lumotni bu erda o'qishingiz mumkin, masalan: " Java keytool buyrug'i yordamida o'z-o'zidan imzolangan SSL sertifikatini yaratish ". Oracle'dan qo'llanmalarni ham o'qishingiz mumkin. Masalan, bu erda: " Server sertifikatini yaratish uchun keytooldan foydalanish ". Masalan, Tutorialspoint Java Online Compiler dan foydalanamiz :
import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.x509.*;
import java.security.cert.*;
import java.security.*;
// Compiler args: -XDignore.symbol.file
public class Main {
  public static void main(String[] args) throws Exception {
    CertAndKeyGen certGen = new CertAndKeyGen("RSA", "SHA256WithRSA", null);
    // generate it with 2048 bits
    certGen.generate(2048);
    PrivateKey privateKey = certGen.getPrivateKey();
    X509Key publicKey = certGen.getPublicKey();
    // prepare the validity of the certificate
    long validSecs = (long) 365 * 24 * 60 * 60; // valid for one year
    // enter your details according to your application
    X500Name principal = new X500Name("CN=My Application,O=My Organisation,L=My City,C=DE");
    // add the certificate information, currently only valid for one year.
    X509Certificate cert = certGen.getSelfCertificate(principal, validSecs);
    // Public Key from Cert equals Public Key from generator
    PublicKey publicKeyFromCert = cert.getPublicKey();
    System.out.println(publicKeyFromCert.equals(publicKey));
  }
}
Ko'rib turganimizdek, sertifikat ochiq kalitni taqdim etish imkoniyatini beradi. Bu usulning kamchiligi bor - biz dan foydalanamiz sun.security, bu xavfli hisoblanadi, chunki... bu paket umumiy Java API ning bir qismi emas. Shuning uchun kompilyatsiya paytida - parametrini ko'rsatish kerak XDignore.symbol.file. Boshqa yo'l bor - sertifikatni qo'lda yaratish. Salbiy tomoni shundaki, u hujjatlashtirilmagan ichki API dan foydalanadi. Biroq, bu haqda bilish foydalidir. Hech bo'lmaganda, chunki RFC-2459 spetsifikatsiyasi qanday qo'llanilishi aniq ko'rinib turadi: “ Internet X.509 ochiq kalit infratuzilmasi ”. Mana bir misol:
// 1. Генерируем пару ключей
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(4096);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 2. Определяем данные сертификата
// Определяем срок действия сертификата
Date from = new Date();
Date to = new Date(from.getTime() + 365 * 1000L * 24L * 60L * 60L);
CertificateValidity interval = new CertificateValidity(from, to);
// Определяем subject name, т.е. Name того, с чем ассоциирован публичный ключ
// CN = Common Name. Через точку с запятой могут быть указаны также другие атрибуты
// См. https://docs.oracle.com/cd/E24191_01/common/tutorials/authz_cert_attributes.html
X500Name owner = new X500Name("cn=Unknown");
// Уникальный в пределах CA, т.е. Certificate Authority (тот, кто выдаёт сертификат) номер
BigInteger number = new BigInteger(64, new SecureRandom());
CertificateSerialNumber serialNumber = new CertificateSerialNumber(number);
// Определяем алгоритм подписи сертификата
AlgorithmId algorithmId = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
CertificateAlgorithmId certificateAlgorithmId = new CertificateAlgorithmId(algorithmId);
// 3. По подготовленной информации создаём сертификат
X509CertInfo info = new X509CertInfo();
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER, serialNumber);
info.set(X509CertInfo.SUBJECT, owner);
info.set(X509CertInfo.ISSUER, owner);
info.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
info.set(X509CertInfo.ALGORITHM_ID, certificateAlgorithmId);
// 4. Подписываем сертификат
X509CertImpl certificate = new X509CertImpl(info);
certificate.sign(keyPair.getPrivate(), "SHA256withRSA");
// 5. Проверка сертификата
try {
	// В случае ошибки здесь будет брошено исключение. Например: java.security.SignatureException
	certificate.verify(keyPair.getPublic());
} catch (Exception e) {
	throw new IllegalStateException(e);
}
Java kriptografiyasi arxitekturasi: Birinchi kirish - 15

Kalit do'koni (KeyStore)

Men gaplashmoqchi bo'lgan oxirgi narsa - bu KeyStore deb nomlangan kalit va sertifikatlar do'koni. Doimiy ravishda sertifikatlar va kalitlarni yaratish qimmat va ma'nosiz ekanligi aniq. Shuning uchun ular qandaydir tarzda xavfsiz tarzda saqlanishi kerak. Buning uchun vosita mavjud - KeyStore. Kalitlar do'koni JCA hujjatlarida " KeyManagement " bo'limida tasvirlangan. U bilan ishlash uchun API juda aniq. Mana kichik bir misol:
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
String alias = "EntityAlias";
java.security.cert.Certificate[] chain = {certificate};
keyStore.setKeyEntry(alias, keyPair.getPrivate(), "keyPassword".toCharArray(), chain);
// Загрузка содержимого (Private Key + Certificate)
Key key = keyStore.getKey(alias, "keyPassword".toCharArray());
Certificate[] certificateChain = keyStore.getCertificateChain(alias);
// Сохранение KeyStore на диск
File file = File.createTempFile("security_", ".ks");
System.out.println(file.getAbsolutePath());
try (FileOutputStream fos = new FileOutputStream(file)) {
	keyStore.store(fos, "keyStorePassword".toCharArray());
}
Misoldan ko'rinib turibdiki, u birinchi navbatda loadKeyStore uchun bajariladi. Ammo bizning holatlarimizda biz birinchi atributni null deb belgiladik, ya'ni. KeyStore uchun manba yo'q. Bu yana saqlash uchun KeyStore bo'sh yaratilganligini anglatadi. Ikkinchi parametr ham null, chunki biz yangi KeyStore yaratmoqdamiz. Agar biz KeyStore-ni fayldan yuklayotgan bo'lsak, bu erda parolni ko'rsatishimiz kerak bo'ladi (do'kon deb ataladigan KeyStore usuliga o'xshash).

Pastki chiziq

Shunday qilib, biz siz bilan Java Kriptografiya Arxitekturasi (aka JCA) doirasidagi eng asosiy va elementar amallarni ko'rib chiqdik. Biz simmetrik va assimetrik shifrlash nima ekanligini va JCAda qanday amalga oshirilayotganini ko'rdik. Sertifikatlar va elektron raqamli imzolar qanday yaratilgani va ulardan qanday foydalanilishini ko‘rdik. Bularning barchasi oddiy asoslar, ularning ortida juda ko'p murakkab va qiziqarli narsalar mavjud. Umid qilamanki, ushbu sharh materiali foydali bo'ladi va sizni ushbu sohani keyingi o'rganishga qiziqtiradi.
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION