Úvod do BouncyCastle s Java

1. Prehľad

BouncyCastle je knižnica Java, ktorá dopĺňa predvolené Java Cryptographic Extension (JCE).

V tomto úvodnom článku si ukážeme, ako používať BouncyCastle na vykonávanie kryptografických operácií, ako je šifrovanie a podpis.

2. Konfigurácia Maven

Predtým, ako začneme pracovať s knižnicou, musíme do našej pridať požadované závislosti pom.xml spis:

 org.bouncycastle bcpkix-jdk15on 1.58 

Upozorňujeme, že najnovšie verzie závislostí môžeme kedykoľvek vyhľadať v centrálnom úložisku Maven.

3. Nastavte súbory politiky jurisdikcie s neobmedzenou silou

Štandardná inštalácia Java je z hľadiska sily kryptografických funkcií obmedzená, je to spôsobené politikami zakazujúcimi použitie kľúča s veľkosťou, ktorá presahuje určité hodnoty, napr. 128 pre AES.

Aby sme prekonali toto obmedzenie, musíme nakonfigurujte súbory politiky jurisdikcie s neobmedzenou silou.

Aby sme to dosiahli, je potrebné si najprv stiahnuť balík pomocou tohto odkazu. Potom musíme rozbaliť komprimovaný súbor do adresára podľa nášho výberu - ktorý obsahuje dva súbory jar:

  • local_policy.jar
  • US_export_policy.jar

Nakoniec musíme hľadať {JAVA_HOME} / lib / security priečinok a nahraďte existujúce súbory zásad tými, ktoré sme tu extrahovali.

Poznač si to v prostredí Java 9 už nemusíme sťahovať balík súborov politík, ktorým sa nastavuje krypto.polícia majetok do neobmedzene je dostatočne:

Security.setProperty ("crypto.policy", "unlimited");

Po dokončení musíme skontrolovať, či konfigurácia funguje správne:

int maxKeySize = javax.crypto.Cipher.getMaxAllowedKeyLength ("AES"); System.out.println ("Max. Veľkosť kľúča pre AES:" + maxKeySize);

Ako výsledok:

Maximálna veľkosť kľúča pre AES: 2147483647

Na základe maximálnej veľkosti kľúča vrátenej getMaxAllowedKeyLength () metódou, môžeme s istotou povedať, že súbory s politikou neobmedzenej sily boli nainštalované správne.

Ak sa vrátená hodnota rovná 128, musíme sa ubezpečiť, že sme súbory nainštalovali do JVM, kde spúšťame kód.

4. Kryptografické operácie

4.1. Príprava certifikátu a súkromného kľúča

Predtým, ako sa pustíme do implementácie kryptografických funkcií, je potrebné najskôr vytvoriť certifikát a súkromný kľúč.

Na testovacie účely môžeme použiť tieto zdroje:

  • Baeldung.cer
  • Baeldung.p12 (heslo = „heslo“)

Baeldung.cer je digitálny certifikát, ktorý využíva medzinárodný štandard infraštruktúry verejných kľúčov X.509, zatiaľ čo Baeldung.p12 je úložisko kľúčov PKCS12 chránené heslom, ktoré obsahuje súkromný kľúč.

Pozrime sa, ako je možné tieto načítať v prostredí Java:

Security.addProvider (nový BouncyCastleProvider ()); CertificateFactory certFactory = CertificateFactory .getInstance ("X.509", "BC"); X509Certificate certificate = (X509Certificate) certFactory .generateCertificate (nový FileInputStream ("Baeldung.cer")); char [] keystorePassword = "heslo" .toCharArray (); char [] keyPassword = "heslo" .toCharArray (); KeyStore keystore = KeyStore.getInstance ("PKCS12"); keystore.load (nový FileInputStream ("Baeldung.p12"), keystorePassword); PrivateKey key = (PrivateKey) keystore.getKey ("baeldung", keyPassword);

Najskôr sme pridali BouncyCastleProvider ako poskytovateľ zabezpečenia dynamicky využívajúci addProvider () metóda.

To možno vykonať aj staticky úpravou súboru {JAVA_HOME} /jre/lib/security/java.security súbor a pridanie tohto riadku:

security.provider.N = org.bouncycastle.jce.provider.BouncyCastleProvider

Po správnom nainštalovaní poskytovateľa sme vytvorili a CertificateFactory objekt pomocou getInstance () metóda.

The getInstance () metóda má dva argumenty; typ certifikátu „X.509“ a poskytovateľ zabezpečenia „BC“.

The certFactory inštancia sa následne použije na vygenerovanie Certifikát X509 objekt, prostredníctvom generateCertificate () metóda.

Rovnakým spôsobom sme vytvorili objekt PKCS12 Keystore, na ktorom naložiť() metóda sa volá.

The getKey () metóda vráti súkromný kľúč spojený s daným aliasom.

Pamätajte, že PKCS12 Keystore obsahuje sadu súkromných kľúčov, každý súkromný kľúč môže mať konkrétne heslo, preto potrebujeme globálne heslo na otvorenie úložiska kľúčov a konkrétne na získanie súkromného kľúča.

Certifikát a pár súkromného kľúča sa používajú hlavne v asymetrických kryptografických operáciách:

  • Šifrovanie
  • Dešifrovanie
  • Podpis
  • Overenie

4.2 Šifrovanie a dešifrovanie CMS / PKCS7

V asymetrickej kryptografii šifrovania vyžaduje každá komunikácia verejný certifikát a súkromný kľúč.

Príjemca je viazaný na certifikát, ktorý je verejne zdieľaný medzi všetkými odosielateľmi.

Jednoducho povedané, odosielateľ potrebuje na zašifrovanie správy certifikát príjemcu, zatiaľ čo príjemca potrebuje na dešifrovanie priradený súkromný kľúč.

Poďme sa pozrieť na to, ako implementovať encryptData () pomocou šifrovacieho certifikátu:

verejný statický bajt [] encryptData (bajty [] údaje, X509Certificate encryptionCertificate) hodí CertificateEncodingException, CMSException, IOException {byte [] encryptedData = null; if (null! = data && null! = encryptionCertificate) {CMSEnvelopedDataGenerator cmsEnvelopedDataGenerator = nový CMSEnvelopedDataGenerator (); JceKeyTransRecipientInfoGenerator jceKey = nový JceKeyTransRecipientInfoGenerator (encryptionCertificate); cmsEnvelopedDataGenerator.addRecipientInfoGenerator (transKeyGen); CMSTypedData msg = new CMSProcessableByteArray (data); OutputEncryptor encryptor = nový JceCMSContentEncryptorBuilder (CMSAlgorithm.AES128_CBC) .setProvider ("BC"). Build (); CMSEnvelopedData cmsEnvelopedData = cmsEnvelopedDataGenerator .generate (msg, šifrovač); encryptedData = cmsEnvelopedData.getEncoded (); } návrat encryptedData; }

Vytvorili sme JceKeyTransRecipientInfoGenerator predmet pomocou certifikátu príjemcu.

Potom sme vytvorili nový CMSEnvelopedDataGenerator objekt a do neho pridal generátor informácií o príjemcovi.

Potom sme použili JceCMSContentEncryptorBuilder triedy na vytvorenie OutputEncrytor pomocou algoritmu AES CBC.

Šifrovač sa použije neskôr na vygenerovanie CMSEnvelopedData objekt, ktorý zapuzdruje zašifrovanú správu.

Nakoniec sa kódovaná reprezentácia obálky vráti ako bajtové pole.

Teraz sa pozrime, čo bude implementácia decryptData () metóda vyzerá takto:

public static byte [] decryptData (byte [] encryptedData, PrivateKey decryptionKey) hodí CMSException {byte [] decryptedData = null; if (null! = encryptedData && null! = decryptionKey) {CMSEnvelopedData envelopedData = new CMSEnvelopedData (encryptedData); Príjemcovia zbierky = envelopedData.getRecipientInfos (). GetRecipients (); KeyTransRecipientInformation recipientInfo = (KeyTransRecipientInformation) recipienti.iterator (). Next (); Príjemca JceKeyTransRecipient = nový JceKeyTransEnvelopedRecipient (decryptionKey); vrátiť recipientInfo.getContent (príjemca); } návrat decryptedData; }

Najskôr sme inicializovali a CMSEnvelopedData objekt pomocou šifrovaného dátového bajtového poľa, a potom sme pomocou služby .použili všetkých zamýšľaných príjemcov správy getRecipients () metóda.

Po dokončení sme vytvorili nový JceKeyTransRecipient objekt spojený s privátnym kľúčom príjemcu.

The recipientInfo inštancia obsahuje dešifrovanú / zapuzdrenú správu, ale nemôžeme ju načítať, pokiaľ nemáme zodpovedajúci kľúč príjemcu.

Nakoniec, vzhľadom na argument kľúča príjemcu, getContent () metóda vráti nespracované bajtové pole extrahované z EnvelopedData tento príjemca je spojený s.

Poďme napísať jednoduchý test, aby sme sa ubezpečili, že všetko funguje presne tak, ako má:

String secretMessage = "Moje heslo je 123456Seven"; System.out.println ("Pôvodná správa:" + secretMessage); byte [] stringToEncrypt = secretMessage.getBytes (); byte [] encryptedData = encryptData (stringToEncrypt, certifikát); System.out.println ("Šifrovaná správa:" + nový reťazec (encryptedData)); byte [] rawData = decryptData (encryptedData, privateKey); Reťazec decryptedMessage = nový Reťazec (rawData); System.out.println ("Dešifrovaná správa:" + decryptedMessage);

Ako výsledok:

Pôvodná správa: Moje heslo je 123456 Sedem šifrovaná správa: 0  *  H   ... Dešifrovaná správa: Moje heslo je 123456Seven

4.3 Podpis a overenie CMS / PKCS7

Podpis a overenie sú kryptografické operácie, ktoré overujú pravosť údajov.

Pozrime sa, ako podpísať tajnú správu pomocou digitálneho certifikátu:

public static byte [] signData (byte [] data, X509Certificate signingCertificate, PrivateKey signingKey) hodí výnimku {byte [] signedMessage = null; Zoznam certList = nový ArrayList (); CMSTypedData cmsData = nový CMSProcessableByteArray (údaje); certList.add (podpisový certifikát); Store certs = new JcaCertStore (certList); CMSSignedDataGenerator cmsGenerator = nový CMSSignedDataGenerator (); ContentSigner contentSigner = nový JcaContentSignerBuilder ("SHA256withRSA"). Build (signingKey); cmsGenerator.addSignerInfoGenerator (nový JcaSignerInfoGeneratorBuilder (nový JcaDigestCalculatorProviderBuilder (). setProvider ("BC") .build ()). build (contentSigner, podpisový certifikát)); cmsGenerator.addCertificates (certifikáty); CMSSignedData cms = cmsGenerator.generate (cmsData, true); signedMessage = cms.getEncoded (); návrat podpísaná správa; } 

Najskôr sme vložili vstup do a CMSTypedData, potom sme vytvorili nový CMSSignedDataGenerator objekt.

Použili sme SHA256sRSA ako podpisový algoritmus a náš podpisový kľúč na vytvorenie nového ContentSigner objekt.

The contentSigner inštancia sa potom použije spolu s podpisovým certifikátom na vytvorenie súboru SigningInfoGenerator objekt.

Po pridaní SignerInfoGenerator a podpisový certifikát do CMSSignedDataGenerator inštanciu nakoniec použijeme generovať () metóda na vytvorenie objektu podpísaných údajov CMS, ktorý nesie aj podpis CMS.

Teraz, keď sme videli, ako podpisovať údaje, pozrime sa, ako overiť podpísané údaje:

public static boolean verifSignedData (byte [] signedData) vyvolá výnimku {X509Certificate signCert = null; ByteArrayInputStream inputStream = nový ByteArrayInputStream (signedData); ASN1InputStream asnInputStream = nový ASN1InputStream (inputStream); CMSSignedData cmsSignedData = nové CMSSignedData (ContentInfo.getInstance (asnInputStream.readObject ())); SignerInformationStore signers = cmsSignedData.getCertificates (). GetSignerInfos (); SignerInformation signer = signers.getSigners (). Iterator (). Next (); Zbierka certCollection = certs.getMatches (signer.getSID ()); X509CertificateHolder certHolder = certCollection.iterator (). Next (); return signer .verify (new JcaSimpleSignerInfoVerifierBuilder () .build (certHolder)); }

Opäť sme vytvorili a CMSSignedData objekt založený na našom podpísanom dátovom bajtovom poli, potom sme pomocou podpisu načítali všetkých signatárov spojených s podpismi getSignerInfos () metóda.

V tomto príklade sme overili iba jedného podpisovateľa, ale pre všeobecné použitie je povinné opakovať zbierku podpisujúcich vrátenú getSigners () metóda a skontrolujte každú zvlášť.

Nakoniec sme vytvorili a SignerInformationVerifier objekt pomocou build () metóda a odovzdala ju overiť () metóda.

Metóda verify () sa vráti pravda ak daný objekt dokáže úspešne overiť podpis na podpisujúcom objekte.

Tu je jednoduchý príklad:

byte [] signedData = signData (rawData, certifikát, privateKey); Boolovská kontrola = verifSignData (signedData); System.out.println (kontrola);

Ako výsledok:

pravda

5. Záver

V tomto článku sme objavili, ako používať knižnicu BouncyCastle na vykonávanie základných kryptografických operácií, ako je šifrovanie a podpis.

V skutočnej situácii často chceme podpísať a potom zašifrovať svoje údaje. Takto ich môže dešifrovať iba príjemca pomocou súkromného kľúča a na základe digitálneho podpisu skontrolovať ich pravosť.

Útržky kódu nájdete ako vždy na serveri GitHub.


$config[zx-auto] not found$config[zx-overlay] not found