Kryptering av fødselsnummer

Kryptering av fødselsnummer

 

Fellestjenester BYGG bruker kryptering av fødselsnummer.

Vi har implementert asymmetrisk kryptering der søknadssystemene vil kryptere fødselsnummer med en offentlig nøkkel. Fellestjenester BYGG arbeidsflyt funksjonen bruker en korresponderende privat nøkkel for å dekryptere personnummeret slik at det kan brukes for adressering i Altinn for meldinger og skjema til privatpersoner. 

FtB krypteringnøkler er av typen RSA (Rivest–Shamir–Adleman) med 1024 bit nøkkelstørrelse. Den offentlige nøkkelen blir levert både som en .pem text fil og en .cer sertifikat fil.

Med 1024 bit kryptering blir et 9 siffer fødselsnummer til en ca. 170 tegn lang tekst streng.

 

 

Krypteringprosess

Våre C# eksempler nedenfor bruker en krypteringsflyt som dette:

  1. Data input er et fødselsnummer som en streng (dette er hva man tidligere la inn i <foedselsnummer> taggen i XML)

  2. Prosess input er den offentlige nøkkelen

  3. Konverter strengen med fødselsnummer til byte array

  4. Krypter byte array med krypteringtjener basert på den offentlige nøkkelen. Resultatet er nytt byte array

  5. Konverter kryptert byte array til en Base64 kodet streng

  6. Den krypterte strengen blir så lagt inn i <foedselsnummer>  taggen i XML istedet for klar tekst versjonen av fødselsnummeret.

 

Innlesing av offentlig nøkkel eksempel (C#)

Det finnes et par alternativer på innlesing av nøkkelen. Vi presenterer to eksempler her. I begge eksemplene ender vi opp med en RSACryptoServiceProvider fra C# System.Security.Cryptography.

I det første eksemplet leser vi inn en .pem fil som der nøkkelen ligger som en tekst fil av på denne måten:

-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ4ZbcozMGh75YeH7DAAIYpc// ... YXh3cj09EdxzUsFLWQIDAQAB -----END PUBLIC KEY-----

Vi har lagt inn PEM filen som en "embeddet resource" i C# prosjektet, andre måter å få tilgang til en fil er mulig.

 

Innlesing av filen:

private static string ReadPublicKeyFromEmbeddedResorce() { // Load public key from Embedded resource file string fileContent; var assembly = Assembly.GetExecutingAssembly(); var resourceName = "DIBK.FellestjenesterBygg.TestEngine.Models.Encryption.ftbtest_public_key.pem"; // namespace plus filename using (Stream stream = assembly.GetManifestResourceStream(resourceName)) using (StreamReader reader = new StreamReader(stream)) { fileContent = reader.ReadToEnd(); } return fileContent; }

Vi setter opp en  RSACryptoServiceProvider via BouncyCastle funksjoner (tilgjengelig fra Nuget). Input er streng med den offentlig nøkkelen fra forrige steg. 

using System.Security.Cryptography; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Security; private static RSACryptoServiceProvider ImportPublicKey(string pem) { PemReader pr = new PemReader(new StringReader(pem)); AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject(); RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)publicKey); RSACryptoServiceProvider csp = new RSACryptoServiceProvider();// cspParams); csp.ImportParameters(rsaParams); return csp; }

Alternativt kan den offentlige nøkkelen installeres som et sertifikat på serveren og hentes via "thumbprint" eller avtrykk. Da må man bruke .cer versjonen av nøkkelen. Det er viktig parameterene "StoreName.My" og "StoreLocation.LocalMachine" stemmer overens med hvor sertifikatet er installert. Koden under henter ut et X509Certificate2. 

 

using System.Security.Cryptography.X509Certificates; static X509Certificate2 FindCertByThumbprint(string thumbPrint) { X509Store certStore = new X509Store(StoreName.My,StoreLocation.LocalMachine); certStore.Open(OpenFlags.ReadOnly); X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbPrint, false); certStore.Close(); if (certCollection.Count == 0) { throw new Exception("Did not find cert for given thumbprint and store"); } else { return certCollection[0]; } }

