1

I'm playing with cryptography and its use with typescript on one side and PHP on the other side. Now I'm looking for routines that can encrypt and decrypt with ecdh's private and shared keys. Any recommendations? At the moment its in a testenvironment to figure out how it works basically. The keys (private and shared) are generated with elliptic.

Edit: The plan is to use tweetnacl and tweetnacl-utilities for Typescript on the clientside and sodium from php 7.2 on the backend. The tweetnacl is well documented and it works to create two keypairs and two shared keys. I can encrypt a string for 'Alice' and decrypt it for 'Bob'. But on the backend I did not found the right corresponding functions...

Next steps after this is a save key exchange...

Ritchie
  • 11
  • 3
  • Also related: https://crypto.stackexchange.com/questions/9987/elgamal-with-elliptic-curves – tylo Sep 03 '19 at 15:42
  • I don't think the alleged duplicates are helpful. They both discuss how EC-Elgamal works, which makes little sense to use for general-purpose applications like this; the only reason to use it would be in exotic applications requiring the homomorphic properties of Elgamal (and even then, EC-Elgamal requires a map between messages and curve points, which is even weirder to work out). – Squeamish Ossifrage Oct 31 '19 at 14:23

1 Answers1

1

Use crypto_box_curve25519xsalsa20poly1305 from libsodium/nacl.

How it works, roughly summarized with all details of encoding and coordinates omitted:

  1. Alice and Bob have public keys $A = [a]G = \underbrace{G + \dotsb + G}_{\text{$a$ times}}$ and $B = [b]G$.
    Here $G$ is the standard base point of Curve25519, $a$ is a secret 256-bit integer known only to Alice, and $b$ is a secret 256-bit integer known only to Bob.

  2. When Alice wants to send the $n^{\mathit{th}}$ message $m_n$ to Bob, she sends the box $c_n = \operatorname{crypto\_box}(m_n, n, B, a)$ to Bob. What this does is:

    • Computes the shared secret key $k = H([a]B) = H([a\cdot b]G)$, where $H$ is HSalsa20.

    • Uses $k$ as the key and $n$ as the nonce to authenticate and encrypt the message $m_n$ using crypto_secretbox_xsalsa20poly1305.

  3. When Bob receives the alleged $n^{\mathit{th}}$ box $c'_n$, which may be $c_n$ or may have been modified in transit or otherwise forged, he opens it with $\operatorname{crypto\_box\_open}(c'_n, n, A, b)$—but he makes sure to immediately drop it on the floor if crypto_box_open fails, meaning that it was a forgery. What this does is:

    • Computes the shared secret key $k = H([b]A) = H([a\cdot b]G)$.

    • Uses $k$ as the key and $n$ as the nonce to authenticate and decrypt the box $c_n$ using crypto_secretbox_xsalsa20poly1305_open.

In other words, crypto_box and crypto_box_open first do a static/static Diffie–Hellman key agreement, and then use the resulting key for an authenticated cipher.

Alice and Bob must never reuse any message number or nonce $n$ with a single pair of sender/receiver public keys or else the security will evaporate. If the communication is bidirectional, i.e. if Alice and Bob both need to send messages to each other, you might have Alice choose even values for $n$ and Bob choose odd values.

Squeamish Ossifrage
  • 48,392
  • 3
  • 116
  • 223
  • Thanks for the explanation. The background is interessting. I prefer to use existing and well tested libraries ;) For Typescript I used tweetnacl and its utilities. This works well for this environment. For the backend on PHP I'm a bit confused. In PHP 7.2 there is a implementation of sodium but I did not found compatibel functions coresponding with tweetnacl. On Typescript I use the box functions: box.keypair() for a new key pair and box.before for the shared key. But I got stuck on the php side... – Ritchie Oct 31 '19 at 07:52
  • yes that's the one I used. On the clientside I have the box.keypair() function to create a new keypair and the box.before to calculate a shared key from the first public key and the second secred key. Also vice versa. On the client it works well: [code] kp1 = box.keyPair(); sk1 = kp1.secretKey; – Ritchie Nov 04 '19 at 09:59
  • was to slow...

    yes that's the one I used. On the clientside I have the box.keypair() function to create a new keypair and the box.before to calculate a shared key from the first public key and the second secred key. Also vice versa. On the client it works well:

    kp1 = box.keyPair(); sk1 = kp1.secretKey; pk1 = kp1.publicKey; kp2 = box.keyPair(); sk2 = kp2.secretKey; pk2 = kp2.publicKey; sk1 = box.before(pk2, sk1); sk2 = box.before(pk1, sk2);

    – Ritchie Nov 04 '19 at 10:13
  • both shared keys are identically. But I did not found a corresponding function on the sodium side. I can create key pairs on php and here also in the same way the shared keys. But I can't create shared keys with the public from tweetnacl on typescript on the client and the private from php on the server and vice versa. The shared are not identically. – Ritchie Nov 04 '19 at 10:14
  • @Ritchie I didn't entirely follow what you said, but unless I misunderstood your example fragment, you seem to be generating both keys in the client (or both keys on the server). If you run the same code on the server, you won't get the same two keys—everyone who calls crypto_box_keypair must get a different key. Each side needs to generate one key pair, and then send the public key to the other side. (The shared secret key which I called $k$ should not appear directly in your program if you just use crypto_box and crypto_box_open.) – Squeamish Ossifrage Nov 04 '19 at 15:15
  • @Ritchie It might help if you sketched the logic that you ran on the client and the server, and what information you exchanged between the two, and what failed. That said, while we can provide advice about the protocol of crypto_box, we're not set up to provide programming help with the details of how to use the TypeScript TweetNaCl or PHP libsodium APIs themselves, except insofar as they implement the crypto_box protocol. – Squeamish Ossifrage Nov 04 '19 at 15:17
  • My playground is Angular/Typescript for the client side and on the same machine php within an apache2 service. First I started on the client with two keypairs to see the identically shared keys. Then I did the same on the "server side". Both sides for itself are fine and I can en and decrypt a string on the "client" and also on the "server". Next step was planed to create only one keypair on the client and one on the server. Exchange the public to calculate a shared. I expected also an identically shared but when I check the shared I recognized a huge difference. – Ritchie Nov 04 '19 at 15:58
  • Then I checked the shared keys. In the test with both keypairs on the client both shared keys have the same length and content. On the server with both keypairs on the server the shared have the same length (but this length is different to the client test) and the shared keys have a bit different content. They have a identically part. One at the beginning and one at the end. I expected a same behaviour on both sides: same length. And I expected a identically shared when I use one keypair on the client and one on the server. – Ritchie Nov 04 '19 at 16:05
  • @Ritchie Something else to try is: Find a test vector in the (say) TypeScript TweetNaCl implementation (perhaps https://github.com/katyo/tweetnacl-ts/blob/master/test/box.ts and https://github.com/katyo/tweetnacl-ts/blob/master/test/data/box.random.ts), and confirm you can reproduce it in TypeScript, so you are sure you understand the API; do the same for PHP libsodium; and then exchange the test vectors from the two libraries to confirm you can use each library to reproduce the other's test vector. – Squeamish Ossifrage Nov 04 '19 at 16:08
  • @Ritchie If you still can't figure it out, you will at least have a minimal working example of failing to use TypeScript TweetNaCl to reproduce PHP libsodium's tests, and a minimal working example of failing to use PHP libsodium to reproduce TypeScrypt TweetNaCl's tests. You can then share the MWEs with the authors of the respective libraries, or post them somewhere, for programming help. – Squeamish Ossifrage Nov 04 '19 at 16:10