package utils import ( "crypto/aes" "crypto/cipher" "crypto/hmac" "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/hex" "encoding/json" "fmt" "os" "strings" "sources.truenas.cloud/code/syscrypt" "sources.truenas.cloud/code/syscrypt/internal/configuration" "sources.truenas.cloud/code/syscrypt/internal/vars" ) //////////////////////////////////////////////////////////////////////////////////////////////////////////////// func HashEntry(value, x25519Str string) string { key := strings.TrimPrefix(x25519Str, vars.PrivateKeyPrefixLabel) h := hmac.New(sha256.New, []byte(key)) h.Write([]byte(value)) return hex.EncodeToString(h.Sum(nil)) } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// func AddSaltEntry(ref, serial, salt, x25519Key string) error { var vault syscrypt.Vault //vaultPath := config.KeyFolder + "/" + config.MasterKeySalt vaultPath := configuration.KeyFolder + "/" + configuration.MasterKeySalt if data, err := os.ReadFile(vaultPath); err == nil { json.Unmarshal(data, &vault) } for _, e := range vault.Entries { if e.Ref == ref { return fmt.Errorf("reference %s already exists", ref) } } encSalt := salt newEntry := syscrypt.SaltEntry{ Ref: ref, Salt: encSalt, } vault.Entries = append(vault.Entries, newEntry) updated, _ := json.MarshalIndent(vault, "", " ") return os.WriteFile(vaultPath, updated, 0644) } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// func VerifySaltEntry(ref, x25519Key string) (salt string, exists bool, err error) { //var vault syscrypt.Vault //vaultPath := config.KeyFolder + "/" + config.MasterKeySalt /* data, err := os.ReadFile(vaultPath) if err != nil { return "", false, err } json.Unmarshal(data, &vault) for _, e := range vault.Entries { if e.Ref == ref { // //decSerial, errS := DecryptString(e.Serial, x25519Key) decSalt, errSalt := DecryptString(e.Salt, x25519Key) if errSalt != nil { return "", false, fmt.Errorf("failed to decrypt entry") } return decSalt, true, nil // // } } */ //return "", false, fmt.Errorf("reference %s not found", ref) return "", false, nil } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// func EncryptString(plaintext, x25519Key string) (string, error) { keyBytes := sha256.Sum256([]byte(x25519Key)) block, _ := aes.NewCipher(keyBytes[:]) gcm, _ := cipher.NewGCM(block) nonce := make([]byte, gcm.NonceSize()) rand.Read(nonce) return base64.StdEncoding.EncodeToString(gcm.Seal(nonce, nonce, []byte(plaintext), nil)), nil } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// func DecryptString(cipherText string, x25519Key string) (string, error) { data, err := base64.StdEncoding.DecodeString(cipherText) if err != nil { return "", err } keyBytes := sha256.Sum256([]byte(x25519Key)) block, _ := aes.NewCipher(keyBytes[:]) gcm, _ := cipher.NewGCM(block) nonceSize := gcm.NonceSize() nonce, ciphertextBytes := data[:nonceSize], data[nonceSize:] plain, err := gcm.Open(nil, nonce, ciphertextBytes, nil) return string(plain), err //keyBytes := sha256.Sum256([]byte(x25519Key)) //block, _ := aes.NewCipher(keyBytes[:]) //gcm, _ := cipher.NewGCM(block) //nonceSize := gcm.NonceSize() //nonce, cipher := cipherText[:nonceSize], cipherText[nonceSize:] //plain, err := gcm.Open(nil, nonce, cipher, nil) //return string(plain), err } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////