Sådan læses PEM-fil for at få offentlige og private nøgler

Java Top

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN

1. Oversigt

I kryptografi med offentlig nøgle (også kendt som asymmetrisk kryptografi) er krypteringsmekanismen afhængig af to relaterede nøgler, en offentlig nøgle og en privat nøgle. Den offentlige nøgle bruges til at kryptere beskeden, mens kun ejeren af ​​den private nøgle kan dekryptere beskeden.

I denne vejledning skal vi se, hvordan man læser offentlige og private nøgler fra en PEM-fil.

Først studerer vi nogle vigtige begreber omkring kryptografi med offentlig nøgle. Derefter lærer vi at læse PEM-filer ved hjælp af ren Java.

Endelig vil vi udforske BouncyCastle-biblioteket som en alternativ tilgang.

2. Begreber

Lad os forstå nogle nøglebegreber, inden vi starter.

X.509 er en standard, der definerer formatet for public-key certifikater. Så dette format beskriver en offentlig nøgle blandt andre oplysninger.

DER er det mest populære kodningsformat til at gemme data som X.509-certifikater, PKCS8 private nøgler i filer. Det er en binær kodning, og det resulterende indhold kan ikke vises med en teksteditor.

PKCS8 er en standardsyntaks til lagring af private nøgleoplysninger. Den private nøgle kan valgfrit krypteres ved hjælp af en symmetrisk algoritme.

Ikke kun kan RSA private nøgler håndteres efter denne standard, men også andre algoritmer. PKCS8 private nøgler udveksles typisk via PEM-kodningsformatet.

PEM er en base-64-kodningsmekanisme for et DER-certifikat. PEM kan også kode for andre slags data såsom offentlige / private nøgler og certifikatanmodninger.

En PEM-fil indeholder også et overskrift og en sidefod, der beskriver typen af ​​kodede data:

----- BEGIN OFFENTLIG KEY ----- ... Base64-kodning af det DER-kodede certifikat ... ----- END OFFENTLIG KEY -----

3. Brug af ren Java

3.1. Læs PEM-data fra en fil

Lad os starte med at læse PEM-filen og gemme dens indhold i en streng:

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

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

Vi skal bygge en hjælpemetode, der får den offentlige nøgle fra den PEM-kodede streng:

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

Lad os antage, at vi modtager en Fil som parameter:

offentlig statisk RSAPublicKey readPublicKey (File-fil) kaster Undtagelse {String key = new String (Files.readAllBytes (file.toPath ()), Charset.defaultCharset ()); String publicKeyPEM = nøgle .replace ("----- BEGIN OFFENTLIG KEY -----", "") .replaceAll (System.lineSeparator (), "") .replace ("----- END OFFENTLIG 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, skal vi først også fjerne sidehovedet, sidefoden og de nye linjer. Derefter skal vi afkode den Base64-kodede streng i dens tilsvarende binære format.

Derefter skal vi indlæse resultatet i en nøglespecifikationsklasse, der er i stand til at håndtere et offentligt nøglemateriale. I vores tilfælde vil vi bruge X509EncodedKeySpec klasse.

Endelig kan vi generere et offentligt nøgleobjekt ud fra specifikationen ved hjælp af KeyFactory klasse.

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

Nu hvor vi ved, hvordan man læser en offentlig nøgle, er algoritmen til at læse en privat nøgle meget ens.

Vi skal bruge en PEM-kodet privat nøgle i PKCS8-format. Lad os se, hvordan sidehovedet og sidefoden ser ud:

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

Som vi tidligere har lært, har vi brug for en klasse, der er i stand til at håndtere PKCS8-nøglemateriale. Det PKCS8EncodedKeySpec klasse udfylder den rolle.

Så lad os se algoritmen:

offentlig RSAPrivateKey readPrivateKey (File-fil) kaster Undtagelse {String key = new String (Files.readAllBytes (file.toPath ()), Charset.defaultCharset ()); Streng privateKeyPEM = nøgle .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); returner (RSAPrivateKey) keyFactory.generatePrivate (keySpec); }

4. Brug af BouncyCastle Library

4.1. Læs offentlig nøgle

Vi skal udforske BouncyCastle-biblioteket og se, hvordan det kan bruges som et alternativ til den rene Java-implementering.

Lad os hente den offentlige nøgle:

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

Der er et par vigtige klasser, som vi skal være opmærksomme på, når vi bruger BouncyCastle:

  • PemReader - tager en Læser som en parameter og analyserer dens indhold. Det fjerner de unødvendige overskrifter og afkoder de underliggende Base64 PEM-data til et binært format.
  • PemObject gemmer resultatet genereret af PemReader.

Lad os desuden se en anden tilgang, der omslutter Java's klasser (X509EncodedKeySpec, KeyFactory) ind i BouncyCastles egen klasse (JcaPEMKeyConverter):

offentlig RSAPublicKey readPublicKeySecondApproach (filfil) kaster IOException {prøv (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. Læs privat nøgle

Vi vil se to eksempler, der minder meget om dem, der er vist ovenfor.

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

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

Lad os omarbejde lidt den anden tilgang fra det foregående afsnit for at læse en privat nøgle:

offentlig RSAPrivateKey readPrivateKeySecondApproach (filfil) kaster IOException {prøv (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, erstattede vi lige SubjectPublicKeyInfo med PrivateKeyInfo og RSAPublicKey med RSAPrivateKey.

4.3. Fordele

Der er et par fordele fra BouncyCastle-biblioteket.

En fordel er, at vi behøver ikke at springe over eller fjerne sidehovedet og sidefoden manuelt. En anden er det vi er ikke ansvarlige for Base64-dekodningen enten. Derfor kan vi skrive mindre fejlberettiget kode med BouncyCastle.

Desuden er BouncyCastle-biblioteket understøtter PKCS1-formatet såvel. På trods af at PKCS1 også er et populært format, der bruges til at gemme kryptografiske nøgler (kun RSA-nøgler), understøtter Java det ikke alene.

5. Konklusion

I denne artikel lærte vi, hvordan man læser offentlige og private nøgler fra PEM-filer.

Først studerede vi et par nøglekoncepter omkring kryptografi med offentlig nøgle. Derefter så vi, hvordan man læser offentlige og private nøgler ved hjælp af ren Java.

Endelig udforskede vi BouncyCastle-biblioteket og lærte, at det er et godt alternativ, da det giver et par fordele i forhold til den rene Java-implementering.

Den fulde kildekode til både Java- og BouncyCastle-tilgange er tilgængelig på GitHub.

Java bund

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN