101 lines
3.0 KiB
Go
101 lines
3.0 KiB
Go
package vault
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
|
|
"github.com/tobischo/gokeepasslib/v3"
|
|
)
|
|
|
|
type SecuritySettings struct {
|
|
Cipher string
|
|
KDF string
|
|
}
|
|
|
|
const (
|
|
CipherAES256 = "aes256"
|
|
CipherChaCha20 = "chacha20"
|
|
KDFAES = "aes-kdf"
|
|
KDFArgon2 = "argon2"
|
|
)
|
|
|
|
func SupportedSecuritySettings() (ciphers []string, kdfs []string) {
|
|
return []string{CipherAES256, CipherChaCha20}, []string{KDFAES, KDFArgon2}
|
|
}
|
|
|
|
func DetectSecuritySettings(config *KDBXConfig) SecuritySettings {
|
|
settings := SecuritySettings{
|
|
Cipher: CipherChaCha20,
|
|
KDF: KDFArgon2,
|
|
}
|
|
if config == nil || config.Header == nil || config.Header.FileHeaders == nil {
|
|
return settings
|
|
}
|
|
if slices.Equal(config.Header.FileHeaders.CipherID, gokeepasslib.CipherAES) {
|
|
settings.Cipher = CipherAES256
|
|
}
|
|
if config.Header.FileHeaders.KdfParameters != nil && slices.Equal(config.Header.FileHeaders.KdfParameters.UUID, gokeepasslib.KdfAES4) {
|
|
settings.KDF = KDFAES
|
|
}
|
|
return settings
|
|
}
|
|
|
|
func NewSecurityConfig(settings SecuritySettings) (*KDBXConfig, error) {
|
|
db := gokeepasslib.NewDatabase(gokeepasslib.WithDatabaseKDBXVersion4())
|
|
config := &KDBXConfig{
|
|
Header: cloneHeader(db.Header),
|
|
InnerHeader: cloneInnerHeader(db.Content.InnerHeader),
|
|
}
|
|
return ApplySecuritySettings(config, settings)
|
|
}
|
|
|
|
func ApplySecuritySettings(config *KDBXConfig, settings SecuritySettings) (*KDBXConfig, error) {
|
|
if config == nil || config.Header == nil || config.Header.FileHeaders == nil {
|
|
return NewSecurityConfig(settings)
|
|
}
|
|
out := &KDBXConfig{
|
|
Header: cloneHeader(config.Header),
|
|
InnerHeader: cloneInnerHeader(config.InnerHeader),
|
|
}
|
|
if out.Header.FileHeaders.KdfParameters == nil {
|
|
defaults := gokeepasslib.NewDatabase(gokeepasslib.WithDatabaseKDBXVersion4())
|
|
out.Header.FileHeaders.KdfParameters = cloneHeader(defaults.Header).FileHeaders.KdfParameters
|
|
}
|
|
switch settings.Cipher {
|
|
case "", CipherChaCha20:
|
|
out.Header.FileHeaders.CipherID = slices.Clone(gokeepasslib.CipherChaCha20)
|
|
out.Header.FileHeaders.EncryptionIV = randomBytes(12)
|
|
case CipherAES256:
|
|
out.Header.FileHeaders.CipherID = slices.Clone(gokeepasslib.CipherAES)
|
|
out.Header.FileHeaders.EncryptionIV = randomBytes(16)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported cipher %q", settings.Cipher)
|
|
}
|
|
|
|
var salt [32]byte
|
|
copy(salt[:], randomBytes(32))
|
|
switch settings.KDF {
|
|
case "", KDFArgon2:
|
|
defaults := gokeepasslib.NewDatabase(gokeepasslib.WithDatabaseKDBXVersion4())
|
|
kdf := defaults.Header.FileHeaders.KdfParameters
|
|
out.Header.FileHeaders.KdfParameters = &gokeepasslib.KdfParameters{
|
|
UUID: slices.Clone(gokeepasslib.KdfArgon2),
|
|
Rounds: kdf.Rounds,
|
|
Salt: salt,
|
|
Parallelism: kdf.Parallelism,
|
|
Memory: kdf.Memory,
|
|
Iterations: kdf.Iterations,
|
|
Version: kdf.Version,
|
|
}
|
|
case KDFAES:
|
|
out.Header.FileHeaders.KdfParameters = &gokeepasslib.KdfParameters{
|
|
UUID: slices.Clone(gokeepasslib.KdfAES4),
|
|
Rounds: 6000,
|
|
Salt: salt,
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("unsupported KDF %q", settings.KDF)
|
|
}
|
|
return out, nil
|
|
}
|