Προγραμματισμός

Base64 κωδικοποίηση και αποκωδικοποίηση σε Java 8

Το Java 8 θα θυμόμαστε κυρίως για την εισαγωγή lambda, ροών, ενός νέου μοντέλου ημερομηνίας / ώρας και της μηχανής Nashorn JavaScript στην Java. Μερικοί θα θυμούνται επίσης το Java 8 για την εισαγωγή διαφόρων μικρών αλλά χρήσιμων λειτουργιών όπως το Base64 API. Τι είναι το Base64 και πώς μπορώ να χρησιμοποιήσω αυτό το API; Αυτή η ανάρτηση απαντά σε αυτές τις ερωτήσεις.

Τι είναι το Base64;

Βάση64 είναι ένα σχήμα κωδικοποίησης δυαδικού κειμένου που αντιπροσωπεύει δυαδικά δεδομένα σε εκτυπώσιμη μορφή συμβολοσειράς ASCII μεταφράζοντάς τα σε παράσταση radix-64. Κάθε ψηφίο Base64 αντιπροσωπεύει ακριβώς 6 bit δυαδικών δεδομένων.

Αίτηση Base64 για έγγραφα σχολίων

Το Base64 περιγράφηκε για πρώτη φορά (αλλά δεν ονομάστηκε) στο RFC 1421: Βελτίωση απορρήτου για ηλεκτρονικό ταχυδρομείο μέσω Διαδικτύου: Μέρος Ι: Διαδικασίες κρυπτογράφησης μηνυμάτων και ελέγχου ταυτότητας. Αργότερα, παρουσιάστηκε επίσημα ως Base64 στο RFC 2045: Επεκτάσεις αλληλογραφίας πολλαπλών χρήσεων (MIME) Μέρος 1: Μορφή σωμάτων μηνυμάτων Διαδικτύου και στη συνέχεια επανεξετάστηκε στο RFC 4648: Οι κωδικοποιήσεις δεδομένων Base16, Base32 και Base64.

Το Base64 χρησιμοποιείται για να αποτρέψει την τροποποίηση δεδομένων κατά τη διαμετακόμιση μέσω συστημάτων πληροφοριών, όπως το ηλεκτρονικό ταχυδρομείο, τα οποία ενδέχεται να μην είναι καθαρά 8-bit (ενδέχεται να αλλοιώσουν τις τιμές των 8-bit). Για παράδειγμα, επισυνάπτετε μια εικόνα σε ένα μήνυμα ηλεκτρονικού ταχυδρομείου και θέλετε η εικόνα να φτάσει στο άλλο άκρο χωρίς να είναι αλλοιωμένη. Το λογισμικό email σας Base64 κωδικοποιεί την εικόνα και εισάγει το αντίστοιχο κείμενο στο μήνυμα, όπως φαίνεται παρακάτω:

Περιεχόμενο-Διάθεση: inline; filename = IMG_0006.JPG Content-Transfer-Encoding: base64 / 9ι / 4R / + RXhpZgAATU0AKgAAAAgACgEPAAIAAAAGAAAAhgEQAAIAAAAKAAAAjAESAAMAAAABAAYA AAEaAAUAAAABAAAAlgEbAAUAAAABAAAAngEoAAMAAAABAAIAAAExAAIAAAAHAAAApgEyAAIAAAAU AAAArgITAAMAAAABAAEAAIdpAAQAAAABAAAAwgAABCRBcHBsZQBpUGhvbmUgNnMAAAAASAAAAAEA ... NOMbnDUk2bGh26x2yiJcsoBIrvtPe3muBbTRGMdeufmH + Nct4chUXpwSPk / qK9GtJRMWWVFbZ0JH I4rf2dkZSbOjt7hhEzwcujA4I7Gust75pYVwAPpXn + kzNLOVYD7xFegWEKPkHsM / pU1F0NKbNS32 o24sSCOlaaFYLUhjky4x9PSsKL5bJsdWkAz3xirH2dZLy1DM2C44zx1FZqL2PTXY / 9 k =

Η εικόνα δείχνει ότι αυτή η κωδικοποιημένη εικόνα ξεκινά με / και τελειώνει με =. ο ... υποδεικνύει κείμενο που δεν έχω δείξει για συντομία. Σημειώστε ότι ολόκληρη η κωδικοποίηση για αυτό ή οποιοδήποτε άλλο παράδειγμα είναι περίπου 33 τοις εκατό μεγαλύτερη από τα αρχικά δυαδικά δεδομένα.

Το λογισμικό email του παραλήπτη θα αποκωδικοποιήσει το Base64 την κωδικοποιημένη εικόνα κειμένου για να επαναφέρει την αρχική δυαδική εικόνα. Για αυτό το παράδειγμα, η εικόνα θα εμφανίζεται ευθυγραμμισμένη με το υπόλοιπο μήνυμα.

Base64 κωδικοποίηση και αποκωδικοποίηση

Το Base64 βασίζεται σε απλούς αλγόριθμους κωδικοποίησης και αποκωδικοποίησης. Λειτουργούν με ένα υποσύνολο 65 χαρακτήρων του US-ASCII όπου καθένας από τους πρώτους 64 χαρακτήρες αντιστοιχεί σε μια ισοδύναμη δυαδική ακολουθία 6-bit. Εδώ είναι το αλφάβητο:

Αξία Κωδικοποίηση Αξία Κωδικοποίηση Αξία Κωδικοποίηση Αξία Κωδικοποίηση Αξία 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63/13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y

Ο 65ος χαρακτήρας (=) χρησιμοποιείται για την πληκτρολόγηση κειμένου με κωδικοποίηση Base64 σε ακέραιο μέγεθος όπως εξηγείται σύντομα.

Ιδιότητα υποσυνόλου

Αυτό το υποσύνολο έχει τη σημαντική ιδιότητα που αντιπροσωπεύεται πανομοιότυπα σε όλες τις εκδόσεις του ISO 646, συμπεριλαμβανομένου του US-ASCII, και όλοι οι χαρακτήρες στο υποσύνολο παρουσιάζονται επίσης ταυτόσημα σε όλες τις εκδόσεις του EBCDIC.

Ο αλγόριθμος κωδικοποίησης λαμβάνει μια ροή εισόδου 8-bit byte. Αυτή η ροή θεωρείται ότι έχει ταξινομηθεί με το πιο σημαντικό bit πρώτα: το πρώτο bit είναι το bit υψηλής τάξης στο πρώτο byte, το όγδοο bit είναι το bit χαμηλής τάξης σε αυτό το byte και ούτω καθεξής.

Από αριστερά προς τα δεξιά, αυτά τα bytes οργανώνονται σε ομάδες 24 bit. Κάθε ομάδα αντιμετωπίζεται ως τέσσερις συνδυασμένες ομάδες 6-bit. Κάθε ομάδα 6-bit ευρετηριάζει σε μια σειρά από τους 64 εκτυπώσιμους χαρακτήρες. ο προκύπτων χαρακτήρας είναι έξοδος.

Όταν είναι διαθέσιμα λιγότερα από 24 bit στο τέλος των κωδικοποιημένων δεδομένων, προστίθενται μηδενικά bit (στα δεξιά) για να σχηματιστεί ένας ακέραιος αριθμός ομάδων 6-bit. Στη συνέχεια, ένα ή δύο = χαρακτήρες pad μπορεί να είναι έξοδος. Υπάρχουν δύο περιπτώσεις που πρέπει να λάβετε υπόψη:

  • Ένα υπολειπόμενο byte: Τέσσερα μηδενικά bits προσαρτώνται σε αυτό το byte για να σχηματίσουν δύο ομάδες 6-bit. Κάθε ομάδα ευρετηριάζει τον πίνακα και προκύπτει ένας χαρακτήρας. Ακολουθώντας αυτούς τους δύο χαρακτήρες, δύο = οι χαρακτήρες μαξιλαριών εξάγονται.
  • Δύο υπόλοιπα byte: Δύο μηδενικά bits προσαρτώνται στο δεύτερο byte για να σχηματίσουν τρεις ομάδες 6-bit. Κάθε ομάδα ευρετηριάζει τον πίνακα και προκύπτει ένας χαρακτήρας. Ακολουθώντας αυτούς τους τρεις χαρακτήρες, ένας = ο χαρακτήρας pad είναι έξοδος.

Ας εξετάσουμε τρία παραδείγματα για να μάθουμε πώς λειτουργεί ο αλγόριθμος κωδικοποίησης. Πρώτα, ας υποθέσουμε ότι θέλουμε να κωδικοποιήσουμε @!*:

Πηγαίνετε ακολουθίες bit ASCII με προεπιλεγμένα 0 bit για να σχηματίσετε bytes 8-bit: @! * 01000000 00100001 00101010 Ο διαχωρισμός αυτής της ομάδας 24-bit σε τέσσερις ομάδες 6-bit αποφέρει τα εξής: 010000 | 000010 | 000100 | 101010 Αυτά τα μοτίβα bit αντιστοιχούν στα ακόλουθα ευρετήρια: 16 2 4 42 Η ευρετηρίαση στο αλφάβητο Base64 που παρουσιάστηκε προηγουμένως αποδίδει την ακόλουθη κωδικοποίηση: QCEq

Θα συνεχίσουμε συντομεύοντας την ακολουθία εισαγωγής σε @!:

Πηγαίνετε ακολουθίες bit ASCII με προεπιλεγμένα 0 bit για να σχηματίσετε bytes 8-bit: @! 01000000 00100001 Δύο μηδενικά bit προσαρτώνται για τη δημιουργία τριών ομάδων 6-bit: 010000 | 000010 | 000100 Αυτά τα μοτίβα bit αντιστοιχούν στα ακόλουθα ευρετήρια: 16 2 4 Η ευρετηρίαση στο αλφάβητο Base64 που παρουσιάστηκε νωρίτερα αποδίδει την ακόλουθη κωδικοποίηση: QCE An = χαρακτήρας pad εξάγεται, αποδίδοντας την ακόλουθη τελική κωδικοποίηση: QCE =

Το τελικό παράδειγμα συντομεύει την ακολουθία εισόδου σε @:

Πηγή ακολουθίας ASCII bit με προπαρασκευασμένα 0 bits για σχηματισμό byte 8-bit: @ 01000000 Τέσσερα μηδενικά bit προσαρτώνται για τη δημιουργία δύο ομάδων 6-bit: 010000 | 000000 Αυτά τα μοτίβα bit αντιστοιχούν στα ακόλουθα ευρετήρια: 16 0 Η ευρετηρίαση στο αλφάβητο Base64 που παρουσιάστηκε προηγουμένως αποδίδει την ακόλουθη κωδικοποίηση: QA Δύο = χαρακτήρες pad εξάγονται, αποδίδοντας την ακόλουθη τελική κωδικοποίηση: QA ==

Ο αλγόριθμος αποκωδικοποίησης είναι το αντίστροφο του αλγορίθμου κωδικοποίησης. Ωστόσο, είναι ελεύθερο να προβείτε στις κατάλληλες ενέργειες κατά την ανίχνευση ενός χαρακτήρα που δεν είναι στο αλφάβητο Base64 ή λανθασμένου αριθμού χαρακτήρων pad.

Παραλλαγές Base64

Έχουν επινοηθεί αρκετές παραλλαγές Base64. Ορισμένες παραλλαγές απαιτούν το κωδικοποιημένο ρεύμα εξόδου να διαιρείται σε πολλές γραμμές σταθερού μήκους με κάθε γραμμή να μην υπερβαίνει ένα ορισμένο όριο μήκους και (εκτός από την τελευταία γραμμή) να διαχωρίζεται από την επόμενη γραμμή μέσω διαχωριστή γραμμής (μεταφορά επιστροφής \ r ακολουθούμενο από ένα linefeed \ n). Περιγράφω τις τρεις παραλλαγές που υποστηρίζονται από το Java Base 8 API API. Δείτε την καταχώριση της Βικιπαίδειας Base64 για μια πλήρη λίστα παραλλαγών.

Βασικός

Το RFC 4648 περιγράφει μια παραλλαγή Base64 γνωστή ως Βασικός. Αυτή η παραλλαγή χρησιμοποιεί το αλφάβητο Base64 που παρουσιάζεται στον Πίνακα 1 των RFC 4648 και RFC 2045 (και φαίνεται νωρίτερα σε αυτήν την ανάρτηση) για κωδικοποίηση και αποκωδικοποίηση. Ο κωδικοποιητής αντιμετωπίζει την κωδικοποιημένη ροή εξόδου ως μία γραμμή. δεν υπάρχουν διαχωριστές γραμμών. Ο αποκωδικοποιητής απορρίπτει μια κωδικοποίηση που περιέχει χαρακτήρες εκτός του αλφαβήτου Base64. Σημειώστε ότι αυτές και άλλες προϋποθέσεις μπορούν να παρακαμφθούν.

ΜΙΜΟΣ

Το RFC 2045 περιγράφει μια παραλλαγή Base64 γνωστή ως ΜΙΜΟΣ. Αυτή η παραλλαγή χρησιμοποιεί το αλφάβητο Base64 που παρουσιάζεται στον Πίνακα 1 του RFC 2045 για κωδικοποίηση και αποκωδικοποίηση. Η κωδικοποιημένη ροή εξόδου οργανώνεται σε γραμμές που δεν υπερβαίνουν τους 76 χαρακτήρες. κάθε γραμμή (εκτός από την τελευταία γραμμή) διαχωρίζεται από την επόμενη γραμμή μέσω διαχωριστή γραμμής. Όλοι οι διαχωριστές γραμμών ή άλλοι χαρακτήρες που δεν βρίσκονται στο αλφάβητο Base64 αγνοούνται κατά την αποκωδικοποίηση.

URL και ασφαλές όνομα αρχείου

Το RFC 4648 περιγράφει μια παραλλαγή Base64 γνωστή ως URL και ασφαλές όνομα αρχείου. Αυτή η παραλλαγή χρησιμοποιεί το αλφάβητο Base64 που παρουσιάζεται στον πίνακα 2 του RFC 4648 για κωδικοποίηση και αποκωδικοποίηση. Το αλφάβητο είναι πανομοιότυπο με το αλφάβητο που παρουσιάστηκε νωρίτερα εκτός από αυτό - αντικαθιστά + και _ αντικαθιστά /. Δεν υπάρχουν διαχωριστές γραμμών. Ο αποκωδικοποιητής απορρίπτει μια κωδικοποίηση που περιέχει χαρακτήρες εκτός του αλφαβήτου Base64.

Η κωδικοποίηση Base64 είναι χρήσιμη στο πλαίσιο μακροχρόνιων δυαδικών δεδομένων και αιτήσεων HTTP GET. Η ιδέα είναι να κωδικοποιήσετε αυτά τα δεδομένα και στη συνέχεια να τα προσθέσετε στο HTTP GET URL. Εάν χρησιμοποιήθηκε η βασική ή η παραλλαγή MIME, οποιαδήποτε + ή / οι χαρακτήρες στα κωδικοποιημένα δεδομένα θα πρέπει να κωδικοποιούνται μέσω URL σε δεκαεξαδικές ακολουθίες (+ γίνεται % 2Β και / γίνεται % 2F). Η προκύπτουσα συμβολοσειρά URL θα ήταν κάπως μεγαλύτερη. Αντικαθιστώντας + με - και / με _, URL και Filename Safe αποτρέπει την ανάγκη για κωδικοποιητές / αποκωδικοποιητές URL (και τις επιπτώσεις τους στα μήκη των κωδικοποιημένων τιμών). Επίσης, αυτή η παραλλαγή είναι χρήσιμη όταν τα κωδικοποιημένα δεδομένα πρόκειται να χρησιμοποιηθούν για ένα όνομα αρχείου, επειδή τα ονόματα αρχείων Unix και Windows δεν μπορούν να περιέχουν /.

Εργασία με το Java Base64 API

Το Java 8 εισήγαγε ένα Base64 API που αποτελείται από το java.util.Base64 τάξη μαζί με το Κωδικοποιητής και Αποκρυπτογράφος ένθετο στατικός τάξεις. Βάση64 παρουσιάζει πολλά στατικός μέθοδοι για την απόκτηση κωδικοποιητών και αποκωδικοποιητών:

  • Base64.Encoder getEncoder (): Επιστρέψτε έναν κωδικοποιητή για τη βασική παραλλαγή.
  • Base64.Decoder getDecoder (): Επιστρέψτε έναν αποκωδικοποιητή για τη βασική παραλλαγή.
  • Base64.Encoder getMimeEncoder (): Επιστρέψτε έναν κωδικοποιητή για την παραλλαγή MIME.
  • Base64.Encoder getMimeEncoder (int lineLength, byte [] lineSeparator): Επιστρέψτε έναν κωδικοποιητή για μια τροποποιημένη παραλλαγή MIME με το δεδομένο Μήκος γραμμής (στρογγυλευμένο στο πλησιέστερο πολλαπλάσιο των 4 - έξοδος που δεν χωρίζεται σε γραμμές όταν Μήκος γραμμής<= 0) και lineSeparator. Ρίχνει java.lang.IllegalArgumentException πότε lineSeparator περιλαμβάνει οποιονδήποτε χαρακτήρα αλφαβήτου Base64 που παρουσιάζεται στον Πίνακα 1 του RFC 2045.

    Κωδικοποιητής RFC 2045, ο οποίος επιστρέφεται από το noargument getMimeEncoder () μέθοδος, είναι μάλλον άκαμπτη. Για παράδειγμα, αυτός ο κωδικοποιητής δημιουργεί κωδικοποιημένο κείμενο με σταθερά μήκη γραμμής (εκτός από την τελευταία γραμμή) 76 χαρακτήρων. Εάν θέλετε έναν κωδικοποιητή να υποστηρίζει RFC 1421, το οποίο καθορίζει ένα σταθερό μήκος γραμμής 64 χαρακτήρων, πρέπει να χρησιμοποιήσετε getMimeEncoder (int lineLength, byte [] lineSeparator).

  • Base64.Decoder getMimeDecoder (): Επιστρέψτε έναν αποκωδικοποιητή για την παραλλαγή MIME.
  • Base64.Encoder getUrlEncoder (): Επιστρέψτε έναν κωδικοποιητή για την παραλλαγή διεύθυνσης URL και ασφαλούς ονόματος αρχείου.
  • Base64.Decoder getUrlDecoder (): Επιστρέψτε έναν αποκωδικοποιητή για την παραλλαγή URL και ονόματος αρχείου Safe.

Base64. Κωδικοποιητής παρουσιάζει διάφορες μεθόδους παρουσίας ασφαλούς νήματος για κωδικοποίηση ακολουθιών byte. Το αποτέλεσμα της μηδενικής αναφοράς σε μία από τις ακόλουθες μεθόδους έχει ως αποτέλεσμα java.lang.NullPointerException:

  • byte [] κωδικοποίηση (byte [] src): Κωδικοποίηση όλων των byte src σε έναν πρόσφατα εκχωρημένο πίνακα byte, τον οποίο επιστρέφει αυτή η μέθοδος.
  • κωδικοποίηση int (byte [] src, byte [] dst): Κωδικοποίηση όλων των byte src προς την dst (ξεκινώντας από το όφσετ 0). Αν dst δεν είναι αρκετά μεγάλο για να διατηρήσει την κωδικοποίηση, IlegalArgumentException ρίχνεται. Διαφορετικά, ο αριθμός των byte που γράφτηκαν dst επιστρέφεται.
  • Κωδικοποίηση ByteBuffer (buffer ByteBuffer): Κωδικοποιήστε όλα τα υπόλοιπα byte στο ρυθμιστής σε μια νέα κατανομή java.nio.ByteBuffer αντικείμενο. Κατά την επιστροφή, ρυθμιστήςΗ θέση θα ενημερωθεί στο όριό της. το όριό του δεν θα έχει αλλάξει. Η επιστρεφόμενη θέση του buffer εξόδου θα είναι μηδέν και το όριό της θα είναι ο αριθμός των κωδικοποιημένων byte που προκύπτουν.
  • String encodeToString (byte [] src): Κωδικοποίηση όλων των byte src σε μια συμβολοσειρά, η οποία επιστρέφεται. Η επίκληση αυτής της μεθόδου ισοδυναμεί με εκτέλεση νέα συμβολοσειρά (κωδικοποίηση (src), StandardCharsets.ISO_8859_1).
  • Base64.Encoder χωρίςPadding (): Επιστρέψτε έναν κωδικοποιητή που κωδικοποιεί ισοδύναμα σε αυτόν τον κωδικοποιητή, αλλά χωρίς να προσθέσετε κανένα χαρακτήρα γεμίσματος στο τέλος των κωδικοποιημένων δεδομένων byte.
  • Αναδίπλωση OutputStream (OS OutputStream): Αναδίπλωση ροής εξόδου για την κωδικοποίηση δεδομένων byte. Συνιστάται να κλείσετε αμέσως την επιστρεφόμενη ροή εξόδου μετά τη χρήση, κατά τη διάρκεια της οποίας θα ξεπλένει όλα τα πιθανά byte που απομένουν στην υποκείμενη ροή εξόδου. Το κλείσιμο της επιστρεφόμενης ροής εξόδου θα κλείσει την υποκείμενη ροή εξόδου.

Base64.Decoder παρουσιάζει διάφορες μεθόδους παρουσίας ασφαλούς νήματος για αποκωδικοποίηση ακολουθιών byte. Το αποτέλεσμα της μηδενικής αναφοράς σε μία από τις ακόλουθες μεθόδους έχει ως αποτέλεσμα NullPointerException: