Kontextrubriker i ASP.NET Core

Bakgrund och teori

I dataskyddssystemet innebär en "nyckel" ett objekt som kan tillhandahålla autentiserade krypteringstjänster. Varje nyckel identifieras av ett unikt ID (ett GUID) och bär med sig algoritmisk information och entropiskt material. Det är avsett att varje nyckel har en unik entropi, men systemet kan inte framtvinga det, och vi måste även ta hänsyn till utvecklare som kan ändra nyckelringen manuellt genom att ändra algoritminformationen för en befintlig nyckel i nyckelringen. För att uppnå våra säkerhetskrav med tanke på dessa fall har dataskyddssystemet ett begrepp om kryptografisk flexibilitet, vilket möjliggör säker användning av ett enda entropiskt värde i flera kryptografiska algoritmer.

De flesta system som stöder kryptografisk flexibilitet gör det genom att inkludera viss identifierande information om algoritmen inuti nyttolasten. Algoritmens OID är i allmänhet en bra kandidat för detta. Ett problem som vi stötte på är dock att det finns flera sätt att ange samma algoritm: "AES" (CNG) och de hanterade klasserna Aes, AesManaged, AesCryptoServiceProvider, AesCng och RijndaelManaged (angivna specifika parametrar) är alla faktiskt samma sak, och vi skulle behöva upprätthålla en mappning av alla dessa till rätt OID. Om en utvecklare vill tillhandahålla en anpassad algoritm (eller till och med en annan implementering av AES!) måste de berätta dess OID. Det här extra registreringssteget gör systemkonfigurationen särskilt smärtsam.

När vi tog ett steg tillbaka bestämde vi oss för att vi närmade oss problemet från fel håll. En OID talar om för dig vad algoritmen är, men vi bryr oss faktiskt inte om detta. Om vi behöver använda ett enda entropiskt värde på ett säkert sätt i två olika algoritmer är det inte nödvändigt för oss att veta vad algoritmerna faktiskt är. Vad vi faktiskt bryr oss om är hur de beter sig. Alla effektiva symmetriska blockchifferalgoritmer är också en stark pseudorandom-permutation (PRP): fixera indata (nyckel, lämndläge, IV, klartext) och chiffertexten kommer med överväldigande sannolikhet att skilja sig från andra symmetriska blockchifferalgoritmer med samma indata. På samma sätt är alla anständiga nyckelade hash-funktioner också en stark pseudorandomfunktion (PRF), och givet en fast indatauppsättning kommer dess utdata till övervägande del att skilja sig från andra nyckelade hash-funktioner.

Vi använder det här konceptet med starka PRP:er och PRF:er för att skapa en kontextrubrik. Den här kontextrubriken fungerar i princip som ett stabilt tumavtryck över de algoritmer som används för en viss åtgärd och ger den kryptografiska flexibilitet som dataskyddssystemet behöver. Den här rubriken är reproducerbar och används senare som en del av undernyckelns härledningsprocess. Det finns två olika sätt att skapa kontextrubriken beroende på de underliggande algoritmernas driftlägen.

CBC-lägeskryptering + HMAC-autentisering

Kontextrubriken består av följande komponenter:

  • [16 bitar] Värdet 00 00, vilket är en markör som betyder "CBC-kryptering + HMAC-autentisering".

  • [32 bitar] Nyckellängden (i byte, big-endian) för den symmetriska blockkrypteringsalgoritmen.

  • [32 bitar] Blockstorleken (i byte, big-endian) för den symmetriska blockkrypteringsalgoritmen.

  • [32 bitar] Nyckellängden (i byte, big-endian) för HMAC-algoritmen. (För närvarande matchar nyckelstorleken alltid sammandragsstorleken.)

  • [32 bitar] Sammandragsstorleken (i byte, big-endian) för HMAC-algoritmen.

  • EncCBC(K_E, IV, ""), som är utdata från den symmetriska blockkrypteringsalgoritmen givet en tom stränginmatning och där IV är en vektor helt noll. Konstruktionen av K_E beskrivs nedan.

  • MAC(K_H, ""), vilket är utdata från HMAC-algoritmen med en tom stränginmatning. Konstruktionen av K_H beskrivs nedan.

Idealiskt sett skulle vi kunna skicka alla nollvektorerna för K_E och K_H. Vi vill dock undvika den situation där den underliggande algoritmen kontrollerar om det finns svaga nycklar innan du utför några åtgärder (särskilt DES och 3DES), vilket förhindrar att du använder ett enkelt eller repeterbart mönster som en helt nollvektor.

I stället använder vi NIST SP800-108 KDF i räknarläge (se NIST SP800-108, s. 5.1) med en nyckel, etikett och kontext utan längd och HMACSHA512 som underliggande PRF. Vi härleder | K_E | + | K_H | byte av utdata och dekomponerar sedan resultatet i K_E och K_H själva. Matematiskt representeras detta på följande sätt.

( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")

Exempel: AES-192-CBC + HMACSHA256

Tänk till exempel på det fall där den symmetriska blockkrypteringsalgoritmen är AES-192-CBC och valideringsalgoritmen är HMACSHA256. Systemet skulle generera kontextrubriken med hjälp av följande steg.

Först, låt ( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = ""), där | K_E | = 192 bits och | K_H | = 256 bits i enlighet med specifikationerna i algoritmerna. Detta leder till K_E = 5BB6..21DD och K_H = A04A..00A9 i exemplet nedan:

5B B6 C9 83 13 78 22 1D 8E 10 73 CA CF 65 8E B0
61 62 42 71 CB 83 21 DD A0 4A 05 00 5B AB C0 A2
49 6F A5 61 E3 E2 49 87 AA 63 55 CD 74 0A DA C4
B7 92 3D BF 59 90 00 A9

Därefter beräknas Enc_CBC (K_E, IV, "") för AES-192-CBC givet IV = 0* och K_E enligt ovan.

result := F474B1872B3B53E4721DE19C0841DB6F

Därefter, beräkna MAC(K_H, "") för HMACSHA256 givet K_H som ovan.

result := D4791184B996092EE1202F36E8608FA8FBD98ABDFF5402F264B1D7211536220C

Detta skapar den fullständiga kontextrubriken nedan:

00 00 00 00 00 18 00 00 00 10 00 00 00 20 00 00
00 20 F4 74 B1 87 2B 3B 53 E4 72 1D E1 9C 08 41
DB 6F D4 79 11 84 B9 96 09 2E E1 20 2F 36 E8 60
8F A8 FB D9 8A BD FF 54 02 F2 64 B1 D7 21 15 36
22 0C

Den här kontextrubriken är tumavtrycket för det autentiserade krypteringsalgoritmparet (AES-192-CBC-kryptering + HMACSHA256 validering). Komponenterna, enligt beskrivningen ovan , är:

  • markören (00 00)

  • blockchiffernyckelns längd (00 00 00 18)

  • block chifferblockets storlek (00 00 00 10)

  • HMAC-nyckellängden (00 00 00 20)

  • HMAC-sammandragsstorleken (00 00 00 20)

  • blockkrypterings-PRP-utdata (F4 74 - DB 6F) och

  • HMAC PRF-utdata (D4 79 - end).

Anmärkning

Kontextrubriken för CBC-lägeskryptering + HMAC-autentisering skapas på samma sätt oavsett om algoritmimplementeringarna tillhandahålls av Windows CNG eller av hanterade typerna SymmetricAlgorithm och KeyedHashAlgorithm. På så sätt kan program som körs på olika operativsystem på ett tillförlitligt sätt producera samma kontextrubrik även om implementeringarna av algoritmerna skiljer sig åt mellan operativsystemen. (I praktiken behöver KeyedHashAlgorithm inte vara en riktig HMAC. Det kan vara valfri nyckelad hash-algoritmtyp.)

Exempel: 3DES-192-CBC + HMACSHA1

Först, låt ( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = ""), där | K_E | = 192 bits och | K_H | = 160 bits enligt angivna algoritmer. Detta leder till K_E = A219..E2BB och K_H = DC4A..B464 i exemplet nedan:

A2 19 60 2F 83 A9 13 EA B0 61 3A 39 B8 A6 7E 22
61 D9 F8 6C 10 51 E2 BB DC 4A 00 D7 03 A2 48 3E
D1 F7 5A 34 EB 28 3E D7 D4 67 B4 64

Därefter beräknar du Enc_CBC (K_E, IV, "") för 3DES-192-CBC givet IV = 0* och K_E enligt ovan.

result := ABB100F81E53E10E

Därefter beräkna MAC(K_H, "") för HMACSHA1 givet K_H enligt ovan.

result := 76EB189B35CF03461DDF877CD9F4B1B4D63A7555

Detta ger den fullständiga kontextrubriken som är ett tumavtryck för det autentiserade krypteringsalgoritmparet (3DES-192-CBC-kryptering + HMACSHA1 validering), som visas nedan:

00 00 00 00 00 18 00 00 00 08 00 00 00 14 00 00
00 14 AB B1 00 F8 1E 53 E1 0E 76 EB 18 9B 35 CF
03 46 1D DF 87 7C D9 F4 B1 B4 D6 3A 75 55

Komponenterna delas upp på följande sätt:

  • markören (00 00)

  • blockchiffrens nyckellängd (00 00 00 18)

  • blockchifferets storlek (00 00 00 08)

  • HMAC-nyckellängden (00 00 00 14)

  • HMAC-sammandragsstorleken (00 00 00 14)

  • blockkrypterings-PRP-utdata (AB B1 - E1 0E) och

  • HMAC PRF-utdata (76 EB - end).

Kryptering i galois-/räknareläge + autentisering

Kontextrubriken består av följande komponenter:

  • [16 bitar] Värdet 00 01, vilket är en markör som betyder "GCM-kryptering + autentisering".

  • [32 bitar] Nyckellängden (i byte, big-endian) för den symmetriska blockkrypteringsalgoritmen.

  • [32 bitar] Nonce-storleken (i byter, big-endian) som används under autentiserade krypteringsåtgärder. (För vårt system är detta fast vid nonce size = 96 bitar.)

  • [32 bitar] Blockstorleken (i byte, big-endian) för den symmetriska blockkrypteringsalgoritmen. (För GCM är detta fast vid blockstorlek = 128 bitar.)

  • [32 bitar] Storleken på autentiseringstaggen (i byte, big-endian) som skapas av den autentiserade krypteringsfunktionen. (För vårt system är detta fast vid taggstorlek = 128 bitar.)

  • [128 bitar] Taggen för Enc_GCM (K_E, nonce, ""), som är utdata från den symmetriska blockkrypteringsalgoritmen med en tom stränginmatning och där nonce är en 96-bitars vektor med enbart nollor.

K_E härleds med samma mekanism som i CBC-kryptering + HMAC-autentiseringsscenariot. Men eftersom det inte finns något K_H i spel här, har vi i princip | K_H | = 0, och algoritmen komprimeras till formen nedan.

K_E = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")

Exempel: AES-256-GCM

Låt först K_E = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = ""), där | K_E | = 256 bits.

K_E := 22BC6F1B171C08C4AE2F27444AF8FC8B3087A90006CAEA91FDCFB47C1B8733B8

Därefter, beräkna autentiseringstaggen för Enc_GCM (K_E, nonce, "") för AES-256-GCM givet nonce = 096 och K_E enligt ovan.

result := E7DCCE66DF855A323A6BB7BD7A59BE45

Detta skapar den fullständiga kontextrubriken nedan:

00 01 00 00 00 20 00 00 00 0C 00 00 00 10 00 00
00 10 E7 DC CE 66 DF 85 5A 32 3A 6B B7 BD 7A 59
BE 45

Komponenterna delas upp på följande sätt:

  • markören (00 01)

  • blockkrypteringens nyckellängd (00 00 00 20)

  • nonce-storleken (00 00 00 0C)

  • blockchifferstorleken (00 00 00 10)

  • autentiseringstaggens storlek (00 00 00 10) och

  • autentiseringstagg som erhålls genom att köra blockchiffer (E7 DC - end).