JavaRush /Java блогы /Random-KK /Java криптографиясының архитектурасы: бірінші кіріспе
Viacheslav
Деңгей

Java криптографиясының архитектурасы: бірінші кіріспе

Топта жарияланған
Деректер алмасудың қауіпсіздігі қазіргі заманғы қолданбалардың маңызды қасиеттерінің бірі болып табылады. Ежелгі заманнан бері адамдар айлакер әдістерді ойлап тапты, олар адамзаттың дамуымен бүкіл криптография ғылымына айналды. Әрине, Java шетте қалмады және әзірлеушілерге Java криптографиялық архитектурасын (JCA) ұсынды. Бұл шолу оның қалай жұмыс істейтіні туралы бірінші түсінік беруі керек.

Алғы сөз

Уақытқа саяхат жасауды ұсынамын. Біздің алдымызда Ежелгі Рим. Ал біздің алдымызда Гай Юлий Цезарь тұр, ол өзінің командирлеріне хабар жібереді. Бұл хабарламада не бар екенін көрейік:
Java криптографиясының архитектурасы: Бірінші кіріспе - 2
Бұл нені білдіруі мүмкін: "ЕСКЕУГЬГМХИФЯ Е УЛП"? Java Online Compiler бағдарламасын ашайық, мысалы: 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);
    }
  }
}
Біздің алдымызда Цезарь шифрінің ең қарапайым орындалуы. Ежелгі Рим тарихшысы Светонийдің «Он екі Цезарьдың өмірі» атты еңбегіне сәйкес, Цезарь өз генералдарына хабарларды дәл осылай шифрлаған. Және бұл криптография сияқты нәрсені пайдалану туралы ең көне сілтемелердің бірі . «Криптография» сөзі ежелгі гректің «жасырын» және «жазу» сөздерінен шыққан, яғни. бұл құпиялылық техникасы туралы ғылым. Java тілінің криптографияға өзіндік қолдауы бар және ол Java Cryptography Architecture (JCA) деп аталады. Сипаттаманы Oracle ресми құжаттамасынан табуға болады - " Java Cryptography Architecture (JCA) ". Мен сізге JCA арқасында қандай мүмкіндіктерге ие болатынымызды қарастыруды ұсынамын.
Java криптографиясының архитектурасы: Бірінші кіріспе - 3

J.C.A.

Біз бұрын білгеніміздей, Java криптографиямен жұмыс істеу үшін Java криптографиялық архитектурасын (JCA) ұсынады. Бұл архитектурада API (яғни интерфейстердің белгілі бір жиынтығы) және провайдерлер (оларды жүзеге асыратын):
Java криптографиясының архитектурасы: Бірінші кіріспе - 4
Құжаттамада айтылғандай, « Java платформасы бірқатар кірістірілген провайдерлерді қамтиды ». Яғни, Java платформасы қажет болған жағдайда кеңейтілуі мүмкін кірістірілген провайдерлердің жиынтығын ұсынады. Сіз мұны өзіңіз көре аласыз:
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());
    }
  }
}
Үшінші тарап провайдерін тіркеу өте оңай. Мысалы: Security.addProvider(new BouncyCastleProvider()); Бұл мысал ең танымал провайдерлердің бірін қосады - BouncyCastle . Бірақ бұл шолуда біз үшінші тарап кітапханаларынсыз тек негізгі құралдарды қолданамыз. Біздің негізгі құжатымыз: « Java криптографиялық архитектурасы (JCA) ». JCA қалай жұмыс істейтінін түсіну дәл осы JCA белсенді қолданылатын технологияларды оңайырақ түсінуге көмектеседі. Мысалы: HTTPS (« HTTP-ден HTTPS-ке » бөлімін қараңыз).
Java криптографиясының архитектурасы: Бірінші кіріспе – 5

MessageDigest

