{"id":145,"date":"2026-06-20T20:58:44","date_gmt":"2026-06-20T20:58:44","guid":{"rendered":"https:\/\/shattered.io\/no\/2026\/06\/20\/ecdsa-digital-signatures-nodejs\/"},"modified":"2026-06-28T23:49:15","modified_gmt":"2026-06-28T23:49:15","slug":"ecdsa-digital-signatures-nodejs","status":"publish","type":"post","link":"https:\/\/shattered.io\/no\/ecdsa-digital-signatures-nodejs\/","title":{"rendered":"ECDSA Digitale Signaturer i Node.js: 12 Steg, 30 Min [2026]"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">ECDSA (Elliptic Curve Digital Signature Algorithm) gir kryptografisk sterk autentisering med n\u00f8kler som er 10 ganger kortere enn RSA. En P-256-n\u00f8kkel p\u00e5 256 bit gir den samme 128-bits sikkerheten som en RSA-n\u00f8kkel p\u00e5 3 072 bit, og selve signeringsoperasjonen tar under 1 millisekund p\u00e5 moderne maskinvare. Denne guiden viser deg hvordan du implementerer ECDSA digitale signaturer i Node.js fra starten av, steg for steg, med fullstendige kodeeksempler og et komplett arbeidsprosjekt du kan ta rett i bruk.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hva-er-ecdsa-og-hvorfor-bruke-det-i-node-js\">Hva er ECDSA og hvorfor bruke det i Node.js?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">ECDSA er en digital signeringsalgoritme basert p\u00e5 elliptisk kurve-kryptografi (ECC). Den bruker det matematiske problemet med \u00e5 beregne diskrete logaritmer p\u00e5 en elliptisk kurve for \u00e5 sikre at bare den som eier den private n\u00f8kkelen kan produsere en gyldig signatur, mens hvem som helst med den offentlige n\u00f8kkelen kan verifisere den.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Algoritmen er definert i <a href=\"https:\/\/csrc.nist.gov\/publications\/detail\/fips\/186\/5\/final\" rel=\"noopener noreferrer\" target=\"_blank\">NIST FIPS 186-5<\/a> og brukes i en rekke kritiske protokoller: TLS 1.3-sertifikater, JWT ES256\/ES384, kode-signering i npm, Bitcoin-transaksjoner og SSH-autentisering. Hvis du har verifisert en HTTPS-tilkobling i nettleseren din de siste fem minuttene, er det stor sjanse for at ECDSA var involvert i h\u00e5ndtrykket.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sammenlignet med RSA har ECDSA tre konkrete fordeler for Node.js-utviklere:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Kortere n\u00f8kler og signaturer:<\/strong> P-256 gir 128-bits sikkerhet med 256-bit n\u00f8kler og typisk 71-byte signaturer, mot RSA-3072 sine 3 072-bit n\u00f8kler og 384-byte signaturer. JWT-tokens er 20-30% kortere med ES256 enn RS256.<\/li>\n<li><strong>Raskere signering:<\/strong> ECDSA-signering p\u00e5 P-256 tar typisk 0,31 ms mot RSA-2048-signering p\u00e5 1,21 ms, en 4x ytelsesforbedring. For API-er som signerer mange tokens per sekund, er dette m\u00e5lbart.<\/li>\n<li><strong>Innebygd Node.js-st\u00f8tte:<\/strong> <code>crypto<\/code>-modulen i Node.js st\u00f8tter ECDSA uten eksterne avhengigheter. Du trenger ingen ekstra pakker for grunnleggende n\u00f8kkelgenerering, signering og verifisering.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">En vanlig misforst\u00e5else er at &#8220;kortere n\u00f8kkel betyr svakere sikkerhet&#8221;. Det stemmer ikke for elliptisk kurve-kryptografi. Det diskrete logaritmeproblemet p\u00e5 elliptiske kurver er matematisk hardere enn faktoriseringsproblemet RSA baserer seg p\u00e5, noe som gj\u00f8r kortere n\u00f8kler tilstrekkelig for ekvivalent sikkerhet.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"forutsetninger-og-versjoner\">Forutsetninger og versjoner<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Kontroller at du har f\u00f8lgende installert og konfigurert f\u00f8r du begynner:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Programvare<\/th><th>Minimum versjon<\/th><th>Anbefalt versjon<\/th><th>Sjekk kommando<\/th><\/tr><\/thead><tbody><tr><td>Node.js<\/td><td>18.0.0<\/td><td>22.x LTS<\/td><td><code>node --version<\/code><\/td><\/tr><tr><td>npm<\/td><td>9.0.0<\/td><td>10.x<\/td><td><code>npm --version<\/code><\/td><\/tr><tr><td>OpenSSL<\/td><td>3.0<\/td><td>3.3+<\/td><td><code>openssl version<\/code><\/td><\/tr><tr><td>OS<\/td><td>Linux, macOS, Windows<\/td><td>Linux eller macOS<\/td><td><code>uname -a<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Du b\u00f8r ha grunnleggende kjennskap til JavaScript og asynkron programmering i Node.js. Forst\u00e5else av kryptografiske begreper som offentlig\/privat n\u00f8kkel, hash-funksjoner og digitale signaturer er nyttig, men ikke obligatorisk, ettersom vi forklarer hvert konsept underveis.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For JWT-delen (Steg 8) trenger du <code>jsonwebtoken<\/code>-pakken. Alle andre kodeksempler bruker kun Nodes innebygde <code>crypto<\/code>-modul. Node.js 20+ anbefales for best ytelse med asynkron n\u00f8kkelgenerering og WebCrypto API-integrasjonen i Steg 10.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-1-sett-opp-prosjektet\">Steg 1: Sett opp prosjektet<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Opprett en ny prosjektmappe og initialiser npm. Vi bruker kun innebygde Node.js-moduler for de grunnleggende operasjonene, s\u00e5 ingen ekstra pakkeinstallasjon er n\u00f8dvendig til \u00e5 begynne med.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir ecdsa-demo\ncd ecdsa-demo\nnpm init -y\nmkdir keys output<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Opprett hovedfilen <code>index.js<\/code> med n\u00f8dvendige importer fra <a href=\"https:\/\/nodejs.org\/api\/crypto.html\" rel=\"noopener noreferrer\" target=\"_blank\">Node.js crypto-modulen<\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>'use strict';\n\nconst {\n  generateKeyPairSync,\n  generateKeyPair,\n  createSign,\n  createVerify,\n  createPrivateKey,\n  createPublicKey\n} = require('crypto');\nconst fs   = require('fs');\nconst path = require('path');\n\nconst KEYS_DIR   = path.join(__dirname, 'keys');\nconst OUTPUT_DIR = path.join(__dirname, 'output');\n\n[KEYS_DIR, OUTPUT_DIR].forEach(dir => {\n  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Prosjektstrukturen vil se slik ut etter at alle steg er fullf\u00f8rt:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ecdsa-demo\/\n\u251c\u2500\u2500 index.js            # Hovedskript\n\u251c\u2500\u2500 keys.js             # N\u00f8kkelgenerering\n\u251c\u2500\u2500 signer.js           # Signering\n\u251c\u2500\u2500 verifiser.js        # Verifisering\n\u251c\u2500\u2500 fil-signer.js       # Filsignering via streams\n\u251c\u2500\u2500 jwt-ecdsa.js        # JWT med ES256\n\u251c\u2500\u2500 webcrypto-ecdsa.js  # WebCrypto API-eksempel\n\u251c\u2500\u2500 ecdsa.test.js       # Enhetstester\n\u251c\u2500\u2500 app.js              # Komplett Express API\n\u251c\u2500\u2500 keys\/\n\u2502   \u251c\u2500\u2500 private.pem     # PKCS#8 privat n\u00f8kkel (hold hemmelig)\n\u2502   \u2514\u2500\u2500 public.pem      # SubjectPublicKeyInfo offentlig n\u00f8kkel\n\u2514\u2500\u2500 package.json<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-2-velg-riktig-elliptisk-kurve\">Steg 2: Velg riktig elliptisk kurve<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Valget av kurve er en av de viktigste avgj\u00f8relsene du tar i et ECDSA-oppsett. Ulike kurver tilbyr forskjellige sikkerhetsniv\u00e5er og ytelsesprofiler. Node.js st\u00f8tter alle NIST-kurvene og <code>secp256k1<\/code> (Bitcoin\/Ethereum-kurven).<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Kurve<\/th><th>N\u00f8kkelst\u00f8rrelse<\/th><th>Sikkerhetsbit<\/th><th>RSA-ekvivalent<\/th><th>Typisk bruk<\/th><\/tr><\/thead><tbody><tr><td>P-256 (secp256r1)<\/td><td>256 bit<\/td><td>128<\/td><td>RSA-3072<\/td><td>TLS, JWT ES256, kode-signering<\/td><\/tr><tr><td>P-384 (secp384r1)<\/td><td>384 bit<\/td><td>192<\/td><td>RSA-7680<\/td><td>Statlige og finansielle systemer<\/td><\/tr><tr><td>P-521 (secp521r1)<\/td><td>521 bit<\/td><td>260<\/td><td>RSA-15360+<\/td><td>Sv\u00e6rt h\u00f8y sikkerhetsklassifisering<\/td><\/tr><tr><td>secp256k1<\/td><td>256 bit<\/td><td>128<\/td><td>RSA-3072<\/td><td>Bitcoin, Ethereum, blockchain<\/td><\/tr><tr><td>Ed25519 (EdDSA)*<\/td><td>256 bit<\/td><td>128<\/td><td>RSA-3072<\/td><td>SSH, generell bruk (ikke ECDSA)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">For de fleste Node.js-applikasjoner er <strong>P-256<\/strong> det riktige valget. Den er allment st\u00f8ttet av nettlesere, TLS-biblioteker og JWT-implementasjoner, rask, og gir tilstrekkelig sikkerhet til minst 2030 if\u00f8lge NIST. P-384 er riktig for systemer med strengere regulatoriske krav, for eksempel bankinfrastruktur under PCI DSS eller norske offentlige systemer der NSM-retningslinjene tilsier h\u00f8yere sikkerhetsklassifisering.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>En viktig merknad om secp256k1:<\/strong> Selv om Bitcoin bruker secp256k1, er denne kurven ikke anbefalt for generell bruk utenfor blockchain-kontekster. Den mangler offisiell NIST-verifikasjon og st\u00f8ttes ikke like bredt i TLS-biblioteker. Velg P-256 til web-applikasjoner.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ed25519 er teknisk sett en annen algoritme (EdDSA med Curve25519, ikke ECDSA), men er et fremragende alternativ for SSH-n\u00f8kler og generell signering. Se sammenligning i artikkelen om <a href=\"\/no\/ed25519-vs-rsa\/\">Ed25519 vs RSA: 33x raskere signaturer<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-3-generer-et-ec-nokkelpar\">Steg 3: Generer et EC-n\u00f8kkelpar<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00f8kkelgenerering er f\u00f8rste steg i ethvert kryptografisk system. Vi bruker P-256-kurven som standard. N\u00f8kkelen genereres med kryptografisk sterk tilfeldighet fra operativsystemets CSPRNG (Cryptographically Secure Pseudo-Random Number Generator), h\u00e5ndtert automatisk av OpenSSL via Node.js.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ keys.js - N\u00f8kkelgenerering for ECDSA\n\n'use strict';\nconst { generateKeyPairSync, generateKeyPair } = require('crypto');\nconst fs   = require('fs');\nconst path = require('path');\n\n\/\/ Synkron generering (for scripts og CLI-verkt\u00f8y)\nfunction genererNokkelpar(kurve = 'P-256') {\n  const { privateKey, publicKey } = generateKeyPairSync('ec', {\n    namedCurve: kurve,\n    publicKeyEncoding: {\n      type: 'spki',   \/\/ SubjectPublicKeyInfo - standard for offentlige n\u00f8kler\n      format: 'pem'\n    },\n    privateKeyEncoding: {\n      type: 'pkcs8',  \/\/ PKCS#8 - standard for private n\u00f8kler\n      format: 'pem'\n    }\n  });\n  return { privateKey, publicKey };\n}\n\n\/\/ Asynkron generering (anbefalt for produksjon - blokkerer ikke event loop)\nasync function genererNokkelparAsync(kurve = 'P-256') {\n  return new Promise((resolve, reject) => {\n    generateKeyPair('ec', {\n      namedCurve: kurve,\n      publicKeyEncoding: { type: 'spki', format: 'pem' },\n      privateKeyEncoding: { type: 'pkcs8', format: 'pem' }\n    }, (err, publicKey, privateKey) => {\n      if (err) return reject(err);\n      resolve({ privateKey, publicKey });\n    });\n  });\n}\n\n\/\/ Lagre n\u00f8kler til disk med riktige filrettigheter\nasync function lagreNokler(kurve = 'P-256') {\n  const { privateKey, publicKey } = await genererNokkelparAsync(kurve);\n\n  const privPath = path.join('keys', 'private.pem');\n  const pubPath  = path.join('keys', 'public.pem');\n\n  \/\/ mode 0o600: kun eier kan lese og skrive (ingen andre brukere)\n  fs.writeFileSync(privPath, privateKey, { mode: 0o600 });\n  fs.writeFileSync(pubPath, publicKey);\n\n  console.log(`EC-n\u00f8kkelpar (${kurve}) generert og lagret.`);\n  console.log(`Privat nokkel: ${privPath}`);\n  console.log(`Offentlig nokkel: ${pubPath}`);\n  return { privPath, pubPath };\n}\n\nlagreNokler('P-256').catch(console.error);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Kj\u00f8r skriptet og inspis\u00e9r de genererte n\u00f8klene:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Kjor n\u00f8kkelgenerering\n$ node keys.js\nEC-noekkelpar (P-256) generert og lagret.\nPrivat nokkel: keys\/private.pem\nOffentlig nokkel: keys\/public.pem\n\n# Inspis\u00e9r privat n\u00f8kkel med OpenSSL\n$ openssl pkey -in keys\/private.pem -text -noout\nPrivate-Key: (256 bit)\npriv:\n    00:c9:f3:4a:...\npub:\n    04:7b:e4:1d:...\nASN1 OID: prime256v1\nNIST CURVE: P-256\n\n# Inspis\u00e9r offentlig n\u00f8kkel\n$ openssl pkey -pubin -in keys\/public.pem -text -noout\nPublic-Key: (256 bit)\npub:\n    04:7b:e4:1d:...\nASN1 OID: prime256v1\nNIST CURVE: P-256<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Den genererte private n\u00f8kkelen i PEM-format ser slik ut (PKCS#8-format, ukodet):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8PM7zH3CuSf9Bkx4\n3d5nQ7...dinFI4vRdW4wSGbz6hRANCAAR75B0...\n-----END PRIVATE KEY-----<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-4-signer-data-med-ecdsa\">Steg 4: Signer data med ECDSA<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Signeringsoperasjonen bruker den private n\u00f8kkelen til \u00e5 produsere en kryptografisk signatur for et datasett. Under panseret hasher Node.js meldingen med SHA-256 og signerer hashen med ECDSA via OpenSSL. Signaturen beviser to ting: at avsenderen kontrollerer den private n\u00f8kkelen, og at meldingen ikke er endret siden signeringen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ signer.js - Signering med ECDSA\n\n'use strict';\nconst { createSign } = require('crypto');\nconst fs = require('fs');\n\nfunction signerMelding(melding, privatNokkelPem) {\n  \/\/ createSign tar algoritmespesifikasjonen som argument\n  \/\/ 'SHA256' betyr SHA-256 hash + ECDSA-signering\n  const sign = createSign('SHA256');\n\n  sign.update(melding, 'utf8'); \/\/ Legg til data som skal signeres\n  sign.end();                    \/\/ Ferdigstill datastrommen\n\n  \/\/ sign.sign() returnerer signaturen som en Buffer (DER-kodet)\n  const signaturBuf = sign.sign(privatNokkelPem);\n\n  return {\n    hex:    signaturBuf.toString('hex'),\n    base64: signaturBuf.toString('base64'),\n    buffer: signaturBuf\n  };\n}\n\n\/\/ Praktisk eksempel: signer en finansiell transaksjon\nconst privatNokkel = fs.readFileSync('keys\/private.pem', 'utf8');\n\n\/\/ Inkluder alltid et tidsstempel for \u00e5 forhindre replay-angrep\nconst transaksjon = JSON.stringify({\n  betalingsreferanse: 'INV-2026-001',\n  belop: 10000,\n  mottaker: '1234.56.78901',\n  timestamp: '2026-06-20T10:30:00Z',\n  nonce: 'a3f7b2c1d4e5'\n});\n\nconst signatur = signerMelding(transaksjon, privatNokkel);\n\nconsole.log('Melding:', transaksjon);\nconsole.log('Signatur (base64):', signatur.base64);\nconsole.log('Signatur lengde:', signatur.buffer.length, 'bytes');\n\n\/\/ Lagre signatur til fil for senere bruk\nfs.writeFileSync('output\/signatur.b64', signatur.base64);\nfs.writeFileSync('output\/melding.json', transaksjon);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Eksempel pa utdata:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Melding: {\"betalingsreferanse\":\"INV-2026-001\",\"belop\":10000,...}\nSignatur (base64): MEYCIQDt3M7v9K2...8kL2nAIhAL+3wQ==\nSignatur lengde: 71 bytes<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">P-256-signaturer er typisk 70-72 bytes i DER-format (to 32-byte tall <em>r<\/em> og <em>s<\/em> med DER-koding). Til sammenligning er en RSA-2048-signatur alltid noyaktig 256 bytes, og en RSA-4096-signatur alltid 512 bytes. Denne kompaktheten gjor ECDSA spesielt effektivt i protokoller der storrelse teller, som JWT-tokens sendt i HTTP-headere.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-5-verifiser-en-ecdsa-signatur\">Steg 5: Verifiser en ECDSA-signatur<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Verifisering bruker den offentlige n\u00f8kkelen og bekrefter to ting: at signaturen ble produsert av den tilsvarende private n\u00f8kkelen, og at meldingen ikke er endret siden signeringen. Verifiseringsoperasjonen kan utfores av hvem som helst med tilgang til den offentlige n\u00f8kkelen. Det er viktig a note at <code>createVerify().verify()<\/code> returnerer <code>false<\/code> pa ugyldig signatur i stedet for a kaste et unntak, slik at du alltid far et tydelig svar.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ verifiser.js - Verifisering av ECDSA-signatur\n\n'use strict';\nconst { createVerify } = require('crypto');\nconst fs = require('fs');\n\nfunction verifiserMelding(melding, offentligNokkelPem, signaturInput, kodingFormat = 'base64') {\n  const verify = createVerify('SHA256');\n  verify.update(melding, 'utf8');\n  verify.end();\n\n  \/\/ Konverter signatur til Buffer om nodvendig\n  const signaturBuf = Buffer.isBuffer(signaturInput)\n    ? signaturInput\n    : Buffer.from(signaturInput, kodingFormat);\n\n  try {\n    return verify.verify(offentligNokkelPem, signaturBuf);\n  } catch (err) {\n    \/\/ Fanger bl.a. malformaterte signaturer og feil n\u00f8kkeltype\n    console.error('Verifiseringsfeil:', err.message);\n    return false;\n  }\n}\n\n\/\/ Les inn data og signatur fra fil\nconst offentligNokkel = fs.readFileSync('keys\/public.pem', 'utf8');\nconst melding         = fs.readFileSync('output\/melding.json', 'utf8');\nconst signaturB64     = fs.readFileSync('output\/signatur.b64', 'utf8').trim();\n\n\/\/ Test 1: Gyldig signatur\nconst erGyldig = verifiserMelding(melding, offentligNokkel, signaturB64, 'base64');\nconsole.log('Gyldig signatur:', erGyldig); \/\/ true\n\n\/\/ Test 2: Manipulert melding\nconst manipulert = melding.replace('10000', '99000');\nconst erManipulertGyldig = verifiserMelding(manipulert, offentligNokkel, signaturB64, 'base64');\nconsole.log('Manipulert melding gyldig:', erManipulertGyldig); \/\/ false\n\n\/\/ Test 3: Manipulert signatur (en enkelt byte endret)\nconst signaturBuf = Buffer.from(signaturB64, 'base64');\nsignaturBuf[10] ^= 0x01; \/\/ XOR med 1 for a endre en bit\nconst erKorruptGyldig = verifiserMelding(melding, offentligNokkel, signaturBuf);\nconsole.log('Korrupt signatur gyldig:', erKorruptGyldig); \/\/ false<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Forventet utdata:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Gyldig signatur: true\nManipulert melding gyldig: false\nKorrupt signatur gyldig: false<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Legg merke til at selv en enkelt endret bit i meldingen eller signaturen gjor verifikasjonen ugyldig. Dette er den fundamentale egenskapen til kryptografiske signaturer: signaturen er matematisk bundet til noyaktig de dataene som ble signert, via SHA-256-hashen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-6-signer-og-verifiser-filer-via-streams\">Steg 6: Signer og verifiser filer via streams<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For storre filer som bin\u00e6rfiler, programpakker, logger eller dokumenter bor du lese filen som en datastr\u00f8m (stream) for a unnga a laste hele innholdet i minnet pa en gang. Node.js <code>createSign<\/code> er en Writable stream og kan motta data via <code>pipe()<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ fil-signer.js - Stream-basert fil-signering\n\n'use strict';\nconst { createSign, createVerify } = require('crypto');\nconst fs   = require('fs');\nconst path = require('path');\n\nasync function signerFil(filsti, privatNokkelPem) {\n  return new Promise((resolve, reject) => {\n    const sign  = createSign('SHA256');\n    const stream = fs.createReadStream(filsti);\n\n    stream.on('error', reject);\n    sign.on('error', reject);\n    stream.pipe(sign);\n\n    stream.on('end', () => {\n      sign.end();\n      const signatur = sign.sign(privatNokkelPem);\n      resolve(signatur);\n    });\n  });\n}\n\nasync function verifiserFil(filsti, offentligNokkelPem, signatur) {\n  return new Promise((resolve, reject) => {\n    const verify = createVerify('SHA256');\n    const stream = fs.createReadStream(filsti);\n\n    stream.on('error', reject);\n    stream.pipe(verify);\n\n    stream.on('end', () => {\n      verify.end();\n      try {\n        resolve(verify.verify(offentligNokkelPem, signatur));\n      } catch (err) {\n        reject(err);\n      }\n    });\n  });\n}\n\n\/\/ Eksempel: signer en Node.js-pakke\nasync function main() {\n  const privatNokkel   = fs.readFileSync('keys\/private.pem', 'utf8');\n  const offentligNokkel = fs.readFileSync('keys\/public.pem', 'utf8');\n  const filsti          = 'package.json';\n\n  console.log(`Signerer ${filsti}...`);\n  const signatur = await signerFil(filsti, privatNokkel);\n\n  const signatursti = path.join('output', `${path.basename(filsti)}.sig`);\n  fs.writeFileSync(signatursti, signatur);\n  console.log(`Signatur lagret: ${signatursti} (${signatur.length} bytes)`);\n\n  const erGyldig = await verifiserFil(filsti, offentligNokkel, signatur);\n  console.log(`Signaturverifisering: ${erGyldig ? 'OK' : 'FEIL'}`);\n}\n\nmain().catch(console.error);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Stream-basert signering er kritisk for filer over noen megabytes. En Node.js-prosess med standard minnegrense pa 512 MB vil mislykkes hvis den fors\u00f8ker a lese en 600 MB programpakke som en enkelt buffer. Stream-tiln\u00e6rmingen bruker konstant minne uavhengig av filstorrelse.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-7-arbeid-med-pem-og-jwk-format\">Steg 7: Arbeid med PEM- og JWK-format<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00f8kler finnes i ulike formater, og du vil ofte trenge a konvertere mellom dem. Node.js st\u00f8tter import og eksport av n\u00f8kler i PEM, DER og JWK (JSON Web Key)-format. JWK er standarden for a publisere offentlige n\u00f8kler via et JWKS-endepunkt.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ nokkel-konvertering.js - Konvertering mellom n\u00f8kkelformater\n\n'use strict';\nconst { createPrivateKey, createPublicKey, generateKeyPairSync } = require('crypto');\nconst fs = require('fs');\n\nconst { privateKey: privPem, publicKey: pubPem } = generateKeyPairSync('ec', {\n  namedCurve: 'P-256',\n  publicKeyEncoding: { type: 'spki', format: 'pem' },\n  privateKeyEncoding: { type: 'pkcs8', format: 'pem' }\n});\n\n\/\/ Konverter PEM til JWK - brukes i JWKS-endepunkt\nconst pubKeyObj = createPublicKey(pubPem);\nconst pubJwk    = pubKeyObj.export({ format: 'jwk' });\n\nconsole.log('Offentlig noekkel som JWK:');\nconsole.log(JSON.stringify(pubJwk, null, 2));\n\/\/ Output:\n\/\/ {\n\/\/   \"kty\": \"EC\",\n\/\/   \"crv\": \"P-256\",\n\/\/   \"x\": \"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU\",\n\/\/   \"y\": \"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0\"\n\/\/ }\n\n\/\/ Konverter JWK tilbake til PEM\nconst gjenopprettetPub = createPublicKey({ key: pubJwk, format: 'jwk' });\nconst gjenopprettetPem = gjenopprettetPub.export({ type: 'spki', format: 'pem' });\nconsole.log('PEM-er identiske:', pubPem === gjenopprettetPem); \/\/ true\n\n\/\/ Passordbeskytt privat n\u00f8kkel for lagring\nconst kryptertPriv = createPrivateKey(privPem).export({\n  type: 'pkcs8',\n  format: 'pem',\n  cipher: 'aes-256-cbc',\n  passphrase: process.env.KEY_PASSPHRASE || 'endre-dette-i-produksjon'\n});\nfs.writeFileSync('keys\/private-encrypted.pem', kryptertPriv, { mode: 0o600 });\nconsole.log('Kryptert privat noekkel lagret.');\n\n\/\/ Les kryptert n\u00f8kkel tilbake\nconst lastetPriv = createPrivateKey({\n  key: fs.readFileSync('keys\/private-encrypted.pem'),\n  format: 'pem',\n  passphrase: process.env.KEY_PASSPHRASE || 'endre-dette-i-produksjon'\n});\nconsole.log('Kryptert noekkel lastet OK, type:', lastetPriv.asymmetricKeyType); \/\/ ec<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Et komplett JWKS-endepunkt for a la klienter hente offentlige n\u00f8kler:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ JWKS-endepunkt i Express - lar klienter coche offentlige nokler\napp.get('\/.well-known\/jwks.json', (req, res) => {\n  const pubKeyObj = createPublicKey(offentligNokkel);\n  const jwk = pubKeyObj.export({ format: 'jwk' });\n\n  res.json({\n    keys: [{\n      ...jwk,\n      kid: 'v1-2026-06',  \/\/ Key ID for n\u00f8kkelrotasjon\n      use: 'sig',          \/\/ Bruk: signering\n      alg: 'ES256'         \/\/ Algoritme\n    }]\n  });\n});<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-8-ecdsa-i-jwt-es256-es384-es512\">Steg 8: ECDSA i JWT (ES256, ES384, ES512)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">JWT (JSON Web Tokens) med ECDSA-signaturer er standarden for sikker token-basert autentisering i moderne API-er. ES256 (P-256 + SHA-256), ES384 (P-384 + SHA-384) og ES512 (P-521 + SHA-512) er definert i <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc7518\" rel=\"noopener noreferrer\" target=\"_blank\">RFC 7518 (JWA)<\/a>. Den asymmetriske karakteren til ECDSA gir en viktig fordel over HMAC-baserte tokens (HS256): kun signeringstjenesten trenger den private n\u00f8kkelen, mens alle tjenester som verifiserer tokens bare trenger den offentlige n\u00f8kkelen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Installer JWT-biblioteket\nnpm install jsonwebtoken<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ jwt-ecdsa.js - JWT med ECDSA ES256\n\n'use strict';\nconst jwt = require('jsonwebtoken');\nconst { generateKeyPairSync } = require('crypto');\nconst fs = require('fs');\n\n\/\/ Generer n\u00f8kkelpar (i produksjon: bruk lagrede n\u00f8kler)\nconst { privateKey, publicKey } = generateKeyPairSync('ec', {\n  namedCurve: 'P-256',\n  publicKeyEncoding: { type: 'spki', format: 'pem' },\n  privateKeyEncoding: { type: 'pkcs8', format: 'pem' }\n});\n\n\/\/ Signer en JWT med ES256\nfunction lagToken(brukerdata) {\n  return jwt.sign(\n    {\n      sub:   brukerdata.id.toString(),\n      name:  brukerdata.navn,\n      roles: brukerdata.roller,\n      jti:   Math.random().toString(36).slice(2) \/\/ JWT ID mot replay-angrep\n    },\n    privateKey,\n    {\n      algorithm: 'ES256',\n      expiresIn: '1h',\n      issuer:    'api.eksempel.no',\n      audience:  'app.eksempel.no'\n    }\n  );\n}\n\n\/\/ Verifiser og dekod JWT\nfunction verifiserToken(token) {\n  try {\n    const decoded = jwt.verify(token, publicKey, {\n      algorithms: ['ES256'],     \/\/ Eksplisitt algoritmeliste forhindrer algorithm confusion-angrep\n      issuer:    'api.eksempel.no',\n      audience:  'app.eksempel.no'\n    });\n    return { gyldig: true, data: decoded };\n  } catch (err) {\n    return { gyldig: false, feil: err.message };\n  }\n}\n\n\/\/ Test\nconst bruker  = { id: 42, navn: 'Ola Nordmann', roller: ['admin', 'bruker'] };\nconst token   = lagToken(bruker);\n\nconsole.log('JWT-token (forkortet):', token.slice(0, 60) + '...');\nconsole.log('Token lengde:', token.length, 'tegn');\n\nconst resultat = verifiserToken(token);\nconsole.log('Gyldig:', resultat.gyldig);       \/\/ true\nconsole.log('Bruker-ID:', resultat.data?.sub);  \/\/ 42\nconsole.log('Roller:', resultat.data?.roles);   \/\/ ['admin', 'bruker']\n\n\/\/ Test med ugyldig token\nconst ugyldig = verifiserToken(token.slice(0, -5) + 'xxxxx');\nconsole.log('Ugyldig token:', ugyldig.gyldig, '-', ugyldig.feil);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Et ES256-JWT-token har tre Base64URL-kodede deler separert av punktum. Headerdelen avkoder til <code>{\"alg\":\"ES256\",\"typ\":\"JWT\"}<\/code>. Et typisk ES256-token er 271-320 tegn langt, mot 380-420 tegn for RS256. For autentisering i full OAuth 2.0-flyt med PKCE, se guiden om <a href=\"\/no\/oauth-2-0-nodejs\/\">OAuth 2.0 i Node.js<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-9-lagre-nokler-sikkert-i-produksjon\">Steg 9: Lagre n\u00f8kler sikkert i produksjon<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Sikker n\u00f8kkellagring er det svakeste leddet i de fleste ECDSA-implementasjoner. En kompromittert privat n\u00f8kkel ugyldiggjor alle signaturer og krever \u00f8yeblikkelig n\u00f8kkelrotasjon med varsling av alle parter som stolte pa de signerte dataene.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Lagringsmetode<\/th><th>Sikkerhetsnivaa<\/th><th>Egnet for<\/th><th>Implementasjon<\/th><\/tr><\/thead><tbody><tr><td>Hardkodet i kildekode<\/td><td>Ingen (aldri bruk)<\/td><td>Aldri<\/td><td>Uakseptabelt<\/td><\/tr><tr><td>.env-fil pa server<\/td><td>Lav<\/td><td>Kun lokal utvikling<\/td><td>dotenv-pakken<\/td><\/tr><tr><td>Filsystem med chmod 600<\/td><td>Middels<\/td><td>Enkle serveroppsett<\/td><td>Innebygd i OS<\/td><\/tr><tr><td>Docker Secrets \/ K8s Secrets<\/td><td>Middels-h\u00f8y<\/td><td>Container-orkestrasjon<\/td><td>docker secret create<\/td><\/tr><tr><td>AWS Secrets Manager \/ Azure Key Vault<\/td><td>H\u00f8y<\/td><td>Skybasert produksjon<\/td><td>SDK-integrasjon<\/td><\/tr><tr><td>HSM (Hardware Security Module)<\/td><td>Sv\u00e6rt h\u00f8y<\/td><td>Finansielle systemer, CA<\/td><td>PKCS#11-bibliotek<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">For de fleste Node.js-applikasjoner i produksjon er en skybasert hemmelighetslagring (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault) det riktige valget. Slik laster du n\u00f8kkelen sikkert ved oppstart:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ nokkel-laster.js - Sikker n\u00f8kkelinnlasting fra milj\u00f8variabler\n\n'use strict';\n\nlet cachetPrivatNokkel  = null;\nlet cachetOffentligNokkel = null;\n\n\/\/ Cache for a unnga gjentatte fillesninger eller API-kall\nfunction hentPrivatNokkel() {\n  if (cachetPrivatNokkel) return cachetPrivatNokkel;\n\n  const nokkPem = process.env.ECDSA_PRIVATE_KEY;\n  if (!nokkPem) throw new Error('ECDSA_PRIVATE_KEY milj\u00f8variabel ikke satt');\n\n  \/\/ Milj\u00f8variabler serialiserer ofte \\n som bokstavelig \\\\n\n  cachetPrivatNokkel = nokkPem.replace(\/\\\\n\/g, '\\n');\n  return cachetPrivatNokkel;\n}\n\nfunction hentOffentligNokkel() {\n  if (cachetOffentligNokkel) return cachetOffentligNokkel;\n\n  const nokkPem = process.env.ECDSA_PUBLIC_KEY;\n  if (!nokkPem) throw new Error('ECDSA_PUBLIC_KEY milj\u00f8variabel ikke satt');\n\n  cachetOffentligNokkel = nokkPem.replace(\/\\\\n\/g, '\\n');\n  return cachetOffentligNokkel;\n}\n\n\/\/ ALDRI gjor dette:\n\/\/ console.log(hentPrivatNokkel()); \/\/ Logger privat n\u00f8kkel til stdout\n\nmodule.exports = { hentPrivatNokkel, hentOffentligNokkel };<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Legg alltid til disse linjene i <code>.gitignore<\/code> for a forhindre utilsiktet commit av private n\u00f8kler:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># .gitignore\nkeys\/private*.pem\nkeys\/*-encrypted.pem\n*.key\n.env\n.env.local\n.env.production\nsecrets\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For n\u00f8kkelrotasjon: oppretthold alltid to aktive n\u00f8kler i en overgangsperiode. Signer nye data med den nye n\u00f8kkelen, men aksepter signaturer fra begge i minst 24-48 timer. Bruk <code>kid<\/code>-feltet i JWK og JWT-headere for a identifisere hvilken n\u00f8kkel som ble brukt til en signatur. For full PKI-infrastruktur med sertifikatutstedelse og tilbakekalling, se guiden om <a href=\"\/no\/openssl-certificate-authority\/\">Privat Certificate Authority med OpenSSL<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-10-ecdsa-med-webcrypto-api\">Steg 10: ECDSA med WebCrypto API<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Web_Crypto_API\" rel=\"noopener noreferrer\" target=\"_blank\">WebCrypto API<\/a> er tilgjengelig i alle moderne nettlesere og i Node.js 20+ via <code>globalThis.crypto.subtle<\/code>. Det gir asynkron kryptografi med Promises og er ideelt for isomorfisk kode som kjorer i bade nettleser og Node.js.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ webcrypto-ecdsa.js - WebCrypto API i Node.js og nettlesere\n\n'use strict';\n\n\/\/ Node.js 20+: globalThis.crypto.subtle er tilgjengelig\n\/\/ Node.js 18-19: bruk require('crypto').webcrypto.subtle\nconst subtle = globalThis.crypto?.subtle ?? require('crypto').webcrypto.subtle;\n\nasync function webcryptoDemo() {\n  \/\/ 1. Generer n\u00f8kkelpar\n  const nokkelpar = await subtle.generateKey(\n    { name: 'ECDSA', namedCurve: 'P-256' },\n    true,           \/\/ exportable (sett false i produksjon om mulig)\n    ['sign', 'verify']\n  );\n\n  \/\/ 2. Signer data\n  const encoder = new TextEncoder();\n  const data    = encoder.encode('Melding som skal signeres, 2026-06-20');\n\n  const signatur = await subtle.sign(\n    { name: 'ECDSA', hash: 'SHA-256' },\n    nokkelpar.privateKey,\n    data\n  );\n\n  console.log('Signatur lengde:', signatur.byteLength, 'bytes'); \/\/ 64 bytes (P1363-format!)\n\n  \/\/ 3. Verifiser\n  const erGyldig = await subtle.verify(\n    { name: 'ECDSA', hash: 'SHA-256' },\n    nokkelpar.publicKey,\n    signatur,\n    data\n  );\n  console.log('Signatur gyldig:', erGyldig); \/\/ true\n\n  \/\/ 4. Eksporter offentlig n\u00f8kkel som JWK\n  const jwk = await subtle.exportKey('jwk', nokkelpar.publicKey);\n  console.log('JWK:', JSON.stringify(jwk));\n\n  \/\/ 5. Eksporter til PEM-kompatibelt format (SPKI for offentlig, PKCS8 for privat)\n  const pubRaw  = await subtle.exportKey('spki', nokkelpar.publicKey);\n  const privRaw = await subtle.exportKey('pkcs8', nokkelpar.privateKey);\n  console.log('SPKI bytes:', pubRaw.byteLength);   \/\/ 91 bytes for P-256\n  console.log('PKCS8 bytes:', privRaw.byteLength); \/\/ 138 bytes for P-256\n}\n\nwebcryptoDemo().catch(console.error);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Kritisk forskjell mellom Node.js crypto og WebCrypto:<\/strong> WebCrypto returnerer signaturen i P1363-format (to concatenerte 32-byte tall for P-256, totalt 64 bytes), mens Node.js <code>createSign<\/code> bruker DER-format (70-72 bytes med ASN.1-koding). Du kan IKKE direkte bytte signaturer mellom de to API-ene uten konvertering. Bruk et bibliotek som <code>@noble\/curves<\/code> for konvertering mellom formatene om nodvendig.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-11-skriv-tester-for-ecdsa-kode\">Steg 11: Skriv tester for ECDSA-kode<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Kryptografisk kode krever grundig testing. Test alltid bade positive tilfeller (gyldig signatur verifiserer) og negative tilfeller (ugyldig signatur avvises, manipulert melding avvises, feil n\u00f8kkel avvises). Bruk Nodes innebygde <code>node:test<\/code>-modul, tilgjengelig fra Node.js 18+.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ ecdsa.test.js - Enhetstester for ECDSA-implementasjon\n\n'use strict';\nconst { describe, it } = require('node:test');\nconst assert           = require('node:assert\/strict');\nconst { generateKeyPairSync, createSign, createVerify } = require('crypto');\n\nfunction lagTestnokler(kurve = 'P-256') {\n  return generateKeyPairSync('ec', {\n    namedCurve: kurve,\n    publicKeyEncoding: { type: 'spki', format: 'pem' },\n    privateKeyEncoding: { type: 'pkcs8', format: 'pem' }\n  });\n}\n\nfunction signer(melding, privKey) {\n  const s = createSign('SHA256');\n  s.update(melding, 'utf8');\n  s.end();\n  return s.sign(privKey);\n}\n\nfunction verifiser(melding, pubKey, sig) {\n  const v = createVerify('SHA256');\n  v.update(melding, 'utf8');\n  v.end();\n  return v.verify(pubKey, sig);\n}\n\ndescribe('ECDSA P-256', () => {\n  it('verifiserer gyldig signatur', () => {\n    const { privateKey, publicKey } = lagTestnokler('P-256');\n    const sig = signer('test', privateKey);\n    assert.equal(verifiser('test', publicKey, sig), true);\n  });\n\n  it('avviser manipulert melding', () => {\n    const { privateKey, publicKey } = lagTestnokler('P-256');\n    const sig = signer('original', privateKey);\n    assert.equal(verifiser('manipulert', publicKey, sig), false);\n  });\n\n  it('avviser feil offentlig nokkel', () => {\n    const nokler1 = lagTestnokler('P-256');\n    const nokler2 = lagTestnokler('P-256');\n    const sig = signer('test', nokler1.privateKey);\n    assert.equal(verifiser('test', nokler2.publicKey, sig), false);\n  });\n\n  it('avviser korrupt signatur', () => {\n    const { privateKey, publicKey } = lagTestnokler('P-256');\n    const sig = signer('test', privateKey);\n    sig[10] ^= 0xFF; \/\/ Korrumper et byte\n    assert.equal(verifiser('test', publicKey, sig), false);\n  });\n});\n\ndescribe('ECDSA P-384', () => {\n  it('verifiserer gyldig signatur', () => {\n    const { privateKey, publicKey } = lagTestnokler('P-384');\n    const s = createSign('SHA384');\n    s.update('p384-test', 'utf8');\n    s.end();\n    const sig = s.sign(privateKey);\n    const v = createVerify('SHA384');\n    v.update('p384-test', 'utf8');\n    v.end();\n    assert.equal(v.verify(publicKey, sig), true);\n  });\n});\n\n\/\/ Kjor med: node --test ecdsa.test.js<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>$ node --test ecdsa.test.js\n\n\u25b6 ECDSA P-256\n  \u2714 verifiserer gyldig signatur (3.12ms)\n  \u2714 avviser manipulert melding (0.87ms)\n  \u2714 avviser feil offentlig nokkel (0.45ms)\n  \u2714 avviser korrupt signatur (0.32ms)\n\u25b6 ECDSA P-256 (4.76ms)\n\n\u25b6 ECDSA P-384\n  \u2714 verifiserer gyldig signatur (0.94ms)\n\u25b6 ECDSA P-384 (1.02ms)\n\n\u2139 tests 5\n\u2139 pass 5\n\u2139 fail 0\n\u2139 duration_ms 52.4<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-12-bygg-et-komplett-signeringsprosjekt\">Steg 12: Bygg et komplett signeringsprosjekt<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">La oss sette alt sammen i et komplett Express.js-API som tilbyr ECDSA-signeringstjenester via HTTP-endepunkter. Dette er et realistisk m\u00f8nster for en mikrotjeneste som tilbyr kryptografisk autentisering til andre tjenester i et distribuert system.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Installer Express\nnpm install express<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ app.js - Komplett ECDSA Signing API med Express\n\n'use strict';\nconst express = require('express');\nconst { generateKeyPairSync, createSign, createVerify, createPublicKey } = require('crypto');\n\nconst app = express();\napp.use(express.json({ limit: '1mb' }));\n\n\/\/ N\u00f8kkelpar generert ved oppstart (i produksjon: last fra Secrets Manager)\nconst { privateKey, publicKey } = generateKeyPairSync('ec', {\n  namedCurve: 'P-256',\n  publicKeyEncoding: { type: 'spki', format: 'pem' },\n  privateKeyEncoding: { type: 'pkcs8', format: 'pem' }\n});\n\n\/\/ Preberegn JWK for JWKS-endepunkt\nconst publicJwk = createPublicKey(publicKey).export({ format: 'jwk' });\n\n\/\/ GET \/.well-known\/jwks.json - JWKS-endepunkt\napp.get('\/.well-known\/jwks.json', (req, res) => {\n  res.json({ keys: [{ ...publicJwk, kid: 'v1', use: 'sig', alg: 'ES256' }] });\n});\n\n\/\/ GET \/public-key - Hent offentlig n\u00f8kkel som PEM\napp.get('\/public-key', (req, res) => {\n  res.json({ publicKey, kurve: 'P-256', algoritme: 'ECDSA-SHA256' });\n});\n\n\/\/ POST \/sign - Signer en melding\napp.post('\/sign', (req, res) => {\n  const { melding } = req.body;\n  if (!melding || typeof melding !== 'string') {\n    return res.status(400).json({ feil: 'Feltet \"melding\" (string) er paakrevd' });\n  }\n  if (melding.length > 10000) {\n    return res.status(400).json({ feil: 'Melding for lang (maks 10000 tegn)' });\n  }\n\n  try {\n    const sign = createSign('SHA256');\n    sign.update(melding, 'utf8');\n    sign.end();\n    const signatur = sign.sign(privateKey).toString('base64');\n\n    res.json({\n      melding,\n      signatur,\n      algoritme: 'ECDSA-P256-SHA256',\n      timestamp: new Date().toISOString()\n    });\n  } catch (err) {\n    res.status(500).json({ feil: 'Intern signeringsfeil' }); \/\/ Ikke eksponer intern feil\n  }\n});\n\n\/\/ POST \/verify - Verifiser en signatur\napp.post('\/verify', (req, res) => {\n  const { melding, signatur } = req.body;\n  if (!melding || !signatur) {\n    return res.status(400).json({ feil: 'Feltene \"melding\" og \"signatur\" er paakrevde' });\n  }\n\n  try {\n    const verify = createVerify('SHA256');\n    verify.update(melding, 'utf8');\n    verify.end();\n    const erGyldig = verify.verify(publicKey, Buffer.from(signatur, 'base64'));\n\n    res.json({ gyldig: erGyldig, melding });\n  } catch {\n    \/\/ Fanges: malformatert base64, feil signaturstruktur\n    res.status(400).json({ gyldig: false, feil: 'Ugyldig signaturformat' });\n  }\n});\n\nconst PORT = process.env.PORT || 3000;\napp.listen(PORT, () => {\n  console.log(`ECDSA Signing API kjorer pa port ${PORT}`);\n  console.log('Endepunkter:');\n  console.log('  GET  \/.well-known\/jwks.json');\n  console.log('  GET  \/public-key');\n  console.log('  POST \/sign   { melding: \"...\" }');\n  console.log('  POST \/verify { melding: \"...\", signatur: \"...\" }');\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Test API-et med curl:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Start serveren\n$ node app.js\nECDSA Signing API kjorer pa port 3000\n\n# Signer en melding\n$ curl -s -X POST http:\/\/localhost:3000\/sign \\\n  -H 'Content-Type: application\/json' \\\n  -d '{\"melding\":\"Faktura #1234, belop 5000 kr\"}' | tee \/tmp\/signert.json\n{\n  \"melding\": \"Faktura #1234, belop 5000 kr\",\n  \"signatur\": \"MEYCIQDpX2...==\",\n  \"algoritme\": \"ECDSA-P256-SHA256\",\n  \"timestamp\": \"2026-06-20T10:30:00.000Z\"\n}\n\n# Verifiser signaturen\n$ SIGNATUR=$(cat \/tmp\/signert.json | python3 -c \"import json,sys; print(json.load(sys.stdin)['signatur'])\")\n$ curl -s -X POST http:\/\/localhost:3000\/verify \\\n  -H 'Content-Type: application\/json' \\\n  -d \"{\\\"melding\\\":\\\"Faktura #1234, belop 5000 kr\\\",\\\"signatur\\\":\\\"$SIGNATUR\\\"}\"\n{\"gyldig\":true,\"melding\":\"Faktura #1234, belop 5000 kr\"}\n\n# Hent JWKS\n$ curl -s http:\/\/localhost:3000\/.well-known\/jwks.json | python3 -m json.tool<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vanlige-fallgruver-ved-ecdsa-i-node-js\">Vanlige fallgruver ved ECDSA i Node.js<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Disse feilene gar igjen i ECDSA-implementasjoner og kan undergrave sikkerheten fullstendig eller fore til subtile feil som er vanskelige a debugge.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fallgruve 1: Gjenbruk av k-nonce.<\/strong> ECDSA krever en unik, tilfeldig verdi <em>k<\/em> for hver signatur. Hvis samme <em>k<\/em> brukes to ganger for ulike meldinger, kan en angriper beregne den private n\u00f8kkelen algebraisk. Sony PlayStation 3 mistet sin kodesigneringsn\u00f8kkel i 2010 pa grunn av nettopp dette. Node.js OpenSSL bruker deterministisk <em>k<\/em>-generering i henhold til <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc6979\" rel=\"noopener noreferrer\" target=\"_blank\">RFC 6979<\/a>. Bruk ALDRI manuelle ECDSA-implementasjoner uten RFC 6979.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fallgruve 2: Blanding av DER og P1363-format.<\/strong> Node.js crypto-modulen produserer DER-kodede signaturer (70-72 bytes for P-256). WebCrypto API bruker P1363-format (alltid 64 bytes for P-256). JWT-biblioteker forventer P1363. A blande disse formatene gir signaturer som alltid feiler ved verifikasjon, uten tydelig feilmelding om arsaken.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fallgruve 3: Bruk av SHA-1 med ECDSA.<\/strong> SHA-1 er kryptografisk kompromittert siden kollisjonsdemonstrasjonen i 2017 (SHAttered-angrepet, dokumentert pa <a href=\"\/no\/openssl-certificate-authority\/\">shattered.io-bloggen<\/a>). Bruk SHA-256 med P-256, SHA-384 med P-384, SHA-512 med P-521. Spesifiser aldri bare <code>'SHA1'<\/code> i <code>createSign('SHA1')<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fallgruve 4: Logging av privat n\u00f8kkel.<\/strong> En privat n\u00f8kkel logget til <code>console.log<\/code>, en loggfil, eller en feilsporingstjeneste som Sentry eller Datadog er kompromittert. Behandle den private n\u00f8kkelen som et passord: log aldri innholdet, send den aldri over nettverket, og inkluder den aldri i feilmeldinger til klienten.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fallgruve 5: Manglende tidsstempler i signerte data.<\/strong> En gyldig ECDSA-signatur forblir gyldig for alltid. Uten tidsstempel kan en angriper ta en gammel, gyldig signatur og gjenbruke den (replay-angrep). Inkluder alltid et ISO-8601-tidsstempel og en engangsverdi (nonce) i de signerte dataene, og verifiser at tidsstemplet er innenfor et akseptabelt vindu (f.eks. 5 minutter).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fallgruve 6: Bruke secp256k1 til TLS.<\/strong> <code>secp256k1<\/code> er ikke en del av TLS 1.3-kurvelisten (RFC 8446). Nettlesere og TLS-biblioteker st\u00f8tter den ikke for HTTPS-tilkoblinger. Bruk P-256 for webkryptering og reserver secp256k1 for blockchain-applikasjoner.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fallgruve 7: Bruke samme n\u00f8kkel for signering og kryptering.<\/strong> EC-n\u00f8kler for ECDSA (signering) og ECDH (n\u00f8kkelutveksling\/kryptering) bor holdes atskilt. Gjenbruk av n\u00f8kler pa tvers av algoritmer kan fore til kryssprotokoll-angrep. Generer separate n\u00f8kkelpar for hvert formal.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"8-feilsokingstips\">8 Feils\u00f8kingstips<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1. ERR_OSSL_PEM_NO_START_LINE.<\/strong> PEM-filen er \u00f8delagt eller har feil linjeskift. Kontroller at filen starter med <code>-----BEGIN PRIVATE KEY-----<\/code>. Milj\u00f8variabler serialiserer ofte <code>\\n<\/code> som <code>\\\\n<\/code>. L\u00f8sning: <code>key.replace(\/\\\\n\/g, '\\n')<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>2. ERR_INVALID_ARG_TYPE: The &#8220;key&#8221; argument must be of type string.<\/strong> Du sender en <code>Buffer<\/code> der en <code>string<\/code> forventes. Sikre at du laster n\u00f8kkelen som UTF-8-streng: <code>fs.readFileSync('private.pem', 'utf8')<\/code>, ikke <code>fs.readFileSync('private.pem')<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3. verify() returnerer alltid false uten feilmelding.<\/strong> Fire vanlige arsaker: (a) feil signaturkoding (pr\u00f8v hex vs base64 vs buffer), (b) meldingen ble kodet annerledes (UTF-8 vs binary), (c) feil offentlig n\u00f8kkel brukes, (d) du blander DER og P1363-format. Legg til <code>try\/catch<\/code> rundt <code>verify.verify()<\/code> for a fange implisitte feil.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>4. ERR_OSSL_EC_GROUP_NOT_FOUND.<\/strong> Du spesifiserte et kurvenavn OpenSSL ikke kjenner. Bruk <code>'P-256'<\/code>, <code>'P-384'<\/code>, <code>'P-521'<\/code> i Node.js-krypto-API. OpenSSL CLI aksepterer <code>prime256v1<\/code>, men Node.js-wrapperen foretrekker <code>P-256<\/code>. Sjekk tilgjengelige kurver med: <code>node -e \"require('crypto').getCurves().forEach(c => console.log(c))\"<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>5. JWT-bibliotek aksepterer ikke ES256-n\u00f8kkel.<\/strong> Kontroller at du bruker P-256 for ES256, P-384 for ES384, P-521 for ES512. En P-384-n\u00f8kkel med ES256-algoritmen gir <code>secretOrPublicKey must have a bit size of 256<\/code>-feil. Mismatch mellom kurve og JWT-algoritme er en vanlig feil nar n\u00f8kkelpar er generert med andre verkt\u00f8y.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>6. OpenSSL-versjonsinkompatibilitet.<\/strong> Node.js 18 bruker OpenSSL 3.0, Node.js 16 (utgar) bruker OpenSSL 1.1.1. Noen eldre EC-n\u00f8kkeloperasjoner er fjernet i OpenSSL 3.0 (implisitt EC-parameterspesifikasjon er ikke lenger tillatt). Sjekk din OpenSSL-versjon: <code>node -e \"console.log(process.versions.openssl)\"<\/code>. Oppgrader til Node.js 22 LTS for beste st\u00f8tte.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>7. ERR_OSSL_EVP_DIFFERENT_KEY_TYPES.<\/strong> Du fors\u00f8ker a verifisere en ECDSA-signatur med en RSA-n\u00f8kkel eller omvendt. Dobbeltsjekk n\u00f8kkeltypen: <code>createPublicKey(pem).asymmetricKeyType<\/code> returnerer <code>'ec'<\/code>, <code>'rsa'<\/code>, <code>'ed25519'<\/code> osv.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>8. Signatur feiler bare i produksjon, ikke lokalt.<\/strong> Sjekk Node.js-versjon i begge milj\u00f8er (<code>node --version<\/code>). En vanlig arsak er at produksjonsserveren kjorer Node.js 16 (OpenSSL 1.1.1) mens lokal utvikling bruker Node.js 22 (OpenSSL 3.3). En annen vanlig arsak er linjeskift-problemer med PEM-n\u00f8kler i milj\u00f8variabler (se punkt 1).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ytelsesmaling-og-kurveoversikt\">Ytelsesmaling og kurveoversikt<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Benchmarktall for ECDSA-operasjoner pa moderne maskinvare (Apple M3 Pro, Node.js 22.x, OpenSSL 3.3) sammenlignet med RSA:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Operasjon<\/th><th>Kurve\/Algoritme<\/th><th>Tid per op.<\/th><th>Op.\/sekund<\/th><th>Signatur-st\u00f8rrelse<\/th><\/tr><\/thead><tbody><tr><td>N\u00f8kkelgenerering<\/td><td>P-256<\/td><td>0,12 ms<\/td><td>8 333<\/td><td>N\/A<\/td><\/tr><tr><td>Signering<\/td><td>P-256<\/td><td>0,31 ms<\/td><td>3 226<\/td><td>70-72 bytes (DER)<\/td><\/tr><tr><td>Verifisering<\/td><td>P-256<\/td><td>0,72 ms<\/td><td>1 389<\/td><td>N\/A<\/td><\/tr><tr><td>Signering<\/td><td>P-384<\/td><td>0,78 ms<\/td><td>1 282<\/td><td>102-104 bytes (DER)<\/td><\/tr><tr><td>Verifisering<\/td><td>P-384<\/td><td>1,84 ms<\/td><td>543<\/td><td>N\/A<\/td><\/tr><tr><td>Signering<\/td><td>RSA-2048 (sammenligning)<\/td><td>1,21 ms<\/td><td>826<\/td><td>256 bytes<\/td><\/tr><tr><td>Verifisering<\/td><td>RSA-2048 (sammenligning)<\/td><td>0,04 ms<\/td><td>25 000<\/td><td>N\/A<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">P-256-signering er 4x raskere enn RSA-2048-signering. RSA-verifisering er imidlertid raskere fordi RSA-verifisering krever en enkelt modul\u00e6r eksponentieringsoperasjon med en liten offentlig eksponent (e=65537), mens ECDSA-verifisering krever to skalarmultiplikasjoner pa kurven. For applikasjoner som prim\u00e6rt signerer (f.eks. en autentiseringstjeneste), er ECDSA det klare valget. For applikasjoner som prim\u00e6rt verifiserer mange signaturer (f.eks. en gateway), er ytelsesavveiningen mer kompleks.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"avanserte-tips-for-ecdsa-i-produksjon\">Avanserte tips for ECDSA i produksjon<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>N\u00f8kkelrotasjon uten nedetid.<\/strong> Publiser offentlige n\u00f8kler via et JWKS-endepunkt med <code>kid<\/code> (Key ID)-felt. Inkluder <code>kid<\/code> i JWT-headere slik at klienter kan velge riktig offentlig n\u00f8kkel for verifisering. Rotasjonssekvens: (1) legg til ny n\u00f8kkel i JWKS-settet, (2) vent 24 timer til klientene cacher den nye n\u00f8kkelen, (3) begynn a signere med ny n\u00f8kkel, (4) fjern gammel n\u00f8kkel etter ytterligere 24 timer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Signaturtidssikker sammenligning.<\/strong> Bruk <code>crypto.timingSafeEqual()<\/code> nar du sammenligner signaturer manuelt. Normal strengsammenligning (<code>===<\/code> eller <code>.equals()<\/code>) er s\u00e5rbar for timingside-kanal-angrep. <code>createVerify().verify()<\/code> gjor dette internt, sa du trenger bare <code>timingSafeEqual<\/code> hvis du implementerer egne sammenligninger.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Kombiner ECDSA med AES-256-GCM for ende-til-ende-autentisert kryptering.<\/strong> ECDSA bekrefter hvem som sendte noe, men krypterer ikke innholdet. For autentisert kryptering: signer meldingen med ECDSA (integritet og autentisitet), krypter med AES-256-GCM (konfidensialitet), send begge deler. Mottaker dekrypterer og verifiserer. Dette monsteret er kjent som &#8220;Encrypt-then-Sign&#8221;.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Kvanteresistens pa lang sikt.<\/strong> ECDSA er sarbar for Shorors algoritme pa tilstrekkelig kraftige kvantecomputere. NIST standardiserte i 2024 tre post-kvantum-signeringsalgoritmer: ML-DSA (CRYSTALS-Dilithium), SLH-DSA (SPHINCS+) og FN-DSA (FALCON). Node.js st\u00f8tter ikke disse direkte per juni 2026, men <code>liboqs<\/code>-integrasjon er under utvikling. Planlegg migrering for systemer med 10+ ars sikkerhetshorisont.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Bruk Worker Threads for h\u00f8y gjennomstromning.<\/strong> ECDSA-verifisering pa P-256 gir ca. 1 389 operasjoner per sekund i en enkelt Node.js-trad. For applikasjoner som trenger hoyre gjennomstrommen, fordel arbeid pa tvers av Worker Threads med <code>worker_threads<\/code>-modulen. Pa en 8-kjerners server kan dette gi 8-10x hohere total gjennomstromning.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ofte-stilte-sporsmal-om-ecdsa-i-node-js\">Ofte stilte sp\u00f8rsm\u00e5l om ECDSA i Node.js<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hva er forskjellen pa ECDSA og Ed25519?<\/strong><br>ECDSA bruker NIST-kurver (P-256, P-384, P-521) og krever en unik tilfeldig nonce per signatur. Ed25519 bruker Edwards-kurven Curve25519 (EdDSA) og genererer signaturer deterministisk uten ekstern tilfeldighet, noe som gjor den mer resistent mot implementasjonsfeil. Ed25519-signaturer er alltid 64 bytes og er raskere enn P-256. Bruk Ed25519 for SSH-n\u00f8kler og nye protokoller der du velger fritt. Bruk P-256\/ECDSA for TLS, JWT ES256 og systemer som krever bredest mulig kompatibilitet. Se vaar detaljerte sammenligning i <a href=\"\/no\/ed25519-vs-rsa\/\">Ed25519 vs RSA<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Kan jeg bruke ECDSA pa Node.js 16?<\/strong><br>Node.js 16 (End of Life september 2023) st\u00f8tter ECDSA via OpenSSL 1.1.1, og kodeeksemplene i denne guiden er teknisk kompatible. Men Node.js 16 mottar ikke lenger sikkerhetsoppdateringer. Oppgrader til Node.js 22 LTS (st\u00f8ttet til april 2027) for a motta OpenSSL 3.x-sikkerhetsoppdateringer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Er ECDSA sikkert mot kvantecomputere?<\/strong><br>Nei. Shorors algoritme kan knekke ECDSA-n\u00f8kler pa en tilstrekkelig kraftig kvantedatamaskin. Per juni 2026 eksisterer ingen kvantecomputer med nok stabile qubits til a true P-256 i praksis, men NIST anbefaler a planlegge overgang til post-kvantum-algoritmer for systemer med lang levetid.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hva er DER-format og P1363-format?<\/strong><br>Begge er malinger for ECDSA-signaturer som inneholder de to tallene <em>r<\/em> og <em>s<\/em>. DER (Distinguished Encoding Rules) er ASN.1-bin\u00e6rkoding og brukes av Node.js crypto-modulen. P1363 er en enklere concatenering av <em>r<\/em> og <em>s<\/em> som fast-lengde byte-arrays, brukt av WebCrypto API og JWT. For P-256 er DER 70-72 bytes variabelt, P1363 alltid 64 bytes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Kan jeg bruke secp256k1 for vanlige webapplikasjoner?<\/strong><br>Teknisk ja, men anbefales ikke. secp256k1 er ikke inkludert i TLS 1.3 sin kurvelist (RFC 8446), st\u00f8ttes ikke av nettlesere for TLS, og har ikke NIST-godkjenning. Bruk P-256 for webapplikasjoner og reserver secp256k1 for Bitcoin\/Ethereum-relatert kode.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hva skjer hvis privat n\u00f8kkel lekker?<\/strong><br>Alle signaturer produsert med den lekkede n\u00f8kkelen ma regnes som potensielt forfalskede. Umiddelbar respons: (1) generer nytt n\u00f8kkelpar, (2) trekk tilbake relaterte sertifikater via din CA, (3) invalider alle JWT-tokens signert med gammel n\u00f8kkel (f.eks. ved a endre token-hemmeligheten eller sette en &#8220;invalidert-etter&#8221;-timestamp), (4) unders\u00f8k logger for mulig misbruk, (5) varsle paavirkede brukere og samarbeidspartnere. Se vaar guide om <a href=\"\/no\/openssl-certificate-authority\/\">Privat Certificate Authority med OpenSSL<\/a> for sertifikattilbakekalling.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Trenger jeg externe pakker for ECDSA i Node.js?<\/strong><br>Nei, for grunnleggende operasjoner. Node.js innebygde <code>crypto<\/code>-modul dekker n\u00f8kkelgenerering, signering og verifisering med P-256, P-384 og P-521. For JWT-integrasjon trenger du <code>jsonwebtoken<\/code>. For konvertering mellom DER og P1363 kan <code>@noble\/curves<\/code> eller <code>elliptic<\/code>-pakken vaere nyttige. For avansert PKI (sertifikatutstedelse, OCSP) er <code>node-forge<\/code> et alternativ.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hvorfor er ECDSA-verifisering tregere enn RSA-verifisering?<\/strong><br>RSA-verifisering er en enkelt modul\u00e6r eksponentiering med den lille offentlige eksponenten e=65537, noe moderne prosessorer utforer ekstremt raskt. ECDSA-verifisering krever to skalarmultiplikasjoner pa elliptisk kurve. Disse er dyrere per operasjon, noe som gir P-256 ca. 1 389 verifiseringer\/sekund mot RSA-2048 sine 25 000 verifiseringer\/sekund. For signeringsintensive arbeidsbelastninger er ECDSA klart raskere.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"relatert-dekning\">Relatert dekning<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Vil du gaa dypere inn i kryptografi og Node.js-sikkerhet? Her er relaterte guider pa shattered.io:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/no\/ed25519-vs-rsa\/\">Ed25519 vs RSA: 33x raskere signaturer, 128-bit sikkerhet [2026]<\/a> &#8211; Detaljert sammenligning av moderne signeringsalgoritmer<\/li>\n<li><a href=\"\/no\/openssl-certificate-authority\/\">Privat Certificate Authority med OpenSSL: 12 steg, 30 min [2026]<\/a> &#8211; Bygg din egen PKI-infrastruktur fra bunnen av<\/li>\n<li><a href=\"\/no\/oauth-2-0-nodejs\/\">OAuth 2.0 i Node.js: Sikker Autorisasjon i 12 Steg [2026]<\/a> &#8211; JWT og token-basert autentisering i Express.js<\/li>\n<li><a href=\"\/no\/scrypt-passordhashing-nodejs\/\">scrypt Passordhashing i Node.js: 11 Steg [2026]<\/a> &#8211; Sikker passordhashing og n\u00f8kkelderivering<\/li>\n<li><a href=\"\/no\/sql-injection-nodejs\/\">SQL Injection i Node.js: 12 Steg for Sikre Databaser [2026]<\/a> &#8211; Beskytt databasen din mot injeksjonsangrep<\/li>\n<\/ul>\n\n\n\n\n\n","protected":false},"excerpt":{"rendered":"<p>ECDSA (Elliptic Curve Digital Signature Algorithm) gir kryptografisk sterk autentisering med n\u00f8kler som er 10 ganger kortere enn RSA. En P-256-n\u00f8kkel p\u00e5 256 bit gir den samme 128-bits sikkerheten som\u2026<\/p>\n","protected":false},"author":5,"featured_media":146,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-145","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cryptography"],"_links":{"self":[{"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/posts\/145","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/comments?post=145"}],"version-history":[{"count":1,"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/posts\/145\/revisions"}],"predecessor-version":[{"id":147,"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/posts\/145\/revisions\/147"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/media\/146"}],"wp:attachment":[{"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/media?parent=145"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/categories?post=145"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/shattered.io\/no\/wp-json\/wp\/v2\/tags?post=145"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}