Как сгенерировать SSH-ключ для доступа на сервер
Разбираемся, как создать шифрованный протокол для связи с сервером и входить в систему без пароля учетной записи.
Введение
Использование SSH-ключей — простой и надежный способ обеспечения безопасности соединения с сервером. В отличие от пароля, взломать SSH-ключ практически невозможно. Сгенерировать SSH-ключ очень просто.
SSH-ключ для Linux/MacOS
Откройте терминал и выполните команду:
$ ssh-keygen -t rsa
На консоль будет выведен следующий диалог:
Enter file in which to save the key (/home/user/.ssh/id_rsa):
Нажмите на клавишу Enter. Далее система предложит ввести кодовую фразу для дополнительной защиты SSH-подключения:
Enter passphrase (empty for no passphrase):
Этот шаг можно пропустить. При ответе на этот и следующий вопрос просто нажмите клавишу Enter.
После этого ключ будет создан, а на консоль будет выведено следующее сообщение:
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
476:b2:a8:7f:08:b4:c0:af:81:25:7e:21:48:01:0e:98 user@localhost
The key's randomart image is:
+--[ RSA 2048]----+
|+.o. |
|ooE |
|oo |
|o.+.. |
|.+.+.. S . |
|. + o + |
| .o . |
| . .. . |
| . |
+-----------------+
Далее выполните в терминале команду:
$ cat ~/.ssh/id_rsa.pub
На консоль будет выведен ключ. Скопируйте его и вставьте в соответствующее поле:
Нажмите на кнопку «Добавить».
Добавив ключ, выполните в терминале команду:
$ ssh root@[IP-адрес сервера]
После этого соединение с сервером будет установлено. Вводить пароль при этом не потребуется.
SSH-ключ для Windows
В OC Windows подключение к удаленным серверам по SSH возможно, например, с помощью клиента Putty. Скачать его можно здесь (ссылка взята с официального сайта). Putty не требует установки — чтобы начать с ним работать, достаточно просто распаковать скачанный архив.
По завершении распаковки запустите файл puttygen.exe.
Выберите тип ключа SSH-2 RSA и длину 2048 бит, а затем нажмите на кнопку Generate:

Во время генерации водите курсором в пустой области окна (это нужно для создания псевдослучайности):

Сохраните сгенерированную пару ключей на локальной машине (кнопки Save public key и Save private key).
Скопируйте сгененированный ключ и вставьте его в соответствующее поле.
Разместите SSH-ключ на облачном сервере Selectel
Для безопасного подключения по зашифрованному протоколу SSH
Заключение
В этой инструкции мы рассмотрели, как создать шифрованный протокол для связи с сервером: сгенерировали SSH-ключ для Linux/MacOS и Windows. Теперь вы можете входить в систему без пароля учетной записи.
Зарегистрируйтесь в панели управления
И уже через пару минут сможете арендовать сервер, развернуть базы данных или обеспечить быструю доставку контента.
Как создать ключ для авторизации по SSH и добавить его на сервер?
![]()
На клиентской стороне должен быть установлен пакет ssh (openssh). На серверах FirstVDS с шаблонами по умолчанию необходимое ПО уже установлено.
Для ОС CentOS, AlmaLinux или RockyLinux выполните команду:
# yum -y install openssh-server openssh-clients
Для ОС Debian или Ubuntu выполните команду:
# apt -y install openssh-server
Дальнейшая инструкция будет одинаковая для всех ОС.
На клиентском компьютере в командной строке выполните команду генерации ключей:
# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase):
Введите путь файла, в который будут помещены ключи. Каталог по умолчанию указан в скобках, в примере /домашний_каталог/.ssh/id_rsa . Если хотите оставить расположение по умолчанию, нажмите Enter.
Пароль (passphrase) используется для ограничения доступа к закрытому ключу. Пароль усложнит использование ключа третьими лицами в случае утраты. Если не хотите использовать секретную фразу, нажмите Enter без заполнения строки.
Успешно сгенерировав пару ключей, вы увидите уведомление:
Your identification has been saved in /root/.ssh/id_rsa Your public key has been saved in /root/.ssh/id_rsa.pub The key fingerprint is: SHA256:JPDzeSan06C9+osd+sKXWP0RmPk4UbSESaTvYn0aXVk root@test-server1.com The key's randomart image is: +---[RSA 3072]----+ |. oo+o | | o .o. | | + o =. E | | = o= . o | | S.=+ .o | | o.@+.o. | | ..oB.=oo. | | +=o= +. | | +**.. | +----[SHA256]-----+
По умолчанию в современных ОС генерация ключей происходит по умолчанию с такими настройками: тип аутентификации — RSA, число бит в ключе — 2048 или 3072.
Рекомендуем позаботится о безопасности ключей. В первую очередь обязательно необходимо задавать пароль (passphrase), который не должен быть простым. С помощью параметра -a можно увеличить время проверки пароля ключа, чтобы усложнить взлом методом грубого перебора (в случае, если ключ будет утерян, у вас будет больше времени на смену ключа на сервере).
Будьте внимательны, слишком большое значение приведет к тому, что вам придется ждать каждый раз при входе на сервер по ключу. Значение по умолчанию — 3 секунды, можно задать 15 секунд. С помощью параметра -b можно задать число бит в ключе — 4096. Получаем такую команду:
# ssh-keygen -b 4096 -a 15
Выбираем директорию, вводим пароль и видим ключ RSA 4096.
Открытый ключ хранится в файле /домашний_каталог/.ssh/id_rsa.pub , закрытый — /домашний_каталог/.ssh/id_rsa .
Никогда и никому не передавайте, не показывайте свой закрытый ключ и не выкладывайте его на публично доступные сервисы (в т.ч. GitLab, GitHub и пр.).

Скопируйте открытый ключ на сервер в файл /домашний_каталог/.ssh/authorized_keys . Одной строкой:
cat ~/.ssh/id_rsa.pub | ssh root@ip-адрес-сервера 'cat >> ~/.ssh/authorized_keys'
Или откройте этот файл на сервере редактором vi и вставьте строку с открытым ключом после ssh-rsa .

Ещё один способ скопировать ключ в authorized_keys — команда echo , которая помещает строку в конец файла.
echo ssh-rsa строка-публичного-ключа >> /root/.ssh/authorized_keys

Теперь можно отключить на сервере аутентификацию по паролю и использовать только SSH-ключи.
Создание SSH-ключей на Windows с PuTTYgen
Если вы используете ОС Windows, то подключиться по SSH к вашему (Linux) серверу можно через PuTTY или OpenSSH . Генерация ключей в этом случае выполняется также при помощи этих программ. В примере мы используем клиент PuTTY.
Запустите приложение PuTTYgen , которое устанавливается вместе с PuTTY.

Выберите тип ключа SSH2-RSA и нажмите Generate .

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

После завершения создания ключей открытый ключ выводится на экран, закрытый хранится в памяти приложения. Чтобы сохранить эти ключи нажмите Save public key и Save private key . Укажите расположение файлов с ключами.

При сохранении закрытого ключа, если не заполнено поле Key passphrase , появится запрос «Хотите ли вы сохранить ключ без секретной фразы?»

Теперь открытый ключ необходимо скопировать на сервер в файл authorized_keys . Используйте WinSCP или другой клиент для работы с файлами на удалённом Linux-сервере. Вы можете скопировать файл с открытым ключом целиком на сервер, чтоб его копия хранилась в папке .ssh

Откройте файл authorized_keys через WinSCP и файл, в который вы сохранили открытый ключ (public), на локальном компьютере текстовым редактором. Скопируйте значение ключа, сохраните и закройте файл в WinSCP.

При запуске PuTTY укажите путь к закрытому ключу на локальном компьютере. Для этого во вкладке Connections → Auth выберите необходимый путь.

Теперь можно отключить на сервере аутентификацию по паролю и использовать только SSH-ключи.
Отключение аутентификации по паролю
Подключитесь к серверу по SSH, используя пароль, и откройте файл sshd_config для редактирования (например, с помощью текстового редактора Vi).
# vi /etc/ssh/sshd_config
Убедитесь, что указан правильный путь к открытым ключам SSH, поставьте значение параметра PasswordAuthentication no .

Перезапустите службу sshd:
# systemctl restart sshd
Подключитесь к серверу по SSH без использования пароля. Например, запустите PuTTY, проверьте, что во вкладке Connections -> Auth содержится путь к закрытому ключу и откройте подключение.
Login as: root Authenticating with public key “rsa-key-20230205” Last login: Sun Feb 5 13:11:24 2023 from 1.1.1.1
В случае успешной аутентификации по SSH-ключу вы получите доступ к командной строке сервера и сообщение вида Authenticating with public key «rsa-key-20230205», где rsa-key-20230205 — имя применённого закрытого ключа, указанное вами в файле authorized_keys.
Создание нового ключа SSH и его добавление в ssh-agent
После проверки наличия существующих ключей SSH можно создать ключ SSH для проверки подлинности, а затем добавить его к агенту SSH.
Platform navigation
About SSH key passphrases
You can access and write data in repositories on GitHub.com using SSH (Secure Shell Protocol). When you connect via SSH, you authenticate using a private key file on your local machine. For more information, see «About SSH.»
When you generate an SSH key, you can add a passphrase to further secure the key. Whenever you use the key, you must enter the passphrase. If your key has a passphrase and you don’t want to enter the passphrase every time you use the key, you can add your key to the SSH agent. The SSH agent manages your SSH keys and remembers your passphrase.
If you don’t already have an SSH key, you must generate a new SSH key to use for authentication. If you’re unsure whether you already have an SSH key, you can check for existing keys. For more information, see «Checking for existing SSH keys.»
If you want to use a hardware security key to authenticate to GitHub, you must generate a new SSH key for your hardware security key. You must connect your hardware security key to your computer when you authenticate with the key pair. For more information, see the OpenSSH 8.2 release notes.
Generating a new SSH key
You can generate a new SSH key on your local machine. After you generate the key, you can add the public key to your account on GitHub.com to enable authentication for Git operations over SSH.
Note: GitHub improved security by dropping older, insecure key types on March 15, 2022.
As of that date, DSA keys ( ssh-dss ) are no longer supported. You cannot add new DSA keys to your personal account on GitHub.com.
RSA keys ( ssh-rsa ) with a valid_after before November 2, 2021 may continue to use any signature algorithm. RSA keys generated after that date must use a SHA-2 signature algorithm. Some older clients may need to be upgraded in order to use SHA-2 signatures.
- Open Terminal Terminal Git Bash .
- Paste the text below, replacing the email used in the example with your GitHub email address.
ssh-keygen -t ed25519 -C "your_email@example.com"
Note: If you are using a legacy system that doesn’t support the Ed25519 algorithm, use:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
This creates a new SSH key, using the provided email as a label.
> Generating public/private ALGORITHM key pair.
When you’re prompted to «Enter a file in which to save the key», you can press Enter to accept the default file location. Please note that if you created SSH keys previously, ssh-keygen may ask you to rewrite another key, in which case we recommend creating a custom-named SSH key. To do so, type the default file location and replace id_ALGORITHM with your custom key name.
> Enter a file in which to save the key (/Users/YOU/.ssh/id_ALGORITHM): [Press enter]
> Enter a file in which to save the key (/c/Users/YOU/.ssh/id_ALGORITHM):[Press enter]
> Enter a file in which to save the key (/home/YOU/.ssh/ALGORITHM):[Press enter]
> Enter passphrase (empty for no passphrase): [Type a passphrase] > Enter same passphrase again: [Type passphrase again]
Adding your SSH key to the ssh-agent
Before adding a new SSH key to the ssh-agent to manage your keys, you should have checked for existing SSH keys and generated a new SSH key. When adding your SSH key to the agent, use the default macOS ssh-add command, and not an application installed by macports, homebrew, or some other external source.
- Start the ssh-agent in the background.
$ eval "$(ssh-agent -s)" > Agent pid 59566
-
First, check to see if your ~/.ssh/config file exists in the default location.
$ open ~/.ssh/config > The file /Users/YOU/.ssh/config does not exist.
touch ~/.ssh/config
Host github.com AddKeysToAgent yes UseKeychain yes IdentityFile ~/.ssh/id_ed25519
- If you chose not to add a passphrase to your key, you should omit the UseKeychain line.
- If you see a Bad configuration option: usekeychain error, add an additional line to the configuration’s’ Host *.github.com section.
Host github.com IgnoreUnknown UseKeychain
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Note: The —apple-use-keychain option stores the passphrase in your keychain for you when you add an SSH key to the ssh-agent. If you chose not to add a passphrase to your key, run the command without the —apple-use-keychain option. The —apple-use-keychain option is in Apple’s standard version of ssh-add . In MacOS versions prior to Monterey (12.0), the —apple-use-keychain and —apple-load-keychain flags used the syntax -K and -A , respectively. If you don’t have Apple’s standard version of ssh-add installed, you may receive an error. For more information, see «Error: ssh-add: illegal option — apple-use-keychain.» If you continue to be prompted for your passphrase, you may need to add the command to your ~/.zshrc file (or your ~/.bashrc file for bash).
If you have GitHub Desktop installed, you can use it to clone repositories and not deal with SSH keys.
-
In a new admin elevated terminal window (PowerShell or CMD), ensure the ssh-agent is running. You can use the «Auto-launching the ssh-agent» instructions in «Working with SSH key passphrases», or start it manually:
# start the ssh-agent in the background Get-Service -Name ssh-agent | Set-Service -StartupType Manual Start-Service ssh-agent
ssh-add /c/Users/YOU/.ssh/id_ed25519
- Start the ssh-agent in the background.
$ eval "$(ssh-agent -s)" > Agent pid 59566
ssh-add ~/.ssh/id_ed25519
Generating a new SSH key for a hardware security key
If you are using macOS or Linux, you may need to update your SSH client or install a new SSH client prior to generating a new SSH key. For more information, see «Error: Unknown key type.»
- Insert your hardware security key into your computer.
- Open Terminal Terminal Git Bash .
- Paste the text below, replacing the email address in the example with the email address associated with your account on GitHub.
ssh-keygen -t ed25519-sk -C "your_email@example.com"
ssh-keygen -t ed25519-sk -C "your_email@example.com"
ssh-keygen -t ed25519-sk -C "your_email@example.com"
Note: If the command fails and you receive the error invalid format or feature not supported, you may be using a hardware security key that does not support the Ed25519 algorithm. Enter the following command instead.
ssh-keygen -t ecdsa-sk -C "your_email@example.com"
> Enter a file in which to save the key (/Users/YOU/.ssh/id_ed25519_sk): [Press enter]
> Enter a file in which to save the key (/c/Users/YOU/.ssh/id_ed25519_sk):[Press enter]
> Enter a file in which to save the key (/home/YOU/.ssh/id_ed25519_sk):[Press enter]
> Enter passphrase (empty for no passphrase): [Type a passphrase] > Enter same passphrase again: [Type passphrase again]
Если хоть раз мечтал написать crack или keygen
Дня 3 назад заглянул на сайт crackmes.one попробовать силы во взломе защит. Просто наугад взялся за «hitTman’s Kolay One!»: просто по оценке Difficulty: 2.0 и Quality: 4.0. Не примитивно, но и не слишком сложно.
Оказалось, форма ввода пароля с подсказкой: текст кнопки «submit password» после нажатия меняется на число. Если попробовать разные символы пароля, заметно, что для одних и тех же символов число не меняется. Очевидно, пароль подается в хеш-функцию, а ее результат попадает на кнопку. Пробуя пары символов, легко узнать что число на кнопке — сумма чисел для символов пароля.

Логично, что программа сравнивает хеш с эталоном прежде чем выдает сообщение «Try harder!». Ищем в сообщение строках бинарника. Повезло: оно даже не зашифровано и на него единственная ссылка в коде.


Очевидно, рядом же и эталон хеша: 12Eh. Легко проверить: из известных хешей символов составить пароль, например «AaAaAaAaAaAaAaAaAaAaAaAaAaAaAa//» и предложить программе, на что она выдает «Great Job».
Автор просил: «find a Valid pass!», но это оказалось просто, да и верный пароль — не один. Куда интересней написать генератор ключей. Пригодится таблица хеш-значений для всего алфавита. Руками вводить символы пароля и записывать на бумаге их хеши долго и скучно, ведь можно заставить программу саму перебрать алфавит.
У OllyDbg есть коллега — Immunity Debugger, он умеет выполнять скрипты на Python. Отыщем хеш-функцию и заставим ее обработать алфавит.
В обработчике ButtonClick (sub_45385C) прямо перед сравнением хеша с эталоном находится вызов sub_4537C4. Похоже, это и есть хеш-функция: она принимает строку пароля и возвращает хеш в EAX. Привычных push для передачи параметров не видно, вероятно, они передаются через регистры. Если так, то var_C содержит указатель на строку-пароль.
Выше вызов sub_432A4C принимает два аргумента: адрес var_C и еще какой-то указатель по смещению от EBX. Ищем что записано в EBX: выше по коду ButtonClick в него записывается содержимое EAX, но прежде нет записей в EAX, значит там тоже находится параметр процедуры. Заглянув в документацию по Delphi видим, что обработчику ButtonClick передается адрес TObject sender. Можно догадаться, что второй аргумент sub_432A4C — это адрес поля ввода на форме, с которого она читает пароль.
Таких вызовов в ButtonClick два: если запустить программу в отладчике, увидим, что sub_00432A4C действительно записывает указатель на строку-пароль в переменную-аргумент.
Если дальше выполнять ButtonClick пошагово в отладчике, можно заметить, что в переменной на стеке появится и текст кнопки — число. Легко догадаться, что sub_407CE0 — это int to string, [ebx+2FCh] — это указатель на кнопку, а sub_00432A7C — это setButtonText.

Теперь подменим пароль перед хешированием: ставим breakpoint по адресу 0x004538B3 — прямо перед вызовом hashFn она же sub_4537C4. Вводим пароль 1234 и средствами отладчика отредактируем содержимое памяти var_C — введем букву A и символ конца строки \0. Сейчас хеш-функция должна вернуть в EAX значение 0x13 (19). Шагаем вперед и. Первая неудача: в EAX — 0x56 (86). Долго думал, пробовал, грешил на Юникод или еще какие скрытые хитрости программы. Оказалось, программа где-то запоминает длину строки и Вместо хеша «A\0» вычисляет хеш «A\034». Хеш \0 равен 0, поэтому если ввести пароль A34 получим хеш 0x56. Значит введем один символ пароля и повторим правки в отладчике — теперь получилось!
Теперь нужно повторить действия для всего алфавита:
- остановиться перед вызовом hashFn
- сменить символ пароля на следующий по алфавиту
- остановиться после вызова hashFn и запомнить хеш символа
- вернуть программу к вызову hashFn
Вот скрипт на Python, который это сделает:
import immlib imm = immlib.Debugger() def main(args): table = <> # break после hashFn imm.setBreakpoint(0x004538B8) mem_password = imm.getRegs()["EAX"] # цикл по печатным символам ASCII for c in range(0x20, 0x7F): b = bytearray() b.append(c) b.append(b'\x00') if imm.writeMemory(mem_password, bytes(b)) '".format(chr(c))) return "ERROR" imm.run() # запоминаем хеш table[c] = imm.getRegs()["EAX"] # Возвращаемся к вызову hashFn imm.setReg("EIP", 0x004538B3) # снова передали указатель на строку-пароль в EAX imm.setReg("EAX", mem_password) imm.run() # запишем результаты в файл with open("C:/a.csv", "w") as out: for c in table: out.write(" ".format(chr(c))) out.write("0x\n".format(table[c])) return "Kolay done"
Как вариант можно вводить пароль 1234 и вызывать imm.writeLong(mem_password, с), чтобы записать байт символа и три нуля следом.
Алфавитом овладели, правило хеширования пароля знаем. Как генерировать пароли?
Наивное решение: перебор всех ключей и проверка каждого. Вот код, что найдет все ключи длины 2:
const string alphabet = //. const unordered_map weights = //. const int N = 2; const int S = 0x12E; string key; void generateKeys(ostream& out) < if (N > else < for (char c : alphabet) < const int w = weights.at(c); if (sum + w > > >
Работает, но захлебывается уже на ключах длиной больше 5.

