Kryptografinen allekirjoittaminen

Nyt käytämme julkisen avaimen (engl. publkic key, PK) menetelmiä digitaalisen allekirjoituksen luomiseksi. Allekirjoittaminen näyttää lähes samalta kuin tiedon salaaminen.

Digitaalinen allekirjoitus on elektronisen maailman vastine perinteisille allekirjoituksille. Allekirjoituksella varmistetaan, että allekirjoittanut taho on hyväksynyt dokumentin. Digitaaliset allekirjoitusmenetelmät ovat julkisen avaimen menetelmiä eli niissä on käytössä salainen ja julkinen avain.

../_images/l8_digitaalinen_allekirjoitus.png

Digitaalisen allekirjoittamisen tapauksessa näiden avainten roolit ovat käänteiset verrattuna julkisen avaimen salaukseen: dokumentin voi allekirjoittaa vain salaisella avaimella, mutta allekirjoituksen voi varmentaa kuka tahansa julkisella avaimella.


Digitaalinen allekirjoitus RSA:n avulla

Edellisellä luennolla esitettyä RSA:ta käytetään erityisesti digitaalisiin allekirjoituksiin.

Käytetään seuraavassa esimerkissä samoja arvoja, joita käytettiin edellisen moduulin esimerkissä julkisen avaimen salauksesta RSA-menetelmällä:

  • salainen avain on \(d = 20753\).

  • julkinen avain on \(n = 29747\) ja \(e = 17\).

Nämä avaimet ovat nyt digitaalisen allekirjoituksen avainpari. Käytämme salaista avainta allekirjoittamiseen, ja allekirjoituksen vahvistaja käyttää julkista avainta allekirjoituksen vahvistamiseen.


Allekirjoituksen laskeminen

Kun Alice haluaa allekirjoittaa viestin \(m\), salataan se salaisella allekirjoitusavaimella eli lasketaan:

\[s = m^d \pmod{n}\]

Tämä on meille tuttu laskentatapa, josta teimme itsellemme Python-kirjastofunktion modulo_potenssiin.

Katsotaan laskenta numeroilla:

  • Alice allekirjoittaa viestin \(m = 313\).

  • Hän laskee allekirjoituksen (engl. signature) \(s = 313^{20753} \pmod{29747} = 15110\).

  • Alice liittää allekirjoituksen viestiin ja lähettää Bobille sekä viestin että omalla salaisella avaimellaan tuottamansa allekirjoituksen \((m,s) = (313,15110)\).


Tehdään allekirjoitus Pythonilla.

Inactive
# Salauksessa lasketaan c^d (mod n) eli modulo_potenssiin käyttöön
from xip import modulo_potenssiin

# Alustetaan Alicen avaimet
d_a = 20753
n_a = 29747
e_a = 17

# Näytetään Alicen avaimet
print("Alicen salainen avain      d = {}".format(d_a))
print("Alicen julkinen avain (n, e) = ({},{})\n".format(n_a,e_a))

# Alice allekirjoittaa viestin 313
viesti = 313
allekirjoitus = modulo_potenssiin(viesti, d_a, n_a)

# Näytetään allekirjoitus
print("Viesti:                  {}".format(viesti))
print("Viestin allekirjoitus:   {}".format(allekirjoitus))
print("Alice lähettää Bobille: ({},{})".format(viesti, allekirjoitus))

Allekirjoituksen varmistaminen

Kun Bob, jolla on Alicen julkinen avain \((n_A,e_A) = (29747,17)\) johon hän luottaa, vastaanottaa viestin ja allekirjoituksen, hän voi varmistaa allekirjoituksen oikeellisuuden laskemalla:

\[m' = s^e \pmod{n}\]

Tätä laskettua arvoa hän vertaa viestiin \(m\). Bob hyväksyy allekirjoituksen jos ja vain jos laskennan lopputulos täsmää saadun allekirjoituksen kanssa, eli \(m=m'\).

Tässä esimerkissä hän siis laskee \(m' = 15110^{17} \pmod{29747} = 313\) ja hyväksyy allekirjoituksen. Jos viestiä olisi muokattu, Bob havaitsisi sen koska vastaanotettu viesti ei tällöin olisi 313. Samoin kävisi jos allekirjoitusta olisi muokattu.

Jos Bob olisi esimerkiksi saanut allekirjoituksen \(s' = 15111\), lasku tuottaisi tuloksen \(15111^{17} \pmod{29747} = 22712\) ja allekirjoitus sekä viesti hylättäisiin.

Bob voi siis luottaa, että viestin \(m=313\) todellakin on allekirjoittanut Alice, koska kenelläkään muulla ei ole allekirjoittamiseen vaadittavaa avainta \(d\).


Varmennetaan allekirjoitus Pythonilla.

Inactive
# Bob luottaa Alicen julkiseen avaimeen - luottamus !
n_a, e_a = (29747, 17)

# Bob vastaanottaa Alicen lähettämän viestin m ja allekirjoituksen s
m, s = (313, 15110)

# Bob tarkistaa Alicen julkisella avaimella allekirjoituksen
m_pilkku = modulo_potenssiin(s, e_a, n_a)

# Näytetään allekirjoitus
print("Alicen lähettämä viesti: {}".format(m))
print("Bobin varmentama viesti: {}".format(m_pilkku))

if m == m_pilkku:
    print("Bob voi luottaa viestin tulleen Alicelta!")
else:
    print("Jotain mätää! Ei taida olla Alicelta viesti.")


Seuraavat kysymykset ovat tekstistä. Myös koodisolut voivat auttaa vastausten selvittämisessä.

Alice käyttää viestin allekirjoittamiseen:

Tuotettu allekirjoitus on:

Bob käyttää Alicen allekirjoituksen varmentamiseksi:

Kun Bob varmentaa allekirjoituksen:


Seuraavan tehtävän ratkaisu on pääteltävissä, mutta ratkaisuun pääsee helpommin kokeilemalla annettuja arvoja aikaisemmassa Python-koodisolussa.

Vastaanotat viestin ja allekirjoituksen \(m=9999\) ja \(s=16971\) . Viestin väitetyn allekirjoittajan julkinen avain on \(n=29747\) ja \(e=17\) , ja allekirjoittamisessa on käytetty yllä esitettyä RSA-menetelmää. Mikä seuraavista pitää paikkansa?


Informaation kiistämättömyys

Digitaalisesta allekirjoituksesta seuraa myös se, että Alice ei voi myöhemmin kiistää allekirjoittaneensa viestiä. Joissain yhteyksissä tämä kiistämättömyys (engl. undeniable signature) on määritelty kryptografian perustavoitteeksi, vaikka kyseessä on kryptografian sivutuotteena syntynyt lisäarvo.

RSA:n tapauksessa digitaalinen allekirjoitusmenetelmä saadaan toteutettua salausmenetelmästä hyvin suoraviivaisesti vaihtamalla salaisen ja julkisen avaimen roolit päinvastaisiksi. Salaisella avaimella siis allekirjoitetaan ja julkisella avaimella varmennetaan allekirjoitus.

Näin voidaan toimia, koska \(e\) ja \(d\) ovat RSA-menetelmässä tietyllä tapaa symmetrisiä. Yleisesti näin ei kuitenkaan ole, eikä kaikista julkisen avaimen salausmenetelmistä pystytä tekemään digitaalisia allekirjoituksia tai päinvastoin.


Digitaalinen allekirjoittaminen käytännössä

Sen sijaan, että allekirjoitettaisiin esimerkiksi koko tietty dokumentti, kuva, video tai äänitiedosto sellaisenaan, digitaalisissa allekirjoituksissa lasketaan käytännössä ensin kyseisestä dokumentista kryptografinen tiiviste (ks. opetusmoduuli 7).

Oletetaan, että Alice on saanut sähköpostissa kakkureseptin vielä tuntemattomalta taholta nimeltään Emilia. Emilia on laskenut kakkureseptistä tiivisteen.

Alla esimerkin vuoksi tuotetaan kakkureseptin tiiviste, jonka Emilia allekirjoittaa salaisella avaimellaan myöhemmin.

Inactive
# otetaan käyttöön SHA256 tiiviste
import hashlib
sha256tiiviste = hashlib.sha256()

# Luetaan kakkuresepti ja muutetaan se tavumuotoon.
with open('./Tekstit/kakkuresepti.txt', 'r') as file:
    resepti = file.readlines()

tavuresepti = ("".join(resepti)).encode()

# Lasketaan kakkureseptin tiiviste
sha256tiiviste.update(tavuresepti)

# Näytetään kakkureseptin SHA256 tiiviste
print("Kakkureseptin SHA256 tiiviste on:")
print(sha256tiiviste.digest().hex())

Yllä oleva kakkureseptistä tuotettu tiiviste olisi siis se informaatio, jonka allekirjoittaisimme. Emme voi kuitenkaan vielä varmentaa Emilian allekirjoitusta, koska emme tiedä kuka hän on, emmekä ole luoneet vielä yhteistä salaisuutta.

Kun informaatiosta lasketaan tiiviste, on mahdollista allekirjoittaa mielivaltaisen kokoisia dokumentteja ilman, että tarvitsee huolehtia rajoitteista, joita allekirjoitusmenetelmä mahdollisesti asettaa allekirjoitettavan viestin koolle. Tämä myös parantaa menetelmän turvallisuutta.

Seuraavaksi pieni pähkinä.


Voiko useamman allekirjoituksen kanssa syntyä ongelma? Tämä vaatii hieman pohdintaa.

Saat käsiisi kaksi saman osapuolen samalla avaimella \(d\) allekirjoittamaa viestiä allekirjoituksineen \((m_1,s_1)\) ja \((m_2,s_2)\). Allekirjoittamiseen on käytetty yllä kuvattua RSA-allekirjoitusmenetelmää. Kerrot allekirjoitukset yhteen eli lasket \(s_3 = s_1 \cdot s_2 \pmod{n}\). Mikä alla olevista väittämistä pitää paikkansa?



Yhteenveto

Digitaalinen allekirjoitus on merkittävässä roolissa, kun rakennamme seuraavassa osiossa julkisen avaimen infrastruktuuria.

  • Allekirjoituksen tuottamisessa käytetään omaa salaista avainta.

  • Allekirjoituksen varmistamiseen käytetään allekirjoittajan julkista avainta.

  • Yleensä allekirjoitetaan kokonaisen viestin sijasta tiiviste.

Kuten kurssilla on mainittu jo aikaisemmin, digitaalisen allekirjoituksen toteuttamiseen on olemassa useita epäsymmetrisiä menetelmiä RSA:n ohella käytetään usein elliptisiin käyriin perustuvia digitaalisia allekirjoituksia. Näiden menetelmien lyhenne on ECDSA, joka tulee sanoista elliptic curve digital signature algorithm.

Alice oli saanut reseptin oletettavasti Emilialta. Osaamme periaatteessa tarkistaa Emilian allekirjoituksen, mutta emme osaa vielä varmistaa, voiko Emilian julkiseen avaimeen luottaa.

Siksi tutustumme julkisen avaimen infrastruktuuriin (engl. Public Key Infrastructure - PKI), jota hyödynnetään rakentaessamme luottamusta internetissä.

Palautusta lähetetään...