JCA құжаттамасында айтылған бірінші нәрсе - MessageDigest. Жалпы алғанда, орыс тіліндегі дайджест бірдей болады - дайджест мағынасы бойынша «резюме» дегенге сәйкес келеді. Бірақ криптографияда дайджест хэш сомасы болып табылады. Сондай-ақ, ағылшын тілінде Digest-ті дайджест ретінде де аударуға болатынын оңай есте сақтай аласыз. Қосымша мәліметтерді JCA құжаттамасынан " MessageDigest " бөлімінде табуға болады. Құжаттамада айтылғандай, MessageDigest дайджест немесе хэш деп аталатын бекітілген өлшемді нәтижені жасайды. Хэширлеу бір жақты функция болып табылады, яғни. егер біз бірдеңені хэштесек, нәтижеден (яғни хэштен) бастапқы көзді ала алмаймыз. Бірақ егер бірдей нысандар хэштелген болса (мысалы, бірдей таңбалардың жолдары), онда олардың хэштері сәйкес болуы керек. Құжаттамада айтылғандай, мұндай хэш кейде деректердің «бақылау сомасы» немесе «сандық саусақ ізі» деп те аталады. Хэшинг әртүрлі алгоритмдер арқылы орындалуы мүмкін. Қолжетімді алгоритмдерді « JDK 8 үшін Java криптографиялық архитектурасының стандартты алгоритм атауының құжаттамасы » құжатында көруге болады . Хэшинг жасап, консольге хэшті басып шығарайық:
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);
    }
  }
}
Хэштеу, мысалы, құпия сөздерді сақтау кезінде пайдалы болуы мүмкін. Енгізілген құпия сөздің хэшін бұрын сақталған хэшпен салыстыруға болатындықтан. Хэштер сәйкес келсе, құпия сөз де сәйкес келеді. Одан да қауіпсіз хэштеу үшін «тұз» деп аталатын ұғым қолданылады. Тұзды SecureRandom класы арқылы жүзеге асыруға болады . Дайджест әдісін орындамас бұрын «тұзды» қосуды сипаттайық:
byte[] salt = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(salt);
digester.update(salt);
Бірақ хэш - бұл бір жақты функция. Бірақ шифрлау және шифрды шешу мүмкіндігін алғыңыз келсе ше?
Java криптографиясының архитектурасы: Бірінші кіріспе - 6

Симметриялық кілт криптографиясы

Симметриялық шифрлау – шифрлау және шифрды шешу үшін бірдей кілтті пайдаланатын шифрлау. Симметриялық шифрлауды пайдалану үшін бізге кілт қажет. Оны алу үшін біз KeyGenerator пайдаланамыз . Сонымен қатар, бізге шифрды білдіретін класс қажет болады ( Cipher ). JCA құжаттамасында « Шифр нысанын жасау » бөлімінде айтылғандай, шифрды жасау үшін тек алгоритмді ғана емес, жолда «трансформацияны» көрсету керек. Трансформация сипаттамасы келесідей көрінеді: "algorithm/rejim/padding":
  • Алгоритм : мұнда біз « Шифрлық (шифрлау) алгоритмдері » үшін стандартты атауларды қарастырамыз . AES пайдалану ұсынылады.
  • Режим : шифрлау режимі. Мысалы: ECB немесе CBC (бұл туралы сәл кейінірек айтатын боламыз)
  • Шегініс/Бөлу : деректердің әрбір блогы бөлек шифрланады. Бұл параметр қанша деректер 1 блок ретінде есептелетінін анықтайды.
Мысалы, келесі түрлендіруді алайық: "AES/ECB/PKCS5Padding". Яғни, шифрлау алгоритмі - AES, шифрлау режимі - ECB (электрондық code кітабының қысқаша нұсқасы), блок өлшемі - PKCS5Padding. PKCS5Padding бір блоктың өлшемі 2 byte (16 бит) екенін айтады. Электрондық code кітапшасының шифрлау режимі әрбір блоктың дәйекті шифрлауын қамтиды:
Java криптографиясының архитектурасы: Бірінші кіріспе – 7
Бұл codeта келесідей көрінуі мүмкін:
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);
  }
}
Егер біз орындасақ, біз қайталауды күтеміз, өйткені біз 32 таңбаны көрсеттік. Бұл таңбалар 16 биттен тұратын 2 блокты құрайды:
Java криптографиясының архитектурасы: Бірінші кіріспе – 8
Бұл жағдайда қайта ойнауды болдырмау үшін басқа режимді пайдалану керек - Cipher Block Chaining (CBC). Бұл режим Initialization Vector (IvParameterSpec сыныбымен ұсынылған) тұжырымдамасын енгізеді. Сондай-ақ осы режимнің арқасында соңғы блокты құру нәтижесі келесі блокты жасау үшін пайдаланылады:
Java криптографиясының архитектурасы: Бірінші кіріспе – 9
Енді оны codeпен жазайық:
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);
  }
}
Көріп отырғанымыздай, нәтижесінде біз қайталанатын шифрлық блоктарды көрмейміз. Осы себепті, ECB режимі ұсынылмайды, өйткені қайталауларды көруге және осы білімді шифрды шешу үшін пайдалануға мүмкіндік береді. ECB және CBC туралы қосымша ақпарат алу үшін мен сізге материалды оқуға кеңес беремін: « Электрондық codeтық кітап режимі ». Бірақ симметриялық шифрлаудың айқын проблемасы бар - сіз қандай да бір жолмен кілтті шифрлайтын адамнан шифрлайтынға беруіңіз керек. Және осы жолда бұл кілтті ұстап алуға болады, содан кейін деректерді ұстауға болады. Ал асимметриялық шифрлау осы мәселені шешуге арналған.
Java криптографиясының архитектурасы: Бірінші кіріспе – 10

