projects:windows:ssh_phrase
Различия
Показаны различия между двумя версиями страницы.
| Предыдущая версия справа и слеваПредыдущая версияСледующая версия | Предыдущая версия | ||
| projects:windows:ssh_phrase [2025/04/15 18:28] – | projects:windows:ssh_phrase [2025/04/15 23:01] (текущий) – | ||
|---|---|---|---|
| Строка 1: | Строка 1: | ||
| ====== SSH Phrase ====== | ====== SSH Phrase ====== | ||
| - | Данный код позволяет указывать фразу из которой будет сгенерирован ключ | + | // |
| + | Не сохраняет | ||
| + | Подходит для защищённого доступа с зашифрованной | ||
| + | |||
| + | **Программа в архиве: | ||
| + | {{ : | ||
| + | |||
| + | |||
| + | <WRAP center round important 90%> | ||
| + | < | ||
| + | в ssh приватном ключе вида | ||
| + | -----BEGIN OPENSSH PRIVATE KEY----- | ||
| + | b3BlbnNzaC1rZXktZ...много base64 | ||
| + | -----END OPENSSH PRIVATE KEY----- | ||
| + | обязательно | ||
| + | иначе будет ошибка при попытке подключения | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | **Исходный код:** | ||
| ++++sshphrase.go| | ++++sshphrase.go| | ||
| <code go sshphrase.go> | <code go sshphrase.go> | ||
| - | // sshphrase.go | + | // sshphrase.go |
| package main | package main | ||
| Строка 20: | Строка 41: | ||
| ) | ) | ||
| - | // ===== marshalOpenSSHPrivateKey: | + | type Pair struct { |
| - | func marshalOpenSSHPrivateKey(privateKey ed25519.PrivateKey) ([]byte, error) { | + | Private |
| - | // Структура для OpenSSH-ключа | + | Public |
| - | type opensshPrivateKey | + | } |
| - | Check1 uint32 | + | |
| - | Check2 uint32 | + | |
| - | Key struct { | + | |
| - | Curve | + | |
| - | PubKey | + | |
| - | Priv | + | |
| - | } | + | |
| - | } | + | |
| - | pub := privateKey.Public().(ed25519.PublicKey) | + | func PairFromED25519(public |
| - | buf := &bytes.Buffer{} | + | privBlock, err := ssh.MarshalPrivateKey(private, "" |
| - | buf.Write([]byte(" | + | if err != nil { |
| - | writeString(buf, " | + | return nil, err |
| - | writeString(buf, "none") // kdf name (без ключевого деривационного алгоритма) | + | } |
| - | writeString(buf, "" | + | |
| - | writeUint32(buf, | + | |
| - | pubKey, | + | var buf bytes.Buffer |
| + | err = pem.Encode(&buf, privBlock) | ||
| if err != nil { | if err != nil { | ||
| return nil, err | return nil, err | ||
| } | } | ||
| - | writeString(buf, | ||
| - | content | + | pubKey, err := ssh.NewPublicKey(public) |
| - | check := uint32(0x01020304) // контрольное значение для валидации | + | if err != nil { |
| - | writeUint32(content, | + | return nil, err |
| - | writeUint32(content, | + | |
| - | writeString(content, | + | |
| - | writeString(content, | + | |
| - | writeString(content, | + | |
| - | content.WriteByte(0) // завершающий ноль | + | |
| - | + | ||
| - | padLen := 8 - (content.Len() % 8) | + | |
| - | for i := 1; i <= padLen; i++ { | + | |
| - | content.WriteByte(byte(i)) | + | |
| } | } | ||
| - | writeString(buf, | ||
| - | final := pem.EncodeToMemory(&pem.Block{ | + | return |
| - | Type: " | + | Private: buf.Bytes(), |
| - | Bytes: buf.Bytes(), | + | Public: ssh.MarshalAuthorizedKey(pubKey), |
| - | }) | + | }, nil |
| - | return final, nil | + | |
| } | } | ||
| - | // ===== Конец marshalOpenSSHPrivateKey ===== | ||
| - | |||
| - | func writeString(w *bytes.Buffer, | ||
| - | writeUint32(w, | ||
| - | w.WriteString(s) | ||
| - | } | ||
| - | |||
| - | func writeUint32(w *bytes.Buffer, | ||
| - | w.WriteByte(byte(v >> 24)) | ||
| - | w.WriteByte(byte(v >> 16)) | ||
| - | w.WriteByte(byte(v >> 8)) | ||
| - | w.WriteByte(byte(v)) | ||
| - | } | ||
| - | |||
| - | // ===== main: CLI-меню, | ||
| func main() { | func main() { | ||
| fmt.Print(" | fmt.Print(" | ||
| Строка 93: | Строка 78: | ||
| phrase := string(b) | phrase := string(b) | ||
| - | // Создание seed на основе хэша введённой фразы | ||
| seed := sha256.Sum256([]byte(phrase)) | seed := sha256.Sum256([]byte(phrase)) | ||
| privateKey := ed25519.NewKeyFromSeed(seed[: | privateKey := ed25519.NewKeyFromSeed(seed[: | ||
| - | publicKey, err := ssh.NewPublicKey(privateKey.Public()) | + | publicKey := privateKey.Public().(ed25519.PublicKey) |
| + | |||
| + | pair, err := PairFromED25519(publicKey, | ||
| if err != nil { | if err != nil { | ||
| - | log.Fatalf(" | + | log.Fatalf(" |
| } | } | ||
| Строка 114: | Строка 100: | ||
| case " | case " | ||
| fmt.Println(" | fmt.Println(" | ||
| - | fmt.Println(string(ssh.MarshalAuthorizedKey(publicKey))) | + | fmt.Println(string(pair.Public)) |
| case " | case " | ||
| fmt.Println(" | fmt.Println(" | ||
| - | keyBytes, err := marshalOpenSSHPrivateKey(privateKey) | + | fmt.Println(string(pair.Private)) |
| - | if err != nil { | + | |
| - | log.Fatalf(" | + | |
| - | } | + | |
| - | fmt.Println(string(keyBytes)) | + | |
| fmt.Println(" | fmt.Println(" | ||
| Строка 135: | Строка 117: | ||
| } | } | ||
| - | // ===== Конец main ===== | + | </code> |
| + | ++++ | ||
| + | <code bash README.md> | ||
| + | # 🔐 sshphrase: генерация SSH-ключей по фразе | ||
| + | ## 📋 Назначение | ||
| + | |||
| + | `sshphrase.exe` — это автономная утилита для Windows, написанная на Go, | ||
| + | предназначенная для генерации пары SSH-ключей (ED25519) на основе вводимой пользователем фразы. | ||
| + | Программа не хранит ключи, не принимает аргументы и не требует доступа к сети. | ||
| + | |||
| + | --- | ||
| + | |||
| + | ## 🧠 Концепция | ||
| + | |||
| + | - 🔑 **Фраза пользователя** используется как единственный секрет | ||
| + | - 🧬 Генерация осуществляется через `SHA256(фраза)` → `ed25519.NewKeyFromSeed` | ||
| + | - 🧾 Публичный ключ можно использовать в `~/ | ||
| + | - 🔒 Приватный ключ никогда не сохраняется автоматически | ||
| + | - 📎 Программа безопасна к публикации: | ||
| + | |||
| + | --- | ||
| + | |||
| + | ## ⚙️ Использование | ||
| + | |||
| + | 1. Запусти `sshphrase.exe` | ||
| + | 2. Введи фразу вручную (ввод скрыт, вставка недоступна) | ||
| + | 3. Выбери действие: | ||
| + | - `1` — показать публичный ключ | ||
| + | - `2` — показать приватный ключ (в OpenSSH формате) | ||
| + | - `0` — выход | ||
| + | |||
| + | Скопируй нужный ключ в буфер и используй при настройке SSH-доступа. | ||
| + | |||
| + | --- | ||
| + | |||
| + | ## 📦 Примеры вывода | ||
| + | |||
| + | ### Публичный ключ | ||
| + | ``` | ||
| + | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILvY... пользователь@фраза | ||
| + | ``` | ||
| + | |||
| + | ### Приватный ключ (OpenSSH) | ||
| + | ``` | ||
| + | -----BEGIN OPENSSH PRIVATE KEY----- | ||
| + | b3BlbnNzaC1rZXktZ...много base64 | ||
| + | -----END OPENSSH PRIVATE KEY----- | ||
| + | ``` | ||
| + | |||
| + | --- | ||
| + | |||
| + | ## 🛡️ Безопасность | ||
| + | |||
| + | - Нет аргументов CLI → невозможен автоматический перебор фраз | ||
| + | - Ввод фразы скрыт (`term.ReadPassword`) → безопасно от shoulder surfing | ||
| + | - Можно вручную добавлять " | ||
| + | - Приватный ключ выводится только по запросу, | ||
| + | - `.exe` можно запускать с зашифрованной флешки | ||
| + | |||
| + | --- | ||
| + | |||
| + | ## 💡 Рекомендации | ||
| + | |||
| + | - Используйте фразы длиной не менее 30 символов | ||
| + | - Добавляйте уникальные метки (например, | ||
| + | - Не храните приватный ключ, если не уверены в среде | ||
| + | - Не используйте одинаковую фразу на разных устройствах — добавляйте контекст | ||
| + | |||
| + | --- | ||
| + | |||
| + | ## 📁 Разработка | ||
| + | |||
| + | Программа написана на Go 1.20+ | ||
| + | |||
| + | ### Сборка | ||
| + | ``` | ||
| + | go build -ldflags=" | ||
| + | ``` | ||
| + | |||
| + | ### Добавление иконки | ||
| + | ``` | ||
| + | rsrc -ico icon.ico | ||
| + | ``` | ||
| + | |||
| + | --- | ||
| + | |||
| + | ## 🧱 Лицензия и открытость | ||
| + | |||
| + | Исходный код открыт. Использование программы безопасно при соблюдении базовой цифровой гигиены. | ||
| + | |||
| + | --- | ||
| + | |||
| + | **Автор: | ||
| + | **Документация создана: | ||
| </ | </ | ||
| - | ++++ | + | |
projects/windows/ssh_phrase.1744730897.txt.gz · Последнее изменение: —
