63 lines
2.1 KiB
Go
63 lines
2.1 KiB
Go
package store
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// SerialLength — длина серийного номера eToken PASS в символах.
|
|
SerialLength = 14
|
|
// DefaultSerialPrefix — префикс серийных номеров eToken PASS.
|
|
DefaultSerialPrefix = "000400"
|
|
// SeedBytes — длина вектора инициализации в байтах.
|
|
SeedBytes = 20
|
|
)
|
|
|
|
// NewSeed генерирует криптографически стойкий вектор инициализации.
|
|
func NewSeed(n int) ([]byte, error) {
|
|
if n <= 0 {
|
|
n = SeedBytes
|
|
}
|
|
b := make([]byte, n)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return nil, fmt.Errorf("не удалось получить случайные данные: %w", err)
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
// NewSerial генерирует серийный номер: заданный префикс и случайный
|
|
// шестнадцатеричный хвост до общей длины SerialLength.
|
|
func NewSerial(prefix string) (string, error) {
|
|
prefix = strings.ToUpper(strings.TrimSpace(prefix))
|
|
if err := ValidateSerial(prefix + "0"); err != nil {
|
|
return "", fmt.Errorf("некорректный префикс серийного номера: %w", err)
|
|
}
|
|
|
|
suffix := SerialLength - len(prefix)
|
|
if suffix < 4 {
|
|
suffix = 4
|
|
}
|
|
b := make([]byte, (suffix+1)/2)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", fmt.Errorf("не удалось получить случайные данные: %w", err)
|
|
}
|
|
return prefix + strings.ToUpper(hex.EncodeToString(b))[:suffix], nil
|
|
}
|
|
|
|
// NewUniqueSerial подбирает серийный номер, которого ещё нет в хранилище.
|
|
func (s *Store) NewUniqueSerial(prefix string) (string, error) {
|
|
for i := 0; i < 100; i++ {
|
|
serial, err := NewSerial(prefix)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if s.file.Section(serial) == nil {
|
|
return serial, nil
|
|
}
|
|
}
|
|
return "", fmt.Errorf("не удалось подобрать свободный серийный номер с префиксом %q", prefix)
|
|
}
|