Šifrovanie a dešifrovanie Java AES

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

Bloková šifra so symetrickým kľúčom hrá dôležitú úlohu v šifrovaní dát. To znamená, že rovnaký kľúč sa používa na šifrovanie aj dešifrovanie. Advanced Encryption Standard (AES) je široko používaný šifrovací algoritmus so symetrickým kľúčom.

V tomto tutoriále sa dozvieme, ako implementovať šifrovanie a dešifrovanie AES pomocou architektúry Java Cryptography Architecture (JCA) v rámci JDK.

2. Algoritmus AES

Algoritmus AES je iteratívna bloková šifra so symetrickým kľúčom podporuje kryptografické kľúče (tajné kľúče) so 128, 192 a 256 bitmi na šifrovanie a dešifrovanie údajov v blokoch so 128 bitmi. Na nasledujúcom obrázku je znázornený algoritmus AES na vysokej úrovni:

Ak dáta, ktoré sa majú zašifrovať, nespĺňajú požiadavku na veľkosť bloku 128 bitov, musia byť vyplnené. Výplň je proces plnenia posledného bloku na 128 bitov.

3. Variácie AES

Algoritmus AES má šesť prevádzkových režimov:

  1. ECB (elektronický číselník)
  2. CBC (Cipher Block Chaining)
  3. CFB (Cipher FeedBack)
  4. OFB (výstup spätnej väzby)
  5. CTR (počítadlo)
  6. GCM (režim Galois / Counter)

Režim činnosti sa môže použiť na zosilnenie účinku šifrovacieho algoritmu. Ďalej môže prevádzkový režim prevádzať blokovú šifru na prúdovú šifru. Každý režim má svoje silné a slabé stránky. Poďme sa rýchlo pozrieť.

3.1. ECB

Tento režim prevádzky je najjednoduchší zo všetkých. Prostý text je rozdelený do blokov s veľkosťou 128 bitov. Potom bude každý blok zašifrovaný rovnakým kľúčom a algoritmom. Preto produkuje rovnaký výsledok pre ten istý blok. Toto je hlavná slabina tohto režimu a neodporúča sa na šifrovanie. Vyžaduje sa vyplnenie údajov.

3.2. CBC

Na prekonanie slabosti ECB používa režim CBC na zvýšenie šifrovania inicializačný vektor (IV). Najskôr CBC použije blok holého textu xor so IV. Potom zašifruje výsledok do bloku šifrovaného textu. V nasledujúcom bloku použije výsledok šifrovania na xor s blokom holého textu až do posledného bloku.

V tomto režime nie je možné paralelizovať šifrovanie, ale možno paralelne dešifrovať. Vyžaduje tiež údaje o výplni.

3.3. CFB

Tento režim možno použiť ako prúdovú šifru. Najskôr zašifruje IV, potom bude xor s blokom holého textu, aby získal ciphertext. Potom CFB zašifruje výsledok šifrovania na xor holého textu. Potrebuje IV.

V tomto režime možno dešifrovať paralelne, ale šifrovanie nie je možné paralelne.

3.4. OFB

Tento režim možno použiť ako prúdovú šifru. Najskôr zašifruje IV. Potom použije výsledky šifrovania na xor holého textu na získanie šifrovaného textu.

Nevyžaduje polstrovanie a nebude ovplyvnená hlučným blokom.

3.5. CTR

Tento režim používa hodnotu počítadla ako IV. Je to veľmi podobné OFB, ale namiesto IV používa zakódované počítadlo zakaždým.

Tento režim má dve silné stránky vrátane šifrovania / dešifrovania paralelizácie a šum v jednom bloku neovplyvňuje ostatné bloky.

3.6. GCM

Tento režim je rozšírením režimu CTR. GCM sa venovala značná pozornosť a je odporúčaný NIST. Model GCM vydáva šifrovací text a autentifikačnú značku. Hlavnou výhodou tohto režimu v porovnaní s ostatnými prevádzkovými režimami algoritmu je jeho účinnosť.

V tomto výučbe použijeme Výplň AES / CBC / PKCS5 algoritmus, pretože je široko používaný v mnohých projektoch.

3.7. Veľkosť údajov po šifrovaní

Ako už bolo spomenuté, AES má veľkosť bloku 128 bitov alebo 16 bajtov. AES nezmení veľkosť a veľkosť šifrovaného textu sa rovná veľkosti čistého textu. V režimoch ECB a CBC by sme tiež mali používať páčkové algoritmy PKCS 5. Takže veľkosť dát po šifrovaní je:

ciphertext_size (bytes) = cleartext_size + (16 - (cleartext_size% 16))

Na ukladanie IV s šifrovaným textom musíme pridať ďalších 16 bajtov.

4. Parametre AES

V algoritme AES potrebujeme tri parametre: vstupné údaje, tajný kľúč a IV. IV sa nepoužíva v režime ECB.

4.1. Vstupné Data

Vstupné údaje do AES môžu byť založené na reťazcoch, súboroch, objektoch a heslách.

4.2. Tajný kľúč

Existujú dva spôsoby generovania tajného kľúča v AES: generovanie z náhodného čísla alebo odvodenie od daného hesla.

V prvom prístupe by mal byť tajný kľúč vygenerovaný z kryptograficky bezpečného (pseudo) generátora náhodných čísel, ako je SecureRandom trieda.

Na vygenerovanie tajného kľúča môžeme použiť KeyGenerator trieda. Definujme metódu generovania kľúča AES s veľkosťou n (128, 192 a 256) bitov:

public static SecretKey generateKey (int n) vyvolá NoSuchAlgorithmException {KeyGenerator keyGenerator = KeyGenerator.getInstance ("AES"); keyGenerator.init (n); SecretKey key = keyGenerator.generateKey (); návratový kľúč; }

V druhom prístupe možno tajný kľúč AES odvodiť od daného hesla pomocou funkcie odvodenia kľúča založenej na hesle, ako je PBKDF2. Potrebujeme tiež soľnú hodnotu na premenu hesla na tajný kľúč. Soľ je tiež náhodná hodnota.

Môžeme použiť SecretKeyFactory trieda s PBKDF2WithHmacSHA256 algoritmus na generovanie kľúča z daného hesla.

Definujme spôsob generovania kľúča AES z daného hesla s 65 536 iteráciami a dĺžkou kľúča 256 bitov:

public static SecretKey getKeyFromPassword (heslo reťazca, soľ reťazca) vyvolá NoSuchAlgorithmException, InvalidKeySpecException {SecretKeyFactory factory = SecretKeyFactory.getInstance ("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec (password.toCharArray (), salt.getBytes (), 65536, 256); SecretKey secret = new SecretKeySpec (factory.generateSecret (spec) .getEncoded (), "AES"); návratové tajomstvo; }

4.3. Inicializačný vektor (IV)

IV je pseudonáhodná hodnota a má rovnakú veľkosť ako blok, ktorý je šifrovaný. Môžeme použiť SecureRandom triedy na vygenerovanie náhodného IV.

Definujme metódu generovania IV:

public static IvParameterSpec generateIv () {byte [] iv = nový bajt [16]; nový SecureRandom (). nextBytes (iv); vrátiť nový IvParameterSpec (iv); }

5. Šifrovanie a dešifrovanie

5.1. String

Na implementáciu šifrovania vstupného reťazca musíme najskôr vygenerovať tajný kľúč a IV podľa predchádzajúcej časti. Ako ďalší krok vytvoríme inštanciu z Šifra triedy pomocou getInstance () metóda.

Ďalej nakonfigurujeme šifrovaciu inštanciu pomocou init () metóda s tajným kľúčom, IV a režim šifrovania. Nakoniec zašifrujeme vstupný reťazec vyvolaním doFinal () metóda. Táto metóda získa bajty vstupu a vráti ciphertext v bajtoch:

public static String encrypt (String algorithm, String input, SecretKey key, IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {Cipher cipher = Cipher cipher = cipher.init (Cipher.ENCRYPT_MODE, kľúč, iv); byte [] cipherText = cipher.doFinal (input.getBytes ()); návrat Base64.getEncoder () .encodeToString (cipherText); }

Na dešifrovanie vstupného reťazca môžeme našu šifru inicializovať pomocou znaku DECRYPT_MODE na dešifrovanie obsahu:

public static String decrypt (String algorithm, String cipherText, SecretKey key, IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IllegalBlockSizeException cipher.init (Cipher.DECRYPT_MODE, kľúč, iv); byte [] plainText = cipher.doFinal (Base64.getDecoder () .decode (cipherText)); vrátiť nový reťazec (plainText); }

Napíšeme testovaciu metódu na šifrovanie a dešifrovanie vstupu reťazca:

@Test void givenString_whenEncrypt_thenSuccess () vyvolá NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException {String input = "baeldung"; Kľúč SecretKey = AESUtil.generateKey (128); IvParameterSpec ivParameterSpec = AESUtil.generateIv (); Reťazcový algoritmus = "AES / CBC / PKCS5Padding"; String cipherText = AESUtil.encrypt (algoritmus, vstup, kľúč, ivParameterSpec); Reťazec plainText = AESUtil.decrypt (algoritmus, cipherText, kľúč, ivParameterSpec); Assertions.assertEquals (input, plainText); }

5.2. Súbor

Teraz zašifrujme súbor pomocou algoritmu AES. Kroky sú rovnaké, ale nejaké potrebujeme IO triedy na prácu so súbormi. Zašifrujme textový súbor:

public static void encryptFile (String algorithm, SecretKey key, IvParameterSpec iv, File inputFile, File outputFile) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, Illegal cipher.init (Cipher.ENCRYPT_MODE, kľúč, iv); FileInputStream inputStream = nový FileInputStream (inputFile); FileOutputStream outputStream = nový FileOutputStream (outputFile); byte [] buffer = nový bajt [64]; int bytesRead; while ((bytesRead = inputStream.read (buffer))! = -1) {byte [] výstup = cipher.update (buffer, 0, bytesRead); if (output! = null) {outputStream.write (output); }} byte [] outputBytes = cipher.doFinal (); if (outputBytes! = null) {outputStream.write (outputBytes); } inputStream.close (); outputStream.close (); }

Pamätajte, že pokus o prečítanie celého súboru - najmä ak je veľký - do pamäte sa neodporúča. Namiesto toho šifrujeme nárazník.

Na dešifrovanie súboru použijeme podobné kroky a inicializujeme našu šifru pomocou DECRYPT_MODE ako sme videli predtým.

Opäť definujme testovaciu metódu na šifrovanie a dešifrovanie textového súboru. V tejto metóde čítame baeldung.txt súbor z adresára testovacích prostriedkov, zašifrujte ho do súboru s názvom baeldung.šifrovanýa potom dešifrujte súbor do nového súboru:

@Test void givenFile_whenEncrypt_thenSuccess () vyvolá NoSuchAlgorithmException, IOException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException {SecretKey key = AESU Reťazcový algoritmus = "AES / CBC / PKCS5Padding"; IvParameterSpec ivParameterSpec = AESUtil.generateIv (); Zdroj zdrojov = nový ClassPathResource ("inputFile / baeldung.txt"); Súbor inputFile = resource.getFile (); Súbor encryptedFile = nový súbor ("classpath: baeldung.encrypted"); Súbor decryptedFile = nový súbor ("document.decrypted"); AESUtil.encryptFile (algoritmus, kľúč, ivParameterSpec, inputFile, encryptedFile); AESUtil.decryptFile (algoritmus, kľúč, ivParameterSpec, encryptedFile, decryptedFile); assertThat (inputFile) .hasSameTextualContentAs (decryptedFile); }

5.3. Na základe hesla

Šifrovanie a dešifrovanie AES môžeme vykonať pomocou tajného kľúča, ktorý je odvodený od daného hesla.

Na vygenerovanie tajného kľúča používame getKeyFromPassword () metóda. Kroky šifrovania a dešifrovania sú rovnaké ako tie, ktoré sú uvedené v časti zadávania reťazcov. Na šifrovanie potom môžeme použiť inštančnú šifru a poskytnutý tajný kľúč.

Napíšme testovaciu metódu:

@Test void givenPassword_whenEncrypt_thenSuccess () vyvolá InvalidKeySpecException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException {String Reťazcové heslo = "baeldung"; Reťazcová soľ = "12345678"; IvParameterSpec ivParameterSpec = AESUtil.generateIv (); Kľúč SecretKey = AESUtil.getKeyFromPassword (heslo, soľ); Reťazec cipherText = AESUtil.encryptPasswordBased (plainText, kľúč, ivParameterSpec); Reťazec decryptedCipherText = AESUtil.decryptPasswordBased (cipherText, kľúč, ivParameterSpec); Assertions.assertEquals (plainText, decryptedCipherText); }

5.4. Objekt

Na šifrovanie objektu Java je potrebné použiť znak SealedObject trieda. Objekt by mal byť Serializovateľné. Začnime definovaním a Študent trieda:

public class Student implementuje Serializable {private String name; súkromný int vek; // štandardní zakladatelia a obstarávatelia} 

Ďalej zašifrujeme Študent objekt:

public static SealedObject encryptObject (Algoritmus reťazca, Serializovateľný objekt, Kľúč SecretKey, IvParameterSpec iv) hodí NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException, IlceptionalBlockSizeConcept = cipher.init (Cipher.ENCRYPT_MODE, kľúč, iv); SealedObject sealedObject = nový SealedObject (objekt, šifra); návrat zapečatenýObjekt; }

Šifrovaný objekt je možné neskôr dešifrovať pomocou správnej šifry:

public static Serializable decryptObject (String algorithm, SealedObject sealedObject, SecretKey key, IvParameterSpec iv) hodí NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, ClassNotFoundException, ClassNotFoundException, ClassNotFoundException, ClassNotFoundException, ClassNotFoundException, ClassNotFoundException, ClassNotFoundException, ClassNotFoundException, ClassNotFoundException, ClassNotFoundException, ClassNotFoundException, cipher.init (Cipher.DECRYPT_MODE, kľúč, iv); Serializable unsealObject = (Serializovateľné) sealedObject.getObject (šifra); vrátiť unsealObject; }

Poďme napísať testovací prípad:

@Test void givenObject_whenEncrypt_thenSuccess () hodí NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException, IOException, BadPaddingException, ClassNotFound = výnimka, ClassNotFound Kľúč SecretKey = AESUtil.generateKey (128); IvParameterSpec ivParameterSpec = AESUtil.generateIv (); Reťazcový algoritmus = "AES / CBC / PKCS5Padding"; SealedObject sealedObject = AESUtil.encryptObject (algoritmus, študent, kľúč, ivParameterSpec); Študentský objekt = (Študent) AESUtil.decryptObject (algoritmus, sealedObject, kľúč, ivParameterSpec); assertThat (študent) .isEqualToComparingFieldByField (objekt); }

6. Záver

V súhrne sme sa naučili, ako šifrovať a dešifrovať vstupné údaje, ako sú reťazce, súbory, objekty a údaje založené na hesle, pomocou algoritmu AES v Jave. Ďalej sme diskutovali o variáciách AES a veľkosti dát po šifrovaní.

Celý zdrojový kód článku je ako vždy 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