Some working example code for wanderers. ATTENTION: still no code for 
verifying signature and MAC checking

#include "stdafx.h"
#include <vector>
#include "simpleJSON\JSON.h"

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif

#include <sstream>
#include <time.h>
#include "cryptopp\eccrypto.h"
#include "cryptopp\oids.h"
#include "cryptopp\hkdf.h"
#include "cryptopp\ecp.h"
#include "cryptopp\hex.h"
#include "cryptopp\osrng.h"
#include "cryptopp\modes.h"
#include "cryptopp\base64.h"
#include "cryptopp\dh.h"
#include "cryptopp\dh2.h"
#include "cryptopp\asn.h"
#include "cryptopp\rsa.h"
#include "cryptopp\pem.h"
#include "cryptopp\files.h"
#include <limits.h>
#include <cstddef>
#undef max
#undef min

using std::string;
using std::vector;
using std::cout;
using namespace std;

string base64_decode(string encoded) {
string decoded;

CryptoPP::Base64Decoder decoder;
decoder.Put((CryptoPP::byte*)encoded.data(), encoded.size());
decoder.MessageEnd();

CryptoPP::word64 size = decoder.MaxRetrievable();
if (size && size <= SIZE_MAX)
{
decoded.resize(size);
decoder.Get((CryptoPP::byte*)&decoded[0], decoded.size());
return decoded;
}
else {
return "";
}
}

std::vector<unsigned char> hex_to_bytes(std::string const& hex)
{
std::vector<unsigned char> bytes;
bytes.reserve(hex.size() / 2);
for (std::string::size_type i = 0, i_end = hex.size(); i < i_end; i += 2)
{
unsigned byte;
std::istringstream hex_byte(hex.substr(i, 2));
hex_byte >> std::hex >> byte;
bytes.push_back(static_cast<unsigned char>(byte));
}
return bytes;
}

int main(int argc, _TCHAR* argv[])
{

//our private key - in need for decrypting, contains X cooordinate
string priv_key_accepted("");
CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> k1;
string decoded;
CryptoPP::StringSource ss1(priv_key_accepted.c_str(), true, new 
CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded)));
k1.Load(CryptoPP::StringStore((const CryptoPP::byte*)decoded.data(), 
decoded.size()).Ref());
CryptoPP::Integer priv_int = k1.GetPrivateExponent();

//our public key not needed for decrypting
string pub_key_accepted("");

//formatted using the base64 representation of the key in uncompressed 
point format. 
//It consists of one magic number which specifies the format (0x04) + two 
32 byte big integers representing the X and Y coordinates in the Elliptic 
Curve
string google_ephemeral_pub_key_accepted("");
string google_pub_key_accepted("");
string encrypted_message_accepted("");

//decoding
string priv_key = base64_decode(priv_key_accepted);
string pub_key = base64_decode(pub_key_accepted);
string google_ephemeral_pub_key = 
base64_decode(google_ephemeral_pub_key_accepted);
string encrypted_message = base64_decode(encrypted_message_accepted);
string google_public_key = base64_decode(google_pub_key_accepted);

//because of ASN.1 format, we'll need only last 65 bytes
google_public_key = google_public_key.substr(-0, 65);

//P-256 curve
CryptoPP::OID curve = CryptoPP::ASN1::secp256r1();

//--part for decrypting payment data
//init auth key agreement domain
CryptoPP::ECDH<CryptoPP::ECP, CryptoPP::NoCofactorMultiplication>::Domain 
dh(curve);
CryptoPP::DH2 dh2(dh);
//load keys
CryptoPP::SecByteBlock privKey;
size_t encodedSize = priv_int.MinEncodedSize(CryptoPP::Integer::UNSIGNED);
privKey.resize(encodedSize);
priv_int.Encode(privKey.BytePtr(), encodedSize, 
CryptoPP::Integer::UNSIGNED);
//google public
CryptoPP::SecByteBlock g_pubKey((const CryptoPP::byte*) 
google_public_key.data(), dh2.StaticPublicKeyLength());
//google ephemeral public
CryptoPP::SecByteBlock g_ephKey((const CryptoPP::byte*) 
google_ephemeral_pub_key.data(), dh2.EphemeralPublicKeyLength());

