I've been trying to understand how to use the Google Cloud Key Management System and have worked through the quick start tutorials and documentation. I created my key rings and their individual keys and tested them using the SDK on my laptop and they work fine.
I then tried working through the Envelope Encryption example as shown at https://deliciousbrains.com/php-encryption-methods/ using my WAMP dev environment on my laptop. I've set up a service account and Environment Variable as described in https://cloud.google.com/docs/authentication/production#auth-cloud-implicit-php.
However, when I try and run the code in my browser I get the following message:
Fatal error: Uncaught Google_Service_Exception: { "error": { "code": 401, "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.", "errors": [ { "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.", "domain": "global", "reason": "unauthorized" } ], "status": "UNAUTHENTICATED" } } in C:\Bitnami\wampstack-7.2.11-0\apache2\htdocs\racingaway\vendor\google\apiclient\src\Google\Http\REST.php:118 Stack trace: #0 C:\Bitnami\wampstack-7.2.11-0\apache2\htdocs\racingaway\vendor\google\apiclient\src\Google\Http\REST.php(94): Google_Http_REST::decodeHttpResponse(Object(GuzzleHttp\Psr7\Response), Object(GuzzleHttp\Psr7\Request), 'Goo in C:\Bitnami\wampstack-7.2.11-0\apache2\htdocs\racingaway\vendor\google\apiclient\src\Google\Http\REST.php on line 118
I have tried following the link in the above message (https://developers.google.com/identity/sign-in/web/devconsole-project), this takes me to https://developers.google.com/identity/sign-in/web/sign-in#before_you_begin, which appears to be about setting up an OAuth client for an end user. However, what I want to do is a server to server authentication. I am now rather confused and would greatly appreciate some sage advice as to what I need to do to get my test application to work.
Code I have used is below:
<?php
use Google_Service_CloudKMS as Kms;
use Google_Service_CloudKMS_DecryptRequest as DecryptRequest;
use Google_Service_CloudKMS_EncryptRequest as EncryptRequest;
class KeyManager
{
private $kms;
private $encryptRequest;
private $decryptRequest;
private $projectId;
private $locationId;
private $keyRingId;
private $cryptoKeyId;
public function __construct(Kms $kms, EncryptRequest $encryptRequest, DecryptRequest $decryptRequest, $projectId, $locationId, $keyRingId, $cryptoKeyId)
{
$this->kms = $kms;
$this->encryptRequest = $encryptRequest;
$this->decryptRequest = $decryptRequest;
$this->projectId = $projectId;
$this->locationId = $locationId;
$this->keyRingId = $keyRingId;
$this->cryptoKeyId = $cryptoKeyId;
}
public function encrypt($data)
{
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = sodium_crypto_secretbox($data, $nonce, $key);
return [
'data' => base64_encode($nonce . $ciphertext),
'secret' => $this->encryptKey($key),
];
}
public function decrypt($secret, $data)
{
$decoded = base64_decode($data);
$key = $this->decryptSecret($secret);
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
return sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
}
private function encryptKey($key)
{
$this->encryptRequest->setPlaintext(base64_encode($key));
$response = $this->kms->projects_locations_keyRings_cryptoKeys->encrypt(
$this->getResourceName(),
$this->encryptRequest
);
return $response['ciphertext'];
}
private function decryptSecret($secret)
{
$this->decryptRequest->setCiphertext($secret);
$response = $this->kms->projects_locations_keyRings_cryptoKeys->decrypt(
$this->getResourceName(),
$this->decryptRequest
);
return base64_decode($response['plaintext']);
}
public function getResourceName()
{
return sprintf(
'projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s',
$this->projectId,
$this->locationId,
$this->keyRingId,
$this->cryptoKeyId
);
}
}
The above class is used by the code below:
<?php
require_once( "get_paths.php" );
require_once( GetIncludePath()."class.keymanager.php" );
use Google_Service_CloudKMS as Kms;
use Google_Service_CloudKMS_DecryptRequest as DecryptRequest;
use Google_Service_CloudKMS_EncryptRequest as EncryptRequest;
$client = new Google_Client();
$client->setAuthConfig(getenv('GOOGLE_APPLICATION_CREDENTIALS'));
$client->addScope('https://www.googleapis.com/auth/cloud-platform');
$keyManager = new KeyManager(
new Kms($client),
new EncryptRequest(),
new DecryptRequest(),
// $projectId,
"snappy-thought-226213",
// $locationId,
"europe-west2",
// $keyRingId,
"racingaway_key_ring",
// $cryptoKeyId
"racingaway_key_2"
);
$encrypted = $keyManager->encrypt('This is a secret!');
var_dump($encrypted);
?>