Асимметриялық шифрлау

Асимметриялық шифрлау немесе Ашық кілтті криптография - бұл жұп кілттерді пайдаланатын шифрлау әдісі: жеке кілт (барлықтан құпия сақталады) және ашық кілт (жалпыға қолжетімді). Бұл бөлу құпия кілтті қауіпсіз сақтай отырып, ақпарат алмасу тараптары арасында ашық кілтпен қауіпсіз алмасу үшін қажет. Кілттер жұбын жасау кезінде KeyGenerator бізге енді жеткіліксіз; бізге KeyPairGenerator қажет . Мысал қарастырайық:
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));
  }
}
Бұл жерде асимметриялық шифрлауды пайдаланған кезде біз әрқашан бір кілтті шифрлау үшін, ал екіншісін шифрды шешу үшін пайдалану үшін KeyPair пайдаланатынын түсіну маңызды. Бірақ өйткені Шифрлаудың мәні мынада: оны тек алушы ғана шеше алады, ол ашық кілтпен шифрланады, ал жекемен ғана шифрланады.
Java криптографиясының архитектурасы: Алғашқы танысу – 11

Сандық қолтаңба

Жоғарыда көргеніміздей, ашық кілтті біле отырып, сіз деректерді тек жеке кілттің иесі ғана шифрын шеше алатындай жібере аласыз. Яғни, асимметриялық шифрлаудың мәні кез келген адам шифрлайды, бірақ біз оқимыз. Сондай-ақ кері proceduresа бар - қолтаңба класымен ұсынылған цифрлық қолтаңба . Электрондық цифрлық қолтаңба келесі алгоритмдерді пайдалана алады: « Қолтаңба алгоритмдері ». JCA құжаттамасы осы екеуін мұқият қарауды ұсынады: DSAwithMD5 және RSAwithMD5 DSA немесе RSA қарағанда жақсы және олардың айырмашылығы неде мына жерден оқуға болады: " Шифрланған файлды тасымалдау үшін қайсысы жақсы жұмыс істейді - RSA немесе DSA? ". Немесе мына жерден талқылауларды оқыңыз: " SSH аутентификация кілттері үшін RSA және DSA ". Сонымен, цифрлық қолтаңба. Бізге бұрынғыдай KeyPair және жаңа Signature сыныбы қажет болады. Егер сіз осы уақытқа дейін онлайн компиляторларда сынақтан өткен болсаңыз, келесі мысал олар үшін біршама қиын болуы мүмкін. Менің мысалым тек осында орындалды: rextester.com . Бізге қажетті сыныптарды импорттаймыз:
import javax.crypto.*;
import java.security.*;
Біз сонымен қатар негізгі әдісті қайта жазамыз:
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));
    }
}
Электрондық цифрлық қолтаңба осылай жұмыс істейді. Цифрлық қолтаңба – қызықты тақырып. Мен сізге осы тақырып бойынша баяндаманы қарауды ұсынамын:
Java криптографиясының архитектурасы: Алғашқы танысу – 12
Жоғарыда біз тараптардың деректер алмасуын көрдік. JCA-да берілген өзара әрекеттесу үшін стандартты интерфейс бар емес пе? Бар екені белгілі болды. Оны қарастырайық.
Java криптографиясының архитектурасы: Алғашқы танысу – 13

Негізгі келісім

Java криптографиялық архитектурасы маңызды құралды ұсынады - Негізгі келісім - бұл протокол. Ол KeyAgreement сыныбымен ұсынылған . JCA құжаттамасында айтылғандай, бұл хаттама бірнеше тараптарға бір криптографиялық кілтті тараптар арасында ешқандай құпия ақпаратты бөліспей орнатуға мүмкіндік береді. Біртүрлі естіледі ме? Содан кейін мысалды қарастырайық:
// 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));
Бұл мысал JCA құжаттамасының мысалынан алынды: " 2 тарап арасындағы Диффи-Хеллман кілт алмасуы ". Кілттік келісім хаттамасын қолданатын Java криптографиялық архитектурасындағы асимметриялық шифрлау шамамен осылай көрінеді. Асимметриялық шифрлау туралы қосымша ақпарат алу үшін ұсынылған бейнелер:
Java криптографиясының архитектурасы: Алғашқы танысу – 14

Сертификаттар

Десерт үшін бізде әлі де маңызды нәрсе бар - сертификаттар. Әдетте, сертификаттар jdk құрамына кіретін keytool қызметтік бағдарламасы арқылы жасалады. Қосымша мәліметтерді, мысалы, мына жерден оқи аласыз: " Java keytool пәрменін пайдаланып өздігінен қол қойылған SSL сертификатын жасау ". Сондай-ақ Oracle нұсқаулығын оқуға болады. Мысалы, мұнда: " Сервер сертификатын жасау үшін пернетақтаны пайдалану ". Мысалы, Tutorialspoint Java Online Compiler бағдарламасын қолданайық :
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));
  }
}
Көріп отырғанымыздай, сертификат ашық кілтті беру мүмкіндігін береді. Бұл әдістің кемшілігі бар - біз пайдаланамыз sun.security, ол қауіпті деп саналады, өйткені... бұл бума жалпыға ортақ Java API бөлігі емес. Сондықтан компиляция кезінде - параметрін көрсету қажет XDignore.symbol.file. Басқа әдіс бар - сертификатты қолмен жасау. Кемшілігі - құжатталмаған ішкі API пайдаланады. Дегенмен, бұл туралы білу пайдалы. Кем дегенде, RFC-2459 спецификациясының қалай қолданылатыны анық көрінетіндіктен: “ Internet X.509 Public Key Infrastructure ”. Міне, мысал:
// 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 криптографиясының архитектурасы: Бірінші кіріспе – 15

Кілттер қоймасы (KeyStore)

Мен айтқым келетін соңғы нәрсе - KeyStore деп аталатын кілттер мен сертификаттар қоймасы. Сертификаттар мен кілттерді үнемі генерациялау қымбат және мағынасыз екені анық. Сондықтан оларды қандай да бір түрде қауіпсіз сақтау керек. Бұл үшін құрал бар - KeyStore. Кілттер қоймасы JCA құжаттамасында « KeyManagement » тарауында сипатталған. Онымен жұмыс істеуге арналған API өте түсінікті. Міне, шағын мысал:
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());
}
Мысалдан көріп отырғаныңыздай, ол алдымен loadKeyStore үшін орындалады. Бірақ біздің жағдайда біз бірінші атрибутты нөл ретінде көрсеттік, яғни. KeyStore үшін ешқандай дереккөз жоқ. Бұл KeyStore одан әрі сақтау үшін бос жасалғанын білдіреді. Екінші параметр де нөлге тең, өйткені біз жаңа KeyStore жасаймыз. Егер біз KeyStore файлын жүктеп жатқан болсақ, мұнда құпия сөзді көрсету керек еді (дүкен деп аталатын KeyStore әдісіне ұқсас).

Төменгі сызық

Сондықтан біз сіздермен Java криптографиялық архитектурасы (aka JCA) аясындағы ең негізгі және қарапайым әрекеттерді қарастырдық. Біз симметриялық және асимметриялық шифрлаудың не екенін және оның JCA-да қалай жүзеге асырылатынын көрдік. Біз сертификаттар мен электрондық цифрлық қолтаңбалардың қалай жасалатынын және олардың қалай қолданылатынын көрдік. Мұның бәрі жай ғана негіздер, олардың артында көптеген күрделі және қызықты нәрселер бар. Бұл шолу материалы пайдалы болады және сізді осы саланы одан әрі зерттеуге қызықтырады деп үміттенемін.
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION