Skip to content

Instantly share code, notes, and snippets.

@digitalhuman
Created January 23, 2021 08:37
Show Gist options
  • Save digitalhuman/2a2b85d61672e4bf83596d41351723ba to your computer and use it in GitHub Desktop.
Save digitalhuman/2a2b85d61672e4bf83596d41351723ba to your computer and use it in GitHub Desktop.
Visual Studio 2019 C/C++ Diffie and Hellman key exchange with PHP 7
#pragma warning(disable : 4996)
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>
#include "openssl/dh.h"
#include "openssl/bn.h"
#include "openssl/pem.h";
using namespace std;
DH *dhp = NULL;
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while ((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4) {
for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j < 4; j++)
char_array_4[j] = 0;
for (j = 0; j < 4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
int main(int argc, char *argv[])
{
BIGNUM* priv_key = NULL;
BIGNUM* apub_key = NULL;
BIGNUM* p = NULL;
BIGNUM* g = NULL;
std::string userPubKey;
std::string prime;
std::string generator;
if (argc < 6) {
printf("%s", "Missing parameters: -p, -key -g");
return -1;
}
//Process parameters
int count;
for (count = 1; count < argc; count+=2)
{
std::string param = (string)argv[count];
if (strcmpi(param.c_str(), "-p") == 0) {
prime = (string)argv[count+1];
}
else if (strcmpi(param.c_str(), "-key") == 0) {
userPubKey = (string)argv[count + 1];
}
else if (strcmpi(param.c_str(), "-g") == 0) {
generator = (string)argv[count+1];
}
}
//Set public key of remote User
BN_hex2bn(&apub_key, userPubKey.c_str());
DH *dhp = DH_new();
if (dhp == NULL) {
return -1;
}
//Set Prime and Generator
BN_hex2bn(&p, prime.c_str());
BN_dec2bn(&g, generator.c_str());
DH_set0_pqg(dhp, p, NULL, g);
if (DH_generate_key(dhp) != 1) {
printf("%s", "Error generating keys.");
return -1;
}
//Print Public Key as Hex
const BIGNUM* exportPublic = DH_get0_pub_key(dhp);
printf("Public Key: %s\r\n", BN_bn2hex(exportPublic));
//Print Private Key as Hex
const BIGNUM* exportPrivate = DH_get0_priv_key(dhp);
printf("Private Key: %s\r\n", BN_bn2hex(exportPrivate));
//Calculate secret
char buf[256] = { 0 };
unsigned char* abuf = NULL;
int alen = DH_size(dhp);
abuf = (unsigned char*)OPENSSL_malloc(alen);
int aout = DH_compute_key(abuf, apub_key, dhp);
printf("\r\nThe shared secret is:\r\n");
std::string encoded = base64_encode(abuf, aout);
printf("%s\r\n", encoded.c_str());
DH_free(dhp);
p = NULL;
g = NULL;
abuf = NULL;
}
<?php
//This is our private key
$myPrivate = '-----BEGIN PRIVATE KEY-----
MIICJgIBADCCARcGCSqGSIb3DQEDATCCAQgCggEBANn6weB11zG7izhfzM4qsITZ
3q/ORkF6+h3RTn7sh8Ji1MpHt3zHcPfdYFvs7V5SJfNN5Xv9L62RN8GwgxwRWIJr
8VBHfL3LyZNMMgnGBGJR0qmoM48iNd8i2ggZYj+H8WVh2y6tGw1YsDI3AFHpZFkN
TvCT1JHl2JfNEgOgSryBO84KDEWLxWaN/4Nqa9x5R0fxKMLjpWNRzEBBKcVeEHIZ
gzl7VKVJEpYC336sjYJE19ZD0O/gWl+q4WeRpDazDi6LDLZgnoDrUgbNAXtDETKL
gKOnYq+iwRWCQicQmaQvGXntmgdriExVacrRnH8o09ioxcVdtPG8WuLeqJczCvsC
AQIEggEEAoIBAH1yv00aZkw/7IIAJL1fZUrpVeO3xKIQDl982HOKS32+o2mUJWbc
DuDMIOvqiUEltEnFQOqDaJue0ucseJdH5Q9JHlSIhuUQiPB/JfEcPlb2QYzXHuAE
fWS94X0wiSxYgKXIL0XceA3yg5bYhDSR3DntdJrbboyYHt/QGQ8WCWiYEa402ovI
x+r7k3BlGxah33HeuqhMCFAfFvWUhLaj85QEmjHTjVMKeeTlNfBS+nscbCcZvLXd
qanvRxYYGdOhgLTcJe/iUsxmAWVTiqrid8MEvtFrenanawTgnPXAp5WtYTCGcsiQ
TBG24ND/tnZpPoPz/Rwlpo1IL4IbvKGRsfU=
-----END PRIVATE KEY-----';
//Copy/paste Public Key from C/C++ application below (hex format)
$remotePublic = hex2bin("29ECC536A85A4AFAD7D63E50545C68CE44A834396886E9A7BAC27E3A08A14C05259BA6E9940FDC512457155A60CAFACD8E43897E1B537A282D39697B75357197B5E3AD7F1826C0216604496AFAEF8999FBCE336C148166AE23E77EC66C0611235110FA8D6180A26425154959FACEC18FEE3EDA68E9355627820C14B44B486C9547ECE62BE72D56A7FAC4747AFCF201D8A4155F63A076234D6BC04DE27E7A7849BF8956E3DB6E51C043CB6FC66889ADE1F8DE756E9194838E8EF8A5CF9C0DD553282DE8A3130CA7752C22C191E5C352AC3BD77EF9270BF37BC807BBDB3F39AE7966B013723E71EAF41082A056D994F64B428183C5BAFEE9C7A41CABCEA868FC34");
$pkey = openssl_get_privatekey($myPrivate);
$privateKeyInfo = openssl_pkey_get_details($pkey);
//Use this Public Key Hex output, as -key parameter in C/C++ application
echo "My public Key (hex):\r\n<br/>";
echo bin2hex($privateKeyInfo["dh"]["pub_key"]);
echo "<br/><br/>";
echo "Remote public Key (hex):\r\n<br/>";
echo bin2hex($remotePublic);
echo "<br/><br/>";
echo "My Shared Secret (hex):\r\n<br/>".DH::create_shared_secret($remotePublic, $pkey);
echo "<br/><br/>";
echo "Remote Shared Secret (hex):\r\n<br/>";
//Copy/paste base64 encoded shared secret from C/C++ application below for validation
echo bin2hex(base64_decode("sASZRPpdNvNk3QLmdd3lD4wtZ0gcXPD+LySNOD7sHTjCPV7SZE++8mdrzWzhSDYcqCYZyPk+EFBsuJ0KG9qg8LxvaM7w98ttl9Q+jdo8elxamOvSNCpgXOUw/UagYC0o1K/EjpIIjQvEIZTKhoKoUxf4Etgbhs0oTu1AXfL3aq6EzNVghW6KPQzk9ZE5S8oC64oZhOu0G7GXFPuLV5vK/TapBR1R0HX2YimJMonYoMkYv9Ii8XgDzFMtLPk7sqVnlTMjykCb6zI3+q6cb9/GcVlDJJU7rdB91HcO4J/Rn5AEVlTFcJ6SqmFLg1lML2KovDx+eG5UvBJZoKc3xw3UzA=="));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment