Reputation: 1321
I want to implement OAuth 1.0
protocol in my C++ project. In order to create OAuth signature I need to implement HMAC-SHA1
algorithm where key
and text
will be some string created according to OAuth specification.
I want to use Crypto++ library for implementing HMAC-SHA1. I found this HMAC-SHA1 example on wiki of project:
AutoSeededRandomPool prng;
SecByteBlock key(16);
prng.GenerateBlock(key, key.size());
string plain = "HMAC Test";
string mac, encoded;
/*********************************\
\*********************************/
// Pretty print key
encoded.clear();
StringSource(key, key.size(), true,
new HexEncoder(
new StringSink(encoded)
) // HexEncoder
); // StringSource
cout << "key: " << encoded << endl;
cout << "plain text: " << plain << endl;
/*********************************\
\*********************************/
try
{
HMAC< SHA256 > hmac(key, key.size());
StringSource(plain, true,
new HashFilter(hmac,
new StringSink(mac)
) // HashFilter
); // StringSource
}
catch(const CryptoPP::Exception& e)
{
cerr << e.what() << endl;
exit(1);
}
/*********************************\
\*********************************/
// Pretty print
encoded.clear();
StringSource(mac, true,
new HexEncoder(
new StringSink(encoded)
) // HexEncoder
); // StringSource
cout << "hmac: " << encoded << endl;
But I can't understand how instead of random generated string use my created key
. I tried just create:
string key=...; //string generated by OAuth specification;
But then appear compiling errors. However when I write:
string plain=...; //string generated by OAuth specification;
Then there is no errors.
And what key length I need to specify? Because I will have keys of different lengths (with 48 and maybe 96 symbols).
Upvotes: 4
Views: 2787
Reputation: 364
I was tasked with a very similar task. Do two-legged OAuth 1.0a in C++. Two-legged because there is no user involved in the process, only the client and the server. As described in: http://oauth.googlecode.com/svn/spec/ext/consumer_request/1.0/drafts/2/spec.html
The complete proof of concept including parsing and decoding the parameters can be found at: https://gist.github.com/duedal/a197fc9f6dc1ad59f08c
Should be easy to build on this to complete it. Mainly need to validate the timestamp+nonce, and of course tie into your project.
Upvotes: 0
Reputation: 102326
It appears there are a few things you need to get familiar with. (Sorry I can't help because I've never had to do it).
First is the Security Architecture. You can find some reading at Beginner's Guide to OAuth – Part III : Security Architecture.
Second is the HMAC-SHA1 signature and format. You can find the overview at OAuth Core HMAC-SHA1.
Third, you need to understand OAuth's encoding and presentation format. You can find some reading at OAuth Core Parameter Encoding.
To answer some of your questions:
You will need to parse and decode the parameters to get the key, signed data, and signature. So you will need to parse and decode three values: oauth_key
, oauth_data
and oauth_signature
.
Then, you will set up your Crypto++ HMAC key
as follows.
SecByteBlock key(SHA1::BLOCKSIZE);
memcpy(key.data(), key.size(), oauth_key);
After that, you would verify with the following:
byte oauth_key[] = ...; // Your parsed and decoded key
string oauth_data = ...; // Your parsed and decoded data
string oauth_signature = ...; // // Your parsed and decoded signature
try
{
SecByteBlock key(SHA1::BLOCKSIZE);
memcpy(key.data(), key.size(), oauth_key);
HMAC< SHA1 > hmac(key, key.size());
const int flags = HashVerificationFilter::THROW_EXCEPTION | HashVerificationFilter::HASH_AT_END;
StringSource ss(oauth_data + oauth_signature + mac, true,
new HashVerificationFilter(hmac, NULL, flags)
); // StringSource
cout << "Verified message" << endl;
}
catch(const CryptoPP::Exception& e)
{
// Handle failure
cerr << e.what() << endl;
}
Another thing Crypto++ might be able to help with is Base64 decoding. Below is from the HexDecoder wiki page, but it applies to Base64Decoder
because the encoders and decoders use the same interface.
string encoded = ...;
string decoded;
StringSource ss(encoded,
new HexDecoder(
new StringSink(decoded)
) // HexDecoder
); // StringSource
So your code would be:
string encoded = ...;
string decoded;
StringSource ss(encoded,
new Base64Decoder(
new StringSink(decoded)
) // Base64Decoder
); // StringSource
The above uses Crypto++'s pipline interface, where data flows from a source to a sink. You can also do it in a more "C" like manner using Put
and Get
on the Base64Decoder
object:
string encoded = ...;
string decoded;
Base64Decoder decoder;
decoder.Put( (byte*)encoded.data(), encoded.size() );
decoder.MessageEnd();
word64 size = decoder.MaxRetrievable();
if(size && size <= SIZE_MAX)
{
decoded.resize(size);
decoder.Get((byte*)decoded.data(), decoded.size());
}
Upvotes: 4