//getting our shared secret (its X coordinate. If using math-oriented path, 
we'll obtain both)
CryptoPP::SecByteBlock sharedA(dh.AgreedValueLength());
bool agree = dh.Agree(sharedA, privKey, g_ephKey);
string str_shared_secret_x((const char*)sharedA.data(), sharedA.size());

//about options:
//CheckMode, OldCofactorMode, SingleHashMode and CofactorMode are 0 google 
says
//OldCofactorMode - just the same as CofactorMode (0 for us)
//SingleHashMode - if somehow true(for us it is false) - then we would send 
only secret to hkdf (0 for us, sending ephemeral||secret)
//CheckMode - throw error while decrypting if R(P[r] = subgr generator over 
random from 1..q-1)[q(prime = subgroup order)] != 0 . also 0 for us

//forming value to send to hkdf:
CryptoPP::byte combined_secret[96];
memcpy(combined_secret, g_ephKey, 65);
memcpy(combined_secret + 65, str_shared_secret_x.data(), 32);

//retrieving shared key using "Key derivation function: HKDFwithSHA256":
//info always the same, as in document 
CryptoPP::byte info[] = { 'G','o','o','g','l','e' };
size_t info_len = sizeof(info) / sizeof(*info);
//empty (32 empty bytes), as said in docs
CryptoPP::byte salt[32] = { 0 };
size_t salt_len = sizeof(salt) / sizeof(*salt);
//secret - what we have found from ECDH
CryptoPP::byte *secret = &(combined_secret[0]);
size_t secret_len = 97;
//to store result
CryptoPP::byte derived[CryptoPP::SHA256::DIGESTSIZE];
size_t derived_len = CryptoPP::SHA256::DIGESTSIZE;
//derivation function
CryptoPP::HKDF<CryptoPP::SHA256> hkdf;
//deriving, result in 'dervied'
hkdf.DeriveKey(&(derived[0]), derived_len, secret, secret_len, NULL, 0, 
info, info_len);

//splitting to two 128-bit length: symmetricEncryptionKey and macKey
CryptoPP::byte symmetricEncryptionKey[16];
CryptoPP::byte macKey[16];
//memcpy(macKey, derived, 16);
//memcpy(symmetricEncryptionKey, derived + 16, 16);
memcpy(symmetricEncryptionKey, derived, 16);
memcpy(macKey, derived + 16, 16);

//checking accepted tag with MAC with HMAC SHA256
//TODO

//decrypting encryptedMessage with AES128 CTR zero IV, no padding, using 
symmetricEncryption key
//zero iv
CryptoPP::byte iv[16] = { 0 };
string decryptedtext;
CryptoPP::CTR_Mode< CryptoPP::AES >::Encryption d;
d.SetKeyWithIV(&(symmetricEncryptionKey[0]), 16, NULL, 16);
CryptoPP::StringSource(reinterpret_cast<const unsigned 
char*>(&(encrypted_message[0])), encrypted_message.size(), true,
new CryptoPP::StreamTransformationFilter(d,
new CryptoPP::StringSink(decryptedtext)
)
);

std::cout << decryptedtext << std::endl;

return 0;

/*
printf("Port listener starting\n");
int iResult;
SOCKET AcceptedSocket = INVALID_SOCKET;
int rc;

int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;


PortListener portListener;
portListener.StartListen();

portListener.~PortListener();
WSACleanup();
*/
return 0;
}

Tested, working. It is not a prod-code, so no proper input, params, return 
and so on included.

-- 
You received this message because you are subscribed to "Crypto++ Users". More 
information about Crypto++ and this group is available at 
http://www.cryptopp.com and 
http://groups.google.com/forum/#!forum/cryptopp-users.
--- 
You received this message because you are subscribed to the Google Groups 
"Crypto++ Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to