2025-10-03 14:45:52 -04:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
|
2025-10-10 11:47:18 -04:00
|
|
|
"github.com/sonr-io/crypto/argon2"
|
|
|
|
|
"github.com/sonr-io/crypto/mpc"
|
|
|
|
|
"github.com/sonr-io/crypto/password"
|
2025-10-03 14:45:52 -04:00
|
|
|
didtypes "github.com/sonr-io/sonr/x/did/types"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// CreateVaultForDIDSecure creates a vault with user-provided password
|
|
|
|
|
func (k Keeper) CreateVaultForDIDSecure(
|
|
|
|
|
ctx context.Context,
|
|
|
|
|
did string,
|
|
|
|
|
owner string,
|
|
|
|
|
vaultID string,
|
|
|
|
|
keyID string,
|
|
|
|
|
userPassword []byte,
|
|
|
|
|
enclaveData *mpc.EnclaveData,
|
|
|
|
|
) (*didtypes.CreateVaultResponse, error) {
|
|
|
|
|
// Validate password strength
|
|
|
|
|
validator := password.NewValidator(password.DefaultPasswordConfig())
|
|
|
|
|
if err := validator.Validate(userPassword); err != nil {
|
|
|
|
|
return nil, fmt.Errorf("password validation failed: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create Argon2id KDF with default secure parameters
|
|
|
|
|
kdf := argon2.New(argon2.DefaultConfig())
|
|
|
|
|
|
|
|
|
|
// Generate secure salt
|
|
|
|
|
salt, err := kdf.GenerateSalt()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to generate salt: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Derive encryption key using Argon2id
|
|
|
|
|
derivedKey := kdf.DeriveKey(userPassword, salt)
|
|
|
|
|
|
|
|
|
|
// Clear password from memory
|
|
|
|
|
defer password.ZeroBytes(userPassword)
|
|
|
|
|
|
|
|
|
|
// Encrypt enclave data with derived key
|
|
|
|
|
encryptedData, err := k.encryptEnclaveData(enclaveData, derivedKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to encrypt vault data: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Store vault with encrypted data and salt
|
|
|
|
|
vaultState, err := k.storeSecureVault(ctx, vaultID, owner, encryptedData, salt)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to store secure vault: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &didtypes.CreateVaultResponse{
|
|
|
|
|
VaultID: vaultState.VaultId,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UnlockVault unlocks a vault using the user's password
|
|
|
|
|
func (k Keeper) UnlockVault(
|
|
|
|
|
ctx context.Context,
|
|
|
|
|
vaultID string,
|
|
|
|
|
userPassword []byte,
|
|
|
|
|
) (*mpc.EnclaveData, error) {
|
|
|
|
|
// Retrieve vault state with salt
|
|
|
|
|
vaultState, err := k.getVaultState(ctx, vaultID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to retrieve vault: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(vaultState.Salt) == 0 {
|
|
|
|
|
return nil, fmt.Errorf("vault salt not found")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create KDF with same config as creation
|
|
|
|
|
kdf := argon2.New(argon2.DefaultConfig())
|
|
|
|
|
|
|
|
|
|
// Derive key using stored salt
|
|
|
|
|
derivedKey := kdf.DeriveKey(userPassword, vaultState.Salt)
|
|
|
|
|
|
|
|
|
|
// Clear password from memory
|
|
|
|
|
defer password.ZeroBytes(userPassword)
|
|
|
|
|
|
|
|
|
|
// Decrypt enclave data
|
|
|
|
|
enclaveData, err := k.decryptEnclaveData(vaultState.EncryptedData, derivedKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to decrypt vault: invalid password")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return enclaveData, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// encryptEnclaveData encrypts enclave data with AES-GCM
|
|
|
|
|
func (k Keeper) encryptEnclaveData(data *mpc.EnclaveData, key []byte) ([]byte, error) {
|
|
|
|
|
// Implementation would use AES-GCM for authenticated encryption
|
|
|
|
|
// This is a placeholder - actual implementation needs crypto/cipher
|
|
|
|
|
|
|
|
|
|
// For now, return a placeholder
|
|
|
|
|
// In production, this would:
|
|
|
|
|
// 1. Serialize enclave data to JSON
|
|
|
|
|
// 2. Create AES-GCM cipher with key
|
|
|
|
|
// 3. Generate nonce
|
|
|
|
|
// 4. Encrypt and authenticate data
|
|
|
|
|
// 5. Return nonce + ciphertext
|
|
|
|
|
|
|
|
|
|
return []byte("encrypted_placeholder"), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// decryptEnclaveData decrypts enclave data
|
|
|
|
|
func (k Keeper) decryptEnclaveData(encryptedData []byte, key []byte) (*mpc.EnclaveData, error) {
|
|
|
|
|
// Implementation would use AES-GCM for authenticated decryption
|
|
|
|
|
// This is a placeholder - actual implementation needs crypto/cipher
|
|
|
|
|
|
|
|
|
|
// For now, return a placeholder
|
|
|
|
|
// In production, this would:
|
|
|
|
|
// 1. Extract nonce from encrypted data
|
|
|
|
|
// 2. Create AES-GCM cipher with key
|
|
|
|
|
// 3. Decrypt and verify authentication
|
|
|
|
|
// 4. Deserialize JSON to enclave data
|
|
|
|
|
// 5. Return decrypted enclave data
|
|
|
|
|
|
|
|
|
|
return &mpc.EnclaveData{}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// storeSecureVault stores encrypted vault data with salt
|
|
|
|
|
func (k Keeper) storeSecureVault(
|
|
|
|
|
ctx context.Context,
|
|
|
|
|
vaultID string,
|
|
|
|
|
owner string,
|
|
|
|
|
encryptedData []byte,
|
|
|
|
|
salt []byte,
|
|
|
|
|
) (*VaultStateWithSalt, error) {
|
|
|
|
|
// This would store the vault state with salt in the database
|
|
|
|
|
// For now, return a placeholder
|
|
|
|
|
|
|
|
|
|
vaultState := &VaultStateWithSalt{
|
|
|
|
|
VaultId: vaultID,
|
|
|
|
|
Owner: owner,
|
|
|
|
|
EncryptedData: encryptedData,
|
|
|
|
|
Salt: salt,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// In production: k.OrmDB.VaultStateTable().Insert(ctx, vaultState)
|
|
|
|
|
|
|
|
|
|
return vaultState, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getVaultState retrieves vault state with salt
|
|
|
|
|
func (k Keeper) getVaultState(ctx context.Context, vaultID string) (*VaultStateWithSalt, error) {
|
|
|
|
|
// This would retrieve the vault state from the database
|
|
|
|
|
// For now, return a placeholder
|
|
|
|
|
|
|
|
|
|
return &VaultStateWithSalt{
|
|
|
|
|
VaultId: vaultID,
|
|
|
|
|
Salt: []byte("placeholder_salt"),
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VaultStateWithSalt extends vault state with salt storage
|
|
|
|
|
type VaultStateWithSalt struct {
|
|
|
|
|
VaultId string
|
|
|
|
|
Owner string
|
|
|
|
|
EncryptedData []byte
|
|
|
|
|
Salt []byte
|
|
|
|
|
}
|