Dette kan gjøres om til en RSACryptoServiceProvider:

using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; X509Certificate2 pubCertFromStore = FindCertByThumbprint(pubKeyThumbprint); RSACryptoServiceProvider privateKeyRsaFromCert = (RSACryptoServiceProvider) pubCertFromStore.PublicKey.Key;

Kryptering av fødselsnummer

Med en RSACryptoServiceProvider kan fødselenummeret krypteres med denne koden:

using System.Security.Cryptography; using System.Text; private static string EncryptString(RSACryptoServciceProvider rsaCryptoPublicKey, string clearText) { UnicodeEncoding byteConverter = new UnicodeEncoding(); byte[] clearTextBytes = byteConverter.GetBytes(clearText); byte[] cipherBytes = rsaCryptoPublicKey.Encrypt(clearTextBytes, false); string cipherTextBase64 = Convert.ToBase64String(cipherBytes); return cipherTextBase64; // legges i <foedselsnummer>  }

De fleste eksemplene er basert på implementasjonen i test motoren som kjører på fellesbygg.dibk.no:

FB-Testmotor / DIBK.FellestjenesterBygg.TestEngine / DIBK.FellestjenesterBygg.TestEngine / Models / Encryption /

https://bitbucket.org/dibk/fb-testmotor/src/1d89fcaaf05a29ebdbb0d608cb8ddd3ef2f8fd1f/DIBK.FellestjenesterBygg.TestEngine/DIBK.FellestjenesterBygg.TestEngine/Models/Encryption/?at=master

 

Offentlige nøkler for FtB testmiljø er tilgjengelig for konsesjonærer på Fellestjenester-Forum under Documents->PublicKeyForFtbEncryption.

 

Krypteringsløsing i Java

Følgende er et eksempel på en implementering i Java.

public static String encrypt(PublicKey key, String plaintext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_16LE); byte[] encryptedBytes = cipher.doFinal(plaintextBytes); String cipherText = Base64.getEncoder().encodeToString(encryptedBytes); return cipherText; }

Public key kan leses fra en pem fil på med følgende funksjoner

public static RSAPublicKey getPublicKey(String filename) throws IOException, GeneralSecurityException { String publicKeyPEM = getKey(filename); return getPublicKeyFromString(publicKeyPEM); } private static String getKey(String filename) throws IOException { // Read key from file String strKeyPEM = ""; BufferedReader br = new BufferedReader(new FileReader(filename)); String line; while ((line = br.readLine()) != null) { strKeyPEM += line + "\n"; } br.close(); return strKeyPEM; } public static RSAPublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException { String publicKeyPEM = key; publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", ""); publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", ""); publicKeyPEM = publicKeyPEM.trim(); publicKeyPEM = publicKeyPEM.replaceAll("\n", ""); byte[] encoded = Base64.getDecoder().decode(publicKeyPEM); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKey pubKey; pubKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded)); return pubKey; }

API for testing

Vi har lagt ut API for å kryptere og dekryptere med vår nøkkel for FtB test server. Disse fungerer ikke på PROD server.

 

Kryptere

GET

https://admbygg.ft-test.dibk.no/api/GetEncryptedString/{fødselsnummer}

https://admbygg.ft-test.dibk.no/api/GetEncryptedString/123456789

 

Dekryptere

POST

https://admbygg.ft-test.dibk.no/api/GetDecryptedString

 

HEADER

Content-Type text/plain

 

BODY

HZ0GJnK98Xf7cNvLbQHXbDDWX9llrtOabNjmXzoy3tNyxej8CaHI/PIDlBenBmLFkYAKfY0yEh0R2AFhzc8pjQSuKymjUybswQLSMnOdF/m+FFWZgU8PCixAFdLbDmulRj50turREq4Lgf1aV3H/qyMBZsz+WfpyuiO8uDloS0w=

(kryptert streng, uten anførselstegn)