Hvordan lese PEM-filer for å få offentlige og private nøkler

Java Top

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET

1. Oversikt

I kryptering med offentlig nøkkel (også kjent som asymmetrisk kryptografi) er krypteringsmekanismen avhengig av to relaterte nøkler, en offentlig nøkkel og en privat nøkkel. Den offentlige nøkkelen brukes til å kryptere meldingen, mens bare eieren av den private nøkkelen kan dekryptere meldingen.

I denne opplæringen skal vi se hvordan du kan lese offentlige og private nøkler fra en PEM-fil.

Først vil vi studere noen viktige konsepter rundt kryptografi med offentlig nøkkel. Deretter lærer vi hvordan du leser PEM-filer ved hjelp av ren Java.

Til slutt vil vi utforske BouncyCastle-biblioteket som en alternativ tilnærming.

2. Konsepter

La oss forstå noen viktige begreper før vi begynner.

X.509 er en standard som definerer formatet på sertifikater med offentlig nøkkel. Så dette formatet beskriver en offentlig nøkkel blant annet informasjon.

DER er det mest populære kodingsformatet for å lagre data som X.509-sertifikater, PKCS8 private nøkler i filer. Det er en binær koding, og det resulterende innholdet kan ikke vises med en tekstredigerer.

PKCS8 er en standard syntaks for lagring av privat nøkkelinformasjon. Den private nøkkelen kan valgfritt krypteres ved hjelp av en symmetrisk algoritme.

Ikke bare kan RSA private nøkler håndteres av denne standarden, men også andre algoritmer. PKCS8 private nøkler byttes vanligvis ut gjennom PEM-kodingsformatet.

PEM er en base-64-kodingsmekanisme for et DER-sertifikat. PEM kan også kode andre typer data som offentlige / private nøkler og sertifikatforespørsler.

En PEM-fil inneholder også en topptekst og en bunntekst som beskriver typen kodede data:

----- BEGIN PUBLIC KEY ----- ... Base64-koding av DER-kodet sertifikat ... ----- END OFFENTLIG Nøkkel -----

3. Bruke ren Java

3.1. Les PEM-data fra en fil

La oss starte med å lese PEM-filen og lagre innholdet i en streng:

Strengnøkkel = ny streng (Files.readAllBytes (file.toPath ()), Charset.defaultCharset ());

3.2. Få offentlig nøkkel fra PEM-streng

Vi skal bygge en verktøymetode som henter den offentlige nøkkelen fra den PEM-kodede strengen:

----- BEGIN PUBLIC KEY ----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjtGIk8SxD + OEiBpP2 / T JUAF0upwuKGMk6wH8Rwov88VvzJrVm2NCticTk5FUg + UG5r8JArrV4tJPRHQyvqK wF4NiksuvOjv3HyIf4oaOhZjT8hDne1Bfv + cFqZJ61Gk0MjANh / T5q9vxER / 7TdU NHKpoRV + NVlKN5bEU / NQ5FQjVXicfswxh6Y6fl2PIFqT2CfjD + FkBPU1iT9qyJYH A38IRvwNtcitFgCeZwdGPoxiPPh1WHY8VxpUVBv / 2JsUtrB / rAIbGqZoxAIWvijJ Pe9o1TY3VlOzk9ASZ1AeatvOir + iDVJ5OpKmLnzc46QgGPUsjIyo6Sje9dxpGtoG QQIDAQAB ----- END OFFENTLIG NØKKEL -----

La oss anta at vi mottar en Fil som parameter:

offentlig statisk RSAPublicKey readPublicKey (filfil) kaster unntak {String key = new String (Files.readAllBytes (file.toPath ()), Charset.defaultCharset ()); Streng publicKeyPEM = nøkkel .replace ("----- BEGIN PUBLIC KEY -----", "") .replaceAll (System.lineSeparator (), "") .replace ("----- END PUBLIC KEY ----- "," "); byte [] kodet = Base64.decodeBase64 (publicKeyPEM); KeyFactory keyFactory = KeyFactory.getInstance ("RSA"); X509EncodedKeySpec keySpec = ny X509EncodedKeySpec (kodet); returnere (RSAPublicKey) keyFactory.generatePublic (keySpec); }

Som vi kan se, må vi først fjerne toppteksten, bunnteksten og de nye linjene også. Deretter må vi dekode den Base64-kodede strengen til det tilsvarende binære formatet.

Deretter må vi laste resultatet inn i en nøkkelspesifikasjonsklasse som kan håndtere et offentlig nøkkelmateriale. I vårt tilfelle skal vi bruke X509EncodedKeySpec klasse.

Til slutt kan vi generere et offentlig nøkkelobjekt fra spesifikasjonen ved hjelp av KeyFactory klasse.

3.3. Få privat nøkkel fra PEM-streng

Nå som vi vet hvordan vi skal lese en offentlig nøkkel, er algoritmen for å lese en privat nøkkel veldig lik.

Vi skal bruke en PEM-kodet privat nøkkel i PKCS8-format. La oss se hvordan topptekst og bunntekst ser ut:

----- BEGIN PRIVATE KEY ----- ... Base64 kodet nøkkel ... ----- END PRIVATE KEY -----

Som vi har lært tidligere, trenger vi en klasse som kan håndtere PKCS8 nøkkelmateriale. De PKCS8EncodedKeySpec klasse fyller den rollen.

Så, la oss se algoritmen:

offentlig RSAPrivateKey readPrivateKey (filfil) kaster unntak {String key = new String (Files.readAllBytes (file.toPath ()), Charset.defaultCharset ()); Streng privateKeyPEM = nøkkel .replace ("----- BEGIN PRIVATE KEY -----", "") .replaceAll (System.lineSeparator (), "") .replace ("----- END PRIVATE KEY ----- "," "); byte [] kodet = Base64.decodeBase64 (privateKeyPEM); KeyFactory keyFactory = KeyFactory.getInstance ("RSA"); PKCS8EncodedKeySpec keySpec = ny PKCS8EncodedKeySpec (kodet); return (RSAPrivateKey) keyFactory.generatePrivate (keySpec); }

4. Bruke BouncyCastle Library

4.1. Les Public Key

Vi skal utforske BouncyCastle-biblioteket og se hvordan det kan brukes som et alternativ til den rene Java-implementeringen.

La oss få den offentlige nøkkelen:

offentlig RSAPublicKey readPublicKey (filfil) kaster unntak {KeyFactory fabrikk = KeyFactory.getInstance ("RSA"); prøv (FileReader keyReader = ny FileReader (fil); PemReader pemReader = ny PemReader (keyReader)) {PemObject pemObject = pemReader.readPemObject (); byte [] innhold = pemObject.getContent (); X509EncodedKeySpec pubKeySpec = ny X509EncodedKeySpec (innhold); returnere (RSAPublicKey) fabrikk.generatePublic (pubKeySpec); }}

Det er noen viktige klasser som vi må være klar over når vi bruker BouncyCastle:

  • PemReader - tar en Leser som parameter og analyserer innholdet. Det fjerner de unødvendige topptekstene og dekoder de underliggende Base64 PEM-dataene til et binært format.
  • PemObject lagrer resultatet generert av PemReader.

La oss dessuten se en annen tilnærming som pakker Java-klassene (X509EncodedKeySpec, KeyFactory) inn i BouncyCastles egen klasse (JcaPEMKeyConverter):

offentlig RSAPublicKey readPublicKeySecondApproach (filfil) kaster IOException {try (FileReader keyReader = ny FileReader (fil)) {PEMParser pemParser = ny PEMParser (keyReader); JcaPEMKeyConverter converter = ny JcaPEMKeyConverter (); SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance (pemParser.readObject ()); returner (RSAPublicKey) converter.getPublicKey (publicKeyInfo); }}

4.2. Les Private Key

Vi kommer til å se to eksempler som er veldig like de som er vist ovenfor.

I det første eksemplet trenger vi bare å erstatte X509EncodedKeySpec klasse med PKCS8EncodedKeySpec klasse og returnere en RSAPrivateKey objekt i stedet for et RSAPublicKey:

offentlig RSAPrivateKey readPrivateKey (filfil) kaster Unntak {KeyFactory fabrikk = KeyFactory.getInstance ("RSA"); prøv (FileReader keyReader = ny FileReader (fil); PemReader pemReader = ny PemReader (keyReader)) {PemObject pemObject = pemReader.readPemObject (); byte [] innhold = pemObject.getContent (); PKCS8EncodedKeySpec privKeySpec = ny PKCS8EncodedKeySpec (innhold); returner (RSAPrivateKey) fabrikk.generatePrivate (privKeySpec); }}

La oss omarbeide litt den andre tilnærmingen fra forrige avsnitt for å lese en privat nøkkel:

offentlig RSAPrivateKey readPrivateKeySecondApproach (filfil) kaster IOException {try (FileReader keyReader = ny FileReader (fil)) {PEMParser pemParser = ny PEMParser (keyReader); JcaPEMKeyConverter converter = ny JcaPEMKeyConverter (); PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance (pemParser.readObject ()); returner (RSAPrivateKey) converter.getPrivateKey (privateKeyInfo); }}

Som vi kan se, erstattet vi nettopp SubjectPublicKeyInfo med PrivateKeyInfo og RSAPublicKey med RSAPrivateKey.

4.3. Fordeler

Det er et par fordeler som tilbys av BouncyCastle-biblioteket.

En fordel er at vi trenger ikke å hoppe over eller fjerne toppteksten og bunnteksten manuelt. En annen er det vi er ikke ansvarlige for Base64-dekodingen enten. Derfor kan vi skrive mindre feilutsatt kode med BouncyCastle.

Videre, den BouncyCastle-biblioteket støtter PKCS1-formatet også. Til tross for at PKCS1 også er et populært format som brukes til å lagre kryptografiske nøkler (kun RSA-nøkler), støtter Java det ikke alene.

5. Konklusjon

I denne artikkelen lærte vi å lese offentlige og private nøkler fra PEM-filer.

Først studerte vi noen få viktige konsepter rundt kryptografi med offentlig nøkkel. Så så vi hvordan vi kunne lese offentlige og private nøkler ved hjelp av ren Java.

Til slutt utforsket vi BouncyCastle-biblioteket og lærte at det er et godt alternativ siden det gir noen fordeler sammenlignet med den rene Java-implementeringen.

Hele kildekoden for både Java- og BouncyCastle-tilnærminger er tilgjengelig på GitHub.

Java bunn

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET