I am trying to decrypt a response Tokens which where encrypted using a Diffie-Hellman (type curve25519) via AES-GCM and additional authenticated data (AAD). I am new to PHP so I am not sure how can this be accomplished.
here is my attempt:
<?php
$private_key = openssl_pkey_get_private("file:///vault-sink/private");
$pub_key_struct = file_get_contents("/vault-sink/public");
$json_public_key = json_decode($pub_key_struct);
$secret = openssl_dh_compute_key($json_public_key->curve25519_public_key, $private_key);
$token_response = file_get_contents("/vault-sink/token.txt");
$token_response_json = json_decode($token_response);
echo $token_response_json->encrypted_payload;
openssl_decrypt(
$secret,
$token_response_json->encrypted_payload,
$token_response_json->nonce,
$aad = "test"
);
error
PHP Fatal error: Uncaught TypeError: openssl_dh_compute_key(): Argument #2 ($private_key) must be of type OpenSSLAsymmetricKey, bool given in /vault-sink/php-client/main.php:10
content of public and private keys:
# cat public
{"curve25519_public_key":"ru7+Ncx9x8Y/pHlj3D/wg+WYCQgqMKuVpAmTjCmf7Hs="}
# cat private
9fd06c52f7fda2b89bb05ac591dbeba8e57984c2bb0e6181ddcf275fb87015b6
So my guess is that the private's key format is not readable by openssl_pkey_get_private function. My question is how can I use these private and public keys in openssl_dh_compute_key?
For more context, below is an example on how I did it with go.
Working example with Go
Generate KeyPair
package main
import (
"encoding/json"
"fmt"
"log"
"os"
dh "github.com/hashicorp/vault/helper/dhutil"
)
func check(e error) {
if e != nil {
log.Fatal(e)
}
}
func generatePublicPrivateKey() {
var keyinfo dh.PublicKeyInfo
public, private, err := dh.GeneratePublicPrivateKey()
check(err)
keyinfo.Curve25519PublicKey = public
pubkey, err := json.Marshal(keyinfo)
check(err)
err = os.WriteFile("public", []byte(pubkey), 0644)
if err != nil {
log.Fatal(err)
}
privateKey := fmt.Sprintf("%x", private)
err = os.WriteFile("private", []byte(privateKey), 0644)
if err != nil {
log.Fatal(err)
}
}
func main() {
generatePublicPrivateKey()
}
output
# cat public
{"curve25519_public_key":"ru7+Ncx9x8Y/pHlj3D/wg+WYCQgqMKuVpAmTjCmf7Hs="}
# cat private
9fd06c52f7fda2b89bb05ac591dbeba8e57984c2bb0e6181ddcf275fb87015b6
Encrypt Token Using Hashicorp Vault
then I run Vault Agent and get the following response ("token.txt"):
{
"curve25519_public_key": "ONwU5iknsVP57p7PdHtN4rzxbivMB4Bt5o2BJFC6oSc=",
"nonce": "AA2VibL5SXE9MU19",
"encrypted_payload": "pPseQIue1IXxutEKoZrjsORj+8AZVgRrcTRvaPVxukzU2w28TL4T0be7aGFKZmHwudiHiNQyp5i8D0ZUgP/ILLYPfhO+gwxUFEDhA4PJNAgKc8nSaMpjG9RipAyRcepgk42SXuRIgZ1D7HrmeWT8"
}
for more info, check https://www.vaultproject.io/docs/agent/autoauth#encrypting-tokens
Decrypt the token
and then I decrypt the response as following
package main
import (
"encoding/hex"
"encoding/json"
"fmt"
"log"
"os"
dh "github.com/hashicorp/vault/helper/dhutil"
)
func check(e error) {
if e != nil {
log.Fatal(e)
}
}
func main() {
var envelope dh.Envelope
var keyinfo dh.PublicKeyInfo
token_env, err := os.ReadFile("token.txt")
check(err)
err = json.Unmarshal(token_env, &envelope)
check(err)
ourPublic, err := os.ReadFile("public")
check(err)
ourPrivate, err := os.ReadFile("private")
check(err)
json.Unmarshal(ourPublic, &keyinfo)
privatekey, err := hex.DecodeString(string(ourPrivate))
check(err)
secret, err := dh.GenerateSharedSecret(privatekey, envelope.Curve25519PublicKey)
check(err)
shared_key, err := dh.DeriveSharedKey(secret, keyinfo.Curve25519PublicKey, envelope.Curve25519PublicKey)
check(err)
test, err := dh.DecryptAES(shared_key, envelope.EncryptedPayload, envelope.Nonce, []byte("test"))
check(err)
fmt.Println(string(test))
}
output
hvs.CAESIB1eP79cHXPc4ttZIz20qL2I2A8kcfNpkhPjvIE4DZt3Gh4KHGh2cy4wNWV1WHB5NWNuZXV1dDMzdkh4YkY2OUE