質問

Is there an example of usage Zend_Crypt_DiffieHellman class? I'm trying to write a desktop application which will comunicate with PHP server on Zend Framework in a secure manner. I'm stuck with understading how I can establish a shared key between two parties. Do I need to obtain a set of my own prime numbers?

Any example of how to use this to obtain shared key would be greatly appreciated!

I think my real question is how to get a prime number and a generator for it!

役に立ちましたか?

解決

How to get a group (consisting of a prime and a generator)

I am by no means a cryptography-expert but I think you should use the "Well-Known Groups" defined in RFC 2412 - The OAKLEY Key Determination Protocol (appendix E.1) or the groups from RFC 3526. You probably have to convert the hexadecimal numbers to decimal first before you use them with Zend_Crypt_DiffieHellman.

Which group should you use?

The bigger, the better - no, just joking.

Depends on how you plan to implement the key-exchange. If you have to execute the DH-exchange on each HTTP request, a bigger group will kill your server, because it'll take more time to compute (but are on the other hand harder to crack). In my example I've used the "Well Known Group 1" with 768 bits and it was fairly slow (okay my dev machine is not the fastest).

You can also add the option that the server and the client agree in a first step on which predefined group to use. For example: You deliver the well known groups 1, 2 and 5 with your application. And before the actual DH-key exchange your parties agree on using group 1 for the actual DH-key exchange. That way you can switch to the bigger groups as the hardware catches up. Of course this group-agreement adds another step to your key-exchange process.

Zend_Crypt_DiffieHellman example

This is a simple example without actually transmitting the public data to another process.

// why disable the use of openssl?
// apparently "computeSecretKey" uses the php function 
// openssl_dh_compute_key which expects an openssl "pkey" resource but
// the Zend Framework (1.11.4) supplies a string
Zend_Crypt_DiffieHellman::$useOpenssl = false;

// here I define the Well Known Group 1 (which consists of the prime and
// the generator) with a 768 bit prime. 
// These can be either hard coded ore your parties agree on which group to
// use in a separate step of the key-exchange process.
$public_prime =
    "155251809230070893513091813125848175563133404943451431320235" .
    "119490296623994910210725866945387659164244291000768028886422" .
    "915080371891804634263272761303128298374438082089019628850917" .
    "0691316593175367469551763119843371637221007210577919";
$public_generator = 2;

// if you want it to go fast use smaller values (these are from the
// Diffie Hellman entry on Wikipedia).
//$public_generator = 5;
//$public_prime = 23;

$bob = new Zend_Crypt_DiffieHellman($public_prime, $public_generator);
$alice = new Zend_Crypt_DiffieHellman($public_prime, $public_generator);

// first generate the private key and the public data on both sides
$bob->generateKeys();
$alice->generateKeys();

// you can access the public data using the "getPublicKey" method.
// You can transmit those values over the wire to the other party. 
echo "bob=", $bob->getPublicKey(), PHP_EOL;
echo "alice=", $alice->getPublicKey(), PHP_EOL;

// After both parties have received the public data from the other party
// they can calculate the shared secret:    
echo "shared(alice)=", $alice->computeSecretKey($bob->getPublicKey()), PHP_EOL;
echo "shared(bob  )=", $bob->computeSecretKey($alice->getPublicKey()), PHP_EOL;
// the values should be equal.

The only thing that really is passed over the wire is the return value of Zend_Crypt_DiffieHellman::getPublicKey. The public data can be encoded as text (Zend_Crypt_DiffieHellman::NUMBER) or as binary data (Zend_Crypt_DiffieHellman::BINARY).

There is another one: Zend_Crypt_DiffieHellman::BTWOC which is the same as binary but with a leading zero byte, so the integer is not treated as "signed" integer - if your client application uses the Java JCE or the .NET Crypto API this one is probably the best for binary transfer.

Unsolicited advice

If you want to make your life easier, do not reinvent SSL - just use the existing SSL implementation via HTTPS.

Most SSL libraries allow you to inspect the server certificate so check the validity of your server certificate on the client (at least check the fingerprint).

And if you need or want to you can check the client's certificate on the server (see Using SSL Client Certificates with PHP).

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top