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.