Programmering

Base64-kodning og afkodning i Java 8

Java 8 vil primært huskes for at introducere lambdas, streams, en ny dato / tidsmodel og Nashorn JavaScript-motoren til Java. Nogle vil også huske Java 8 for at introducere forskellige små, men nyttige funktioner såsom Base64 API. Hvad er Base64, og hvordan bruger jeg denne API? Dette indlæg besvarer disse spørgsmål.

Hvad er Base64?

Base64 er et binært-til-tekst-kodningsskema, der repræsenterer binære data i et ASCII-strengformat, der kan udskrives, ved at oversætte det til en radix-64-repræsentation. Hvert Base64-ciffer repræsenterer nøjagtigt 6 bit binære data.

Base64 anmodning om kommentardokumenter

Base64 blev første gang beskrevet (men ikke navngivet) i RFC 1421: Forbedring af privatlivets fred for elektronisk internetpost: Del I: Beskedkryptering og godkendelsesprocedurer. Senere blev det officielt præsenteret som Base64 i RFC 2045: Multipurpose Internet Mail Extensions (MIME), del 1: Format af internetmeddelelsesorganer, og derefter revideret i RFC 4648: Base16, Base32 og Base64 Data Encodings.

Base64 bruges til at forhindre data i at blive ændret under transit gennem informationssystemer, såsom e-mail, der muligvis ikke er 8-bit rene (de kan muligvis forvrænge 8-bit-værdier). For eksempel vedhæfter du et billede til en e-mail-besked og ønsker, at billedet skal ankomme i den anden ende uden at blive forvansket. Din e-mail-software Base64-koder billedet og indsætter den tilsvarende tekst i meddelelsen som illustreret nedenfor:

Indholdsdisposition: inline; filename = IMG_0006.JPG Content-Transfer-Encoding: base64 / 9j / 4R / + RXhpZgAATU0AKgAAAAgACgEPAAIAAAAGAAAAhgEQAAIAAAAKAAAAjAESAAMAAAABAAYA AAEaAAUAAAABAAAAlgEbAAUAAAABAAAAngEoAAMAAAABAAIAAAExAAIAAAAHAAAApgEyAAIAAAAU AAAArgITAAMAAAABAAEAAIdpAAQAAAABAAAAwgAABCRBcHBsZQBpUGhvbmUgNnMAAAAASAAAAAEA ... NOMbnDUk2bGh26x2yiJcsoBIrvtPe3muBbTRGMdeufmH + Nct4chUXpwSPk / qK9GtJRMWWVFbZ0JH I4rf2dkZSbOjt7hhEzwcujA4I7Gust75pYVwAPpXn + kzNLOVYD7xFegWEKPkHsM / pU1F0NKbNS32 o24sSCOlaaFYLUhjky4x9PSsKL5bJsdWkAz3xirH2dZLy1DM2C44zx1FZqL2PTXY / 9k =

Illustrationen viser, at dette kodede billede starter med / og slutter med =. Det ... angiver tekst, som jeg ikke har vist for kortfattethed. Bemærk, at hele kodningen for dette eller ethvert andet eksempel er omkring 33 procent større end de originale binære data.

Modtagerens e-mail-software vil Base64-afkode det kodede tekstbillede for at gendanne det originale binære billede. I dette eksempel vises billedet inline sammen med resten af ​​meddelelsen.

Base64-kodning og afkodning

Base64 er afhængig af enkle kodnings- og dekodningsalgoritmer. De arbejder med en 65-tegns undersæt af US-ASCII, hvor hver af de første 64 tegn kortlægges til en ækvivalent 6-bit binær sekvens. Her er alfabetet:

Værdi kodning Værdi kodning Værdi kodning Værdi kodning 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 (pude) = 15 P 32 g 49 x 16 Q 33 h 50 y

Den 65. karakter (=) bruges til at padde Base64-kodet tekst til en integreret størrelse som forklaret kort.

Delsæt ejendom

Dette delsæt har den vigtige egenskab, at det er repræsenteret identisk i alle versioner af ISO 646, inklusive US-ASCII, og alle tegn i delsættet er også repræsenteret identisk i alle versioner af EBCDIC.

Kodningsalgoritmen modtager en inputstrøm på 8-bit bytes. Denne strøm formodes at være bestilt med den mest betydningsfulde bit først: den første bit er højordensbit i den første byte, den ottende bit er den laveste ordensbit i denne byte og så videre.

Fra venstre mod højre er disse bytes organiseret i 24-bit grupper. Hver gruppe behandles som fire sammenkædede 6-bit grupper. Hver 6-bit gruppe indekseres i en matrix med de 64 udskrivbare tegn; den resulterende karakter sendes ud.

Når der er færre end 24 bit til rådighed i slutningen af ​​de data, der kodes, tilføjes nul bits (til højre) for at danne et integreret antal 6-bit grupper. Så en eller to = pad-tegn vises muligvis. Der er to tilfælde at overveje:

  • En tilbageværende byte: Fire nul bit føjes til denne byte for at danne to 6-bit grupper. Hver gruppe indekserer arrayet, og et resulterende tegn udsendes. Efter disse to tegn, to = pad tegn vises.
  • To resterende byte: To nul bit føjes til den anden byte for at danne tre 6-bit grupper. Hver gruppe indekserer arrayet, og et resulterende tegn udsendes. Efter disse tre tegn, en = pad-karakter er output.

Lad os overveje tre eksempler for at lære, hvordan kodningsalgoritmen fungerer. Antag først, at vi ønsker at kode @!*:

Kilde ASCII-bitsekvenser med forudbestemte 0 bits til dannelse af 8-bit bytes: @! * 01000000 00100001 00101010 Opdeling af denne 24-bit gruppe i fire 6-bit grupper giver følgende: 010000 | 000010 | 000100 | 101010 Disse bitmønstre svarer til følgende indekser: 16 2 4 42 Indeksering i Base64-alfabetet vist tidligere giver følgende kodning: QCEq

Vi fortsætter med at forkorte indgangssekvensen til @!:

Kilde ASCII-bitsekvenser med forudgående 0 bit til dannelse af 8-bit bytes: @! 01000000 00100001 To nul bit tilføjes til at lave tre 6-bit grupper: 010000 | 000010 | 000100 Disse bitmønstre svarer til følgende indekser: 16 2 4 Indeksering i Base64-alfabetet, der er vist tidligere, giver følgende kodning: QCE An = padtegn udføres, hvilket giver følgende endelige kodning: QCE =

Det sidste eksempel forkorter indgangssekvensen til @:

Kilde ASCII-bitsekvens med forudbestemte 0 bits til dannelse af 8-bit byte: @ 01000000 Fire nul bit er tilføjet for at lave to 6-bit grupper: 010000 | 000000 Disse bitmønstre svarer til følgende indekser: 16 0 Indeksering i Base64-alfabetet, der er vist tidligere, giver følgende kodning: QA To = padtegn udsendes, hvilket giver følgende endelige kodning: QA ==

Afkodningsalgoritmen er den omvendte af kodningsalgoritmen. Det er dog frit at træffe passende handlinger ved påvisning af et tegn, der ikke er i Base64-alfabetet, eller et forkert antal pad-tegn.

Base64-varianter

Flere Base64-varianter er blevet udtænkt. Nogle varianter kræver, at den kodede outputstrøm opdeles i flere linjer med fast længde, hvor hver linje ikke overstiger en bestemt længdegrænse og (bortset fra den sidste linje) adskilles fra den næste linje via en linjeseparator (vognretur \ r efterfulgt af en linefeed \ n). Jeg beskriver de tre varianter, der understøttes af Java 8s Base64 API. Tjek Wikipedia's Base64-post for en komplet liste over varianter.

Grundlæggende

RFC 4648 beskriver en Base64-variant kendt som Grundlæggende. Denne variant bruger Base64-alfabetet præsenteret i tabel 1 i RFC 4648 og RFC 2045 (og vist tidligere i dette indlæg) til kodning og afkodning. Koderen behandler den kodede outputstrøm som en linje; der udsendes ingen linjeseparatorer. Dekoderen afviser en kodning, der indeholder tegn uden for Base64-alfabetet. Bemærk, at disse og andre bestemmelser kan tilsidesættes.

MIME

RFC 2045 beskriver en Base64-variant kendt som MIME. Denne variant bruger Base64-alfabetet præsenteret i tabel 1 i RFC 2045 til kodning og afkodning. Den kodede outputstrøm er organiseret i linjer på højst 76 tegn; hver linje (undtagen den sidste linje) adskilles fra den næste linje via en linjeseparator. Alle linjeseparatorer eller andre tegn, der ikke findes i Base64-alfabetet, ignoreres under afkodningen.

URL og filnavn sikkert

RFC 4648 beskriver en Base64-variant kendt som URL og filnavn sikkert. Denne variant bruger Base64-alfabetet præsenteret i tabel 2 i RFC 4648 til kodning og afkodning. Alfabetet er identisk med det tidligere viste alfabet bortset fra det - erstatter + og _ erstatter /. Der udsendes ingen linjeseparatorer. Dekoderen afviser en kodning, der indeholder tegn uden for Base64-alfabetet.

Base64-kodning er nyttig i sammenhæng med lange binære data og HTTP GET-anmodninger. Ideen er at kode disse data og derefter tilføje dem til HTTP GET URL. Hvis Basic- eller MIME-varianten blev brugt, blev nogen + eller / tegn i de kodede data skulle være URL-kodede i hexadecimale sekvenser (+ bliver til % 2B og / bliver til % 2F). Den resulterende URL-streng ville være noget længere. Ved at erstatte + med - og / med _, URL og filnavn Safe fjerner behovet for URL-kodere / dekodere (og deres indvirkning på længden af ​​kodede værdier). Denne variant er også nyttig, når de kodede data skal bruges til et filnavn, fordi Unix- og Windows-filnavne ikke kan indeholde /.

Arbejder med Java's Base64 API

Java 8 introducerede en Base64 API bestående af java.util.Base64 klasse sammen med dens Koder og Dekoder indlejret statisk klasser. Base64 præsenterer flere statisk metoder til at opnå kodere og dekodere:

  • Base64.Encoder getEncoder (): Returner en encoder til Basic-varianten.
  • Base64.Decoder getDecoder (): Returner en dekoder til Basic-varianten.
  • Base64.Encoder getMimeEncoder (): Returner en indkoder til MIME-varianten.
  • Base64.Encoder getMimeEncoder (int lineLength, byte [] lineSeparator): Returner en indkoder til en modificeret MIME-variant med det givne lineLength (afrundet til nærmeste multiplum af 4 - output ikke adskilt i linjer når lineLength<= 0) og lineSeparator. Det kaster java.lang.IllegalArgumentException hvornår lineSeparator inkluderer ethvert Base64-alfabettegn, der er præsenteret i tabel 1 i RFC 2045.

    RFC 2045's encoder, som returneres fra noargumentet getMimeEncoder () metode er ret stiv. For eksempel opretter koderen kodet tekst med faste linjelængder (undtagen den sidste linje) på 76 tegn. Hvis du vil have en indkoder, der understøtter RFC 1421, som angiver en fast linjelængde på 64 tegn, skal du bruge getMimeEncoder (int lineLength, byte [] lineSeparator).

  • Base64.Decoder getMimeDecoder (): Returner en dekoder til MIME-varianten.
  • Base64.Encoder getUrlEncoder (): Returner en indkoder til URL- og filnavnesikker variant.
  • Base64.Decoder getUrlDecoder (): Returner en dekoder til URL- og Filename Safe-variant.

Base64.Encoder præsenterer flere threadsafe-instansmetoder til kodning af bytesekvenser. At overføre nulhenvisningen til en af ​​følgende metoder resulterer i java.lang.NullPointerException:

  • byte [] kode (byte [] src): Kod alle byte i src til et nyligt allokeret byte-array, som denne metode returnerer.
  • int-kode (byte [] src, byte [] dst): Kod alle byte i src til dst (starter ved forskydning 0). Hvis dst er ikke stor nok til at holde kodningen, IllegalArgumentException kastes. Ellers er antallet af byte skrevet til dst returneres.
  • ByteBuffer-kode (ByteBuffer-buffer): Kod alle resterende byte i buffer til en nyligt tildelt java.nio.ByteBuffer objekt. Ved retur bufferposition vil blive opdateret til sin grænse; dens grænse er ikke blevet ændret. Den returnerede outputbuffers position er nul, og dens grænse er antallet af resulterende kodede byte.
  • String encodeToString (byte [] src): Kod alle byte i src til en streng, som returneres. Påkald af denne metode svarer til udførelse ny streng (kode (src), StandardCharsets.ISO_8859_1).
  • Base64.Encoder withoutPadding (): Returner en koder, der koder ækvivalent til denne koder, men uden at tilføje noget polstringstegn i slutningen af ​​de kodede bytdata.
  • OutputStream wrap (OutputStream os): Indpak en outputstrøm til kodning af bytdata. Det anbefales at straks lukke den returnerede outputstrøm efter brug, hvor den vil skylle alle mulige resterende byte til den underliggende outputstrøm. Lukning af den returnerede outputstrøm lukker den underliggende outputstrøm.

Base64.Decoder præsenterer flere threadsafe-instansmetoder til afkodning af bytesekvenser. At overføre nulhenvisningen til en af ​​følgende metoder resulterer i NullPointerException: