Java AES titkosítás és visszafejtés
Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:
>> ELLENŐRIZZE A FOLYAMATOT1. Áttekintés
A szimmetrikus kulcsú blokkos titkosítás fontos szerepet játszik az adatok titkosításában. Ez azt jelenti, hogy ugyanazt a kulcsot használják mind a titkosításhoz, mind a visszafejtéshez. Az Advanced Encryption Standard (AES) egy széles körben használt szimmetrikus kulcsú titkosítási algoritmus.
Ebben az oktatóanyagban megtudhatjuk, hogyan lehet az AES titkosítást és visszafejtést megvalósítani a JDK-ban lévő Java Cryptography Architecture (JCA) segítségével.
2. AES algoritmus
Az AES algoritmus egy iteratív, szimmetrikus kulcsú blokkos titkosítás támogatja a 128, 192 és 256 bites kriptográfiai kulcsokat (titkos kulcsokat) az adatok titkosításához és visszafejtéséhez 128 bites blokkokban. Az alábbi ábra a magas szintű AES algoritmust mutatja:
Ha a titkosítandó adatok nem felelnek meg a 128 bites blokkméret követelményének, akkor azt ki kell tölteni. A kitöltés az utolsó blokk 128 bitesre való feltöltésének folyamata.
3. AES variációk
Az AES algoritmusnak hat működési módja van:
- EKB (elektronikus kódkönyv)
- CBC (Cipher Block Chaining)
- CFB (Cipher FeedBack)
- OFB (kimeneti visszacsatolás)
- CTR (számláló)
- GCM (Galois / Számláló mód)
A működési mód alkalmazható a titkosítási algoritmus hatásának erősítése érdekében. Ezenkívül a működési mód átalakíthatja a blokk titkosítást stream titkosítássá. Minden módnak megvan a maga ereje és gyengesége. Nézzünk át gyorsan.
3.1. EKB
Ez a működési mód a legegyszerűbb. A sima szöveg 128 bit méretű blokkokra van osztva. Ezután minden blokkot ugyanazzal a kulccsal és algoritmussal titkosítunk. Ezért ugyanarra a blokkra ugyanazt az eredményt adja. Ez a mód fő gyengesége és titkosításhoz nem ajánlott. Kitöltési adatokat igényel.
3.2. CBC
Az EKB gyengeségének leküzdése érdekében a CBC mód inicializáló vektort (IV) használ a titkosítás bővítésére. Először is, a CBC a sima szövegblokkot használja xor a IV-vel. Ezután titkosítja az eredményt a rejtjeles szövegblokkba. A következő blokkban a titkosítási eredményt használja a sima szövegblokkal az utolsó blokkig.
Ebben a módban a titkosítás nem párhuzamos, de a visszafejtés párhuzamos. Ez is kitöltési adatokat igényel.
3.3. CFB
Ez az üzemmód stream-rejtjelként használható. Először titkosítja az IV-t, majd a sima szöveg blokkjának megszerzéséhez xor-t használ a sima szöveg blokkhoz. Ezután a CFB titkosítja a titkosítási eredményt a sima szöveg xorára. Szüksége van egy IV.
Ebben a módban a visszafejtés párhuzamosítható, de a titkosítás nem párhuzamos.
3.4. OFB
Ez a mód stream-rejtjelként használható. Először is titkosítja a IV. Ezután a titkosítási eredményeket használja a sima szöveg megszerzésére a rejtjeles szöveg megszerzéséhez.
Nem igényel kitöltési adatokat, és a zajos blokk nem fogja befolyásolni.
3.5. CTR
Ez a mód a számláló értékét használja IV-ként. Nagyon hasonlít az OFB-hez, de a számlálót minden alkalommal titkosításra használja a IV helyett.
Ennek a módnak két erőssége van, beleértve a titkosítás / visszafejtés párhuzamosítását, és az egyik blokkban lévő zaj nem befolyásolja a többi blokkot.
3.6. GCM
Ez az üzemmód a CTR mód kiterjesztése. A GCM jelentős figyelmet kapott, és a NIST javasolja. A GCM modell titkosított szöveget és hitelesítési címkét ad ki. Ennek a módnak a fő előnye az algoritmus többi működési módjához képest a hatékonysága.
Ebben az oktatóanyagban a AES / CBC / PKCS5Padding algoritmus, mert sok projektben széles körben használják.
3.7. Az adatok mérete a titkosítás után
Mint korábban említettük, az AES blokkmérete 128 bit vagy 16 bájt. Az AES nem változtatja meg a méretet, és a titkosított szöveg mérete megegyezik a tiszta szöveg méretével. Ezenkívül az EKB és a CBC módban használnunk kell egy párnázási algoritmust PKCS 5. Tehát az adatok mérete a titkosítás után:
rejtjelezett_méret (bájt) = tiszta szöveg_méret + (16 - (tiszta szöveg_méret% 16))
Az IV titkosított szöveggel történő tárolásához további 16 bájtot kell hozzáadnunk.
4. AES paraméterek
Az AES algoritmusban három paraméterre van szükségünk: bemeneti adatok, titkos kulcs és IV. A IV-et nem EKB-módban használják.
4.1. Beviteli adat
Az AES bemeneti adatai lehetnek karakterlánc, fájl, objektum és jelszó alapúak.
4.2. Titkos kulcs
Kétféle módon lehet titkos kulcsot előállítani az AES-ben: véletlen számból generálni vagy adott jelszóból levezetni.
Első megközelítésben a titkos kulcsot egy kriptográfiailag biztonságos (ál) véletlenszám-generátorból kell létrehozni, mint például SecureRandom osztály.
Titkos kulcs előállításához használhatjuk a KeyGenerator osztály. Határozzunk meg egy módszert az AES kulcs előállítására a méretével n (128, 192 és 256) bitek:
public static SecretKey generatorKey (int n) NoSuchAlgorithmException {KeyGenerator keyGenerator = KeyGenerator.getInstance ("AES") dob; keyGenerator.init (n); SecretKey kulcs = keyGenerator.generateKey (); visszatérési kulcs; }
A második megközelítésben az AES titkos kulcs egy adott jelszóból származtatható egy olyan jelszóalapú kulcs levezetési függvény segítségével, mint a PBKDF2. Sóértékre is szükségünk van ahhoz, hogy a jelszót titkos kulccsá alakítsuk. A só szintén véletlenszerű érték.
Használhatjuk a SecretKeyFactory osztály a PBKDF2WithHmacSHA256 algoritmus kulcs generálásához egy adott jelszóból.
Határozzunk meg egy módszert az AES kulcs előállítására egy adott jelszóból 65 536 iterációval és 256 bites kulcshosszal:
public static SecretKey getKeyFromPassword (karakterlánc jelszó, karakterlánc só) dobja a NoSuchAlgorithmException, InvalidKeySpecException {SecretKeyFactory factory = SecretKeyFactory.getInstance ("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec (jelszó.toCharArray (), salt.getBytes (), 65536, 256); SecretKey secret = új SecretKeySpec (gyár.generateSecret (spec) .getEncoded (), "AES"); visszatérési titok; }
4.3. Inicializálási vektor (IV)
A IV ál-véletlenszerű érték, és ugyanolyan méretű, mint a titkosított blokk. Használhatjuk a SecureRandom osztály véletlenszerű generálásához IV.
Határozzunk meg egy módszert egy IV előállítására:
public static IvParameterSpec generálIv () {byte [] iv = új byte [16]; új SecureRandom (). nextBytes (iv); return new IvParameterSpec (iv); }
5. Titkosítás és visszafejtés
5.1. Húr
A bemeneti karakterlánc-titkosítás megvalósításához először elő kell állítanunk a titkos kulcsot és az IV-et az előző szakasz szerint. Következő lépésként létrehozunk egy példányt a Rejtjel osztály a getInstance () módszer.
Ezenkívül egy titkosító példányt konfigurálunk a benne() módszer titkos kulccsal, IV és titkosítási móddal. Végül a bemeneti karakterláncot kódoljuk a doFinal () módszer. Ez a módszer megkapja a bemeneti bájtokat, és visszaadja a titkosított szöveget bájtokban:
public static String encrypt (karakterlánc-algoritmus, karakterlánc-bevitel, SecretKey-kulcs, IvParameterSpec iv) dobja a NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPizeignalxxception cipher.init (Cipher.ENCRYPT_MODE, kulcs, iv); byte [] cipherText = cipher.doFinal (input.getBytes ()); return Base64.getEncoder () .encodeToString (cipherText); }
Egy bemeneti karakterlánc visszafejtéséhez inicializálhatjuk a rejtjelünket a DECRYPT_MODE a tartalom visszafejtése:
nyilvános statikus karakterlánc visszafejtése (karakterlánc-algoritmus, String cipherText, SecretKey kulcs, IvParameterSpec iv) dobja a NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyExlegception = BadPadget (BadPadgetx) cipher.init (Cipher.DECRYPT_MODE, kulcs, iv); byte [] plainText = cipher.doFinal (Base64.getDecoder () .decode (cipherText)); return new String (plainText); }
Írjunk egy tesztmódszert egy karakterlánc bemenet titkosításához és visszafejtéséhez:
@Test void givenString_whenEncrypt_thenSuccess () dobja a NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPeldung; NoSuchPadding; SecretKey kulcs = AESUtil.generateKey (128); IvParameterSpec ivParameterSpec = AESUtil.generateIv (); Karakterlánc-algoritmus = "AES / CBC / PKCS5Padding"; String cipherText = AESUtil.encrypt (algoritmus, input, kulcs, ivParameterSpec); String plainText = AESUtil.decrypt (algoritmus, cipherText, kulcs, ivParameterSpec); Assertions.assertEquals (input, plainText); }
5.2. File
Most titkosítsunk egy fájlt az AES algoritmus segítségével. A lépések ugyanazok, de szükségünk van néhányra IO osztályok dolgozni a fájlokat. Titkosítsunk egy szöveges fájlt:
public static void encryptFile (Karakterlánc algoritmus, SecretKey kulcs, IvParameterSpec iv, File inputFile, File outputFile) az IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException cipher.init (Cipher.ENCRYPT_MODE, kulcs, iv); FileInputStream inputStream = új FileInputStream (inputFile); FileOutputStream outputStream = új FileOutputStream (outputFile); bájt [] puffer = új bájt [64]; int bytesRead; while ((bytesRead = inputStream.read (puffer))! = -1) {byte [] output = cipher.update (puffer, 0, bytesRead); if (output! = null) {outputStream.write (output); }} bájt [] outputBytes = cipher.doFinal (); if (outputBytes! = null) {outputStream.write (outputBytes); } inputStream.close (); outputStream.close (); }
Felhívjuk figyelmét, hogy nem ajánlott a teljes fájlt memóriába olvasni - főleg ha nagy -. Ehelyett egy puffert kódolunk egyszerre.
A fájl dekódolásához hasonló lépéseket alkalmazunk, és a segítségével inicializáljuk a rejtjelünket DECRYPT_MODE mint azt korábban láttuk.
Ismét adjunk meg egy tesztelési módszert egy szöveges fájl titkosításához és visszafejtéséhez. Ebben a módszerben a baeldung.txt fájlt a teszt erőforrás könyvtárból, titkosítsa egy nevű fájlba baeldung.titkosítva, majd dekódolja a fájlt egy új fájlba:
A @Test void givenFile_whenEncrypt_thenSuccess () dobja a NoSuchAlgorithmException, IOException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException Noilt Karakterlánc-algoritmus = "AES / CBC / PKCS5Padding"; IvParameterSpec ivParameterSpec = AESUtil.generateIv (); Erőforrás = új ClassPathResource ("inputFile / baeldung.txt"); Fájl inputFile = resource.getFile (); File encryptedFile = new File ("classpath: baeldung.encrypted"); File decryptedFile = new File ("document.decrypted"); AESUtil.encryptFile (algoritmus, kulcs, ivParameterSpec, inputFile, encryptedFile); AESUtil.decryptFile (algoritmus, kulcs, ivParameterSpec, encryptedFile, decryptedFile); assertThat (inputFile) .hasSameTextualContentAs (decryptedFile); }
5.3. Jelszó alapú
Az AES titkosítást és visszafejtést megtehetjük egy titkos kulcs segítségével, amely egy adott jelszóból származik.
Titkos kulcs előállításához a getKeyFromPassword () módszer. A titkosítási és a visszafejtési lépések megegyeznek a karakterlánc beviteli szakaszban bemutatottakkal. Ezután a példányosított titkosítást és a mellékelt titkos kulcsot használhatjuk a titkosítás végrehajtására.
Írjunk egy tesztmódszert:
@Test void givenPassword_whenEncrypt_thenSuccess () InvalidKeySpecException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParam; InvalidAlgorithmParam; Karakterlánc jelszó = "baeldung"; Vonósó = "12345678"; IvParameterSpec ivParameterSpec = AESUtil.generateIv (); SecretKey kulcs = AESUtil.getKeyFromPassword (jelszó, só); String cipherText = AESUtil.encryptPasswordBased (plainText, kulcs, ivParameterSpec); String decryptedCipherText = AESUtil.decryptPasswordBased (cipherText, kulcs, ivParameterSpec); Assertions.assertEquals (plainText, decryptedCipherText); }
5.4. Tárgy
Java objektum titkosításához a SealedObject osztály. Az objektum legyen Sorosítható. Kezdjük azzal, hogy meghatározzuk a Diák osztály:
public class A diák végrehajtja a Serializable {private String name; privát int kor; // szabványos beállítók és szerelők}
Ezután titkosítsuk a Diák tárgy :
public static SealedObject encryptObject (Karakterlánc algoritmus, Serializálható objektum, SecretKey kulcs, IvParameterSpec iv) dobja a NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyExcet, InvalidKeyException, cipher.init (Cipher.ENCRYPT_MODE, kulcs, iv); SealedObject sealedObject = új SealedObject (objektum, rejtjel); return sealedObject; }
A titkosított objektum később visszafejthető a helyes rejtjel használatával:
public static Serializable decryptObject (String algoritmus, SealedObject sealedObject, titkos kulcsát kulcs, IvParameterSpec IV) dob NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, ClassNotFoundException, BadPaddingException, IllegalBlockSizeException, IOException {Cipher titkosító = Cipher.getInstance (algoritmus); cipher.init (Cipher.DECRYPT_MODE, kulcs, iv); Serializable unsealObject = (Serializable) sealedObject.getObject (rejtjel); return unsealObject; }
Írjunk egy tesztesetet:
@Test void givenObject_whenEncrypt_thenSuccess () dob NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException, IOException, BadPaddingException, ClassNotFoundException {Student diák = új Student ( "Baeldung", 20); SecretKey kulcs = AESUtil.generateKey (128); IvParameterSpec ivParameterSpec = AESUtil.generateIv (); Karakterlánc-algoritmus = "AES / CBC / PKCS5Padding"; SealedObject sealedObject = AESUtil.encryptObject (algoritmus, tanuló, kulcs, ivParameterSpec); Student object = (Student) AESUtil.decryptObject (algoritmus, sealedObject, kulcs, ivParameterSpec); assertThat (hallgató) .isEqualToComparingFieldByField (objektum); }
6. Következtetés
Összefoglalva, megtanultuk, hogyan kell titkosítani és visszafejteni a bemeneti adatokat, például a karakterláncokat, fájlokat, objektumokat és jelszó alapú adatokat, a Java AES algoritmusának felhasználásával. Ezenkívül megvitattuk az AES variációit és az adatok méretét a titkosítás után.
Mint mindig, a cikk teljes forráskódja elérhető a GitHubon.
Java alsó