**Difija-Helmana atslēgu apmaiņa** jeb **DH** (angļu: *Diffie–Hellman key exchange*) ir kriptogrāfisks algoritms/protokols (jo tur ir iesaistītas vismaz 2 puses) simetrisko atslēgu apmaiņai (ģenerēšanai) izmantojot nedrošu (kuru noklausās) kanālu. Šī metode pirmo reizi tika publicēta 1976. gadā.

Lai arī DH tīrā veidā ir neautentificēts (anonīms) protokols, to izmanto par pamatu dažādiem autentifikācijas un šifrēšanas protokoliem (TLS). To lieto lai ģenerētu vienreizējas lietošanas atslēgas, lai arī to var lietot ilgtermiņā lietojamām atslēgām. Uz DH ir bāzēts ECC ECDH algoritms. No lietošanas viedokļa tas ir ļoti līdzīgs parastajam DH, tikai parametru (P,G) vietā ir kāda definēta eliptiskā līkne.

Darbība
-------

Sākumā uzģenerē DH parametrus, kas sastāv no liela pirmskaitļa P un tam piesaistīta skaitļa G. G parasti ir mazs (2 vai 5). P ir liels (1024+ biti), jo no tā ir atkarīga drošība. Sasniedzamais drošības līmenis ir salīdzināms ar RSA parametru *n*. DH parametru ģenerēšanas process ir lēns, lēnāks kā RSA atslēgu ģenerēšana. Parasti tos parametrus uzģenerē viens gals un aizsūta otram. Vienus un tos pašus parametrus (P,G) var lietot daudzām nesaistītām sesijām. 

Pēc tam katrs gals izvēlas gadījumskaitļus X (Xa un Xb)(*privātā atslēga*) un aprēķina skaitļus Y (Ya un Yb)(*publiskā atslēga*).

Y=GX(mod P)
No Xa iegūst Ya un attiecīgi no Xb iegūst Yb. Attiecīgo Y aizsūta uz otru galu (tas gals kas ģenerēja (P,G), aizsūta arī (P,G), lai otrs gals varētu sarēķināt savu Y. Y aprēķināšana no P,G,X ir daudz ātrāka kā RSA atslēgas ģenerēšana. P, X un Y ir apmēram līdzīga izmēra skaitļi. Dažos aprakstos Xa un Xb apzīmē kā a un b, attiecīgos Ya un Yb tad apzīmē kā A un B.

Pēc tam no saņemtajiem datiem aprēķina:

s=YbXa(mod P) (tajā galā kam ir pieejams Xa un kas uzģenerēja Ya)
s=YaXb(mod P) (otrā galā),
s šajā gadījumā ir simetriskā atslēga vai slepeni dati no kuriem iegūst simetrisko atslēgu.

Caur datu kanālu tika pārsūtīti P, G, Ya un Yb. Nezinot Xa vai Xb nevar aprēķināt s.

Ja datu kanālu ne tikai noklausās, bet var arī izmainīt, tad vidū var ierīkot 2 atsevišķas sesijas uz abiem galiem un dabūt atšifrētos datus no turienes. Šo *ievainojamību* var novērst autentificējot vienu vai abus galus (piem. TLS gadījumā parametri P,G stāv serverī un tas katrai klienta sesijai ģenerē savu X,Y un pie *ServerHello* nosūta P,G,Y parakstītus ar servera sertifikāta privāto atslēgu (parasti tā ir RSA atslēga), tā kā, ja parakstītos datus pa vidu izmainītu, tie vairs neatbilstu servera sertifikāta un tādejādi šo jaukšanos pa vidu varētu pamanīt.)

Lai arī plašāk lietotajos DH pielietojumos (TLS, SSH un līdzīgi) gandrīz vienmēr katrai jaunai sesijai ģenerē jaunus (X,Y), ir iespējams arī variants, kad atslēgu (X,Y) uzģenerē vienreiz un lieto daudzām sesijām. Šādā gadījumā publisko atslēgu (P,G,Y) var ielikt sertifikātā (kopā ar citiem datiem) un to sertifikātu var parakstīt kāds CA. TLS\_DH\_RSA un TLS\_DH\_DSS *ciphersuites* lieto sertifikātus ar šādu atslēgu. Tādā gadījumā, izveidojot sesiju, otrs gals (klients) uzģenerē savu atslēgu pāri un aizsūta savu publisko atslēgu (kā parasti). Vēl, ja šajā gadījumā lieto klienta autentifikāciju, klienta sertifikāts arī var saturēt statisku DH publisko atslēgu. (Tai gan ir jābūt bāzētai uz tiem pašiem parametriem (P.G) kā serverim). TLS šajā gadījumā vienmēr aprēķinās vienu un to pašu slepeno simetriskās atslēgas komponentu. Šis ir vienīgais TLS klienta autentifikācijas gadījums, kad klients neko neparaksta. DH tādejādi var būt ar: 

* *ephemeral-ephemeral* atslēgām, kad abi gali katrai sesijai ģenerē jaunas atslēgas (TLS, SSH, utt.),
* *ephemeral-static* atslēgām, kad viens gals lieto statisku atslēgu, bet otrs katrai sesijai ģenerē jaunu (šo ir iespējams lietot arī e-pasta vai failu šifrēšanai),
* *static-static* atslēgām, kad abiem galiem ir statiskas (ilgu laiku nemainīgas) atslēgas.

Piemērs
-------

Šajā piemērā ir lietoti mazi skaitļi, tie ir pārāk mazi lai nodrošinātu reālu drošību, bet tie ir vienkārši aprēķināmi. Darbības principi nemainās.

Parametri: P=23, G=5;

galā "a" izvēlas Xa=6 un aprēķina Ya:

Ya=56 mod 23
Ya=15625 mod 23
Ya=8
galā "b" izvēlas Xb=15 un apreķina Yb:

Yb=515 mod 23
Yb=30517578125 mod 23
Yb=19
gals "a" aizsūta galam "b" savu Ya (8), gals "b" aizsūta galam "a" savu Yb (19)

gals "a" aprēķina *s*:

s=196 mod 23
s=47045881 mod 23
s=2
gals "b" aprēķina *s*:

s=815 mod 23
s=35184372088832 mod 23
s=2
Ja kādam ir pieejami abi X (Xa un Xb), s var sarēķināt arī šādi:

s=56\*15 mod 23
s=515\*6 mod 23
s=590 mod 23
s=807793566946316088741610050849573099185363389551639556884765625 mod 23
s=2
Operāciju *x mod y* garā (bet vienkāršā) veidā ar kalkulatoru var sarēķināt arī šādi: x/y --> būs kaut kāds skaitlis z,nnn, nnn ignorē, sarēķina x-y\*z, kas ir dalīšanas atlikums, tas arī ir rezultāts.