package security import ( "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/sha256" "encoding/base64" "fmt" "io" "os" "path/filepath" "golang.org/x/crypto/pbkdf2" ) const ( saltSize = 32 iterations = 100000 keySize = 32 ) // GetMachineKey генерирует ключ на основе уникальных характеристик машины func GetMachineKey() ([]byte, error) { // Используем hostname и другие системные параметры hostname, err := os.Hostname() if err != nil { return nil, err } // Добавляем путь к исполняемому файлу для уникальности exePath, err := os.Executable() if err != nil { return nil, err } // Комбинируем для создания уникального ключа combined := hostname + exePath hash := sha256.Sum256([]byte(combined)) return hash[:], nil } // Encrypt шифрует данные с использованием AES-256-GCM func Encrypt(plaintext []byte, password string) (string, error) { // Генерируем соль salt := make([]byte, saltSize) if _, err := io.ReadFull(rand.Reader, salt); err != nil { return "", err } // Получаем машинный ключ machineKey, err := GetMachineKey() if err != nil { return "", err } // Комбинируем пароль с машинным ключом combinedPassword := append([]byte(password), machineKey...) // Генерируем ключ шифрования key := pbkdf2.Key(combinedPassword, salt, iterations, keySize, sha256.New) // Создаем AES cipher block, err := aes.NewCipher(key) if err != nil { return "", err } // Используем GCM для аутентифицированного шифрования gcm, err := cipher.NewGCM(block) if err != nil { return "", err } // Генерируем nonce nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", err } // Шифруем ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) // Комбинируем соль и зашифрованные данные result := append(salt, ciphertext...) return base64.StdEncoding.EncodeToString(result), nil } // Decrypt расшифровывает данные func Decrypt(encryptedData string, password string) ([]byte, error) { // Декодируем из base64 data, err := base64.StdEncoding.DecodeString(encryptedData) if err != nil { return nil, err } if len(data) < saltSize { return nil, fmt.Errorf("неверный формат зашифрованных данных") } // Извлекаем соль salt := data[:saltSize] ciphertext := data[saltSize:] // Получаем машинный ключ machineKey, err := GetMachineKey() if err != nil { return nil, err } // Комбинируем пароль с машинным ключом combinedPassword := append([]byte(password), machineKey...) // Генерируем ключ key := pbkdf2.Key(combinedPassword, salt, iterations, keySize, sha256.New) // Создаем AES cipher block, err := aes.NewCipher(key) if err != nil { return nil, err } // Используем GCM gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonceSize := gcm.NonceSize() if len(ciphertext) < nonceSize { return nil, fmt.Errorf("неверный размер зашифрованных данных") } nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] // Расшифровываем plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, fmt.Errorf("ошибка расшифровки: неверный пароль или поврежденные данные") } return plaintext, nil } // SecureDelete безопасно удаляет файл (перезаписывает случайными данными) func SecureDelete(filepath string) error { // Получаем размер файла info, err := os.Stat(filepath) if err != nil { return err } size := info.Size() // Открываем файл для записи file, err := os.OpenFile(filepath, os.O_WRONLY, 0) if err != nil { return err } defer file.Close() // Перезаписываем случайными данными 3 раза for i := 0; i < 3; i++ { randomData := make([]byte, size) if _, err := rand.Read(randomData); err != nil { return err } if _, err := file.WriteAt(randomData, 0); err != nil { return err } if err := file.Sync(); err != nil { return err } } // Удаляем файл return os.Remove(filepath) } // SetFilePermissions устанавливает строгие права доступа к файлу func SetFilePermissions(path string) error { // Только владелец может читать и писать return os.Chmod(path, 0600) } // ProtectDirectory защищает директорию и все файлы в ней func ProtectDirectory(dirPath string) error { // Устанавливаем права на директорию if err := os.Chmod(dirPath, 0700); err != nil { return err } // Защищаем все файлы в директории entries, err := os.ReadDir(dirPath) if err != nil { return err } for _, entry := range entries { if !entry.IsDir() { filePath := filepath.Join(dirPath, entry.Name()) if err := SetFilePermissions(filePath); err != nil { return err } } } return nil }