В комментариях к предыдущей статье справедливо заметили, что помнить множество паролей — напрягает.

И ведь действительно так: придумать сложный, запоминающийся пароль, даже в стиле известного «девятнадцать обезьян...» и потом не перепутать, сколько точно было обезьян — это трудно.

И тут я увидел валяющиеся без дела USB‑токены...

Ну, так получилось: один старый, но когда‑то навороченный Aladdin, а другой современный, но простой Rutoken Lite, оставшийся после апгрейда.
Что, если использовать их?

Надо сказать, что на самом деле я с ними раньше вообще не работал, ну кроме «вставить в компьютер и следовать инструкциям на сайте», поэтому разобраться наконец, что это вообще такое, было интересно.

Вообще с этими токенами просто беда какая‑то: в основном они у нас используются либо для банк‑клиентов, либо для общения с госструктурами, поэтому все описания их работы можно условно разделить на две категории:

Первая — это описание для «Мариванны», в стиле «красненький подходит для алкоголя, а синенький не подходит для алкоголя!», «установите нашу программу ХХХХ, она лучше! (лицензия на год столько то денег), напишите полстраницы заклинаний, если не помогло — позвоните по тел 8-800...»

Вторая — от людей глубоко в теме, искусно владеющих канцеляритом типа «получить сертификат в УЦ ЕГАИС с использованием СКЗИ ФСТЭК НЖТИ-1100», где довольно подробно расписано как обновить сертификаты в той самой программе ХХХХ, а если она выдает ошибку 003 425 255 то установить компонент из пакета MS VStudio или пакет DirectX 10.0 (ну, как‑то так, примерно такое советовали сделать).

Но как же оно работает‑то? И как это можно использовать для себя?
В общем, оказалось довольно просто.

Логика работы ключей

В целом все эти USB‑токены разных видов можно поделить на два типа:

  • простые, фактически «флешка с пинкодом»

  • сложные, со встроенной криптографией

Например, тот старый Aladdin — сложный, Rutoken Lite — простой, Rutoken ЭЦП 2/3 — сложный.
На простые, по факту, можно просто что‑то записать, и что‑то оттуда прочитать, при этом это что‑то можно закрыть пинкодом. Если пинкод не введен — данные не получить, если ввести несколько раз неправильно — токен блокируется.

У сложных возможностей больше, можно записать публичные и приватные ключи для ассимметричного шифрования (причем оно понимает, какой ключ — какой), можно сгенерировать эти ключи прямо в токене, можно что‑то зашифровать или расшифровать, используя ключи..
В общем что‑то вроде встроенного openssl.

Зачем это нужно: из «сложного» токена нельзя никак извлечь созданный или записанный в него приватный ключ.
Можно использовать при шифровании на токене, но невозможно извлечь и скопировать, никому.
Поэтому токен всегда один, и всегда конкретно этот — если требуется ограничить доступ к чему‑то, с контролем, что «пользователь может быть только один» — используется именно такой ключ.

Из «простого», зная пинкод, можно прочитать ключ, а значит при желании владелец ключа может его копировать, дублировать и т. д.
Отличие от флешки только в том, что нужен одновременно и токен, и пинкод, сложнее незаметно украсть, но в остальном — все в руках владельца.

Подключаем USB-токен

Для работы с ними в Linux можно использовать специальную утилиту pkcs11-tool.
Команды более‑менее стандартны, но есть важный нюанс: нужен драйвер, умеющий работать с конкретным ключом.
В pkcs11-tool это называется module, по факту ‑.so — библиотека.

В частности, для Aladdin такой драйвер для arm64 мне найти не удалось, а вот для Rutoken он есть, если поискать на сайте. Поэтому дальнейшие эксперименты пока только с Rutoken Lite.

Как уже сказал, это — простой токен, «флешка с пином», шифровать он не умеет, разные ключи не понимает, понимает только один вид данных — просто data. А вот что они означают и как с ними дальше работать — за это уже должна отвечать внешняя программа. Это и буду использовать.

Для начала нужно установить пакеты:

apt install pcscd pcsc_tools opensc

Вставляем USB Rutoken Lite

lsusb 
... 
Bus 001 Device 016: ID 0a89:0025 Aktiv Rutoken lite 
...

Как минимум, через USB его видно.
Попробуем команду pcsc_scan - она должна вывести небольшую "простыню" с упоминанием Rutoken, после чего программу можно закрыть по Ctrl-C.

Если всё так - значит, устройство работает и успешно опознано.
Попробуем с ним что-то сделать:

pkcs11-tool -L 
Available slots: 
Slot 0 (0x0): Aktiv Rutoken lite 00 00   (token not recognized)

