Digitálne podpisy v Jave

Java Top

Práve som oznámil nové Naučte sa jar kurz zameraný na základy jari 5 a Spring Boot 2:

>> SKONTROLUJTE KURZ

1. Prehľad

V tomto výučbe sa dozvieme viac o Mechanizmus digitálneho podpisu a ako ho môžeme implementovať pomocou architektúry Java Cryptography Architecture (JCA). Preskúmame KeyPair, MessageDigest, Cipher, KeyStore, certifikát, a Podpis JCA API.

Začneme pochopením toho, čo je digitálny podpis, ako vygenerovať pár kľúčov a ako certifikovať verejný kľúč od certifikačnej autority (CA). Potom uvidíme, ako implementovať digitálny podpis pomocou rozhrania JCA API na nízkej a vysokej úrovni.

2. Čo je digitálny podpis?

2.1. Definícia digitálneho podpisu

Digitálny podpis je technika na zabezpečenie:

  • Integrita: správa sa pri prenose nezmenila
  • Autenticita: autorom správy je naozaj ten, za koho sa vydáva
  • Neodmietnutie: autor správy nemôže neskôr poprieť, že boli zdrojom

2.2. Posielanie správy s digitálnym podpisom

Technicky vzaté, adigitálny podpis je šifrovaný hash (súhrn, kontrolný súčet) správy. To znamená, že zo správy vygenerujeme hash a zašifrujeme ho súkromným kľúčom podľa zvoleného algoritmu.

Správa, šifrovaný hash, zodpovedajúci verejný kľúč a algoritmus sa potom odošlú. Toto je klasifikované ako správa s digitálnym podpisom.

2.3. Príjem a kontrola digitálneho podpisu

Na kontrolu digitálneho podpisu prijímač správ vygeneruje z prijatej správy nový hash, pomocou verejného kľúča dešifruje prijatý šifrovaný hash a porovná ich. Ak sa zhodujú, digitálny podpis sa údajne overí.

Mali by sme poznamenať, že šifrujeme iba hash správy, a nie samotnú správu. Inými slovami, digitálny podpis sa nesnaží správu utajiť. Náš digitálny podpis iba dokazuje, že správa sa počas prepravy nezmenila.

Po overení podpisu sme si istí, že autorom správy mohol byť iba vlastník súkromného kľúča.

3. Digitálny certifikát a identita verejného kľúča

Certifikát je dokument, ktorý spája identitu s daným verejným kľúčom. Certifikáty podpisuje subjekt tretej strany, ktorý sa nazýva Certifikačná autorita (CA).

Vieme, že ak sa hash, ktorý dešifrujeme pomocou zverejneného verejného kľúča, zhoduje so skutočným hashom, potom je správa podpísaná. Ako však vieme, že verejný kľúč skutočne pochádzal od správnej entity? Rieši sa to použitím digitálnych certifikátov.

Digitálny certifikát obsahuje verejný kľúč a je podpísaný iným subjektom. Samotný podpis tejto entity môže byť overený iným subjektom atď. Nakoniec máme reťazec certifikátov. Každá najvyššia entita osvedčuje verejný kľúč nasledujúcej entity. Subjekt najvyššej úrovne je podpísaný sám sebou, čo znamená, že jeho verejný kľúč je podpísaný jeho vlastným súkromným kľúčom.

X.509 je najpoužívanejší formát certifikátu a dodáva sa buď v binárnom formáte (DER) alebo v textovom formáte (PEM). JCA už implementáciu poskytuje prostredníctvom Certifikát X509 trieda.

4. Správa KeyPair

Pretože digitálny podpis používa súkromný a verejný kľúč, použijeme triedy JCA PrivateKey a PublicKey na podpis a kontrolu správy, resp.

4.1. Získanie KeyPair

Vytvorenie dvojice kľúčov medzi súkromným a verejným kľúčom, použijeme Javu keytool.

Vygenerujme si kľúčový pár pomocou genkeypair príkaz:

keytool -genkeypair -alias senderKeyPair -keyalg RSA -keysize 2048 \ -dname "CN = Baeldung" -validita 365 -storetype PKCS12 \ -keystore sender_keystore.p12 -storepass changeit

Tak sa pre nás vytvorí súkromný kľúč a zodpovedajúci verejný kľúč. Verejný kľúč je zabalený do certifikátu s vlastným podpisom X.509, ktorý je zabalený do jedného reťazca certifikátu s jedným prvkom. Reťazec certifikátov a súkromný kľúč ukladáme do súboru Keystore sender_keystore.p12, ktoré môžeme spracovať pomocou rozhrania KeyStore API.

Tu sme použili formát úložiska kľúčov PKCS12, ktorý je štandardným a odporúčaným formátom JKS, ktorý je proprietárny v Java. Tiež by sme si mali pamätať heslo a alias, pretože ich použijeme v nasledujúcej podsekcii pri načítaní súboru Keystore.

4.2. Načítanie súkromného kľúča na podpísanie

Na podpísanie správy potrebujeme inštanciu PrivateKey.

Pomocou KeyStore API a predchádzajúci súbor úložiska kľúčov, sender_keystore.p12, môžeme získať PrivateKey objekt:

KeyStore keyStore = KeyStore.getInstance ("PKCS12"); keyStore.load (nový FileInputStream ("sender_keystore.p12"), "changeit"); PrivateKey privateKey = (PrivateKey) keyStore.getKey ("senderKeyPair", "changeit");

4.3. Zverejnenie verejného kľúča

Predtým, ako môžeme zverejniť verejný kľúč, musíme sa najskôr rozhodnúť, či použijeme certifikát s vlastným podpisom alebo certifikát podpísaný CA.

Ak používate certifikát s vlastným podpisom, musíme ho iba exportovať zo súboru Keystore. Môžeme to urobiť pomocou exportný koncert príkaz:

keytool -exportcert -alias senderKeyPair -storetype PKCS12 \ -keystore sender_keystore.p12 -file \ sender_certificate.cer -rfc -storepass changeit

Inak, ak budeme pracovať s certifikátom podpísaným CA, musíme vytvoriť žiadosť o podpísanie certifikátu (CSR). Robíme to pomocou certreq príkaz:

keytool -certreq -alias senderKeyPair -storetype PKCS12 \ -keystore sender_keystore.p12 -file -rfc \ -storepass changeit> sender_certificate.csr

Súbor CSR, sender_certificate.csr, sa potom zašle certifikačnej autorite na účely podpísania. Keď to urobíte, dostaneme podpísaný verejný kľúč zabalený do certifikátu X.509, a to buď v binárnom (DER), alebo textovom (PEM) formáte. Tu sme použili rfc možnosť pre formát PEM.

Verejný kľúč, ktorý sme dostali od CA, sender_certificate.cer, bol teraz podpísaný CA a môže byť sprístupnený pre klientov.

4.4. Načítanie verejného kľúča na overenie

Po prístupe k verejnému kľúču ho môže prijímač načítať do svojho úložiska kľúčov pomocou importcert príkaz:

keytool -importcert -alias receiverKeyPair -storetype PKCS12 \ -keystore receiver_keystore.p12 -file \ sender_certificate.cer -rfc -storepass changeit

A pomocou KeyStore API ako predtým, môžeme získať a PublicKey inštancia:

KeyStore keyStore = KeyStore.getInstance ("PKCS12"); keyStore.load (nový FileInputStream ("receiver_keytore.p12"), "changeit"); Certifikát certifikát = keyStore.getCertificate ("receiverKeyPair"); PublicKey publicKey = certificate.getPublicKey ();

Teraz, keď máme PrivateKey inštancia na strane odosielateľa a inštancia PublicKey na strane prijímača môžeme zahájiť proces podpisovania a overovania.

5. Digitálny podpis s MessageDigest a Šifra Triedy

Ako sme videli, digitálny podpis je založený na hašovaní a šifrovaní.

Zvyčajne používame MessageDigest triedy s SHA alebo MD5 na hašovanie a Šifra trieda pre šifrovanie.

Teraz začnime implementovať mechanizmy digitálneho podpisu.

5.1. Generuje sa hash správy

Správa môže byť reťazec, súbor alebo akékoľvek iné údaje. Zoberme si teda obsah jednoduchého súboru:

byte [] messageBytes = Files.readAllBytes (Paths.get ("message.txt"));

Teraz, pomocou MessageDigest, poďme použiť stráviť metóda na generovanie hash:

MessageDigest md = MessageDigest.getInstance ("SHA-256"); byte [] messageHash = md.digest (messageBytes);

Tu sme použili algoritmus SHA-256, ktorý je najbežnejšie používaný. Ďalšie alternatívy sú MD5, SHA-384 a SHA-512.

5.2. Šifrovanie vygenerovaného hašovania

Na zašifrovanie správy potrebujeme algoritmus a súkromný kľúč. Tu použijeme algoritmus RSA. Algoritmus DSA je ďalšou možnosťou.

Vytvorme a Šifra inštanciu a inicializujte ju na šifrovanie. Potom zavoláme doFinal () spôsob šifrovania predtým hašovanej správy:

Šifrovacia šifra = Cipher.getInstance ("RSA"); cipher.init (Cipher.ENCRYPT_MODE, privateKey); byte [] digitalSignature = cipher.doFinal (messageHash);

Podpis je možné uložiť do súboru na neskoršie odoslanie:

Files.write (Paths.get ("digital_signature_1"), digitalSignature);

V tomto okamihu sa správa, digitálny podpis, verejný kľúč a algoritmus odošlú všetky a prijímač môže pomocou týchto informácií overiť integritu správy.

5.3. Overenie podpisu

Keď dostaneme správu, musíme overiť jej podpis. Za týmto účelom dešifrujeme prijatý zašifrovaný hash a porovnáme ho s hashom, ktorý urobíme z prijatej správy.

Prečítajte si prijatý digitálny podpis:

byte [] encryptedMessageHash = Files.readAllBytes (Paths.get ("digital_signature_1"));

Na dešifrovanie vytvoríme a Šifra inštancia. Potom voláme doFinal metóda:

Šifrovacia šifra = Cipher.getInstance ("RSA"); cipher.init (Cipher.DECRYPT_MODE, publicKey); byte [] decryptedMessageHash = cipher.doFinal (encryptedMessageHash);

Ďalej z prijatej správy vygenerujeme nový hash správy:

byte [] messageBytes = Files.readAllBytes (Paths.get ("message.txt")); MessageDigest md = MessageDigest.getInstance ("SHA-256"); byte [] newMessageHash = md.digest (messageBytes);

A nakoniec skontrolujeme, či sa novo generovaný hash správy zhoduje s dešifrovaným:

boolean isCorrect = Arrays.equals (decryptedMessageHash, newMessageHash);

V tomto príklade sme použili textový súbor message.txt simulovať správu, ktorú chceme poslať, alebo umiestnenie tela správy, ktorú sme dostali. Za normálnych okolností by sme očakávali, že našu správu dostaneme spolu s podpisom.

6. Digitálny podpis pomocou Podpis Trieda

Doteraz sme na vytváranie vlastného procesu overovania digitálneho podpisu používali nízkoúrovňové API. To nám pomáha pochopiť, ako to funguje, a umožňuje nám to prispôsobiť si ho.

JCA však už ponúka špecializované API vo forme Podpis trieda.

6.1. Podpisovanie správy

Na zahájenie procesu podpisovania najskôr vytvoríme inštanciu súboru Podpis trieda. Potrebujeme podpisový algoritmus. Potom inicializujeme Podpis s našim súkromným kľúčom:

Signature signature = Signature.getInstance ("SHA256withRSA"); signature.initSign (privateKey);

Algoritmus podpisu, ktorý sme vybrali, SHA256sRSA v tomto príklade, je kombináciou hashovacieho algoritmu a šifrovacieho algoritmu. Medzi ďalšie alternatívy patria SHA1 sRSA, SHA1withDSAa MD5withRSA, medzi inými.

Ďalej pokračujeme v podpise bajtového poľa správy:

byte [] messageBytes = Files.readAllBytes (Paths.get ("message.txt")); signature.update (messageBytes); byte [] digitalSignature = signature.sign ();

Podpis môžeme uložiť do súboru pre neskoršie odoslanie:

Files.write (Paths.get ("digital_signature_2"), digitalSignature);

6.2. Overenie podpisu

Na overenie prijatého podpisu opäť vytvoríme a Podpis inštancia:

Signature signature = Signature.getInstance ("SHA256withRSA");

Ďalej inicializujeme Podpis objekt na overenie zavolaním na initVerify metóda, ktorá vyžaduje verejný kľúč:

signature.initVerify (publicKey);

Potom musíme do objektu podpisu pridať bajty prijatých správ vyvolaním znaku aktualizovať metóda:

byte [] messageBytes = Files.readAllBytes (Paths.get ("message.txt")); signature.update (messageBytes);

A nakoniec môžeme skontrolovať podpis zavolaním na overiť metóda:

boolean isCorrect = signature.verify (obdržaný podpis);

7. Záver

V tomto článku sme sa najskôr pozreli na to, ako funguje digitálny podpis a ako vytvoriť dôveru v digitálny certifikát. Potom sme implementovali digitálny podpis pomocou MessageDigest,Šifra, a Podpis triedy z architektúry Java Cryptography Architecture.

Videli sme podrobne, ako podpisovať údaje pomocou súkromného kľúča a ako overiť podpis pomocou verejného kľúča.

Ako vždy, kód z tohto článku je k dispozícii na GitHub.

Java dole

Práve som oznámil nové Naučte sa jar kurz zameraný na základy jari 5 a Spring Boot 2:

>> SKONTROLUJTE KURZ

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