Using only php to decrypt zend-crypt hybrid

332 views Asked by At

I'm developing an API that to return sensitive data will require a sort of handshake, which will return a public key for the client to encrypt the information before sending it to the API.

For the API I am using expressive zend and to perform the handshake, I am using the zend-crypt module, more specifically Hybrid encryption.

the workflow is more or less the following:

The client application sends a public key to the api. The API uses this public key to encrypt, using hybrid encryption, the public key provided by the server. The public key of the encrypted server is returned to the client The client must decrypt the key to be able to use it for cryptography of sensitive data.

Below is the source code that performs public key cryptography:

$publicKeyStr = $request->getHeader('hello');

try {
    $publicKey = new \Zend\Crypt\PublicKey\Rsa\PublicKey(base64_decode($publicKeyStr[0]));

    $b64Key = base64_encode($this->crypto->getPublicKey());

    $hybridCrypt = new \Zend\Crypt\Hybrid();

    $serverPk = $hybridCrypt->encrypt($b64Key, $publicKey);   

    return new \Zend\Diactoros\Response\JsonResponse(array('hello'=>$serverPk));
} catch (\Zend\Crypt\PublicKey\Rsa\Exception\RuntimeException $ex) {
    return new \Zend\Diactoros\Response\EmptyResponse(\Fig\Http\Message\StatusCodeInterface::STATUS_UNAUTHORIZED);
}

My question is this: How do I decrypt this public key on a client that does not use the framework, pure PHP only, for example?

Since this API can be used for mobile application development or desktop software, I need to understand the logic to decrypt to be able to perform tests on different platforms.

I am currently performing integration testing of this middleware using Codeception, and the test code is this:

public function testPublicKeyAccess(ApiTester $I)
{
    $I->wantTo('Test if API return a valid public key');

    $I->am('Client');
    $I->amBearerAuthenticated($this->token);
    $I->haveHttpHeader('hello', base64_encode($this->publicKey));
    $I->sendGET('/handshake');


    $I->seeResponseCodeIs(200);
    $I->seeResponseContainsJson();

    $response = json_decode($I->grabResponse());

    list($encryptedKeys, $msg) = explode(';', $response->hello);
    $keysArr = explode(':', $encryptedKeys);
    $encryptedKey = base64_decode($keysArr[1]);

    // Decrypt $envKey, this works

    $envKey = '';
    openssl_private_decrypt($encryptedKey, $envKey,  $this->privateKey, OPENSSL_PKCS1_OAEP_PADDING);

    // Decrypt public key, this don't works
    $cipher = 'aes-256-cbc';
    $hmacSize = 46;
    $hmac = mb_substr($msg, 0, $hmacSize, '8bit');

    $ivSize = 32; //openssl_cipher_iv_length($cipher);
    $iv = mb_substr($msg, $hmacSize, $ivSize, '8bit'); // 64

    $cipherText = base64_decode(mb_substr($msg, $hmacSize+$ivSize, null, '8bit'));

    $serverKey = '';

    codecept_debug(var_dump($ivSize));

    openssl_open($cipherText, $serverKey, $envKey, $this->privateKey, $cipher, $ivSize);
    codecept_debug(var_dump($cipherText));
    codecept_debug(var_dump($serverKey));

    $I->assertRegExp('/-----BEGIN PUBLIC KEY-----(.*)-----END PUBLIC KEY-----/s', $serverKey);
}
0

There are 0 answers