Как и сказано выше - токен найден, но pkcs11-tool не умеет с ним работать из коробки. Нужен драйвер, module.
Тут пришлось идти на сайт, искать драйвера.
Т.к. у меня Armbian, т.е. Debian под arm64 - обычные x86 пакеты не подошли, но по счастью, там есть раздел Другие (MIPS, Байкал, ARM...)

Осталось скачать архив, найти в нем подходящий .deb-файл, распаковать его, извлечь .so-библиотеку и положить ее в /usr/lib/

dpkg -x librtpkcs11ecp_2.18.0.0-1_arm64.deb tmpdir
cd tmpdir

(не хотелось устанавливать неизвестно что сразу в систему - поэтому просто распаковка, а потом перенести что куда надо вручную).

Внутри tmpdir — структура каталогов, в которой нужно найти библиотеку, и скопировать ее на место (в версии для x86 скорее всего никаких существенных отличий не будет)

cp librtpkcs11ecp.so /usr/lib/

Теперь пробуем еще раз:

pkcs11-tool --module librtpkcs11ecp.so -L
Available slots:
Slot 0 (0x0): Aktiv Rutoken lite 00 00
  token label        : Rutoken lite 
  token manufacturer : Aktiv Co.
  token model        : Rutoken lite
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 67.4
  firmware version   : 32.2
  serial num         : xxxxxxxx
  pin min/max        : 6/249
Slot 1 (0x1):
  (empty)
Slot 2 (0x2):
  (empty)
....

Вот, теперь заработало!

Слоты - это понятие, относящееся к стандарту PKCS#11: их в принципе несколько, в каждом может находиться "token", причем в одном физическом ключе может быть несколько слотов с токенами, но в данном случае токен один и занимает Slot 0.

Интересно поле token flags, там могут быть указания на необходимость замены пинов, либо еще какая иформация. В данном случае токен инициализирован, пины уже настроены, ничего делать не требуется.
Отдельно заметим флаг rng, это означает, что токен может быть генератором случайной последовательности.

Работа с токеном

Во-первых, доступы.

Права доступа определяются пинкодом. Есть обычный, пользовательский пинкод, и административный, SO (Security Officer) PIN.
Если ввести неправильно несколько раз пользовательский пинкод - он будет заблокирован, но его можно сменить используя административный.
Если заблокируется административный - можно переинициализировать токен с потерей всех данных в нем.

PIN по умолчанию - 12345678, SO PIN - 87654321. Их можно поменять:

pkcs11-tool --module librtpkcs11ecp.so --login --login-type user --change-pin
pkcs11-tool --module librtpkcs11ecp.so --login --login-type so --change-pin

Соответственно, первая команда - пинкод для обычного юзера, вторая меняет административный (SO) пинкод.

Чтобы не вводить пинкод вручную - можно указать его в командной строке

pkcs11-tool --module librtpkcs11ecp.so --login --login-type user --pin 12345678

или в переменной окружения

PIN="12345678" pkcs11-tool --module librtpkcs11ecp.so --login --login-type user --pin env:PIN

Чужую командную строку можно подсмотреть через ps, а вот так заданную переменную окружения - через /proc/, для чего нужны соответствующие права.

То, что "умеет" делать токен - называется механизмами. Проверим:

pkcs11-tool --module librtpkcs11ecp.so --list-mechanism
Using slot 0 with a present token (0x0)
Supported mechanisms:

Ожидаемо. Механизмов у Rutoken Lite нет, он почти ничего не умеет.
Умеет только записывать и читать файлы:

pkcs11-tool --module librtpkcs11ecp.so --type data --label 'Secret' --write-object secret.txt
pkcs11-tool --module librtpkcs11ecp.so --type data --label 'Secret' --read-object 

Указывать тип данных нужно обязательно, правда, все равно он никаких других кроме data не понимает. Если добавить --private и --pin/--login - записанный файл будет защищен пинкодом.

Можно посмотреть, что записано на токене:

pkcs11-tool --module librtpkcs11ecp.so -O 
pkcs11-tool --module librtpkcs11ecp.so -O --pin 12345678

Защищенные записи без пинкода не видны, поэтому первая команда не покажет --private записи, вторая покажет все.

Еще этот окен умеет генерировать случайные данные в виде байтов:

pkcs11-tool --module librtpkcs11ecp.so --generate-random 512

Создаст 512 случайных байт.
Всё остальное, внутреннее шифрование и прочее, требует более продвинутых токенов, и с этим не работает.

Практическое применение

Что можно полезного с ним сделать?

Да, он не поддерживает внутреннего шифрования, приватных/публичных ключей, но зато он умеет просто хранить некие данные.

В принципе, на него можно записать и приватный, и публичный ключи для асимметричного шифрования - просто сам по себе он их не различает, этим должна заниматься внешняя программа.

Но тут вопрос в другом: асимметричное шифрование - это всё-таки больше корпоративные дела: электронные подписи, шифрование для конкретного получателя.
Для персонального использования для себя лично - оно в общем-то особо и не надо, когда все возможные отправители и получатели всегда один человек.

Зато он прекрасно подходит для хранения ключей симметричного шифрования, причем длинных и неподбирабельных. Каждому можно дать какое-то короткое имя, а потом использовать их, просто вызывая по этому имени из токена.

Таким образом, схема работы вырисовывается следующая:
1 - программа (скрипт) управления ключами в токене
2 - программа шифрования с использованием токена
3 - программа дешифрования с использованием токена

Реализация

Во-первых, нужно убедиться, что токен подключен, если нет - предложить подключить или выйти.

Во‑вторых, если подключен — запросить пинкод. Хотя pkcs11-tool умеет сам запрашивать пинкод — будет неудобно делать это постоянно, на каждый чих программы.
Затем прочитать имеющиеся ключи, пронумеровать их, и предложить удалить, или создать новый.

При создании ключа задействовал функцию токена — генерацию случайных байт. Конечно, есть и другие способы — но что она зря будет пропадать?

Поскольку пароль потом предполагается вводить «как текст» — эта последовательность байт пребразуется в строку base64, так и сохраняется. Для преобразования используется openssl.

На всякий случай, с расчетом на эксперименты с асимметричными ключами, немного усложнил названия симметричных ключей — они все называются «key XXXXX». Можно было бы обойтись и без этого, стандарт PKCS#11 предполагает разные типы данных — но конкретно Rutoken Lite их не понимает.

Для шифрования слегка модифицировал скрипты encrypt-decrypt из предыдущей статьи, добавив возможность вызова ключа из токена.

А чтобы не плодить кучу скриптов - скомпоновал в один. Разные функции вызываются в зависимости от разного имени исполняемого файла, точно так же как с busybox:

crypto_pack - создает нужные симлинки
crypto_keys - управление ключами
crypto_encode - шифрование
crypto_decode - расшифровка

Многобукв...
#!/bin/bash

# v 0.1

MAGICK="enc1"

pkcslib="librtpkcs11ecp.so"
cipher="aes-256-ctr"

progname=${0##*/}


prepare_token(){
  token=$(pkcs11-tool --module "$pkcslib" -T 2>/dev/null | awk -F': ' '/token model/{print $2}')

  while [ "x$token" = "x" ]; do

    echo "No token found!"
    read -p "Insert it and press any key for try again, or q for exit: " ans
    echo

    if [ "x$ans" = "xq" ];then
      exit 0
    fi

    token=$(pkcs11-tool --module "$pkcslib" -T 2>/dev/null | awk -F': ' '/token model/{print $2}')
  done

  echo "$token found"
  echo

  read -s -p 'Enter PIN: ' pincode
  echo

  if [ "x$pincode" = "x" ];then
    exit 0
  fi

}


crypto_keys(){

  prepare_token

  while true; do
  
    mapfile -t OBJECTS < <(PINCODE="$pincode" pkcs11-tool --module "$pkcslib" --pin env:PINCODE -O --type data 2>/dev/null | awk -F': ' '/label: / {print $2}' | sed -e 's/^\s*'"'"'//' -e 's/'"'"'\s*$//' | grep '^key ')

    if [ ${#OBJECTS[@]} -eq 0 ]; then
      echo "No keys inside."
    else
      echo "Found keys:"
      for i in "${!OBJECTS[@]}"; do
        name="${OBJECTS[$i]}"
        name="${name#* }"
        printf "%d:   %s\n" $((i+1)) "$name"
      done
    fi

    echo
    read -p "Select key for deletion, n (new key) or q (quit): " choice
    echo

    case "$choice" in
      q|Q)
        echo "Bye..."
        exit 0
        ;;
      n|N)
        read -p "Enter new key name: " new_label
        if [ "x$new_label" != "x" ]; then

          tmpfile=$( mktemp )
        
          pkcs11-tool --module "$pkcslib" --generate-random 100 2>/dev/null | openssl base64 -A > "$tmpfile"
          PINCODE="$pincode" pkcs11-tool --module "$pkcslib" --pin env:PINCODE \
            --write-object "$tmpfile" --private \
            --type data --label "key $new_label" 2>/dev/null >/dev/null

          rm -f "$tmpfile"
        fi
        ;;
      [0-9]*)
        index=$((choice-1))
        if [ $index -ge 0 ] && [ $index -lt ${#OBJECTS[@]} ]; then
          name="${OBJECTS[$index]}"
          name="${name#* }"
          
          read -p "Remove key '$name'? (y/N): " confirm
          echo

          if [ "x$confirm" = "xy" ]; then
            echo "Deletion '$label'..."
            PINCODE="$pincode" pkcs11-tool --module "$pkcslib" --pin env:PINCODE \
              --delete-object --type data --label "key $name" 2>/dev/null
          else
            echo "Cancelled."
          fi
        else
          echo "Incorrect number."
        fi
        ;;
      *)
        echo "Unknown command."
        ;;
    esac

    echo
  done
}

pwd_encrypt(){
  output="$infile.enc"
  echo -n "$MAGICK" > "$output"
  openssl dgst -sha256 -binary "$infile" >> "$output" 
  echo -n "$pass1" | openssl enc -"$cipher" -salt -in "$infile" -pbkdf2 -pass stdin >> "$output"
}

crypto_encode(){
  read -p "Password, key, or quit? (p/k/q): " ans
  echo

  if [ "x$ans" = "xp" ]; then
  
    read -p "Enter password: " -s pass1
    echo

    if [ "x$pass1" = "x" ] ; then
      exit 0
    fi

    pwd_encrypt

  elif [ "x$ans" = "xk" ]; then
  
    prepare_token

    while true; do
  
      mapfile -t OBJECTS < <(PINCODE="$pincode" pkcs11-tool --module "$pkcslib" --pin env:PINCODE -O --type data 2>/dev/null | awk -F': ' '/label: / {print $2}' | sed -e 's/^\s*'"'"'//' -e 's/'"'"'\s*$//' | grep '^key ')

      if [ ${#OBJECTS[@]} -eq 0 ]; then
        echo "No keys inside."
      else
        echo "Found keys:"
        for i in "${!OBJECTS[@]}"; do
          name="${OBJECTS[$i]}"
          name="${name#* }"
          printf "%d:   %s\n" $((i+1)) "$name"
        done
      fi

      echo
      read -p "Select key or q (quit): " choice

      case "$choice" in
        q|Q)
          echo "Bye..."
          exit 0
          ;;
        [0-9]*)
          index=$((choice-1))
          if [ $index -ge 0 ] && [ $index -lt ${#OBJECTS[@]} ]; then
            name="${OBJECTS[$index]}"
            name="${name#* }"

            pass1=$(PINCODE="$pincode" pkcs11-tool --module "$pkcslib" --pin env:PINCODE --read-object --type data --label "key $name" 2>/dev/null)

            pwd_encrypt

            exit 0
          else
            echo "Incorrect number."
          fi
          ;;
        *)
          echo "Unknown command."
          ;;
      esac

      echo
    done
  fi
}

pwd_decrypt(){
  tmp_out=$(mktemp -p .)
  tmp_in=$(mktemp -u -p .)

  mkfifo "$tmp_in"
  tail -c +37 "$infile" > "$tmp_in" &

  echo -n "$pass1" | openssl enc -"$cipher" -d -in "$tmp_in" -out "$tmp_out" -pbkdf2 -pass stdin
  rm "$tmp_in"

  openssl dgst -sha256 -binary "$tmp_out" | cmp -n 32 -s --ignore-initial=0:4 - "$infile"
  if [ $? -ne 0 ]; then
    echo "Incorrect password"
    rm "$tmp_out"
    exit 2
  fi

  mv "$tmp_out" "$orig"
  echo "Ok, $orig decoded"
}

crypto_decode(){

  echo -n "$MAGICK" | cmp -n 4 -s - "$infile"
  if [ $? -ne 0 ]; then
    echo "File $infile has unknown format"
    exit 1
  fi
  
  orig=$(echo $infile | grep -oP '[^/]+(?=\.enc$)')

  if [ "x$orig" = "x" ] ; then
    echo "File $infile has unknown format"
    exit 1
  fi

  if [ -f "$orig" ] ; then
    msg="File $orig already exists, enter new name or overwrite? "
    echo "$msg"
    read -e -i "$orig" -p "> " orig
    echo
  fi 
  if [ "x$orig" = "x" ] ; then
    exit 0
  fi

  read -p "Password, key, or quit? (p/k/q): " ans
  echo

  if [ "x$ans" = "xp" ]; then
  
    read -s -p "Enter password: " pass1
    echo

    if [ "x$pass1" = "x" ] ; then
      exit 0
    fi

    pwd_decrypt

    exit 0

  elif [ "x$ans" = "xk" ]; then
    prepare_token

    while true; do
  
      mapfile -t OBJECTS < <(PINCODE="$pincode" pkcs11-tool --module "$pkcslib" --pin env:PINCODE -O --type data 2>/dev/null | awk -F': ' '/label: / {print $2}' | sed -e 's/^\s*'"'"'//' -e 's/'"'"'\s*$//' | grep '^key ')

      if [ ${#OBJECTS[@]} -eq 0 ]; then
        echo "No keys inside."
      else
        echo "Found keys:"
        for i in "${!OBJECTS[@]}"; do
          name="${OBJECTS[$i]}"
          name="${name#* }"
          printf "%d:   %s\n" $((i+1)) "$name"
        done
      fi

      echo
      read -p "Select key or q (quit): " choice

      case "$choice" in
        q|Q)
          echo "Bye..."
          exit 0
          ;;
        [0-9]*)
          index=$((choice-1))
          if [ $index -ge 0 ] && [ $index -lt ${#OBJECTS[@]} ]; then
            name="${OBJECTS[$index]}"
            name="${name#* }"

            pass1=$(PINCODE="$pincode" pkcs11-tool --module "$pkcslib" --pin env:PINCODE --read-object --type data --label "key $name" 2>/dev/null)

            pwd_decrypt

            exit 0
          else
            echo "Incorrect number."
          fi
          ;;
        *)
          echo "Unknown command."
          ;;
      esac

      echo
    done
  fi
}

if [ "$progname" = "crypto_keys" ]; then
  crypto_keys
elif [ "$progname" = "crypto_encode" ]; then
  if [ -f "$1" ] ; then
    infile=$1
    crypto_encode
  else
    echo "No input file"
  fi
elif [ "$progname" = "crypto_decode" ]; then
  if [ -f "$1" ] ; then
    infile=$1
    crypto_decode
  else
    echo "No input file"
  fi
else
  if [ ! -f "crypto_keys" ]; then ln -s crypto_pack crypto_keys ; fi
  if [ ! -f "crypto_encode" ]; then ln -s crypto_pack crypto_encode ; fi
  if [ ! -f "crypto_decode" ]; then ln -s crypto_pack crypto_decode ; fi
fi

Закинул на ГитХаб

Результат - шифровать файлы можно, это работает. Ключи - либо на токене, либо вводится пароль вручную. Сделано в порядке "а попробую?", но вроде и пользоваться можно.

И всегда надо помнить про область применимости: аппаратный токен - это уязвимость сама по себе, его можно потерять, поломать, его можно отнять и попросить сообщить пинкод, тем более что сам по себе факт его наличия как бы провоцирует это сделать.

Комментарии (0)


  1. Mur81
    25.09.2025 00:55

    Интересно на чём у него генератор псевдослучайных чисел основан.


    1. mmMike
      25.09.2025 00:55

      Производители смарткарт/токенов утверждают, что это не псевдо.
      Правда подробностей, например, разработчик NXP мне не смог/не захотел рассказать.
      Когда я всем этим занимался...


      1. JBFW Автор
        25.09.2025 00:55

        Была у меня книжечка, там был алгоритм генерации псевдослучайной последовательности, как писали - хороший.
        А вот сам алгоритм крайне простой, его запросто на МК реализовать, даже примитивном.


        1. Mur81
          25.09.2025 00:55

          Любой такой алгоритм требует какое-то начальное значение (может я не корректно в терминах криптографии пишу, но смысл думаю понятен). Вот и интересно что является таким значением в Рутокене. Тот же Криптопро предпочитает использовать биологический генератор (то самое "подвигайте мышкой", о котором ниже упомянули) хотя мог бы моментально получить значение из токена если он доступен.


          1. JBFW Автор
            25.09.2025 00:55

            Насколько помню - там было несколько входящих значений, которые влияли на эту последовательность.
            Если бы решал задачу сейчас - можно было бы взять за основу счетчик (что там будет внутри МК - микросекунды, миллисекунды, абстрактные такты), и плясать от них.

            Момент начала генерации кода от момента подачи питания - штука довольно случайная, особенно если успело пройти под миллион тактов.
            Конечно, если задаться целью, зная код, имея железо, и время для сбора статистики...

            Почему те взяли за основы мышку? Ну, так решили.
            В Линуксе есть свой /dev/urandom, в Винде тоже вроде что-то подобное...


            1. Mur81
              25.09.2025 00:55

              Вы рассуждаете как программист, которому поставили задачу написать генератор (псевдо)случайных чисел. И в общем совершенно правы, но только в том случае если эти числа будут использоваться НЕ для целей криптографии. Для генерации, например, GUID - вполне себе.

              В криптографии же получение случайных чисел это краеугольный камень. И в этом случае оказывается, что последовательность полученная скажем на основе тиков МК не такая уж и случайная. Скажем условная Марьиванна сгенерировала ключевую пару. Мы знаем, что она приходит на работу в 9:00 и включает компьютер, а ключ был сгенерирован до обеда в 13:00 (да хоть бы даже и до конца дня). Значит с высокой долей вероятности мы понимаем, что до момента генерации ключа устройство, на котором он генерировался, отработало от 0 до 4 часов. Если алгоритм генерации последовательности инициализируется количеством тактов (или чем-то подобным), то мы получили диапазон этих значений. Зная сам алгоритм дальше уже дело техники. Конечно упрощённо, но суть ясна.

              Поэтому та же Криптопро предпочитает использовать т.н. биологический генератор ибо как там этот кожаный мешок будет двигать мышка 30 сек вещь гораздо менее предсказуемая чем количество тактов МК, прошедших с момента его запуска.

              Собственно по этому и стало интересно как это сделано внутри Рутокена. Ведь тут бай дизайн предполагается, что это будет использоваться именно в криптографии, а не в генерации GUID или там розыгрыше очередного Айфона на канале Вилсакома. Вопрос весьма пикантный в силу того, что Рутокен Лайт это крайне примитивное устройство за 3 копейки. Вряд ли там используются какие-то серьёзные аппаратные датчики (которые ниже уже упомянули), на основе электромагнитных возмущений, распада ядра атома, космического излучения или что-то подобного (и это все не прикол).


              1. JBFW Автор
                25.09.2025 00:55

                Подозреваю, что создатели чипа просчитали вероятности математически, а не полагаясь на "здравый смысл".

                Поясню: допустим, мы берем за основу тики процессора, параметр А у нас - word от счетчика, параметр В - word от счетчика со сдвигом.
                Разумеется, они связаны, общее число вариантов конечно, последовательности для каждого известны и т.д.

                По здравому смыслу так и будет: приходит Мариванна в 9, до 13 генерирует ключ, скорее всего в 10:30 (как показали наблюдения за ней)

                Но сам счетчик - unsigned long, с периодом обращения, ну скажем, около часа, малейшее отклонение интервала от 9:00 и 10:30 дает расхождения в пределах 65536 вариантов параметра А, * на еще какое-то, меньшее, количество вариантов параметра В. Увеличим частоту - увеличим варианты В.

                Опять же, это число конечно, и если последовательности нам известны - можем предугадать.
                Но - вероятность этого = 1/ (65536 * тыщи), к тому же от последовательности у нас небольшой кусочек, генерируется она вообще однократно (ну ладно, раз в квартал) - в общем, всё плохо с подбором.

                А вот движение мыши - в теории непредсказуемо, но оно тоже ограничено параметрами экрана, т.е. количество вариантов конечно, и скорее всего из всего их массива будет только "влево-вправо по дуге несколько раз".

                Остается только рассчитать вероятности предсказания того и другого - подозреваю, что они будут примерно одинаковы, если вообще не в пользу "мыши".

                Но это только предположение


                1. Mur81
                  25.09.2025 00:55

                  Я тоже не настоящий криптограф ) Но думаю, что нам только КАЖЕТСЯ, что в таком подходе вероятность достаточная. Примерно тоже самое, что я сейчас писал в соседнем комментарии про антенну и АЦП. Т.е. с бытовой точки зрения это действительно будет случайное число достаточное для любых "бытовых" нужд. Но вот математик с нами наверное не согласится. Поэтому как раз при отсутствии надёжного генератора предпочтение отдаётся кожаному мешку с мышкой. Получается, что несмотря на то, что кожаный мешок скорее всего подвигает мышку вправо-влево (хотя лично я всегда двигаю как можно более заковырестей) но накладывая на это разрешающую способность сенсора мышки получается результат надёжней чем на тактах процессора.


              1. inkelyad
                25.09.2025 00:55

                Вряд ли там используются какие-то серьёзные аппаратные датчики (которые ниже уже упомянули), на основе электромагнитных возмущений, распада ядра атома, космического излучения или что-то подобного (и это все не прикол).

                Интересно, а просто сделать антенну на печатной плате и скормить то, что она напринимала в АЦП чипа - сильно проблемно c точки зрения отсутствия нужной случайности? Или датчик вибрации (чем шумнее, тем лучше) поставить. Я, возможно, ошибаюсь, но с современными ширпотребовскими чипами 'за 3 копейки' тут даже особо стараться не нужно - нужные блоки в нем уже почти наверняка будут.


                1. Mur81
                  25.09.2025 00:55

                  Антенна на АЦП - плохо. На самом деле это весьма забавно, но такой эксперимент может проделать большинство (я надеюсь) обитателей Хабра (я проделывал).

                  Берём банально Ардуино, вешаем на ногу АЦП отрезок провода, читаем получившиеся значения. Убеждаемся, что мы получаем хаотические (на первый взгляд) значения в диапазоне 0..255 (если правильно помню АЦП там 8-и битный, давно дело было). Теперь читаем значения с АЦП в цикле и выводим на график x=время, y=значение. Убеждаемся, что мы получили что-то подозрительно напоминающее синусоиду с частотой 50 Гц. Что бы это могло быть? :)

                  Мораль этого всего такова, что многие процессы с житейской точки зрения весьма похожи на хаотические. Однако при применении к ним математики оказывается, что до настоящей случайности там ооойй как далеко. И серьёзная криптография относится к этому вопросу очень серьёзно. Можно наверно даже сказать, что она на этом буквально основана.


                  1. inkelyad
                    25.09.2025 00:55

                    Берём банально Ардуино, вешаем на ногу АЦП отрезок провода, читаем получившиеся значения.

                    Так я не про кусок провода а про нормально рассчитанную антенну, которая будет ловить и усиливать что-нибудь интересное.

                    Убеждаемся, что мы получили что-то подозрительно напоминающее синусоиду с частотой 50 Гц. Что бы это могло быть? :)

                    Я подозреваю, что даже так будет все-таки шумная синусоида, а нам это и надо.


                  1. RTFM13
                    25.09.2025 00:55

                    Предположим у нас АЦП 10 бит. Берём младшие 4 (биты 0 - 3). А биты 2-5 используем для джиттера (при этом проверяем что входной сигнал имеет размах гарантирующий кратное переполнение (например не менее 8 бит). Получаем экспоненциальное расхождение погрешности. Скипаем для надёжности первые несколько десятков бит. Так можно достаточно быстро насобирать например сотни бит, что уже серьезно. Даже если пару бит "выпадут" из ключа 512 бит, это обычно не фатально.

                    Есть еще методика повышения разрядности АЦП сложением с периодическим сигналом с одновременным усреднением. Убрав из неё усреднение мы можем более эффективно извлекать шум из сигнала.

                    Вообще нехитрой схемой можно получить практически чистый дробовой шум полупроводника. Тут и антенна не нужна, и, более того, при грамотном дизайне оно будет почти невосприимчиво к внешним воздействиям. Усиливаем до тех же 10 бит добавляя шум усилителя и берём только младший бит. Получаем случайность практически уровня радиоактивного распада.

                    PS
                    Напомнило


                    1. inkelyad
                      25.09.2025 00:55

                      И вот так мы выяснили, что если не надо сертифицироваться в ФСБ, то все что требуется для генерации адекватных случайных чисел - это добавить на плату микросхему усилителя попаршивее стоимость рубль/мешок.


              1. min8
                25.09.2025 00:55

                Всегда было интересно, если записать движения мышкой и воспроизвести, будет ли идентичный ключ?


            1. RTFM13
              25.09.2025 00:55

              если успело пройти под миллион тактов.

              Если вы в качестве основы берёте количество тактов от нуля до миллиона, то какой- бы вы статический алгоритм к нему не применили - у вас все равно максимум миллион вариантов. Это вообще ни о чём.


      1. Shaman_RSHU
        25.09.2025 00:55

        Вообще для этого используются аппаратные датчики. По крайней мере так требуют регуляторы (ФСБ) по отечественной криптографии (СКЗИ).

        Broadcom SSL Crypto Accelerator Card BCM95821/22/SSN 110042-30
        ПАК Соболь

        Можно с помощью того-же СКЗИ КриптоПро и ПАК Соболь "намайнить" кучу случайных чисел, сохранить их в файл и потом использовать.


        1. Rsa97
          25.09.2025 00:55

          "намайнить" кучу случайных чисел, сохранить их в файл и потом использовать

          Напомнило


    1. RoasterToaster
      25.09.2025 00:55

      На " подвигайте мышкой"

      Пользователь рандомно двигает курсор по экрану в течение секунд 30


      1. JBFW Автор
        25.09.2025 00:55

        не, это программа такое делает. Ключ выдает мгновенно.


  1. mmMike
    25.09.2025 00:55

    все эти токены это исторически smartcard+usb ридер в одной упаковке.
    pcsc - это стандарт работы с SmartCard ридером.

    У GemAlto, например, был переходной вариант USB ридер в формате "флешки" в котором можно было отщелкнув крышечку вставить/заменить карту (обрезанная до контактной площадки как SIM карта.

    Где то в районе 2008..2009 (могу ошибаться в датах. лень копать/вспоминать) стандарт работы через APDU с приложением на смарт картах стал более менее стандартизированным и подогнаным под PKCS#11.


  1. Rsa97
    25.09.2025 00:55

    Можно использовать при шифровании на токене, но невозможно извлечь и скопировать, никому.

    А какие токены выдаёт налоговая? Формально в них некопируемые сертификаты. По факту скопировать можно, если знать как.


    1. mixan
      25.09.2025 00:55

      Бывают не экспортируемые, и не извлекаемые. Налоговая делает не экспортируемые. Их да, вытащить можно. Не извлекаемые - я не нашел решения.


    1. JBFW Автор
      25.09.2025 00:55

      Либо Rutoken Lite или S, если физлицо (копируемые - там только пароль хранить), либо Rutoken ЭЦП - некопируемые сертификаты генерируются на ключе, либо Jacarta (там вроде тоже и такой и такой варианты есть).

      Остальное несертифицированное, и официально нельзя использовать.

      Можно просто принести свой, купленный отдельно - сертифицированный, конечно.


    1. aamonster
      25.09.2025 00:55

      Никакие она не выдаёт, сам покупаешь и приходишь с ним. Взял простой (rutoken lite) – получи сертификат в формате богомерзкого КриптоПро, взял сложный (rutoken ecp)– можешь заказать в формате pkcs#11, неизвлекаемый (мне кажется разумным).

      Ну и где-то (например, ЕГАИС) – только сложный.


      1. JBFW Автор
        25.09.2025 00:55

        Видимо, где как. В нашей районной могут продать на месте, или можно купить буквально за углом в вендинговом автомате, или заказать на маркетплейсе и придти с ним...


        1. aamonster
          25.09.2025 00:55

          За углом – да, и в Питере так же. Только сильно дороже, чем на маркетплейсе. Но кто не купил заранее – бегают и покупают, чтоб время не терять.


      1. aborouhin
        25.09.2025 00:55

        взял сложный (rutoken ecp)– можешь заказать в формате pkcs#11, неизвлекаемый (мне кажется разумным).

        Мне вот наоборот - не кажется. Я готов брать на себя ответственность за безопасное хранение своих ключей ЭЦП, но совершенно не готов поставить критически важные процессы в зависимость от утери/кражи/изъятия/повреждения одного конкретного материального носителя, оперативно восстановить который не всегда возможно (начиная от физического нахождения руководителя вдали от родины, заканчивая всяческими корпоративными спорами, наложенными ограничениями и т.п.) Так что возможность записать ключ на Rutoken Lite, который копируется общеизвестными способами, хоть как-то спасает.


        1. aamonster
          25.09.2025 00:55

          Дело ваше. В норме это решается более чем одним токеном, а вот связка rutoken lite + crypto pro у меня симпатии не вызывает. Ну не нравится мне сама идея загружать ключ в память и делать с ним что-то – тогда можно и без свистка вообще обойтись, обычной флешкой. Или, как это сейчас принято, приложением на смартфоне.

          Плюс rutoken эцп позволяет многие операции выполнять без криптопро – э это, скажу вам, большое улучшение. Этот монстр Франкенштейна, расползающийся по системе и не работающий ни на чём, кроме винды – веский довод для поиска альтернатив. Какой та Макс? Вот где ужас.


          1. aborouhin
            25.09.2025 00:55

            А как в ФНС записать ключ ЭЦП на более чем один токен?.. Что-то я такой опции не увидел.

            Вообще я токен использую только один раз - чтобы скопировать ключ с него в реестр виртуальной машины, специально выделенной для работы с госпорталами, КриптоПро и прочими не внушающими доверия штуками. А дальше уже контролирую доступ к этой виртуалке и делаю её бекапы.


            1. aamonster
              25.09.2025 00:55

              Ваш вариант мне нравится, при нём мне тоже кажется достаточным ограничиться "флешкой с пин-кодом", раз уж нельзя просто на флешке или ещё каким вменяемым способом отдать в налоговую свой публичный ключ.

              Ключ более чем на один токен – нельзя, и это нормально. Правильное решение – несколько ключей.


  1. Sosnin
    25.09.2025 00:55

    что интересно за денюжку тот же Тензор - дает обычные, экспортируемые (а следовательно менее защищенные от "слива")


  1. alephis
    25.09.2025 00:55

    На сколько помню, у продвинутых токенов была опция вроде FIPS, не позволявшая штатными средствами больше ничего сделать с заблокированным токеном, в том числе полный сброс.

    От утери/порчи токена можно защититься например наличием нескольких токенов, с одинаковым содержимым, например.


  1. Squoworode
    25.09.2025 00:55

    запоминающийся пароль, даже в стиле известного "девятнадцать обезьян ..."

    С запоминаемостью у него не очень: ведь обезьян было не 19...


    1. JBFW Автор
      25.09.2025 00:55

      Вот именно! )

      Однако, пароль вы вспомнили, я вижу...