Когда речь заходит о звуке клавиатуры, в голове у меня сидит одно число: 95%. В 2023 году Харрисон, Тореини и Мехрнежад положили iPhone рядом с MacBook Pro и обучили нейросеть на звуке клавиш. Она угадала 95% нажатий и 93% на записи Zoom, сделанной через микрофон самого ноутбука. В 2025 году Спата с соавторами получили 98,3% на тех же данных MacBook, потом записали механическую клавиатуру и сообщили о 99% на ней. У меня есть небольшой инструмент earshot, он слушает микрофон и переводит речь в текст. Тот же микрофон слышит каждую клавишу, которую я нажимаю. Про 95% я читал несколько раз и ни разу не спросил, на чём именно это мерили. Оба датасета открыты под лицензией MIT, поэтому в этот раз я их скачал и посмотрел.
Как устроен замер
Оба набора устроены одинаково. 36 клавиш, цифры и буквы. Каждая клавиша записана отдельным файлом WAV, в нём 25 нажатий подряд примерно раз в секунду. У Харрисона 2 записи одного и того же MacBook. Одна сделана телефоном, лежащим на салфетке из микрофибры, другая через Zoom с частотой 32 кГц с шумоподавлением на минимуме. Набор KAD от Спаты это механическая клавиатура и смартфон в 17 см от неё, плюс 10 паролей, набранных клавиша за клавишей, каждый своей записью.
Я хотел посмотреть, сколько возьмёт простая модель, поэтому без глубокой сети. Python 3.12, numpy 2.5.3, scipy 1.18.1, scikit-learn 1.9.0 на 4 ядрах. Каждое нажатие вырезается по порогу энергии, который подстраивается, пока в файле не найдётся ровно 25 нажатий. Потом 330 мс звука превращаются в логарифмическую мел-спектрограмму из 64 полос и на неё смотрит логистическая регрессия. Случайное угадывание при 36 клавишах даёт 2,8%.
Для проверки я делил нажатия по их месту в файле: нажатия с 0 по 4 в одном блоке, с 5 по 9 в следующем и так далее. При случайном разбиении у большинства тестовых нажатий соседи по времени попали бы в обучение. Здесь сосед в обучении есть только у нажатий на краю блока.
Вышло 92,4% на MacBook через телефон, 84,6% через Zoom и 99,3% на механической клавиатуре. Линейная модель без аугментации оказалась в пределах 3 пунктов от сети Харрисона на записи с телефона. На механической клавиатуре она сравнялась с 99% у Спаты. Этого я не ждал. На Zoom она отстала на 8 пунктов. На записи с телефона Спата с соавторами получили 98,3%, на 6 пунктов больше моего. В статьях данные делили иначе, так что сравнение грубое.
Где я перестал верить
Потом я ещё раз посмотрел на устройство файлов и меня это насторожило. Каждая клавиша живёт в своей записи. Допустим, телефон немного сдвинулся между записью a и записью b. Тогда классификатор может выучить файл вместо клавиши. Проверка выше этого не заметит, потому что тестовые нажатия берутся из тех же файлов.
Поэтому я обучил ту же модель на тишине. От каждого нажатия я взял 200 мс, которые начинаются через 400 мс после него. Звук там уже на 24–36 дБ тише нажатия. И спросил, какой клавише принадлежит этот кусок тишины. На MacBook через телефон тишина назвала клавишу в 29,4% случаев, через Zoom в 16,1%, на механической клавиатуре в 39,4%. Это в 6–14 раз выше случайного уровня.
Самой записи, без нажатия, хватает, чтобы назвать клавишу. Классификатор на нажатиях, возможно, тоже этим пользуется. Насколько, по этим файлам я сказать не могу.
Пароли KAD это проверка, в которой файл помочь не может. Там клавиши идут друг за другом внутри одной записи. Я обучил модель на всех 900 нажатиях из файлов клавиш и проверил на 100 нажатиях внутри 10 паролей. Сколько символов в каждом пароле, я заранее сообщил коду, который вырезает нажатия. Верными оказались 77 из 100. В 93 из 100 верная клавиша была в первой пятёрке. Целиком угадался 1 пароль из 10, baseball47. Хуже всех вышел position90, услышанный как ppsvtnpk00.
Из 23 неверных догадок 10 попали на физического соседа верной клавиши. Случайная пара клавиш на этой раскладке оказывается соседней в 13% случаев. Со словарём это полезный список кандидатов, но для пароля с цифрами в конце всё равно нужно 10 верных догадок подряд.
Спата с соавторами сделали похожую проверку, на 8 паролях, записанных позже на той же клавиатуре. Их сеть получила в среднем 89,1%. Их паролей в открытом наборе нет, поэтому напрямую сравнить я не могу, но это на 12 пунктов выше моих 77. В статье Харрисона такой проверки нет.
Где ломается
Другая запись той же клавиатуры. Я обучил модель на записи с телефона и проверил на записи Zoom, тот же MacBook и тот же человек за клавиатурой. Вышло 6,3%. Обратное направление дало 4,9%. Я думал, что причина в разной полосе частот: Zoom на 32 кГц против 44,1 кГц у телефона. Поэтому я оставил только мел-полосы ниже 8 кГц и вычел из каждой записи её средний логарифмический мел-спектр, это вроде грубого эквалайзера. Лучшее, что из этого вышло, 12%, в 4 раза выше случайного. Здесь меняются сразу три вещи: микрофон, сеанс записи и обработка Zoom. Разделить их я не могу. 92% и 85% на первом графике это 2 отдельные модели, каждая обучена на своей записи.
Шум. Здесь я сначала ошибся. Я добавил белый шум на 30 дБ тише нажатия и модель MacBook упала до случайного угадывания. Я какое-то время искал ошибку в коде шума, прежде чем сравнил уровни по полосам. Большая часть звука комнаты в записи телефона приходится на нижние полосы. Выше 1,1 кГц там так тихо, что даже шум на 60 дБ тише нажатия громче комнаты. Так в 47 полосах из 64. Когда последние 5 нажатий каждого файла отложены на проверку, у модели было 88% на чистых нажатиях, 43% при 60 дБ и 5,6% при 50 дБ. Я предполагаю, что она опирается на эти почти беззвучные верхние полосы.
Тогда я добавил тот же шум того же уровня и в обучающие нажатия. Модель MacBook держит 86% при 60 дБ, 61% при 30 дБ и 26% при 0 дБ, где шум так же громок, как само нажатие. Механическая клавиатура остаётся на 97% даже при 0 дБ. Каждая из этих моделей знала уровень шума заранее.
Обучающие данные. Всё это требует размеченных нажатий именно этой клавиатуры именно в этом месте. На тех же отложенных нажатиях 1 размеченное нажатие на клавишу дало модели MacBook 11%, 5 нажатий 41%, 20 нажатий 88%. Механической клавиатуре нужно меньше: 50% с 1 нажатия и 89% с 5. Кто-то должен сначала нажать каждую клавишу под запись или атакующему придётся разметить нажатия другим способом. Работы, где это делают без разметки, используют языковую модель. Это отдельная задача и я её не повторял.
Чего я не проверял
Я не записывал свою клавиатуру. Замер шёл на сервере без микрофона, так что всё выше это 2 открытых датасета и 3 записи. В наборе Харрисона печатал один человек, про KAD не сказано. Я не пробовал глубокие сети из статей, так что перенос между записями с ними может выйти лучше. Я не пробовал печатать в обычном темпе, где нажатия накладываются, потому что моей нарезке нужно 200 мс между нажатиями. На записи MacBook в окне тишины звук ещё затухает, так что часть из этих 29% может приходиться на звук самой клавиши. Проверка на паролях от этого не зависит. Каждое число здесь получено за 1 прогон. Мои модели детерминированы, а генератор шума запускается с фиксированным зерном.
Для меня итог скромнее заголовка. Звук клавиши действительно выдаёт клавишу. На проверке паролями моя линейная модель получила 77 из 100, а сеть Спаты 89,1% на своих. Но в обоих случаях это та же клавиатура, та же комната и тот же микрофон, что и при обучении. С моей моделью другая запись того же MacBook опускает результат до 5 или 6%. Какая часть из 95% на MacBook пришла из файла, по этому датасету я сказать не могу.