88 lines
1.7 KiB
Go
88 lines
1.7 KiB
Go
package credential
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"strings"
|
|
)
|
|
|
|
const CurrentVersion uint32 = 1
|
|
|
|
var (
|
|
ErrVaultUnavailable = errors.New("credential vault unavailable")
|
|
ErrUnsupportedVersion = errors.New("unsupported credential version")
|
|
)
|
|
|
|
type Vault struct {
|
|
root string
|
|
}
|
|
|
|
func NewVault(root string) (*Vault, error) {
|
|
root = strings.TrimSpace(root)
|
|
if root == "" {
|
|
return nil, ErrVaultUnavailable
|
|
}
|
|
key, err := loadOrCreateKey(root)
|
|
if err != nil {
|
|
return nil, ErrVaultUnavailable
|
|
}
|
|
for index := range key {
|
|
key[index] = 0
|
|
}
|
|
return &Vault{root: root}, nil
|
|
}
|
|
|
|
func (v *Vault) Version() uint32 {
|
|
if v == nil {
|
|
return 0
|
|
}
|
|
return CurrentVersion
|
|
}
|
|
|
|
func (v *Vault) Encrypt(plaintext string) (string, error) {
|
|
if v == nil {
|
|
return "", ErrVaultUnavailable
|
|
}
|
|
value, err := Encrypt(v.root, plaintext)
|
|
if err != nil {
|
|
return "", ErrVaultUnavailable
|
|
}
|
|
return value, nil
|
|
}
|
|
|
|
func (v *Vault) Decrypt(version uint32, ciphertext string) (string, error) {
|
|
if v == nil {
|
|
return "", ErrVaultUnavailable
|
|
}
|
|
if version != CurrentVersion {
|
|
return "", ErrUnsupportedVersion
|
|
}
|
|
value, err := Decrypt(v.root, ciphertext)
|
|
if err != nil {
|
|
return "", ErrVaultUnavailable
|
|
}
|
|
return value, nil
|
|
}
|
|
|
|
// Fingerprint 使用数据库外主密钥计算固定长度校验值,不能用于恢复原文。
|
|
func (v *Vault) Fingerprint(value string) (string, error) {
|
|
if v == nil {
|
|
return "", ErrVaultUnavailable
|
|
}
|
|
key, err := readKey(v.root)
|
|
if err != nil {
|
|
return "", ErrVaultUnavailable
|
|
}
|
|
defer func() {
|
|
for index := range key {
|
|
key[index] = 0
|
|
}
|
|
}()
|
|
mac := hmac.New(sha256.New, key)
|
|
_, _ = mac.Write([]byte("smail-plugin-setting-v1\x00"))
|
|
_, _ = mac.Write([]byte(value))
|
|
return hex.EncodeToString(mac.Sum(nil)), nil
|
|
}
|