This is a small demo webservice in Ruby using Sinatra Framwork and OpenSSL to create a (not so) secure key exchange between client and server using three methods: RSA, Diffie Hellman Ephemeral (DHE) and Elliptic Curve Diffie Hellman Ephemeral (ECDHE).
-
With RSA, the scenario is:
- Client chooses a random AES key and random Init Vector
- Client encrypts
key
andiv
using pre-defined RSA public key. - Client sends encrypted data to server.
- Server receives encrypted data, then uses private key located on server to decrypt to get
key
- Now both client and server have
key
, and use it to encrypt data in each request/response after that.
Pros:
+ Speed is fast (maybe the fastest)
+ Very easy to implement
Cons:
+ Pure AES key is transferred during connection. They're just protected by RSA
-
With DHE, the scenario is:
- Client creates DH instance, which contains base
G
, modulusp
, its own privatea
and publicA
- Client sends
G
,p
,A
to server. - Server creates DH instance from
G
andp
sent by client, calculates its own privateb
and publicB
, and calculates Shared secrets
by usingA
sent by client. - Server sends
B
back to client - Client uses
B
to calculate Shared secrets
- Both client and server use first 16 bytes of shared secret
s
as AES Key, and use it to encrypt data in each request/response after that.`
- Client creates DH instance, which contains base
Pros:
+ AES Key is not transferred during connection, they're calculated on client and server.
Cons:
+ Slow speed (when DH Key Size is big, it needs to generate values from the very beginning of key exchange process whenever client make a call to this api, this maybe resolved using static DH params, see `gen_dhparam.rb` to know how to generate DH param in Ruby)
+ Can't use RSA as an overall layer (in this case, due to the large amount of data being sent)
+ Bit harder to implement
NOTE: To use static DH Parameters, both client and server have to agree to use the same fixed DH param, then modify the code.
File server.rb
, API /dhe
, change them to:
# file dhparam.pem is pre-generated and pre-shared on both client and server
serverDH = OpenSSL::PKey::DH.new File.read("dhparam.pem")
File ``client.rb, method
sendDHE`, change them to:
# file dhparam.pem is pre-generated and pre-shared on both client and server
clientDH = OpenSSL::PKey::DH.new File.read("dhparam.pem")
# Must be used to generate public and private keypair before it can be used.
clientDH.generate_key!
# Since base G and modulus p is pre-shared, so they needn't to be sent during key exchange
# Just need to generate new A and a
dhStruct = {
"A" => clientDH.pub_key.to_s(16)
}
-
With ECDHE, the scenario is:
- Client creates ECDH instance, which generates a keypair
cpub
andcpriv
usingprime256v1
group - Client sends
cpub
to server - Server creates ECDH instance, which generates a keypair,
spub
andspriv
usingprime256v1
group - Server computes shared secret
s
by using client'cpub
- Server sends
spub
to client - Client computes shared secret
s
by using server'spub
- Both client and server use first 16 bytes of shared secret
s
as AES Key, and use it to encrypt data in each request/response after that.`
- Client creates ECDH instance, which generates a keypair
Pros:
+ Slightly fast and more secure
+ AES Key are not transferred during connection, they're calculated on client and server.
+ Can use RSA as an overall layer to make it more secure (in this case)
Cons:
+ Bit harder to implement
NOTE: Requires ruby >= 2.3.0
, as requested by openssl
gems
Install gems using
$ bundle install
Execute server:
$ ruby server.rb
By default, the server is at http://localhost:4567/
Test with client:
$ ruby client.rb
-
server.rb
: Main web service, exposing APIs for clients to call -
client.rb
: The name explains it all ;) -
make_keypair.rb
: Simple Ruby script to generate RSA Keypair using OpenSSL -
private_key
: RSA Private key in PEM format generated bymake_keypair.rb
-
pubkey.pub
: RSA Public key in PEM format generated bymake_keypair.rb
-
Gemfile
: Ruby gems list to use withbundle
-
README.md
: What you're reading -
gen_dhparam.rb
: Generate DH params -
network_sample.pcap
: Sample network traffic captured -
dhparam.pem
: Static DH parameters generated bygen_dhparam.rb