{"id":92,"date":"2026-06-16T16:56:30","date_gmt":"2026-06-16T16:56:30","guid":{"rendered":"https:\/\/shattered.io\/fi\/2026\/06\/16\/ed25519-allekirjoitus-nodejs\/"},"modified":"2026-06-16T16:57:48","modified_gmt":"2026-06-16T16:57:48","slug":"ed25519-allekirjoitus-nodejs","status":"publish","type":"post","link":"https:\/\/shattered.io\/fi\/ed25519-allekirjoitus-nodejs\/","title":{"rendered":"Ed25519 Node.js:ss\u00e4: 10 vaihetta, 30 min [2026]"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Ed25519 on noussut modernin digitaalisen allekirjoituksen oletusvalinnaksi. Avain on vain 32 tavua, allekirjoitus 64 tavua, ja turvataso vastaa noin 128:aa bitti\u00e4. T\u00e4ss\u00e4 oppaassa rakennat t\u00e4ysin toimivan allekirjoitusj\u00e4rjestelm\u00e4n pelk\u00e4ll\u00e4 Node.js:n sis\u00e4\u00e4nrakennetulla <code>crypto<\/code>-moduulilla, ilman ulkoisia riippuvuuksia. K\u00e4ymme l\u00e4pi 9 konkreettista vaihetta noin 30 minuutissa: avainparin luonti, allekirjoitus, vahvistus, avainten tallennus, JWT EdDSA-algoritmilla sek\u00e4 valmis tiedostojen eheyden varmistusty\u00f6kalu.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ed25519 m\u00e4\u00e4riteltiin RFC 8032 -standardissa osana EdDSA-allekirjoitusperhett\u00e4, ja Node.js on tukenut sit\u00e4 natiivisti versiosta 12 l\u00e4htien. Vuonna 2026 vakaa valinta on Node.js 24 LTS. Oppaan koodi toimii my\u00f6s Node.js 20:ss\u00e4. P\u00e4ivitetty 16. kes\u00e4kuuta 2026.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mika-ed25519-on-ja-miksi-se-on-oletusvalinta-2026\">Mik\u00e4 Ed25519 on ja miksi se on oletusvalinta 2026<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ed25519 on EdDSA-allekirjoitusskeeman (Edwards-curve Digital Signature Algorithm) yleisimmin k\u00e4ytetty muunnelma. Se rakentuu Edwardsin muotoon kirjoitetulle Curve25519-elliptiselle k\u00e4yr\u00e4lle, jonka julkaisi Daniel J. Bernsteinin tutkimusryhm\u00e4. Standardi RFC 8032 m\u00e4\u00e4rittelee sek\u00e4 Ed25519:n ett\u00e4 vahvemman Ed448:n. K\u00e4yt\u00e4nn\u00f6ss\u00e4 l\u00e4hes kaikki sovellukset k\u00e4ytt\u00e4v\u00e4t Ed25519:\u00e4\u00e4, koska se tarjoaa erinomaisen tasapainon nopeuden, koon ja turvallisuuden v\u00e4lill\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ed25519:n keskeinen ero perinteiseen ECDSA-allekirjoitukseen on determinismi. ECDSA tarvitsee jokaiselle allekirjoitukselle tuoreen satunnaisen kertaluvun (nonce). Jos sama kertaluku vuotaa tai toistuu kahdessa allekirjoituksessa, hy\u00f6kk\u00e4\u00e4j\u00e4 voi laskea salaisen avaimen. T\u00e4m\u00e4 virhe on kaatanut tuotantoj\u00e4rjestelmi\u00e4 Sonyn PlayStation 3:sta l\u00e4htien. Ed25519 johtaa kertaluvun deterministisesti salaisesta avaimesta ja viestist\u00e4 hajautusfunktion avulla, joten satunnaislukugeneraattorin heikkous ei vuoda avainta. T\u00e4m\u00e4 tekee Ed25519:st\u00e4 operatiivisesti turvallisemman kuin nonce-pohjaiset skeemat.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ed25519 on jo kaikkialla. OpenSSH suosittelee sit\u00e4 SSH-avaimien oletustyypiksi. TLS 1.3 tukee EdDSA-sertifikaattiallekirjoituksia. Signal-protokolla nojaa Ed25519-allekirjoituksiin avaintenvaihdossaan. Age-salausty\u00f6kalu ja lukuisat lohkoketjut k\u00e4ytt\u00e4v\u00e4t samaa k\u00e4yr\u00e4\u00e4. JWT- ja JOSE-maailmassa algoritmin tunniste on yksinkertaisesti <code>EdDSA<\/code>. Kun yhdist\u00e4t t\u00e4m\u00e4n pienen avainkoon ja korkean nopeuden, ymm\u00e4rr\u00e4t miksi Ed25519 on vuonna 2026 modernin sovelluskehityksen oletus.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">T\u00e4rke\u00e4 rajaus heti alkuun: Ed25519 tekee vain allekirjoituksia ja niiden vahvistusta. Se ei salaa dataa eik\u00e4 vaihda avaimia. Jos tarvitset avaintenvaihtoa tai salausta, k\u00e4yt\u00e4t samaa matemaattista k\u00e4yr\u00e4\u00e4 mutta eri funktiota nimelt\u00e4 X25519. Lue ero tarkasti kohdasta &#8220;Yleiset sudenkuopat&#8221;, sill\u00e4 juuri t\u00e4m\u00e4 sekaannus on aloittelijoiden yleisin virhe.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Miksi juuri nyt, vuonna 2026? Kolme syyt\u00e4 ajaa siirtym\u00e4\u00e4. Ensinn\u00e4kin laskentateho on halventunut niin paljon, ett\u00e4 RSA-2048:n hidas allekirjoitus alkaa olla pullonkaula suuren liikenteen palveluissa, ja siirtym\u00e4 RSA-4096:een vain pahentaa ongelmaa. Toiseksi mobiili- ja IoT-laitteet hy\u00f6tyv\u00e4t dramaattisesti pienemmist\u00e4 avaimista ja matalammasta laskentakuormasta. Kolmanneksi koko ekosysteemi on kypsynyt: Node.js, selaimet, SSH, TLS-kirjastot ja JOSE-standardit tukevat Ed25519:\u00e4\u00e4 vakaasti, joten yhteensopivuusesteet, jotka aiemmin pakottivat RSA:han, ovat suurelta osin poistuneet. T\u00e4m\u00e4 opas antaa sinulle valmiudet hy\u00f6dynt\u00e4\u00e4 t\u00e4t\u00e4 siirtym\u00e4\u00e4 k\u00e4yt\u00e4nn\u00f6ss\u00e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ed25519-vs-rsa-vs-ecdsa-vertailutaulukko\">Ed25519 vs RSA vs ECDSA: vertailutaulukko<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ennen koodausta kannattaa ymm\u00e4rt\u00e4\u00e4, miksi Ed25519 voittaa useimmissa nykyaikaisissa k\u00e4ytt\u00f6tapauksissa. Alla oleva taulukko vertaa kolmea yleisint\u00e4 allekirjoitusalgoritmia ominaisuuksilla, joilla on k\u00e4yt\u00e4nn\u00f6n merkityst\u00e4 tuotannossa. Avain- ja allekirjoituskoot ovat tarkkoja, mittasin ne t\u00e4m\u00e4n oppaan esimerkkikoodilla.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Ominaisuus<\/th><th>Ed25519<\/th><th>ECDSA (P-256)<\/th><th>RSA-2048<\/th><\/tr><\/thead><tbody><tr><td>Julkisen avaimen koko<\/td><td>32 tavua<\/td><td>~65 tavua<\/td><td>~270 tavua<\/td><\/tr><tr><td>Salaisen avaimen koko (raaka)<\/td><td>32 tavua<\/td><td>32 tavua<\/td><td>~1190 tavua<\/td><\/tr><tr><td>Allekirjoituksen koko<\/td><td>64 tavua<\/td><td>~70-72 tavua<\/td><td>256 tavua<\/td><\/tr><tr><td>Turvataso<\/td><td>~128 bitti\u00e4<\/td><td>~128 bitti\u00e4<\/td><td>~112 bitti\u00e4<\/td><\/tr><tr><td>Deterministinen<\/td><td>Kyll\u00e4<\/td><td>Ei (oletuksena)<\/td><td>Kyll\u00e4 (RSASSA-PKCS1)<\/td><\/tr><tr><td>Nonce-vuodon riski<\/td><td>Ei<\/td><td>Korkea<\/td><td>Ei<\/td><\/tr><tr><td>Allekirjoitusnopeus<\/td><td>Eritt\u00e4in nopea<\/td><td>Nopea<\/td><td>Hidas<\/td><\/tr><tr><td>Vahvistusnopeus<\/td><td>Nopea<\/td><td>Nopea<\/td><td>Eritt\u00e4in nopea<\/td><\/tr><tr><td>Node.js-natiivituki<\/td><td>v12+<\/td><td>v12+<\/td><td>v0.x+<\/td><\/tr><tr><td>Kvanttiturvallinen<\/td><td>Ei<\/td><td>Ei<\/td><td>Ei<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-block-table__caption\">Koot mitattu Node.js 20:n crypto-moduulilla. RSA:n nopeudet riippuvat avainkoosta.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Taulukko kertoo selke\u00e4n tarinan. Ed25519:n julkinen avain mahtuu yhteen QR-koodiin, kun RSA-2048-avain on l\u00e4hes kymmenkertainen. Allekirjoitus on 64 tavua, nelj\u00e4sosa RSA:n 256 tavusta. Allekirjoittaminen on dramaattisesti nopeampaa kuin RSA:lla, ja determinismi poistaa kokonaisen luokan haavoittuvuuksia. RSA voittaa vain yhdess\u00e4 mittarissa: julkisen avaimen vahvistus on hieman nopeampaa pienell\u00e4 eksponentilla. Useimmissa palvelimissa allekirjoituksia syntyy enemm\u00e4n kuin niit\u00e4 vahvistetaan, joten Ed25519 on kokonaisuutena tehokkaampi.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Yksi rivi ansaitsee huomion: yksik\u00e4\u00e4n n\u00e4ist\u00e4 ei ole kvanttiturvallinen. Riitt\u00e4v\u00e4n tehokas kvanttitietokone, joka ajaa Shorin algoritmia, murtaisi sek\u00e4 RSA:n ett\u00e4 kaikki elliptisen k\u00e4yr\u00e4n skeemat, Ed25519 mukaan lukien. T\u00e4m\u00e4 ei ole akuutti uhka vuonna 2026, mutta se ohjaa pitk\u00e4n aikav\u00e4lin suunnittelua kohti hybridiratkaisuja. Palaamme t\u00e4h\u00e4n edistyneiss\u00e4 vinkeiss\u00e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"esivaatimukset-ja-versiot\">Esivaatimukset ja versiot<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">T\u00e4m\u00e4 opas k\u00e4ytt\u00e4\u00e4 p\u00e4\u00e4osin Node.js:n sis\u00e4\u00e4nrakennettua <code>crypto<\/code>-moduulia, joten asennettavaa on v\u00e4h\u00e4n. Vahvista versiot ennen aloitusta. Suosittelen Node.js 24 LTS:\u00e4\u00e4, joka on vuoden 2026 vakaa pitk\u00e4n tuen julkaisu. Koodi toimii identtisesti my\u00f6s Node.js 20:ss\u00e4 ja 22:ssa.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Komponentti<\/th><th>V\u00e4himm\u00e4isversio<\/th><th>Suositus 2026<\/th><th>Tarkistuskomento<\/th><\/tr><\/thead><tbody><tr><td>Node.js<\/td><td>20.x<\/td><td>24 LTS<\/td><td><code>node -v<\/code><\/td><\/tr><tr><td>npm<\/td><td>10.x<\/td><td>10.8+<\/td><td><code>npm -v<\/code><\/td><\/tr><tr><td>OpenSSL (Noden sis\u00e4inen)<\/td><td>3.0+<\/td><td>3.x<\/td><td><code>node -p process.versions.openssl<\/code><\/td><\/tr><tr><td>jose (vain JWT-vaihe)<\/td><td>5.0<\/td><td>5.x<\/td><td><code>npm ls jose<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Tarvitset my\u00f6s perustiedot komentorivilt\u00e4 ja JavaScriptin moduuleista. K\u00e4yt\u00e4mme moderneja ES-moduuleja (<code>import<\/code>), mutta kaikki esimerkit toimivat my\u00f6s CommonJS-syntaksilla (<code>require<\/code>), jos vaihdat tuontilauseet. Varmista lopuksi, ett\u00e4 OpenSSL on versiota 3, koska vanha 1.1.1 on saavuttanut elinkaarensa lopun eik\u00e4 saa en\u00e4\u00e4 tietoturvap\u00e4ivityksi\u00e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-1-projektin-alustus\">Vaihe 1: Projektin alustus<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Luo uusi hakemisto ja alusta projekti. Asetamme <code>type: \"module\"<\/code>, jotta voimme k\u00e4ytt\u00e4\u00e4 ES-moduulien <code>import<\/code>-syntaksia. T\u00e4m\u00e4 on vuoden 2026 suositeltu tapa kirjoittaa uutta Node.js-koodia.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir ed25519-allekirjoitus && cd ed25519-allekirjoitus\nnpm init -y\nnpm pkg set type=\"module\"\nnode -v   # vahvista: v20.x tai uudempi<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Luo hakemistorakenne. Pid\u00e4mme avaimet erillisess\u00e4 <code>keys<\/code>-kansiossa ja lis\u00e4\u00e4mme sen heti <code>.gitignore<\/code>-tiedostoon, jotta salaiset avaimet eiv\u00e4t koskaan p\u00e4\u00e4dy versionhallintaan. T\u00e4m\u00e4 on yksi t\u00e4rkeimmist\u00e4 tavoista v\u00e4ltt\u00e4\u00e4 avainvuoto.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir keys src\necho \"keys\/\" >> .gitignore\necho \"node_modules\/\" >> .gitignore<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Projektirakenne on nyt valmis. Seuraavissa vaiheissa t\u00e4yt\u00e4mme <code>src<\/code>-kansion moduuleilla, joista jokainen hoitaa yhden vastuun: avainten luonti, allekirjoitus, vahvistus ja lopulta valmis CLI-ty\u00f6kalu. T\u00e4m\u00e4 modulaarisuus tekee koodista helposti testattavaa ja uudelleenk\u00e4ytett\u00e4v\u00e4\u00e4 tuotannossa.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-2-ed25519-avainparin-luonti\">Vaihe 2: Ed25519-avainparin luonti<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Luodaan ensimm\u00e4inen avainpari. Node.js:n <code>crypto.generateKeyPairSync<\/code> tukee tyyppi\u00e4 <code>\"ed25519\"<\/code> suoraan. Funktio palauttaa kaksi <code>KeyObject<\/code>-oliota: julkisen ja salaisen avaimen. Toisin kuin RSA, Ed25519 ei tarvitse modulus- tai eksponenttiparametreja, koska k\u00e4yr\u00e4 on kiinte\u00e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/generate.js\nimport { generateKeyPairSync } from 'crypto';\n\nexport function luoAvainpari() {\n  const { publicKey, privateKey } = generateKeyPairSync('ed25519');\n  return { publicKey, privateKey };\n}\n\n\/\/ Pikatesti suoraan ajettaessa\nif (import.meta.url === `file:\/\/${process.argv[1]}`) {\n  const { publicKey, privateKey } = luoAvainpari();\n  const pubDer = publicKey.export({ type: 'spki', format: 'der' });\n  const privDer = privateKey.export({ type: 'pkcs8', format: 'der' });\n  console.log('Julkinen avain (DER):', pubDer.length, 'tavua');\n  console.log('Salainen avain (DER):', privDer.length, 'tavua');\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Aja moduuli ja katso tulos. Saat tarkat tavukokom\u00e4\u00e4r\u00e4t, jotka vahvistavat ett\u00e4 avaimet ovat aitoja Ed25519-avaimia.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ node src\/generate.js\nJulkinen avain (DER): 44 tavua\nSalainen avain (DER): 48 tavua<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Numerot ovat opettavaisia. Raaka Ed25519-julkisavain on vain 32 tavua, mutta SPKI-muotoinen DER-koodaus lis\u00e4\u00e4 12 tavua ASN.1-otsaketta, jolloin tulos on 44 tavua. Salainen avain PKCS#8-muodossa on 48 tavua. N\u00e4m\u00e4 otsakkeet kertovat ty\u00f6kaluille, ett\u00e4 kyseess\u00e4 on nimenomaan Ed25519-avain, joten ne ovat hy\u00f6dyllisi\u00e4 yhteensopivuuden kannalta. Vaiheessa 8 n\u00e4yt\u00e4mme, miten saat k\u00e4siisi pelk\u00e4t 32 raakatavua, kun tarvitset maksimaalista tiiviytt\u00e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-3-avainten-tallennus-ja-lataus-pem-muodossa\">Vaihe 3: Avainten tallennus ja lataus PEM-muodossa<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Avaimet ovat hy\u00f6dytt\u00f6mi\u00e4, jos ne katoavat prosessin sulkeutuessa. Tallennetaan ne levylle PEM-muodossa, joka on yleisin tekstipohjainen avainformaatti ja yhteensopiva OpenSSL:n, OpenSSH:n ja useimpien kielten kirjastojen kanssa. Salainen avain kirjoitetaan tiukoilla tiedosto-oikeuksilla (0600), jotta vain omistaja voi lukea sen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/storage.js\nimport { writeFileSync, readFileSync } from 'fs';\nimport { createPublicKey, createPrivateKey } from 'crypto';\n\nexport function tallennaAvaimet(publicKey, privateKey, hakemisto = 'keys') {\n  const pubPem = publicKey.export({ type: 'spki', format: 'pem' });\n  const privPem = privateKey.export({ type: 'pkcs8', format: 'pem' });\n\n  writeFileSync(`${hakemisto}\/public.pem`, pubPem);\n  \/\/ mode 0o600 = vain omistaja saa lukea ja kirjoittaa\n  writeFileSync(`${hakemisto}\/private.pem`, privPem, { mode: 0o600 });\n}\n\nexport function lataaAvaimet(hakemisto = 'keys') {\n  const publicKey = createPublicKey(readFileSync(`${hakemisto}\/public.pem`));\n  const privateKey = createPrivateKey(readFileSync(`${hakemisto}\/private.pem`));\n  return { publicKey, privateKey };\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">PEM-tiedosto on luettavaa teksti\u00e4. Julkinen avain alkaa rivill\u00e4 <code>-----BEGIN PUBLIC KEY-----<\/code> ja salainen rivill\u00e4 <code>-----BEGIN PRIVATE KEY-----<\/code>. Huomaa, ettei salainen avain ole t\u00e4ss\u00e4 viel\u00e4 salasanasuojattu. Tuotannossa kannattaa joko salata se erikseen tai s\u00e4ilytt\u00e4\u00e4 avaintenhallintapalvelussa kuten HashiCorp Vaultissa tai pilvialustan KMS:ss\u00e4. K\u00e4sittelemme salasanasuojausta vianm\u00e4\u00e4rityksess\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Yksi k\u00e4yt\u00e4nn\u00f6n etu PEM-muodossa on yhteistoiminta OpenSSL:n kanssa. Voit tarkistaa luomasi avaimen komentorivilt\u00e4 komennolla <code>openssl pkey -in keys\/private.pem -text -noout<\/code>, joka tulostaa avaimen tyypin ja raakatavut. T\u00e4m\u00e4 on hy\u00f6dyllist\u00e4, kun integroit Node.js-koodia muiden kielten tai j\u00e4rjestelmien kanssa.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-4-viestin-allekirjoitus\">Vaihe 4: Viestin allekirjoitus<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Nyt p\u00e4\u00e4semme ytimeen. Ed25519:n allekirjoitus tehd\u00e4\u00e4n funktiolla <code>crypto.sign<\/code>. T\u00e4ss\u00e4 on ratkaisevan t\u00e4rke\u00e4 yksityiskohta, joka kompastuttaa l\u00e4hes jokaisen aloittelijan: ensimm\u00e4inen argumentti, joka on muiden algoritmien kohdalla hajautusfunktion nimi, on Ed25519:ll\u00e4 oltava <code>null<\/code>. Syyn\u00e4 on se, ett\u00e4 Ed25519 hoitaa hajautuksen sis\u00e4isesti osana algoritmia (se k\u00e4ytt\u00e4\u00e4 SHA-512:ta). Jos annat sille esimerkiksi merkkijonon <code>\"sha256\"<\/code>, saat virheen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/sign.js\nimport { sign } from 'crypto';\n\nexport function allekirjoita(viesti, privateKey) {\n  \/\/ viesti voi olla Buffer tai merkkijono; muunnetaan Bufferiksi\n  const data = Buffer.isBuffer(viesti) ? viesti : Buffer.from(viesti, 'utf8');\n  \/\/ HUOM: ensimmainen argumentti on null, ei hajautusfunktion nimi\n  const allekirjoitus = sign(null, data, privateKey);\n  return allekirjoitus; \/\/ 64 tavun Buffer\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Allekirjoitus on aina tasan 64 tavua riippumatta viestin pituudesta. Allekirjoitatpa yhden tavun tai yhden gigatavun, tulos on 64 tavua. T\u00e4m\u00e4 johtuu siit\u00e4, ett\u00e4 Ed25519 hajauttaa viestin ensin kiinte\u00e4pituiseksi ja allekirjoittaa hajautuksen. Pieni demonstraatio havainnollistaa determinismin: sama viesti ja sama avain tuottavat aina t\u00e4sm\u00e4lleen saman allekirjoituksen. T\u00e4m\u00e4 on tahallinen ominaisuus, ei vika.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ node -e '\nimport(\".\/src\/generate.js\").then(async (g) => {\n  const { sign } = await import(\"crypto\");\n  const { privateKey } = g.luoAvainpari();\n  const a = sign(null, Buffer.from(\"Hei Suomi\"), privateKey);\n  const b = sign(null, Buffer.from(\"Hei Suomi\"), privateKey);\n  console.log(\"Pituus:\", a.length, \"tavua\");\n  console.log(\"Determinismi:\", a.equals(b));\n})'\nPituus: 64 tavua\nDeterminismi: true<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Tallenna allekirjoitus yleens\u00e4 Base64- tai heksamuodossa, kun l\u00e4het\u00e4t sen verkon yli tai tallennat tietokantaan. Buffer muuntuu Base64:ksi komennolla <code>allekirjoitus.toString('base64')<\/code>. Muista k\u00e4ytt\u00e4\u00e4 samaa koodausta vahvistuksessa, sill\u00e4 koodausten sekaannus on yleisin syy siihen, ett\u00e4 muuten oikea allekirjoitus ei vahvistu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-5-allekirjoituksen-vahvistus\">Vaihe 5: Allekirjoituksen vahvistus<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Vahvistus on allekirjoituksen peilikuva. Funktio <code>crypto.verify<\/code> ottaa saman <code>null<\/code>-argumentin, alkuper\u00e4isen viestin, julkisen avaimen ja allekirjoituksen. Se palauttaa totuusarvon: <code>true<\/code> jos allekirjoitus on aito ja viesti on muuttumaton, muuten <code>false<\/code>. Vahvistus ei koskaan heit\u00e4 poikkeusta v\u00e4\u00e4r\u00e4n allekirjoituksen vuoksi, joten \u00e4l\u00e4 luota try-catch-lohkoon vaan tarkista paluuarvo.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/verify.js\nimport { verify } from 'crypto';\n\nexport function vahvista(viesti, allekirjoitus, publicKey) {\n  const data = Buffer.isBuffer(viesti) ? viesti : Buffer.from(viesti, 'utf8');\n  const sig = Buffer.isBuffer(allekirjoitus)\n    ? allekirjoitus\n    : Buffer.from(allekirjoitus, 'base64');\n  return verify(null, data, publicKey, sig);\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Testataan koko ketju yhdess\u00e4: luonti, allekirjoitus, vahvistus ja viel\u00e4 peukaloidun viestin hylk\u00e4\u00e4minen. T\u00e4m\u00e4 on opettavaisin yksitt\u00e4inen testi koko oppaassa, koska se osoittaa ett\u00e4 allekirjoitus sitoo viestin sis\u00e4ll\u00f6n. Jos yksikin tavu muuttuu, vahvistus ep\u00e4onnistuu.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/demo.js\nimport { luoAvainpari } from '.\/generate.js';\nimport { allekirjoita } from '.\/sign.js';\nimport { vahvista } from '.\/verify.js';\n\nconst { publicKey, privateKey } = luoAvainpari();\nconst viesti = 'Tilisiirto: 1500 EUR tilille FI21 1234 5600 0007 85';\n\nconst sig = allekirjoita(viesti, privateKey);\nconsole.log('Aito viesti vahvistuu:', vahvista(viesti, sig, publicKey));\n\nconst vaarennos = 'Tilisiirto: 9999 EUR tilille FI21 1234 5600 0007 85';\nconsole.log('Peukaloitu viesti vahvistuu:', vahvista(vaarennos, sig, publicKey));<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>$ node src\/demo.js\nAito viesti vahvistuu: true\nPeukaloitu viesti vahvistuu: false<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Juuri t\u00e4m\u00e4 on digitaalisen allekirjoituksen koko arvolupaus. Vastaanottaja voi varmistua kahdesta asiasta: viesti tuli sen avaimen haltijalta, jonka julkiseen avaimeen h\u00e4n luottaa, ja viesti\u00e4 ei ole muutettu matkalla. Halutessasi syvent\u00e4\u00e4 allekirjoitusten teoriaa, lue tausta-artikkelimme <a href=\"\/fi\/digitaaliset-allekirjoitukset\/\">digitaalisista allekirjoituksista<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-6-komentorivityokalu-avainten-lataukseen\">Vaihe 6: Komentorivity\u00f6kalu avainten lataukseen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Yhdistet\u00e4\u00e4n edelliset palaset pieneksi komentorivity\u00f6kaluksi, joka lataa levylle tallennetut avaimet ja allekirjoittaa annetun tiedoston. T\u00e4m\u00e4 on realistinen kuva siit\u00e4, miten allekirjoitusta k\u00e4ytet\u00e4\u00e4n esimerkiksi julkaisuputkessa tai ohjelmistopakettien allekirjoituksessa.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/cli.js\nimport { readFileSync } from 'fs';\nimport { luoAvainpari } from '.\/generate.js';\nimport { tallennaAvaimet, lataaAvaimet } from '.\/storage.js';\nimport { allekirjoita } from '.\/sign.js';\nimport { vahvista } from '.\/verify.js';\n\nconst komento = process.argv[2];\n\nif (komento === 'keygen') {\n  const { publicKey, privateKey } = luoAvainpari();\n  tallennaAvaimet(publicKey, privateKey);\n  console.log('Avaimet tallennettu kansioon keys\/');\n} else if (komento === 'sign') {\n  const tiedosto = process.argv[3];\n  const { privateKey } = lataaAvaimet();\n  const sig = allekirjoita(readFileSync(tiedosto), privateKey);\n  console.log(sig.toString('base64'));\n} else if (komento === 'verify') {\n  const tiedosto = process.argv[3];\n  const sigB64 = process.argv[4];\n  const { publicKey } = lataaAvaimet();\n  const ok = vahvista(readFileSync(tiedosto), sigB64, publicKey);\n  console.log(ok ? 'KELVOLLINEN' : 'HYLATTY');\n  process.exit(ok ? 0 : 1);\n} else {\n  console.log('Kaytt\u00f6: node src\/cli.js [keygen|sign &lt;tiedosto&gt;|verify &lt;tiedosto&gt; &lt;sig&gt;]');\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ty\u00f6nkulku on suoraviivainen. Luo avaimet kerran, allekirjoita tiedostoja tarpeen mukaan ja vahvista ne julkisella avaimella. Huomaa, ett\u00e4 <code>verify<\/code>-komento palauttaa my\u00f6s oikean poistumiskoodin (0 onnistuessa, 1 ep\u00e4onnistuessa), joten voit ketjuttaa sen shell-skripteihin ja CI-putkiin.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ node src\/cli.js keygen\nAvaimet tallennettu kansioon keys\/\n\n$ echo \"julkaisu v1.0.0\" > release.txt\n$ node src\/cli.js sign release.txt\n8Xk2...lWfQ==   # 64 tavun allekirjoitus base64-muodossa\n\n$ node src\/cli.js verify release.txt \"8Xk2...lWfQ==\"\nKELVOLLINEN<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-7-jwt-tokenit-eddsa-algoritmilla\">Vaihe 7: JWT-tokenit EdDSA-algoritmilla<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Yksi suosituimmista Ed25519:n k\u00e4ytt\u00f6tapauksista on JWT-tokenien allekirjoitus. JOSE-standardissa Ed25519-allekirjoituksen algoritmitunniste on <code>EdDSA<\/code>. Verrattuna yleiseen HMAC-pohjaiseen <code>HS256<\/code>-algoritmiin EdDSA on ep\u00e4symmetrinen: palvelin allekirjoittaa salaisella avaimella, ja kuka tahansa voi vahvistaa tokenin julkisella avaimella ilman p\u00e4\u00e4sy\u00e4 salaiseen avaimeen. T\u00e4m\u00e4 on ihanteellista mikropalveluarkkitehtuurissa.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Node.js:n <code>crypto<\/code> ei tarjoa valmista JWT-kerrosta, joten k\u00e4yt\u00e4mme t\u00e4h\u00e4n moderneja standardeja noudattavaa <code>jose<\/code>-kirjastoa (versio 5). Asenna se ensin.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install jose<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/jwt.js\nimport { SignJWT, jwtVerify, generateKeyPair } from 'jose';\n\nconst { publicKey, privateKey } = await generateKeyPair('EdDSA', {\n  crv: 'Ed25519',\n});\n\n\/\/ Allekirjoita token\nconst token = await new SignJWT({ rooli: 'admin', sub: 'kayttaja-42' })\n  .setProtectedHeader({ alg: 'EdDSA' })\n  .setIssuedAt()\n  .setIssuer('shattered.io')\n  .setExpirationTime('1h')\n  .sign(privateKey);\n\nconsole.log('Token:', token);\n\n\/\/ Vahvista token\nconst { payload } = await jwtVerify(token, publicKey, {\n  issuer: 'shattered.io',\n});\nconsole.log('Hy\u00f6tykuorma:', payload);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">T\u00e4m\u00e4 tuottaa JWT:n, jonka otsakkeessa lukee <code>\"alg\":\"EdDSA\"<\/code>. Token on lyhyt ja allekirjoitus nopea, mik\u00e4 on etu suuren liikenteen API:ssa. Jos haluat syventy\u00e4 JWT-todennuksen kokonaiskuvaan istuntojen, p\u00e4\u00e4ttymisaikojen ja virkistystokenien kanssa, lue erillinen oppaamme <a href=\"\/fi\/jwt-todennus-nodejs\/\">JWT-todennuksesta Node.js:ss\u00e4<\/a>. T\u00e4rkein turvas\u00e4\u00e4nt\u00f6 EdDSA-tokeneissa on sama kuin aina: m\u00e4\u00e4rit\u00e4 vahvistuksessa sallittu algoritmi eksplisiittisesti, jotta hy\u00f6kk\u00e4\u00e4j\u00e4 ei voi vaihtaa sit\u00e4 esimerkiksi arvoon <code>none<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-8-raakojen-avainten-ja-jwk-muodon-kasittely\">Vaihe 8: Raakojen avainten ja JWK-muodon k\u00e4sittely<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Joskus tarvitset pelk\u00e4t 32 raakatavua, esimerkiksi kun integroit j\u00e4rjestelm\u00e4\u00e4n, joka odottaa Ed25519-avaimen ilman ASN.1-otsaketta, tai kun siirr\u00e4t avaimen selaimen WebCrypto-rajapinnalle. Helpoin tapa Node.js:ss\u00e4 on vied\u00e4 avain JWK-muotoon (JSON Web Key) ja lukea sielt\u00e4 <code>x<\/code>-kentt\u00e4, joka sis\u00e4lt\u00e4\u00e4 raa&#8217;an julkisen avaimen base64url-koodattuna.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/raw.js\nimport { generateKeyPairSync, createPublicKey } from 'crypto';\n\nconst { publicKey } = generateKeyPairSync('ed25519');\n\n\/\/ Vie JWK-muotoon\nconst jwk = publicKey.export({ format: 'jwk' });\nconsole.log('JWK:', jwk);\n\/\/ { crv: 'Ed25519', x: 'xwEQNL...V6o', kty: 'OKP' }\n\n\/\/ Pura raaka 32 tavun julkinen avain\nconst raaka = Buffer.from(jwk.x, 'base64url');\nconsole.log('Raaka julkinen avain:', raaka.length, 'tavua');\n\n\/\/ Rakenna KeyObject takaisin raakatavuista JWK:n kautta\nconst palautettu = createPublicKey({\n  key: { kty: 'OKP', crv: 'Ed25519', x: raaka.toString('base64url') },\n  format: 'jwk',\n});\nconsole.log('Palautus onnistui:', palautettu.asymmetricKeyType);<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>$ node src\/raw.js\nJWK: { kty: 'OKP', crv: 'Ed25519', x: 'xwEQNL...V6o' }\nRaaka julkinen avain: 32 tavua\nPalautus onnistui: ed25519<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">JWK on my\u00f6s JOSE-ekosysteemin oletusformaatti, joten t\u00e4m\u00e4 sama esitys kelpaa suoraan JWT-vahvistukseen ja avaintenjakelupisteille (JWKS). Kirjaintunniste <code>OKP<\/code> tarkoittaa &#8220;Octet Key Pair&#8221;, joka on JOSE:n nimi Edwards-k\u00e4yr\u00e4n avaimille. Raakatavuesitys on tiivein mahdollinen ja sopii tilanteisiin, joissa jokainen tavu on kallis, kuten lohkoketjuissa tai sulautetuissa laitteissa.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-9-valmis-projekti-tiedostojen-eheyden-varmistus\">Vaihe 9: Valmis projekti, tiedostojen eheyden varmistus<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Kootaan kaikki yhteen t\u00e4ydeksi, k\u00e4yt\u00e4nn\u00f6lliseksi projektiksi: ty\u00f6kalu, joka allekirjoittaa kokonaisen hakemiston tiedostot ja tuottaa manifestin, jonka avulla voi my\u00f6hemmin todistaa, ettei yksik\u00e4\u00e4n tiedosto ole muuttunut. T\u00e4m\u00e4 on sama periaate, jolla Linux-jakelut allekirjoittavat pakettinsa ja jolla ohjelmistojulkaisut suojataan peukalointia vastaan.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/manifest.js\nimport { readFileSync, writeFileSync, readdirSync, statSync } from 'fs';\nimport { join } from 'path';\nimport { createHash } from 'crypto';\nimport { lataaAvaimet } from '.\/storage.js';\nimport { allekirjoita } from '.\/sign.js';\nimport { vahvista } from '.\/verify.js';\n\nfunction hajauta(polku) {\n  return createHash('sha256').update(readFileSync(polku)).digest('hex');\n}\n\nfunction listaa(hakemisto) {\n  return readdirSync(hakemisto)\n    .map((nimi) => join(hakemisto, nimi))\n    .filter((p) => statSync(p).isFile());\n}\n\nexport function luoManifesti(kohdeHakemisto) {\n  const { privateKey } = lataaAvaimet();\n  const tiedostot = listaa(kohdeHakemisto).reduce((acc, p) => {\n    acc[p] = hajauta(p);\n    return acc;\n  }, {});\n\n  const sisalto = JSON.stringify(tiedostot);\n  const sig = allekirjoita(sisalto, privateKey).toString('base64');\n  writeFileSync('manifest.json', JSON.stringify({ tiedostot, sig }, null, 2));\n  console.log(`Allekirjoitettu ${Object.keys(tiedostot).length} tiedostoa`);\n}\n\nexport function tarkistaManifesti() {\n  const { publicKey } = lataaAvaimet();\n  const { tiedostot, sig } = JSON.parse(readFileSync('manifest.json'));\n\n  \/\/ 1. Vahvista manifestin allekirjoitus\n  if (!vahvista(JSON.stringify(tiedostot), sig, publicKey)) {\n    throw new Error('Manifestin allekirjoitus on virheellinen');\n  }\n  \/\/ 2. Vertaa jokaisen tiedoston nykyinen hajautus tallennettuun\n  for (const [polku, odotettu] of Object.entries(tiedostot)) {\n    if (hajauta(polku) !== odotettu) {\n      throw new Error(`Tiedosto muuttunut: ${polku}`);\n    }\n  }\n  console.log('Kaikki tiedostot eheit\u00e4 ja allekirjoitus kelvollinen');\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Logiikka on kaksitasoinen ja siksi vahva. Ensin se laskee jokaisesta tiedostosta SHA-256-hajautuksen ja kokoaa ne JSON-rakenteeseen. Sitten se allekirjoittaa koko rakenteen Ed25519:ll\u00e4. Tarkistuksessa allekirjoitus vahvistetaan ensin, mik\u00e4 takaa ett\u00e4 hajautuslista itsess\u00e4\u00e4n on aito, ja vasta sitten verrataan kunkin tiedoston nykyist\u00e4 hajautusta. Yksikin muuttunut tavu miss\u00e4 tahansa tiedostossa tai itse manifestissa johtaa hylk\u00e4ykseen. SHA-256:n roolista voit lukea lis\u00e4\u00e4 <a href=\"\/fi\/sha-256\/\">SHA-256-artikkelistamme<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">T\u00e4m\u00e4 projekti on jo tuotantokelpoinen pohja. Lis\u00e4\u00e4m\u00e4ll\u00e4 aikaleiman, version ja allekirjoittajan tunnisteen manifestiin saat t\u00e4yden ohjelmistojulkaisun allekirjoitusj\u00e4rjestelm\u00e4n alle 200 koodirivill\u00e4, ilman ainuttakaan raskasta riippuvuutta.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vaihe-10-webhook-allekirjoitusten-vahvistus-expressissa\">Vaihe 10: Webhook-allekirjoitusten vahvistus Expressiss\u00e4<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Yksi yleisimmist\u00e4 reaalimaailman k\u00e4ytt\u00f6tapauksista on saapuvien webhookien aitouden tarkistus. Kun ulkoinen palvelu (maksunv\u00e4litt\u00e4j\u00e4, GitHub, oma mikropalvelusi) l\u00e4hett\u00e4\u00e4 sinulle HTTP-pyynn\u00f6n, haluat varmistua ett\u00e4 pyynt\u00f6 tuli aidolta l\u00e4hett\u00e4j\u00e4lt\u00e4 eik\u00e4 huijarilta. L\u00e4hett\u00e4j\u00e4 allekirjoittaa pyynn\u00f6n rungon Ed25519-salaisella avaimellaan ja liitt\u00e4\u00e4 allekirjoituksen otsakkeeseen. Sin\u00e4 vahvistat sen heid\u00e4n julkisella avaimellaan.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">T\u00e4ss\u00e4 on kriittinen yksityiskohta, joka kaataa monta toteutusta: allekirjoitus lasketaan tarkalleen niist\u00e4 raakatavuista, jotka kulkivat verkossa. Jos j\u00e4senn\u00e4t rungon JSON-objektiksi ja sarjallistat sen uudelleen, tavut muuttuvat (avainj\u00e4rjestys, v\u00e4lily\u00f6nnit) ja vahvistus ep\u00e4onnistuu. Siksi k\u00e4yt\u00e4mme <code>express.raw<\/code>-v\u00e4liohjelmistoa, joka antaa meille koskemattoman rungon Bufferina.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/webhook.js\nimport express from 'express';\nimport { verify, createPublicKey } from 'crypto';\nimport { readFileSync } from 'fs';\n\nconst app = express();\n\/\/ Tarvitsemme RAA'AN rungon, ei j\u00e4sennelty\u00e4 JSON:ia\napp.use(express.raw({ type: '*\/*' }));\n\nconst lahettajanAvain = createPublicKey(readFileSync('keys\/public.pem'));\n\napp.post('\/webhook', (req, res) => {\n  const otsake = req.get('X-Signature');\n  if (!otsake) return res.status(400).send('Allekirjoitus puuttuu');\n\n  const sig = Buffer.from(otsake, 'base64');\n  const aito = verify(null, req.body, lahettajanAvain, sig);\n\n  if (!aito) {\n    console.warn('Hyl\u00e4tty webhook: virheellinen allekirjoitus');\n    return res.status(401).send('Virheellinen allekirjoitus');\n  }\n\n  const data = JSON.parse(req.body.toString('utf8'));\n  console.log('Aito webhook vastaanotettu:', data.tapahtuma);\n  res.status(200).send('OK');\n});\n\napp.listen(3000, () => console.log('Webhook-palvelin portissa 3000'));<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vahvistuksen j\u00e4lkeen, ja vasta sitten, j\u00e4senn\u00e4mme rungon JSON:iksi. J\u00e4rjestys on t\u00e4rke\u00e4: \u00e4l\u00e4 koskaan luota dataan ennen kuin allekirjoitus on tarkistettu. T\u00e4m\u00e4 malli suojaa kahdelta hy\u00f6kk\u00e4ykselt\u00e4 kerralla. Ensinn\u00e4kin huijari ei voi v\u00e4\u00e4rent\u00e4\u00e4 pyynt\u00f6\u00e4 ilman salaista avainta. Toiseksi, jos joku muuttaa rungon yht\u00e4kin tavua matkalla, vahvistus hylk\u00e4\u00e4 sen. Ep\u00e4symmetrinen malli on t\u00e4ss\u00e4 erityisen hy\u00f6dyllinen: vastaanottajan ei tarvitse jakaa mit\u00e4\u00e4n salaisuutta l\u00e4hett\u00e4j\u00e4n kanssa, vaan pelkk\u00e4 julkinen avain riitt\u00e4\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tuotannossa kannattaa lis\u00e4t\u00e4 my\u00f6s aikaleima allekirjoitettuun runkoon ja hyl\u00e4t\u00e4 liian vanhat pyynn\u00f6t, jotta hy\u00f6kk\u00e4\u00e4j\u00e4 ei voi toistaa vanhaa kelvollista pyynt\u00f6\u00e4 (replay-hy\u00f6kk\u00e4ys). Aikaleima sis\u00e4llytet\u00e4\u00e4n allekirjoitettuun dataan, jolloin sit\u00e4 ei voi muuttaa havaitsematta. T\u00e4m\u00e4 on sama suojaperiaate, jota k\u00e4ytet\u00e4\u00e4n esimerkiksi maksurajapintojen webhookeissa.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ed25519-vs-hmac-milloin-kumpaakin-kaytetaan\">Ed25519 vs HMAC: milloin kumpaakin k\u00e4ytet\u00e4\u00e4n<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ed25519 ja HMAC ratkaisevat osin samaa ongelmaa, viestin aitouden ja eheyden, mutta hyvin eri tavoin. Ero on symmetria. HMAC k\u00e4ytt\u00e4\u00e4 yht\u00e4 jaettua salaista avainta: sama avain sek\u00e4 luo ett\u00e4 vahvistaa tarkistussumman. Ed25519 on ep\u00e4symmetrinen: salainen avain allekirjoittaa, julkinen avain vahvistaa. T\u00e4m\u00e4 yksi ero m\u00e4\u00e4r\u00e4\u00e4 l\u00e4hes kaiken muun.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Ominaisuus<\/th><th>Ed25519<\/th><th>HMAC-SHA256<\/th><\/tr><\/thead><tbody><tr><td>Avainmalli<\/td><td>Ep\u00e4symmetrinen<\/td><td>Symmetrinen (jaettu salaisuus)<\/td><\/tr><tr><td>Vahvistaja tarvitsee<\/td><td>Vain julkisen avaimen<\/td><td>Saman salaisen avaimen<\/td><\/tr><tr><td>Kuka voi luoda allekirjoituksen<\/td><td>Vain salaisen avaimen haltija<\/td><td>Kuka tahansa salaisuuden tiet\u00e4v\u00e4<\/td><\/tr><tr><td>Kiist\u00e4m\u00e4tt\u00f6myys<\/td><td>Kyll\u00e4<\/td><td>Ei<\/td><\/tr><tr><td>Tulosteen koko<\/td><td>64 tavua<\/td><td>32 tavua<\/td><\/tr><tr><td>Nopeus<\/td><td>Nopea<\/td><td>Eritt\u00e4in nopea<\/td><\/tr><tr><td>Paras k\u00e4ytt\u00f6<\/td><td>Julkinen vahvistus, useat osapuolet<\/td><td>Sama osapuoli molemmissa p\u00e4iss\u00e4<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Valinta on k\u00e4yt\u00e4nn\u00f6ss\u00e4 yksinkertainen. Jos sama luotettu j\u00e4rjestelm\u00e4 sek\u00e4 luo ett\u00e4 tarkistaa tarkistussumman (esimerkiksi istuntoev\u00e4ste, jonka oma palvelimesi allekirjoittaa ja tarkistaa), HMAC on nopeampi ja yksinkertaisempi. Jos taas eri osapuolet luovat ja vahvistavat (julkiset webhookit, ohjelmistojulkaisut, hajautetut j\u00e4rjestelm\u00e4t), Ed25519 on oikea valinta, koska sinun ei tarvitse luovuttaa salaista avainta vahvistajalle. HMAC:n yksityiskohdat l\u00f6yd\u00e4t <a href=\"\/fi\/hmac-node-js\/\">HMAC-oppaastamme<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">T\u00e4rke\u00e4 turvaero on kiist\u00e4m\u00e4tt\u00f6myys. Koska HMAC:n salaisuus on jaettu, kumpi tahansa osapuoli on voinut luoda tarkistussumman, joten et voi todistaa kolmannelle osapuolelle kuka sen teki. Ed25519:ll\u00e4 vain salaisen avaimen haltija on voinut allekirjoittaa, joten allekirjoitus on todiste alkuper\u00e4st\u00e4. T\u00e4m\u00e4 on syy siihen, miksi lailliset asiakirjat, ohjelmistopaketit ja lohkoketjutransaktiot k\u00e4ytt\u00e4v\u00e4t nimenomaan ep\u00e4symmetrisi\u00e4 allekirjoituksia, ei HMAC:ia.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ed25519-reaalimaailmassa-ssh-tls-ja-lohkoketjut\">Ed25519 reaalimaailmassa: SSH, TLS ja lohkoketjut<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Kun ymm\u00e4rr\u00e4t miten Ed25519 toimii koodissa, kannattaa n\u00e4hd\u00e4 miss\u00e4 kohtaamasi j\u00e4rjestelm\u00e4t jo k\u00e4ytt\u00e4v\u00e4t sit\u00e4. T\u00e4m\u00e4 auttaa hahmottamaan, miksi algoritmi on niin keskeinen modernissa tietoturvassa.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">SSH on selkein esimerkki. Kun luot uuden SSH-avaimen komennolla <code>ssh-keygen -t ed25519<\/code>, saat t\u00e4sm\u00e4lleen saman 32 tavun julkisen avaimen, jonka t\u00e4m\u00e4n oppaan koodi tuottaa. OpenSSH on suositellut Ed25519:\u00e4\u00e4 RSA:n sijaan jo vuosia, koska se on nopeampi, lyhyempi ja turvallisempi oletusarvoilla. Jos avaat tiedoston <code>~\/.ssh\/id_ed25519.pub<\/code>, n\u00e4et saman julkisen avaimen base64-koodattuna. Voit jopa allekirjoittaa tiedostoja SSH-avaimellasi komennolla <code>ssh-keygen -Y sign<\/code>, mik\u00e4 k\u00e4ytt\u00e4\u00e4 sis\u00e4isesti samaa Ed25519-operaatiota kuin <code>crypto.sign<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">TLS 1.3 -k\u00e4ttelyss\u00e4 palvelin voi esitt\u00e4\u00e4 EdDSA-allekirjoitetun sertifikaatin. Vaikka useimmat julkiset varmenneviranomaiset k\u00e4ytt\u00e4v\u00e4t yh\u00e4 ECDSA:ta tai RSA:ta yhteensopivuussyist\u00e4, sis\u00e4isiss\u00e4 PKI-j\u00e4rjestelmiss\u00e4 ja modernissa palveluverkossa Ed25519-sertifikaatit yleistyv\u00e4t. Niiden etu on pieni koko ja nopea k\u00e4ttely, mik\u00e4 v\u00e4hent\u00e4\u00e4 viivett\u00e4 jokaisessa yhteydess\u00e4. HTTPS:n ja TLS:n kokonaiskuvasta voit lukea <a href=\"\/fi\/https-ja-tls\/\">HTTPS- ja TLS-artikkelistamme<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lohkoketjut ovat ehk\u00e4 n\u00e4kyvin Ed25519:n k\u00e4ytt\u00f6alue. Useat suuret verkot, kuten Solana, Cardano, Stellar ja Monero, k\u00e4ytt\u00e4v\u00e4t Ed25519:\u00e4\u00e4 transaktioiden allekirjoitukseen. Syy on sama kuin aina: pieni avain ja allekirjoitus s\u00e4\u00e4st\u00e4v\u00e4t arvokasta lohkotilaa, deterministisyys poistaa nonce-vuotoriskin, ja vahvistus on nopeaa kun tuhansia transaktioita pit\u00e4\u00e4 tarkistaa sekunnissa. Kun siirr\u00e4t varoja t\u00e4llaisessa verkossa, lompakkosi tekee tarkalleen saman <code>sign<\/code>-operaation kuin vaiheessa 4 rakentamasi funktio.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">My\u00f6s Signal-protokolla, age-salausty\u00f6kalu, Tor-verkon uudemmat palvelutunnisteet ja lukuisat pakettienhallintaj\u00e4rjestelm\u00e4t nojaavat Ed25519:\u00e4\u00e4n. Kun hallitset t\u00e4m\u00e4n oppaan koodin, ymm\u00e4rr\u00e4t siis suuren osan modernin tietoturvainfrastruktuurin allekirjoituskerroksesta. Sama 64 tavun allekirjoitus suojaa niin SSH-kirjautumistasi, ohjelmistop\u00e4ivityksi\u00e4si kuin kryptolompakkoasi.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"yleiset-sudenkuopat-ja-miten-valtat-ne\">Yleiset sudenkuopat ja miten v\u00e4lt\u00e4t ne<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ed25519 on yksinkertainen k\u00e4ytt\u00e4\u00e4, mutta muutama virhe toistuu jatkuvasti. T\u00e4ss\u00e4 viisi yleisint\u00e4 sudenkuoppaa ja niiden korjaukset.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1. Ed25519:n k\u00e4ytt\u00f6 salaukseen.<\/strong> T\u00e4m\u00e4 on ehdottomasti yleisin virhe. Ed25519 tekee vain allekirjoituksia, se ei salaa mit\u00e4\u00e4n. Jos haluat salata dataa tai vaihtaa avaimia, k\u00e4yt\u00e4t X25519:\u00e4\u00e4 (samaa k\u00e4yr\u00e4\u00e4 eri funktiolla) yhdess\u00e4 symmetrisen salaajan kuten AES-256-GCM:n tai ChaCha20-Poly1305:n kanssa. \u00c4l\u00e4 koskaan yrit\u00e4 &#8220;salata&#8221; julkisella allekirjoitusavaimella.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>2. Ed25519:n ja Curve25519\/X25519:n sekoittaminen.<\/strong> Ne pohjautuvat samaan matemaattiseen k\u00e4yr\u00e4\u00e4n, mutta ovat eri tarkoituksiin: Ed25519 allekirjoituksiin, X25519 avaintenvaihtoon. Et voi k\u00e4ytt\u00e4\u00e4 Ed25519-avainta avaintenvaihtoon suoraan. Tunnista oikea ty\u00f6kalu nimell\u00e4 ennen kuin valitset.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3. Hajautusfunktion nimen antaminen sign-funktiolle.<\/strong> Kuten vaiheessa 4 korostettiin, <code>crypto.sign('sha256', ...)<\/code> heitt\u00e4\u00e4 virheen Ed25519:lle. Ensimm\u00e4isen argumentin on oltava <code>null<\/code>, koska algoritmi hajauttaa viestin sis\u00e4isesti SHA-512:lla.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>4. Salaisen avaimen tallennus versionhallintaan.<\/strong> Salainen avain on koko j\u00e4rjestelm\u00e4n turvallisuuden perusta. Jos se vuotaa Git-historiaan tai lokitiedostoon, hy\u00f6kk\u00e4\u00e4j\u00e4 voi v\u00e4\u00e4rent\u00e4\u00e4 mink\u00e4 tahansa allekirjoituksen. Lis\u00e4\u00e4 <code>keys\/<\/code> heti <code>.gitignore<\/code>-tiedostoon ja harkitse salaisen avaimen salasanasuojausta tai KMS-s\u00e4ilytyst\u00e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>5. Koodausten sekaannus allekirjoituksessa.<\/strong> Jos allekirjoitat raakatavuista mutta vahvistat merkkijonosta (tai sekoitat base64:n ja heksan), vahvistus ep\u00e4onnistuu vaikka avaimet olisivat oikein. P\u00e4\u00e4t\u00e4 yksi koodaus (suosittelen base64:\u00e4\u00e4 tai base64url:\u00e4\u00e4) ja k\u00e4yt\u00e4 sit\u00e4 johdonmukaisesti koko ketjussa. Muista my\u00f6s, ett\u00e4 UTF-8-merkkijono pit\u00e4\u00e4 koodata samalla tavalla molemmissa p\u00e4iss\u00e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vianmaaritys-8-yleista-virhetta-ja-ratkaisut\">Vianm\u00e4\u00e4ritys: 8 yleist\u00e4 virhett\u00e4 ja ratkaisut<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Kun jokin menee pieleen, virheilmoitus on harvoin itsest\u00e4\u00e4n selv\u00e4. T\u00e4m\u00e4 taulukko kokoaa kahdeksan yleisint\u00e4 Ed25519-virhett\u00e4 Node.js:ss\u00e4 ja niiden korjaukset.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Oire tai virhe<\/th><th>Syy<\/th><th>Ratkaisu<\/th><\/tr><\/thead><tbody><tr><td><code>ERR_OSSL_EVP_UNSUPPORTED<\/code><\/td><td>OpenSSL-versio ei tue Ed25519:\u00e4\u00e4 tai avain on v\u00e4\u00e4r\u00e4ss\u00e4 muodossa<\/td><td>P\u00e4ivit\u00e4 Node.js 20+ (OpenSSL 3) ja varmista avaimen tyyppi<\/td><\/tr><tr><td>verify palauttaa aina false<\/td><td>Viestin koodaus eroaa allekirjoituksen ja vahvistuksen v\u00e4lill\u00e4<\/td><td>K\u00e4yt\u00e4 samaa Buffer-koodausta (utf8) molemmissa p\u00e4iss\u00e4<\/td><\/tr><tr><td><code>error:... wrong tag<\/code> avainta ladatessa<\/td><td>Yritet\u00e4\u00e4n ladata julkista avainta salaisena tai p\u00e4invastoin<\/td><td>K\u00e4yt\u00e4 createPublicKey julkiselle, createPrivateKey salaiselle<\/td><\/tr><tr><td>sign heitt\u00e4\u00e4 virheen algoritmista<\/td><td>Annettu hajautusfunktion nimi nullin sijaan<\/td><td>K\u00e4yt\u00e4 <code>sign(null, data, key)<\/code><\/td><\/tr><tr><td><code>ERR_INVALID_ARG_TYPE<\/code><\/td><td>Viesti tai allekirjoitus ei ole Buffer tai TypedArray<\/td><td>Muunna <code>Buffer.from(...)<\/code> ennen kutsua<\/td><\/tr><tr><td>JWT-vahvistus ep\u00e4onnistuu &#8220;alg&#8221; virheell\u00e4<\/td><td>Sallittua algoritmia ei m\u00e4\u00e4ritetty tai se on v\u00e4\u00e4r\u00e4<\/td><td>Aseta otsake <code>alg: 'EdDSA'<\/code> ja salli se vahvistuksessa<\/td><\/tr><tr><td>PEM-tiedosto ei lataudu<\/td><td>Rivinvaihdot tai otsakerivit korruptoituneet<\/td><td>Varmista BEGIN\/END-rivit ja LF-rivinvaihdot<\/td><\/tr><tr><td>Salainen avain pyyt\u00e4\u00e4 salasanaa<\/td><td>Avain on salasanasuojattu mutta lataus ei anna salasanaa<\/td><td>Lis\u00e4\u00e4 <code>passphrase<\/code>-parametri createPrivateKey-kutsuun<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Useimmat ongelmat juontavat kahdesta l\u00e4hteest\u00e4: koodausten ep\u00e4johdonmukaisuudesta tai avaimen muodon sekaannuksesta. Jos verify palauttaa odottamatta false, tulosta sek\u00e4 viesti ett\u00e4 allekirjoitus heksamuodossa molemmissa p\u00e4iss\u00e4 ja vertaa ne tavu tavulta. Yhdeks\u00e4ss\u00e4 tapauksessa kymmenest\u00e4 ongelma l\u00f6ytyy sielt\u00e4. Jos ep\u00e4ilet OpenSSL-tukea, aja <code>node -p process.versions.openssl<\/code> ja varmista ett\u00e4 tulos alkaa numerolla 3.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Salasanasuojattu salainen avain ladataan antamalla <code>passphrase<\/code>-arvo. Esimerkiksi <code>createPrivateKey({ key: pem, format: 'pem', passphrase: 'salasana' })<\/code>. Jos saat virheen &#8220;bad decrypt&#8221;, salasana on v\u00e4\u00e4r\u00e4. T\u00e4m\u00e4 on yleinen kompastuskivi siirrytt\u00e4ess\u00e4 suojaamattomista avaimista tuotantokelpoisiin salattuihin avaimiin.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"edistyneet-vinkit-tuotantokayttoon\">Edistyneet vinkit tuotantok\u00e4ytt\u00f6\u00f6n<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ed25519ph-suurille-tiedostoille\">Ed25519ph suurille tiedostoille<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Perus-Ed25519 (kutsutaan my\u00f6s PureEdDSA) lukee koko viestin kahdesti allekirjoituksen aikana. Eritt\u00e4in suurille tiedostoille t\u00e4m\u00e4 voi olla tehotonta. RFC 8032 m\u00e4\u00e4rittelee my\u00f6s esihajautusvariantin Ed25519ph, joka allekirjoittaa viestin hajautuksen koko viestin sijaan. Node.js:n ydin-API ei suoraan paljasta ph-tilaa, joten k\u00e4yt\u00e4nn\u00f6ss\u00e4 hajautat tiedoston itse SHA-512:lla ja allekirjoitat hajautuksen, tai siirryt libsodiumiin, joka tarjoaa moniosaisen allekirjoitusrajapinnan.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"libsodium-selaimeen-ja-eri-alustoille\">libsodium selaimeen ja eri alustoille<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Jos tarvitset saman koodin selaimessa, palvelimella ja mobiilissa, <code>libsodium-wrappers<\/code> on kyps\u00e4 ja laajalti auditoitu valinta. Se tarjoaa funktiot <code>crypto_sign_keypair<\/code>, <code>crypto_sign_detached<\/code> ja <code>crypto_sign_verify_detached<\/code>, jotka vastaavat t\u00e4m\u00e4n oppaan operaatioita. libsodium k\u00e4ytt\u00e4\u00e4 aina raakoja 32- ja 64-tavuisia esityksi\u00e4, joten se sopii hyvin yhteen vaiheen 8 raakatavujen kanssa. Node.js:n ydin-crypto on silti suositeltava palvelinpuolella, koska se on riippuvuusvapaa ja OpenSSL-pohjainen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"avainten-kierto-ja-kvanttisiirtyma\">Avainten kierto ja kvanttisiirtym\u00e4<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Suunnittele avainten kierto alusta alkaen. Lis\u00e4\u00e4 julkiseen avaimeen tunniste (key ID), jotta voit py\u00f6ritt\u00e4\u00e4 useita avaimia rinnakkain ja vanhentaa vanhat hallitusti. Pitk\u00e4n aikav\u00e4lin riski on kvanttitietokoneet: Ed25519 ei ole kvanttiturvallinen. NIST julkaisi vuonna 2024 standardin ML-DSA (entinen Dilithium) kvanttiturvalliselle allekirjoitukselle. Vuonna 2026 k\u00e4yt\u00e4nn\u00f6n suositus on hybridiallekirjoitus, jossa sama data allekirjoitetaan sek\u00e4 Ed25519:ll\u00e4 ett\u00e4 ML-DSA:lla, jolloin j\u00e4rjestelm\u00e4 on turvallinen niin kauan kuin kumpikaan ei ole murrettu. Lis\u00e4\u00e4 aiheesta l\u00f6yd\u00e4t <a href=\"\/fi\/cryptography-hub\/\">kryptografian teemasivultamme<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"usein-kysytyt-kysymykset\">Usein kysytyt kysymykset<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"onko-ed25519-turvallisempi-kuin-rsa\">Onko Ed25519 turvallisempi kuin RSA?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">K\u00e4yt\u00e4nn\u00f6ss\u00e4 kyll\u00e4, useimmissa skenaarioissa. Ed25519 tarjoaa noin 128 bitin turvatason 32 tavun avaimella, kun RSA-2048 antaa noin 112 bitti\u00e4 paljon suuremmalla avaimella. Ed25519:n determinismi poistaa my\u00f6s nonce-vuotoriskin, joka on kaatanut ECDSA-toteutuksia. RSA ei ole rikki, mutta uusiin j\u00e4rjestelmiin Ed25519 on yleens\u00e4 parempi valinta.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"voiko-ed25519lla-salata-dataa\">Voiko Ed25519:ll\u00e4 salata dataa?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ei. Ed25519 tekee vain digitaalisia allekirjoituksia. Salaukseen ja avaintenvaihtoon k\u00e4ytet\u00e4\u00e4n X25519:\u00e4\u00e4, joka pohjautuu samaan k\u00e4yr\u00e4\u00e4n mutta on eri operaatio. Datan salaukseen yhdist\u00e4t X25519-avaintenvaihdon symmetriseen salaajaan kuten AES-256-GCM:\u00e4\u00e4n.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"mista-node-js-versiosta-ed25519-on-tuettu\">Mist\u00e4 Node.js-versiosta Ed25519 on tuettu?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Node.js on tukenut Ed25519:\u00e4\u00e4 natiivisti versiosta 12 l\u00e4htien. Vuonna 2026 suosittelemme Node.js 24 LTS:\u00e4\u00e4, joka k\u00e4ytt\u00e4\u00e4 OpenSSL 3:a. T\u00e4m\u00e4n oppaan koodi toimii muuttumattomana my\u00f6s Node.js 20:ssa ja 22:ssa.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"miksi-sama-viesti-tuottaa-aina-saman-allekirjoituksen\">Miksi sama viesti tuottaa aina saman allekirjoituksen?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">T\u00e4m\u00e4 on tarkoituksellinen ominaisuus, ei vika. Ed25519 on deterministinen: se johtaa allekirjoituksen sis\u00e4isen kertaluvun salaisesta avaimesta ja viestist\u00e4 eik\u00e4 satunnaisluvusta. T\u00e4m\u00e4 poistaa satunnaislukugeneraattorin heikkouksiin liittyv\u00e4t avainvuodot, jotka vaivaavat ECDSA:ta.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"kuinka-suuri-ed25519-allekirjoitus-on\">Kuinka suuri Ed25519-allekirjoitus on?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Aina tasan 64 tavua, viestin pituudesta riippumatta. Julkinen avain on 32 raakatavua (44 tavua SPKI-DER-muodossa) ja salainen avain 32 raakatavua (48 tavua PKCS#8-DER-muodossa). Pieni koko on yksi Ed25519:n suurimmista eduista.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"onko-ed25519-kvanttiturvallinen\">Onko Ed25519 kvanttiturvallinen?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ei. Kuten kaikki elliptisen k\u00e4yr\u00e4n ja RSA-pohjaiset skeemat, Ed25519 olisi haavoittuvainen riitt\u00e4v\u00e4n tehokkaalle kvanttitietokoneelle, joka ajaa Shorin algoritmia. T\u00e4m\u00e4 ei ole akuutti uhka vuonna 2026, mutta pitk\u00e4n aikav\u00e4lin j\u00e4rjestelmiss\u00e4 kannattaa suunnitella hybridiratkaisu NIST:n standardoiman ML-DSA:n kanssa.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"tarvitsenko-ulkoisen-kirjaston-ed25519lle-node-jsssa\">Tarvitsenko ulkoisen kirjaston Ed25519:lle Node.js:ss\u00e4?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Et perusoperaatioihin. Node.js:n sis\u00e4\u00e4nrakennettu <code>crypto<\/code>-moduuli hoitaa avainten luonnin, allekirjoituksen ja vahvistuksen ilman riippuvuuksia. Ulkoista kirjastoa kuten <code>jose<\/code> tarvitset vain JWT-tokeneihin ja <code>libsodium-wrappers<\/code> jos haluat saman koodin selaimeen tai esihajautustilan.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"mita-eroa-on-ed25519lla-ja-ed448lla\">Mit\u00e4 eroa on Ed25519:ll\u00e4 ja Ed448:lla?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Molemmat ovat EdDSA-variantteja RFC 8032:ssa. Ed25519 tarjoaa noin 128 bitin turvatason 32 tavun avaimella ja 64 tavun allekirjoituksella, kun Ed448 nostaa turvatason noin 224 bittiin suuremmilla 57 tavun avaimilla ja 114 tavun allekirjoituksilla. K\u00e4yt\u00e4nn\u00f6ss\u00e4 l\u00e4hes kaikki k\u00e4ytt\u00e4v\u00e4t Ed25519:\u00e4\u00e4, koska sen turvataso riitt\u00e4\u00e4 reilusti ja se on nopeampi ja tiiviimpi. Ed448 on harvinainen erikoistapaus eritt\u00e4in pitk\u00e4ik\u00e4isille avaimille.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"voinko-vahvistaa-node-jsssa-luodun-allekirjoituksen-selaimessa\">Voinko vahvistaa Node.js:ss\u00e4 luodun allekirjoituksen selaimessa?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Kyll\u00e4. Selaimen WebCrypto-rajapinta tukee Ed25519:\u00e4\u00e4 moderneissa selaimissa, ja voit tuoda julkisen avaimen JWK-muodossa vaiheen 8 mukaisesti. Vaihtoehtoisesti <code>libsodium-wrappers<\/code> toimii identtisesti sek\u00e4 Node.js:ss\u00e4 ett\u00e4 selaimessa. Allekirjoitus ja avain ovat samat tavut alustasta riippumatta, kunhan k\u00e4yt\u00e4t samaa koodausta.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"aiheeseen-liittyvaa\">Aiheeseen liittyv\u00e4\u00e4<\/h3>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"\/fi\/digitaaliset-allekirjoitukset\/\">Digitaaliset allekirjoitukset: miten ne toimivat<\/a><\/li><li><a href=\"\/fi\/jwt-todennus-nodejs\/\">JWT-todennus Node.js:ss\u00e4: 12 vaihetta<\/a><\/li><li><a href=\"\/fi\/hmac-node-js\/\">HMAC-SHA256 Node.js:ss\u00e4<\/a><\/li><li><a href=\"\/fi\/sha-256\/\">SHA-256 selitettyn\u00e4<\/a><\/li><li><a href=\"\/fi\/hash-funktiot\/\">Kryptografiset hajautusfunktiot<\/a><\/li><li><a href=\"\/fi\/cryptography-hub\/\">Kryptografia: kattava teemasivu<\/a><\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ulkoiset-lahteet\">Ulkoiset l\u00e4hteet<\/h3>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8032\" target=\"_blank\" rel=\"noopener\">RFC 8032: EdDSA (Ed25519 ja Ed448)<\/a><\/li><li><a href=\"https:\/\/nodejs.org\/api\/crypto.html\" target=\"_blank\" rel=\"noopener\">Node.js crypto -moduulin dokumentaatio<\/a><\/li><li><a href=\"https:\/\/ed25519.cr.yp.to\/\" target=\"_blank\" rel=\"noopener\">Ed25519-algoritmin alkuper\u00e4issivu<\/a><\/li><li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc8037\" target=\"_blank\" rel=\"noopener\">RFC 8037: EdDSA JOSE- ja JWT-k\u00e4ytt\u00f6\u00f6n<\/a><\/li><li><a href=\"https:\/\/doc.libsodium.org\/\" target=\"_blank\" rel=\"noopener\">libsodium-kirjaston dokumentaatio<\/a><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><em>P\u00e4ivitetty 16. kes\u00e4kuuta 2026. Kaikki koodiesimerkit testattu Node.js 20:lla ja toimivat my\u00f6s Node.js 24 LTS:ll\u00e4.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ed25519 on noussut modernin digitaalisen allekirjoituksen oletusvalinnaksi. Avain on vain 32 tavua, allekirjoitus 64 tavua, ja turvataso vastaa noin 128:aa bitti\u00e4. T\u00e4ss\u00e4 oppaassa rakennat t\u00e4ysin toimivan allekirjoitusj\u00e4rjestelm\u00e4n pelk\u00e4ll\u00e4 Node.js:n sis\u00e4\u00e4nrakennetulla\u2026<\/p>\n","protected":false},"author":9,"featured_media":93,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,2],"tags":[],"class_list":["post-92","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-10","category-cryptography"],"_links":{"self":[{"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/posts\/92","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/comments?post=92"}],"version-history":[{"count":1,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/posts\/92\/revisions"}],"predecessor-version":[{"id":94,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/posts\/92\/revisions\/94"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/media\/93"}],"wp:attachment":[{"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/media?parent=92"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/categories?post=92"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/shattered.io\/fi\/wp-json\/wp\/v2\/tags?post=92"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}