От перестановки мест слагаемых сумма не меняется, так что код можно улучшить: пусть он перебирает сочетания.
bool nextCombination(vector& nums, int n) < const int k = nums.size(); for (int i = k - 1; 0 return true; > > return false; > bool TestKey(const vector& nums) < int sum = 0; for (int i : nums) < sum += weights.at(alphabet[i]); >return S == sum; > string MakeKey(const vector& nums) < string key; for (int i : nums) < key.push_back(alphabet[i]); >return key; > void generateKeys(ostream& out) < vectornums(N); for (int i = 0; i < N; ++i) < nums[i] = i; >do < if (TestKey(nums)) < ++cnt; out > while (nextCombination(nums, alphabet.size())); >
Теперь можно дождаться, пока он найдет все сочетания длины 7.

А если хочется ключи длиннее? Можно останавливаться на первом найденном ключе — авось повезет. Время, когда перебор наткнется на первый верный ключ непредсказуемо. Я так и не дождался, пока программа найдет первый верный ключ длины 20.

Можно ли найти лучшее решение, чем перебор всех сочетаний? Например, если известен один верный ключ, как перейти к следующему?
vx -> ?
Аналогия: чтобы получить следующее число, добавляем 1 к младшему разряду и, если необходимо, выполняем перенос:
18, 19, 20, .
Можно заменять символы пароля так, чтобы его хеш не менялся. Беда в том, что для ‘x’ нет равноценной замены.
0x01 001: %)+/5;=CGIOSYaegkmq 0x08 008: 1 0x0c 00c: y 0x0d 00d: # 0x0f 00f: ! 0x11 011: '7 0x13 013: AM 0x14 014: " 0x15 015: 3[ 0x16 016: & 0x17 017: 9U 0x19 019: _w 0x1a 01a: . 0x1b 01b: E 0x1d 01d: s 0x1f 01f: > 0x20 020: : 0x21 021: -W 0x22 022: > 0x23 023: ] 0x28 028: ,JQ 0x29 029: ?o 0x2b 02b: 2 0x2c 02c: R 0x2d 02d: < 0x2e 02e: 4V 0x31 031: K 0x32 032: (^ 0x36 036: * 0x37 037: $ 0x38 038: j 0x39 039: c 0x3a 03a: D 0x3e 03e: v 0x3f 03f: @ 0x40 040: 8Lz 0x41 041: u 0x42 042: 6 0x49 049: b 0x4a 04a: F 0x4c 04c: 0\ 0x4e 04e: B 0x57 057: i 0x5a 05a: N 0x5c 05c: X 0x5e 05e: t 0x64 064: | 0x6a 06a: Phn 0x6c 06c: < 0x72 072: f 0x75 075: d 0x7b 07b: H 0x7e 07e: r 0x88 088: p 0x8c 08c: T 0x90 090: Z 0x9c 09c: ` 0xac 0ac: l 0xba 0ba: ~ 0xf0 0f0: x
Возьмем другой ключ из 3х символов: Zr%. Заменяя % можно пройтись по нескольким ключам:
Zr% -> Zr) -> Zr+ -> . -> Zrq
Попробуем найти замену для rq. Пришлось обойти все пары символов алфавита и вычислить их хеши.
Zrq -> Zt- -> ZtW -> Zuv
Что делать дальше - непонятно. Сменить Z на другой символ? У Z нет равноценных замен, придется перебором снова найти первый подходящий ключ.
Так и не придумал алгоритм перехода от одного известного ключа к следующему: если есть идеи, пишите в комментариях.
Что если вместо перебора всех сочетаний склеивать пары ключей и складывать их хеши? По сложности алгоритм оказался не лучше перебора: время работы быстро растет с увеличением алфавита и длины ключа, к тому же программа падает из-за нехватки памяти. Можно ее чуть сэкономить, но количество пар на каждом шаге все равно растет слишком быстро при алфавите в 95 букв.
// Длина ключа N - степень двойки void generateKeys(ostream& out) < for (int n = 1; n < N; n next_weights; for (auto i = weights.begin(); i != weights.end(); ++i) < for (auto j = next(i); j != weights.end(); ++j) < const string& s1 = i->first; int w1 = i->second; const string& s2 = j->first; int w2 = j->second; int len = s1.length() + s2.length(); if (len == n * 2) < string s3(len, 0); int w3 = w1 + w2; merge(s1.begin(), s1.end(), s2.begin(), s2.end(), s3.begin()); if (len < N) < next_weights[s3] = w3; >if (N == len && S == w3) < out > > > weights.swap(next_weights); > >
