Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 97 additions & 98 deletions phase/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,19 +122,19 @@ func EncryptAsymmetric(plaintext, publicKeyHex string) (string, error) {
return "", err
}

// Spin up ephemeral X25519 keys
// Spin up ephemeral X25519 keys
kp, err := RandomKeyPair()
if err != nil {
return "", err
}

// Perform a DHKA
// Perform a DHKA
sessionKeys, err := ClientSessionKeys(kp, recipientPubKeyBytes)
if err != nil {
return "", err
}

// Encrypt data with XChaCha20-poly1305
// Encrypt data with XChaCha20-poly1305
ciphertext, err := EncryptB64(plaintext, sessionKeys.Tx)
if err != nil {
return "", err
Expand All @@ -145,99 +145,99 @@ func EncryptAsymmetric(plaintext, publicKeyHex string) (string, error) {
}

func DecryptAsymmetric(ciphertextString, privateKeyHex, publicKeyHex string) (string, error) {
segments := strings.Split(ciphertextString, ":")

version := segments[1]
if version != "v1" {
err := fmt.Errorf("unsupported version: %s", version)
log.Println(err)
return "", err
}

ephemeralPublicKeyBytes, err := hex.DecodeString(segments[2])
if err != nil {
log.Printf("Failed to decode ephemeral public key hex: %v\n", err)
return "", err
}

privateKeyBytes, err := hex.DecodeString(privateKeyHex)
if err != nil {
log.Printf("Failed to decode private key hex: %v\n", err)
return "", err
}

publicKeyBytes, err := hex.DecodeString(publicKeyHex)
if err != nil {
log.Printf("Failed to decode public key hex: %v\n", err)
return "", err
}

kp := sodium.KXKP{
PublicKey: sodium.KXPublicKey{Bytes: publicKeyBytes},
SecretKey: sodium.KXSecretKey{Bytes: privateKeyBytes},
}

// Perform DHKA
sessionKeys, err := ServerSessionKeys(kp, ephemeralPublicKeyBytes)
if err != nil {
return "", err
}

// Extract ciphertext from ph.
ciphertextB64 := segments[3]

// Decrypt data with XChaCha20-poly1305
plaintext, err := DecryptB64(ciphertextB64, sessionKeys.Rx)
if err != nil {
log.Printf("Failed to decrypt asymmetrically: %v\n", err)
return "", err
}
return plaintext, nil
segments := strings.Split(ciphertextString, ":")

version := segments[1]
if version != "v1" {
err := fmt.Errorf("unsupported version: %s", version)
log.Println(err)
return "", err
}

ephemeralPublicKeyBytes, err := hex.DecodeString(segments[2])
if err != nil {
log.Printf("Failed to decode ephemeral public key hex: %v\n", err)
return "", err
}

privateKeyBytes, err := hex.DecodeString(privateKeyHex)
if err != nil {
log.Printf("Failed to decode private key hex: %v\n", err)
return "", err
}

publicKeyBytes, err := hex.DecodeString(publicKeyHex)
if err != nil {
log.Printf("Failed to decode public key hex: %v\n", err)
return "", err
}

kp := sodium.KXKP{
PublicKey: sodium.KXPublicKey{Bytes: publicKeyBytes},
SecretKey: sodium.KXSecretKey{Bytes: privateKeyBytes},
}

// Perform DHKA
sessionKeys, err := ServerSessionKeys(kp, ephemeralPublicKeyBytes)
if err != nil {
return "", err
}

// Extract ciphertext from ph.
ciphertextB64 := segments[3]

// Decrypt data with XChaCha20-poly1305
plaintext, err := DecryptB64(ciphertextB64, sessionKeys.Rx)
if err != nil {
log.Printf("Failed to decrypt asymmetrically: %v\n", err)
return "", err
}
return plaintext, nil
}

// decryptSecret decrypts a secret's key, value, and optional comment using asymmetric decryption.
func DecryptSecret(secret map[string]interface{}, privateKeyHex, publicKeyHex string) (decryptedKey string, decryptedValue string, decryptedComment string, err error) {
// Decrypt the key
key, ok := secret["key"].(string)
if !ok {
err = fmt.Errorf("key is not a string")
return
}
decryptedKey, err = DecryptAsymmetric(key, privateKeyHex, publicKeyHex)
if err != nil {
log.Printf("Failed to decrypt key: %v\n", err)
return
}

// Decrypt the value
value, ok := secret["value"].(string)
if !ok {
err = fmt.Errorf("value is not a string")
return
}
decryptedValue, err = DecryptAsymmetric(value, privateKeyHex, publicKeyHex)
if err != nil {
log.Printf("Failed to decrypt value: %v\n", err)
return
}

// Decrypt the comment if it exists
comment, ok := secret["comment"].(string)
if ok && comment != "" {
decryptedComment, err = DecryptAsymmetric(comment, privateKeyHex, publicKeyHex)
if err != nil {
log.Printf("Failed to decrypt comment: %v\n", err)
err = nil
}
}

return decryptedKey, decryptedValue, decryptedComment, nil
// Decrypt the key
key, ok := secret["key"].(string)
if !ok {
err = fmt.Errorf("key is not a string")
return
}
decryptedKey, err = DecryptAsymmetric(key, privateKeyHex, publicKeyHex)
if err != nil {
log.Printf("Failed to decrypt key: %v\n", err)
return
}

// Decrypt the value
value, ok := secret["value"].(string)
if !ok {
err = fmt.Errorf("value is not a string")
return
}
decryptedValue, err = DecryptAsymmetric(value, privateKeyHex, publicKeyHex)
if err != nil {
log.Printf("Failed to decrypt value: %v\n", err)
return
}

// Decrypt the comment if it exists
comment, ok := secret["comment"].(string)
if ok && comment != "" {
decryptedComment, err = DecryptAsymmetric(comment, privateKeyHex, publicKeyHex)
if err != nil {
log.Printf("Failed to decrypt comment: %v\n", err)
err = nil
}
}

return decryptedKey, decryptedValue, decryptedComment, nil
}

// Decrypt decrypts the provided ciphertext using the Phase encryption mechanism.
func DecryptWrappedKeyShare(Keyshare1 string, Keyshare0 string, AppToken string, Keyshare1UnwrapKey string, PssUserPublicKey string, Host string) (string, error) {
func DecryptWrappedKeyShare(Keyshare1 string, Keyshare0 string, TokenType string, AppToken string, Keyshare1UnwrapKey string, PssUserPublicKey string, Host string) (string, error) {
// Fetch the wrapped key share using the app token and host
wrappedKeyShare, err := network.FetchAppKey(AppToken, Host)
wrappedKeyShare, err := network.FetchAppKey(TokenType, AppToken, Host)
if err != nil {
log.Fatalf("Failed to fetch wrapped key share: %v", err)
return "", err
Expand Down Expand Up @@ -293,24 +293,23 @@ func GenerateEnvKeyPair(seed string) (publicKeyHex, privateKeyHex string, err er
return "", "", fmt.Errorf("incorrect seed length: expected 32 bytes, got %d", len(seedBytes))
}

// Prepare the seed as KXSeed
var seedKX sodium.KXSeed
copy(seedKX.Bytes[:], seedBytes)
// Prepare the seed as KXSeed
var seedKX sodium.KXSeed
copy(seedKX.Bytes[:], seedBytes)

// Allocate slice if KXSeed.Bytes is a slice
seedKX.Bytes = make([]byte, len(seedBytes))
copy(seedKX.Bytes, seedBytes)

// Generate key pair from seed
keyPair := sodium.SeedKXKP(seedKX)
// Generate key pair from seed
keyPair := sodium.SeedKXKP(seedKX)

publicKeyHex = hex.EncodeToString(keyPair.PublicKey.Bytes[:])
privateKeyHex = hex.EncodeToString(keyPair.SecretKey.Bytes[:])
publicKeyHex = hex.EncodeToString(keyPair.PublicKey.Bytes[:])
privateKeyHex = hex.EncodeToString(keyPair.SecretKey.Bytes[:])

return publicKeyHex, privateKeyHex, nil
return publicKeyHex, privateKeyHex, nil
}


// Blake2bDigest generates a BLAKE2b hash of the input string with a salt using the sodium library.
func Blake2bDigest(inputStr, salt string) (string, error) {
hashSize := 32 // 32 bytes (256 bits) as an example
Expand Down Expand Up @@ -370,4 +369,4 @@ func ReconstructSecret(share1, share2 string) (string, error) {

// Encode the reconstructed secret back to a hex string.
return hex.EncodeToString(reconstructedSecret), nil
}
}
57 changes: 28 additions & 29 deletions phase/misc/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,57 @@ import (
)

const (
Version = "1.0.1"
PhVersion = "v1"
Version = "1.0.2"
PhVersion = "v1"
PhaseCloudAPIHost = "https://console.phase.dev"
)

var (
VerifySSL = false
PhaseDebug = false
VerifySSL = true
PhaseDebug = false
)

var (

// Compiled regex patterns
PssUserPattern = regexp.MustCompile(`^pss_user:v(\d+):([a-fA-F0-9]{64}):([a-fA-F0-9]{64}):([a-fA-F0-9]{64}):([a-fA-F0-9]{64})$`)
PssServicePattern = regexp.MustCompile(`^pss_service:v(\d+):([a-fA-F0-9]{64}):([a-fA-F0-9]{64}):([a-fA-F0-9]{64}):([a-fA-F0-9]{64})$`)
// CrossEnvPattern = regexp.MustCompile(`\$\{(.+?)\.(.+?)\}`)

// CrossEnvPattern = regexp.MustCompile(`\$\{(.+?)\.(.+?)\}`)
// LocalRefPattern = regexp.MustCompile(`\$\{([^.]+?)\}`)

// Regex to identify secret references
SecretRefRegex = regexp.MustCompile(`\$\{([^}]+)\}`)
)

// Regex to identify secret references
SecretRefRegex = regexp.MustCompile(`\$\{([^}]+)\}`)
)

type Environment struct {
ID string `json:"id"`
Name string `json:"name"`
EnvType string `json:"env_type"`
ID string `json:"id"`
Name string `json:"name"`
EnvType string `json:"env_type"`
}

type EnvironmentKey struct {
ID string `json:"id"`
Environment Environment `json:"environment"`
IdentityKey string `json:"identity_key"`
WrappedSeed string `json:"wrapped_seed"`
WrappedSalt string `json:"wrapped_salt"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
DeletedAt *string `json:"deleted_at"`
User *string `json:"user"`
ID string `json:"id"`
Environment Environment `json:"environment"`
IdentityKey string `json:"identity_key"`
WrappedSeed string `json:"wrapped_seed"`
WrappedSalt string `json:"wrapped_salt"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
DeletedAt *string `json:"deleted_at"`
User *string `json:"user"`
}

type App struct {
ID string `json:"id"`
Name string `json:"name"`
Encryption string `json:"encryption"`
EnvironmentKeys []EnvironmentKey `json:"environment_keys"`
ID string `json:"id"`
Name string `json:"name"`
Encryption string `json:"encryption"`
EnvironmentKeys []EnvironmentKey `json:"environment_keys"`
}

type AppKeyResponse struct {
WrappedKeyShare string `json:"wrapped_key_share"`
Apps []App `json:"apps"`
WrappedKeyShare string `json:"wrapped_key_share"`
Apps []App `json:"apps"`
}

type GetContextOptions struct {
Expand All @@ -69,4 +68,4 @@ type FindEnvironmentKeyOptions struct {
EnvName string
AppName string
AppID string
}
}
Loading