I am developing an application to secure communications between a client and an embedded linux server. I am very new to the field of cryptography, so at this stage I am looking more for guidance - especially when it comes to vulnerabilities in my approach.
The server will not be connected to the internet. I am looking for a way to implement a one time password authentication - (presumably the OTP would be generated via some shared secret exchanged between the client and server). I do not want to store static keys on the server, so I was thinking something along the lines of using Diffie-Hellman ephemeral key exchange could be used to exchange these keys or something along those lines. Could someone give me some pointers as to how I could approach solving this problem - or better still if this has already been done. I was thinking of using OpenSSL to put the server pieces together and the client needs to be more open ended - Java/C++/Platform agnostic. Perhaps there are some OpenSSL examples that do something similar to this, if so please send them along.
EDIT: So I've been doing a bit of experimentation since posting the question yesterday. I was able to verify that I can successfully create a shared secret using an ephemeral Diffie-Hellman key exchange. I got a C++ proof of concept working using the OpenSSL library, as shown in block of code below (which I adapted from various snippets I found online, sorry I lost the links). From what I can tell, this should be sufficient to get One Time Passwords working between the client and the server. For this latter solution, I was thinking about linking to the OATH Toolkit library for HOTP or TOTP Algorithm support.
The idea would be that once the shared secret was exchanged, the server could make up an OTP with both the shared secret and some server random data. Once the client knows this OTP they would provide it to login and authenticate. I am not sure if I have completely gotten this wrong of if what I am proposing is not possible (or more likely full of holes).
The following block of code shows how to the Diffie-Hellman shared secrets are identical (given a common generator and prime which is established via the DH_generate_parameters_ex.... and cloned for the client and server using the DHparams_dup API the DH keys replaced via the EVP_PKEY_set1_DH call)
auto dhparams = DH_new();
if ( DH_generate_parameters_ex(dhparams, 512, DH_GENERATOR_5, nullptr) != 0 ) {
// duplicate the existing parameters for alice
auto dhparams_alice = DHparams_dup(dhparams);
// generate Alice's private and public key values
// should return 1 for success
auto res = DH_generate_key(dhparams_alice);
// Use the same generator and bitlength parameters
auto dhparams_bob = DHparams_dup(dhparams);
// generate Bob's private and public key values
// should return 1 for success
res = DH_generate_key(dhparams_bob);
auto key_alice = EVP_PKEY_new();
// should return 1 for success
res = EVP_PKEY_set1_DH(key_alice, dhparams_alice);
auto key_bob = EVP_PKEY_new();
// should return 1 for success
res = EVP_PKEY_set1_DH(key_bob, dhparams_bob);
// Compute the shared secret using Alice's private key and Bob's public key.
// unique pointer, so automatically destroyed.
size_t keyLen1 = 0;
auto key1 = dh_derive(key_alice, key_bob, keyLen1);
// Compute the shared secret using Bob's private key and Alice's public key.
// unique pointer, so automatically destroyed.
size_t keyLen2 = 0;
auto key2 = dh_derive(key_bob, key_alice, keyLen2);
// Prove correctness by showing Alicia and Beth derived the same secret
if (keyLen1 != keyLen2 || memcmp(key1.get(), key2.get(), keyLen1) != 0) {
std::cout << "Shared Secret different" << std::endl;
}
EVP_PKEY_free(key_alice);
EVP_PKEY_free(key_bob);
DH_free(dhparams_alice);
DH_free(dhparams_bob);
DH_free(dhparams);