Я люблю программировать на Go, но больше всего сейчас мне нравится программировать в gobot для Raspberry Pi. Каждое изменение в коде требует определенное время на нудные операции, связанные с обновлением кода. Сначала я должен остановить процесс, так как Filezilla отказывается писать в исполняемый файл, когда процесс запущен, загрузить новый исполняемый файл по SFTP и запустить его (это не только нудно, но еще 10-20 секунд простоя, когда процесс остановлен).
Аналогичная ситуация меня преследует и при разработке для обычного веба на Go. Именно в gobot я вынужден очень часто обновлять код, что связанно со стилем разработки, который приносит мне удовольствие в свободное время. С разработкой нового пакета обновлять код, написанный на Go стало проще и быстрее.
Сейчас расскажу, как пользоваться моим пакетом и как он устроен.
go get github.com/CossackPyra/updater
Этой командой вы установили мой updater в ваш Go, также вы можете установить тулзу в командную строку следующей командой:
go get github.com/CossackPyra/updater/pyra-poster
Вот пример веб-сервиса с возможностью обновления:
package main
import (
"fmt"
"io"
"net/http"
"os"
"github.com/CossackPyra/updater"
)
func main() {
http.HandleFunc("/", handle_def)
os.Mkdir("tmp", 0700)
u1 := updater.UpdaterServer("tmp", []byte("1234567890123456"), os.Args[0])
http.Handle("/updater-me", u1)
http.ListenAndServe(":9999", nil)
}
func handle_def(w http.ResponseWriter, r *http.Request) {
fmt.Println("def ", r.Method)
io.WriteString(w, "v 24n")
io.WriteString(w, r.URL.Path)
println(r.URL.Path)
}
Именно следующие 3 строчки добавляют возможность обновлять программу:
"github.com/CossackPyra/updater"
...
u1 := updater.UpdaterServer("tmp", []byte("1234567890123456"), os.Args[0])
http.Handle("/updater-me", u1)
В данном случает все шифруется 16-байтовым ключом []byte(«1234567890123456»), а 31323334353637383930313233343536 это его шестнадцатеричное представление. new-service новый исполняемый файл, и вот команда, чтобы обновить старый процесс.
pyra-poster 31323334353637383930313233343536 new-service http://127.0.0.1:9999/updater-me
Как это работает?
Весь код уместился в 280 строках. У меня больше доверия в коду, в котором можно быстро разобраться. Я не до конца уверен в криптографической стойкости моего алгоритма шифрования и как вообще можно быть уверенным в чем-то подобном, поэтому мне интересно его обсудить с вами.
При инициализации хендлера в updater.UpdaterServer, генерится случайная последовательность 16 байт (rand1). Для того, чтобы обновить код, надо выполнить два запроса к хендлеру. Первый GET запрос получает эти случайные 16 байт (rand1). Случайные 16 байт (rand1) и секретный пароль (key1) используются для того, чтобы зашифровать отправляемый исполняемый файл алгоритмом AES и отправить шифрограмму методом POST.
Сначала буфер наполняется данными согласно следующему рецепту:
— Случайные 20 байт (это не rand1, а rand0 — в настоящий момент они никак не используются);
— 20 байт — хеш исполняемого файла sha1;
— «pyra-poster» — последовательность байт, название протокола;
— 6 байт (1 — int16 Little Endian, 0 — int32 Little Endian) — версия протокола;
— сам исполняемый файл.
На этот буфер налагается гамма-функция методом xor, полученная блочным шифром AES(key1, rand1). В результате получается, шифротекст, который отправляется в хендлер методом POST.
На сервере для дешифрования на последовательность накладывается гамма AES(key1, rand1), проверяется заголовок «pyra-poster»(1,0), исполняемый файл сохраняется во временную папку и вычисляется хеш по алгоритму sha1 и сравнивается со sha1 из заголовка. Если хеши равны, то можно полагать с большой вероятностью, что это аутентичный файл созданный хозяином сервиса.
После обновления сервиса rand1 меняется и поэтому, перехватив шифротекст, повторно загрузить его нельзя. Рассчитать key1, имея rand1, и зная особенность заголовка «pyra-poster»(1,0) или, даже имея исполняемый файл, также достаточно сложно.
16-байтовый (128 бит) ключ key1 можно заменить на 32-байтовый (256 бит) без каких-либо дополнительных изменений в коде. Большинство веб броузеров как раз используют шифрование AES 256 бит.
Пользуйтесь на здоровье.
Автор: pyra