De veegactie duurde 41 minuten

Op 30 juli werkte iemand 1.196 bitcoinadressen af en haalde ze leeg, goed voor 1.082,65 bitcoin ter waarde van ongeveer 70,2 miljoen dollar, in een venster van 41 minuten. Niemand brak een slot open. Geen apparaat werd aangeraakt, geen gebruiker gephisht, geen server gekraakt. De aanvaller had dat allemaal niet nodig, want de privésleutels die deze adressen beschermden konden vanaf nul worden uitgerekend. Eerste berichten schatten het verlies op bijna 38 miljoen dollar; toen onderzoekers klaar waren met tellen, kwam het cijfer op bijna het dubbele uit.

De betrokken apparaten waren Coldcard-hardwareportemonnees van Coinkite, precies de productcategorie die men koopt om sleutels bij netwerken vandaan te houden. Dat maakt het incident een uur aandacht waard voor elke ondernemer, wat hij ook van bitcoin vindt. Het falen vond niet plaats aan de buitengrens waarvoor iedereen begroot. Het vond plaats op het moment dat het geheim werd aangemaakt, jaren voordat iemand probeerde het te stelen.

Een macro op nul zette de terugval aan

Coinkites eigen technische relaas is ongewoon openhartig over het mechanisme. In maart 2021 werd de seedgeneratie tijdens een migratie naar libsecp256k1 van Bitcoin Core omgeleid van de routine die de hardwaregenerator voor willekeurige getallen van het apparaat aanriep naar een algemene functie. Dat nieuwe pad kwam uit bij de softwarevariant van MicroPython in plaats van bij Coldcards hardware-implementatie. De terugvalcode zelf bestond al sinds mei 2018 en had de seedgeneratie tot die migratie nooit geraakt.

Waarom hij überhaupt meegecompileerd werd, hoort thuis in uw eigen controlelijst. De bewaking rond de terugval toetste of een configuratiemacro gedefinieerd was, niet of die op één stond. De ontwikkelaars hadden hem op nul gezet, in de betekenis dat de hardwaregenerator daar niet nodig was, en een macro op nul is nog steeds een gedefinieerde macro. De bewaking las de aanwezigheid van de waarde in plaats van de waarde zelf, en zette de terugval aan. Niemand schreef zwakke cryptografie. De hardwaregenerator bestond en werkte. Hij was alleen niet langer datgene waaruit de seed werd getrokken.

Vijf jaar verstreken en elke test bleef groen

Op Mk2- en Mk3-apparaten met firmware 4.0.1 tot en met 4.1.9 droegen de ontstane seeds ongeveer 40 bits entropie in plaats van de 128 die een woordgroep van twaalf woorden hoort te hebben. Op Mk4, Mk5 en Q was het beeld beter maar niet veilig: ingenieurs hadden waarden uit de beveiligingselementen door de generatortoestand gemengd als, in Coinkites bewoording, een reserve op de reserve, wat die seeds op ruwweg 72 bits bracht. Beide getallen zijn op dezelfde manier rampzalig. Toeval valt niet te zien. Een sleutel met 40 bits erachter ondertekent transacties, verifieert adressen en herstelt vanaf een back-up precies als een sleutel met 128, dus elke functionele test die het bedrijf en zijn klanten vijf jaar lang draaiden slaagde terecht, terwijl het product kapot was.

Coinkite geeft daarnaast een detail prijs dat de meeste leveranciers begraven zouden hebben. Enkele weken geleden, schrijft het bedrijf, gebruikte het een van de beste beschikbare AI-modellen om de eigen code op beveiligingsproblemen na te lopen, en dat model vond deze fout niet. Daar mag u even bij stilstaan voordat de volgende leverancier vertelt dat zijn code door een model is nagekeken. Het defect was achteraf niet subtiel en was niet verborgen, maar het huisde in de naad tussen een bouwconfiguratie en een cryptografische aanname, precies de naad die een beoordelaar die op codekwaliteit leest het minst snel als beveiligingsgrens behandelt.

De oplossing beschermt de volgende sleutel, niet de vorige

Coinkite bracht op 31 juli gecorrigeerde firmware uit voor elk getroffen model en elke tak: 4.2.0 voor Mk2 en Mk3, 5.6.0 voor Mk4 en Mk5, 1.5.0Q voor Q en de bijbehorende edge-builds. Daarna publiceerde het de zin die zwaarder weegt dan de patch. Het bijwerken van de firmware verandert of repareert een bestaande seed niet. De instructie luidt: installeer de gecorrigeerde firmware, genereer een nieuwe seed op het bijgewerkte apparaat, noteer en controleer de back-up voordat u iets stort, bevestig een nieuw ontvangstadres op het scherm van het apparaat, stuur een kleine testtransactie en verplaats pas daarna de resterende middelen.

Dat is een migratie, geen update, en in dat onderscheid ligt de hele les. Twee dingen konden een portemonnee redden die in het getroffen venster is gemaakt: vijftig onafhankelijke, privé geworpen dobbelsteenworpen die via de eigen dobbelfunctie zijn ingevoerd, aangezien Coldcard deze in de seed verrekende, of een sterke, unieke wachtwoordzin die als aparte barrière voor de zwakke seed staat. Coinkite raadt zelfs gebruikers met zo'n zin aan zo snel als praktisch te migreren. TAPSIGNER, OPENDIME en SATSCARD draaien op andere codebases en zijn niet getroffen.

Inventariseer wat u genereerde, niet alleen wat u draait

Vrijwel elk patchproces dat een eigenaar ooit heeft goedgekeurd behandelt de softwareversie als risico-eenheid. U verneemt dat een versie kwetsbaar is, u werkt hem bij, de blootstelling eindigt. Entropiedefecten breken dat model volledig, want de schade zit niet in de draaiende code maar in voorwerpen die de code uitgaf en overhandigde: sleutels, tokens, sessie-identificatoren, herstelcodes, API-geheimen, certificaten. Die voorwerpen overleven de versie die ze maakte, reizen mee naar back-ups en systemen van derden, en dragen de zwakte blijvend met zich mee. Het bijwerken van de generator stopt de productie van slechte geheimen. Aan de voorraad verandert het niets.

De vraag aan elke leverancier wiens product namens u geheimen aanmaakt, is dus niet alleen welke versies getroffen zijn. Het is welke geheimen op een getroffen versie zijn gegenereerd, hoe u ze opsomt en wat het vervangingspad is. Dat geldt ver buiten hardwareportemonnees: de HSM in de betaalketen, de certificaatautoriteit, de lijn voor apparaatuitgifte, de identiteitsdienst die langlopende tokens uitgeeft. Overal waar een machine iets slaat waarop u later vertrouwt, is het defecte venster wat geïnventariseerd moet worden, en vrijwel niemand houdt dat bij.