JavaRush /Java Blog /Random-TL /Java Cryptography Architecture: Unang panimula

Java Cryptography Architecture: Unang panimula

Nai-publish sa grupo
Ang seguridad ng pagpapalitan ng data ay isa sa pinakamahalagang katangian ng mga modernong aplikasyon. Mula noong sinaunang panahon, ang mga tao ay gumawa ng mga tusong pamamaraan, na sa pag-unlad ng sangkatauhan ay naging buong agham ng Cryptography. Natural, hindi tumabi ang Java at nag-alok sa mga developer ng Java Cryptography Architecture (JCA). Ang pagsusuri na ito ay dapat magbigay ng unang ideya kung paano ito gumagana.

Paunang Salita

Iminumungkahi kong maglakbay pabalik sa nakaraan. Nasa harap natin ang Sinaunang Roma. At sa harap natin ay si Gaius Julius Caesar, na nagpadala ng mensahe sa kanyang mga kumander. Tingnan natin kung ano ang nasa mensaheng ito:
Java Cryptography Architecture: Unang panimula - 2
Ano ang maaaring ibig sabihin nito: "ЕСКЕУГЬГМХИФЯ Е УЛП"? Buksan natin ang Java Online Compiler, halimbawa: 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);
    }
  }
}
Bago sa amin ay ang pinakasimpleng pagpapatupad ng Caesar Cipher. Ayon sa gawain ng sinaunang Romanong mananalaysay na si Suetonius na pinamagatang “The Lives of the Twelve Caesars,” ganito mismo ang pag-encrypt ni Caesar ng mga mensahe sa kanyang mga heneral. At ito ay isa sa mga pinaka sinaunang sanggunian sa paggamit ng isang bagay tulad ng Cryptography . Ang salitang "cryptography" ay nagmula sa mga sinaunang salitang Griyego na "nakatago" at "magsulat", i.e. ito ay ang agham ng mga diskarte sa privacy. Ang Java ay may sariling suporta para sa cryptography at ito ay tinatawag na Java Cryptography Architecture (JCA). Ang paglalarawan ay matatagpuan sa opisyal na dokumentasyon mula sa Oracle - " Java Cryptography Architecture (JCA) ". Iminumungkahi kong tingnan mo kung anong mga pagkakataon ang makukuha namin salamat sa JCA.
Arkitektura ng Java Cryptography: Unang panimula - 3

J.C.A.

Gaya ng natutunan natin dati, nag-aalok ang Java ng Java Cryptography Architecture (JCA) para sa pagtatrabaho sa cryptography. Ang arkitektura na ito ay naglalaman ng isang API (ibig sabihin, isang tiyak na hanay ng mga interface) at mga provider (na nagpapatupad ng mga ito):
Arkitektura ng Java Cryptography: Unang panimula - 4
Gaya ng sinasabi ng dokumentasyon, " Ang Java platform ay may kasamang bilang ng mga built-in na provider ". Iyon ay, ang Java platform ay nagbibigay ng isang set ng mga built-in na provider na maaaring palawakin kung kinakailangan. Maaari mong makita ito para sa iyong sarili:
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());
    }
  }
}
Ang pagpaparehistro ng isang third party provider ay napakadali. Halimbawa: Security.addProvider(new BouncyCastleProvider()); Ang halimbawang ito ay nag-uugnay sa isa sa mga pinakasikat na provider - BouncyCastle . Ngunit sa pagsusuring ito gagamitin lang namin ang mga pangunahing tool, nang walang mga aklatan ng third-party. Ang aming pangunahing dokumento: " Java Cryptography Architecture (JCA) ". Ang pag-unawa sa kung paano gumagana ang JCA ay makakatulong sa iyong mas madaling maunawaan ang mga teknolohiya kung saan ang parehong JCA ay aktibong ginagamit. Halimbawa: HTTPS (tingnan ang " Mula sa HTTP hanggang HTTPS ").
Arkitektura ng Java Cryptography: Unang panimula - 5

MessageDigest

Ang unang bagay na binanggit sa dokumentasyon ng JCA ay MessageDigest. Sa pangkalahatan, ang Digest sa Russian ay magiging pareho - ang isang digest ay tumutugma sa kahulugan sa "isang buod". Ngunit sa cryptography, ang isang digest ay isang hash sum. Madali mo ring maaalala na sa English Digest ay maaari ding isalin bilang digest. Higit pang mga detalye ang makikita sa dokumentasyon ng JCA sa seksyong " MessageDigest ". Tulad ng sinasabi ng dokumentasyon, ang MessageDigest ay bumubuo ng isang nakapirming laki na resulta na tinatawag na digest o hash. Ang pag-hash ay isang one-way na function, i.e. kung naghash kami ng isang bagay, pagkatapos ay mula sa resulta (i.e. mula sa hash) hindi namin makuha ang orihinal na pinagmulan. Ngunit kung ang magkaparehong mga bagay ay na-hash (halimbawa, mga string ng magkaparehong mga character), dapat magkatugma ang kanilang hash. Gaya ng nakasaad sa dokumentasyon, ang naturang hash ay tinatawag ding "checksum" o "digital fingerprint" ng data. Maaaring isagawa ang pag-hash gamit ang iba't ibang mga algorithm. Maaaring matingnan ang mga available na algorithm sa dokumentong " Java Cryptography Architecture Standard Algorithm Name Documentation para sa JDK 8 ". Gawin natin ang hashing at i-print ang hash sa console:
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);
    }
  }
}
Maaaring maging kapaki-pakinabang ang pag-hash, halimbawa, kapag nag-iimbak ng mga password. Dahil ang hash ng ipinasok na password ay maaaring suriin laban sa isang naunang na-save na hash. Kung magkatugma ang mga hash, magkatugma rin ang password. Para sa mas ligtas na pag-hash, isang konsepto na tinatawag na "asin" ang ginagamit. Maaaring ipatupad ang asin gamit ang SecureRandom class . Bago isagawa ang paraan ng pagtunaw, ilarawan natin ang pagdaragdag ng "asin":
byte[] salt = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(salt);
digester.update(salt);
Ngunit ang hash ay isang one-way na function. Ngunit paano kung gusto mong makapag-encrypt at mag-decrypt?
Arkitektura ng Java Cryptography: Unang panimula - 6

Symmetric key cryptography

Ang simetriko encryption ay encryption na gumagamit ng parehong key para sa encryption at decryption. Upang magamit ang simetriko na pag-encrypt kailangan namin ng isang susi. Upang makuha ito ginagamit namin ang KeyGenerator . Bilang karagdagan, kakailanganin namin ang isang klase na kumakatawan sa isang cipher ( Cipher ). Tulad ng nakasaad sa dokumentasyon ng JCA sa seksyong " Paglikha ng Cipher Object ", upang lumikha ng Cipher kailangan mong tukuyin hindi lamang isang algorithm, ngunit isang "pagbabago" sa linya. Ganito ang hitsura ng paglalarawan ng pagbabagong-anyo: "algorithm/mode/padding":
  • Algorithm : dito tinitingnan natin ang mga karaniwang pangalan para sa " Cipher (Encryption) Algorithms ". Inirerekomenda na gumamit ng AES.
  • Mode : mode ng pag-encrypt. Halimbawa: ECB o CBC (pag-uusapan natin ito sa ibang pagkakataon)
  • Indentation/Split : Ang bawat bloke ng data ay naka-encrypt nang hiwalay. Tinutukoy ng parameter na ito kung gaano karaming data ang binibilang bilang 1 block.
Halimbawa, kunin ang sumusunod na pagbabago: "AES/ECB/PKCS5Padding". Ibig sabihin, ang encryption algorithm ay AES, ang encryption mode ay ECB (maikli para sa Electronic Codebook), ang block size ay PKCS5Padding. Sinasabi ng PKCS5Padding na ang laki ng isang bloke ay 2 bytes (16 bits). Ang Electronic Codebook encryption mode ay kinabibilangan ng sequential encryption ng bawat block:
Arkitektura ng Java Cryptography: Unang panimula - 7
Maaaring ganito ang hitsura nito sa 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);
  }
}
Kung i-execute natin, aasahan nating makakakita tayo ng repeat, kasi tinukoy namin ang 32 character. Ang mga character na ito ay bumubuo ng 2 bloke ng 16 bits:
Arkitektura ng Java Cryptography: Unang panimula - 8
Upang maiwasan ang replay sa kasong ito, dapat kang gumamit ng isa pang mode - Cipher Block Chaining (CBC). Ang mode na ito ay nagpapakilala sa konsepto ng Initialization Vector (kinakatawan ng klase ng IvParameterSpec). At salamat din sa mode na ito, ang resulta ng pagbuo ng huling bloke ay gagamitin upang makabuo ng susunod:
Arkitektura ng Java Cryptography: Unang panimula - 9
Isulat natin ito sa 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);
  }
}
Tulad ng nakikita natin, bilang isang resulta hindi namin nakikita ang paulit-ulit na mga bloke ng cipher. Para sa kadahilanang ito, ang ECB mode ay hindi inirerekomenda, dahil ginagawang posible na makita ang mga pag-uulit at gamitin ang kaalamang ito para sa pag-decryption. Para sa karagdagang impormasyon tungkol sa ECB at CBC, ipinapayo ko sa iyo na basahin ang materyal: " Electronic codebook mode ". Ngunit ang simetriko na pag-encrypt ay may malinaw na problema - kailangan mong ilipat ang susi mula sa nag-encrypt patungo sa nag-encrypt. At sa landas na ito, ang susi na ito ay maaaring ma-intercept at pagkatapos ay magiging posible na ma-intercept ang data. At ang asymmetric encryption ay idinisenyo upang malutas ang problemang ito.
Arkitektura ng Java Cryptography: Unang panimula - 10

Asymmetric na pag-encrypt

Ang Asymmetric encryption o Public-key cryptography ay isang paraan ng pag-encrypt na gumagamit ng isang pares ng mga key: isang pribadong key (pinananatiling lihim sa lahat) at isang pampublikong key (available sa publiko). Ang paghihiwalay na ito ay kinakailangan upang ligtas na palitan ang pampublikong susi sa pagitan ng mga partido sa pagpapalitan ng impormasyon, habang pinananatiling ligtas ang sikretong susi. Kapag gumagawa ng key pair, ang KeyGenerator ay hindi na sapat para sa amin; kailangan namin ng KeyPairGenerator . Tingnan natin ang isang halimbawa:
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));
  }
}
Mahalagang maunawaan dito na kapag gumagamit ng asymmetric encryption, palagi naming ginagamit ang KeyPair para gumamit ng isang key para sa encryption at isa pa para sa decryption. Pero kasi Ang punto ng pag-encrypt ay ang tatanggap lamang ang makakapag-decrypt nito; ito ay naka-encrypt gamit ang isang pampublikong susi, at na-decrypt lamang gamit ang isang pribado.
Java Cryptography Architecture: Unang kakilala - 11

Digital na lagda

Tulad ng nakita natin sa itaas, alam ang pampublikong key, maaari kang magpadala ng data upang ang may-ari lamang ng pribadong key ang makakapag-decrypt nito. Iyon ay, ang kakanyahan ng asymmetric encryption ay ang sinumang nag-encrypt, ngunit kami lamang ang nagbabasa. Mayroon ding reverse procedure - isang digital signature, na kinakatawan ng Signature class . Maaaring gamitin ng digital signature ang mga sumusunod na algorithm: " Signature Algorithms ". Iminumungkahi ng dokumentasyon ng JCA na tingnang mabuti ang dalawang ito: DSAwithMD5 at RSAwithMD5 Ano ang mas mahusay kaysa sa DSA o RSA at ano ang kanilang pagkakaiba na maaari mong basahin dito: " Alin ang Pinakamahusay para sa Mga Naka-encrypt na Paglipat ng File - RSA o DSA? ". O basahin ang mga talakayan dito: " RSA vs. DSA para sa mga SSH authentication key ". Kaya, digital signature. Kakailanganin namin, tulad ng dati, isang KeyPair at isang bagong klase ng Signature. Kung nasubukan mo na sa mga online compiler sa ngayon, ang sumusunod na halimbawa ay maaaring medyo mahirap para sa kanila. Ang aking halimbawa ay tumakbo lamang dito: rextester.com . Ini-import namin ang mga klase na kailangan namin:
import javax.crypto.*;
import java.security.*;
Isusulat din namin ang pangunahing paraan:
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));
    }
}
Ito ay kung paano gumagana ang isang digital na lagda. Ang digital signature ay isang kawili-wiling paksa. Pinapayuhan ko kayong tingnan ang ulat sa paksang ito:
Java Cryptography Architecture: Unang kakilala - 12
Sa itaas nakita namin kung paano nagpapalitan ng data ang mga partido. Wala bang ilang karaniwang interface para sa pakikipag-ugnayang ito na ibinigay sa JCA? Meron pala. Tingnan natin ito.
Arkitektura ng Java Cryptography: Unang kakilala - 13

KeyAgreement

Ang Java Cryptography Architecture ay nagpapakilala ng isang mahalagang tool - Ang pangunahing kasunduan ay isang protocol. Ito ay kinakatawan ng KeyAgreement class . Gaya ng nakasaad sa dokumentasyon ng JCA, pinapayagan ng protocol na ito ang maraming partido na magtakda ng parehong cryptographic key nang hindi nagbabahagi ng anumang lihim na impormasyon sa pagitan ng mga partido. Kakaibang tunog? Pagkatapos ay tingnan natin ang isang halimbawa:
// 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));
Ang halimbawang ito ay kinuha mula sa halimbawa ng dokumentasyon ng JCA: " Diffie-Hellman Key Exchange between 2 Parties ". Ito ay halos kung ano ang hitsura ng asymmetric encryption sa Java Cryptography Architecture gamit ang Key agreement protocol. Para sa higit pang impormasyon tungkol sa asymmetric encryption, inirerekomendang mga video:
Arkitektura ng Java Cryptography: Unang kakilala - 14

Mga sertipiko

Well, para sa dessert mayroon pa rin kaming isang bagay na hindi gaanong mahalaga - mga sertipiko. Karaniwan, ang mga sertipiko ay nabuo gamit ang keytool utility na kasama sa jdk. Maaari kang magbasa ng higit pang mga detalye, halimbawa, dito: " Pagbuo ng isang self-signed SSL certificate gamit ang Java keytool command ". Maaari mo ring basahin ang mga manwal mula sa Oracle. Halimbawa, dito: " Upang Gamitin ang keytool upang Gumawa ng Sertipiko ng Server ". Halimbawa, gamitin natin ang 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));
  }
}
Tulad ng nakikita natin, ang isang sertipiko ay nagbibigay ng kakayahang magbigay ng isang pampublikong susi. Ang pamamaraang ito ay may disbentaha - ginagamit namin sun.security, na itinuturing na peligroso, dahil... ang package na ito ay hindi bahagi ng pampublikong Java API. Iyon ang dahilan kung bakit sa panahon ng compilation ito ay kinakailangan upang tukuyin ang parameter - XDignore.symbol.file. May isa pang paraan - upang lumikha ng isang sertipiko nang manu-mano. Ang downside ay gumagamit ito ng panloob na API na hindi nakadokumento. Gayunpaman, kapaki-pakinabang na malaman ang tungkol dito. Sa pinakamababa, dahil malinaw na nakikita kung paano ginagamit ang detalye ng RFC-2459: “ Internet X.509 Public Key Infrastructure ”. Narito ang isang halimbawa:
// 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);
}
Arkitektura ng Java Cryptography: Unang panimula - 15

Keystore (KeyStore)

Ang huling bagay na gusto kong pag-usapan ay ang tindahan ng susi at sertipiko, na tinatawag na KeyStore. Malinaw na ang patuloy na pagbuo ng mga sertipiko at susi ay mahal at walang kabuluhan. Samakatuwid, kailangan nilang maiimbak kahit papaano nang ligtas. Mayroong isang tool para dito - KeyStore. Inilalarawan ang key store sa dokumentasyon ng JCA sa " KeyManagement " na kabanata. Ang API para sa pagtatrabaho dito ay napakalinaw. Narito ang isang maliit na halimbawa:
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());
}
Tulad ng nakikita mo mula sa halimbawa, ito ay unang isinasagawa loadpara sa KeyStore. Ngunit sa aming kaso, tinukoy namin ang unang katangian bilang null, i.e. walang source para sa KeyStore. Nangangahulugan ito na ang KeyStore ay nilikhang walang laman upang mas mai-save ito. Ang pangalawang parameter ay null din, dahil gumagawa kami ng bagong KeyStore. Kung naglo-load kami ng KeyStore mula sa isang file, kakailanganin naming tumukoy ng password dito (katulad ng KeyStore method na tinatawag na store).

Bottom line

Kaya't sinuri namin sa iyo ang pinakapangunahing at elementarya na mga aksyon sa loob ng balangkas ng Java Cryptography Architecture (aka JCA). Nakita namin kung ano ang simetriko at asymmetric na pag-encrypt at kung paano ito ipinapatupad sa JCA. Nakita namin kung paano nilikha ang mga certificate at digital signature at kung paano ginagamit ang mga ito. Ang lahat ng ito ay mga pangunahing kaalaman lamang, sa likod kung saan mayroong maraming mas kumplikado at kawili-wiling mga bagay. Umaasa ako na ang materyal sa pagsusuri na ito ay magiging kapaki-pakinabang at magiging interesado ka sa karagdagang pag-aaral ng lugar na ito.
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION