Reputation: 463
Is it possible to use crypto++ library to decode arbitrary ASN1 data (which has couple of sequences and integers) which I have in a byte array. ash.h contains methods which all take BufferedTransformation as input, but that class is interface for different ciphers and hashes, which really seems to be not related to my simple case at all. I also found ASN1Object in cryptlib.h but it's another interface and I haven't managed to find any implementing classes.
Have I thought it way too complex for myself or is it actually difficult to decode arbitrary ASN1 data?
I am actually using this in Swift/objective-c iOS application, so if anyone has a simple solution with whatever else tool, let me know.
EDIT: Adding an example structure of the data
SEQUENCE
SEQUENCE
INTEGER
INTEGER
SEQUENCE
INTEGER
INTEGER
There's always the parent sequence which contains 1 to n sequences which contain 2 integers (elgamal encryption pair (g^r, mh^r)) each.
Upvotes: 3
Views: 1430
Reputation: 102245
SEQUENCE
SEQUENCE
INTEGER
INTEGER
SEQUENCE
INTEGER
INTEGER
For this, you would want something like:
ArraySource as(data, size);
Integer i1, i2, i3, i4;
BERSequenceDecoder d1(as);
BERSequenceDecoder d2(d1);
i1.BERDecode(d2);
i2.BERDecode(d2);
d2.MessageEnd();
BERSequenceDecoder d3(d2);
i3.BERDecode(d3);
i4.BERDecode(d3);
d3.MessageEnd();
d1.MessageEnd();
which contain 2 integers (elgamal encryption pair (g^r, mh^r)) each.
Once you have the parameters (see below), you should call one of the Initialize
functions with the parameters. Don't call the ones that take a PRNG because they create parameters and keys.
See gfpcrypt.h for some of the relevant class definitions. Also see ElGamal - Crypto++ Wiki.
Here's an example that generates integer pairs and packages them in ASN.1 structures like you desire. It then reads them back in and stops when there's nothing left to consume (i.e., the inner Integer pairs are optional).
You would run it like ./asn1-test.exe
or ./asn1-test.exe 3
or ./asn1-test.exe 6
or ./asn1-test.exe 128
. The size is only 48-bits so you don't waste time generating integers you don't need.
static const unsigned int BIT_COUNT = 48;
int main(int argc, char* argv[])
{
unsigned int count = 2;
if(argc >= 2 && argv[1] != NULL)
{
istringstream iss(argv[1]);
iss >> count;
if(iss.fail()) count = 2;
}
cout << "Testing " << count << " integer pairs" << endl;
// Count to pairs
count *= 2;
try
{
AutoSeededRandomPool prng;
vector<Integer> vv;
vv.resize(count);
for(unsigned int i = 0; i < count; i += 2)
{
vv[i] = Integer(prng, BIT_COUNT);
vv[i + 1] = Integer(prng, BIT_COUNT);
}
// Scratch for holding ASN.1 encoded structures in Crypto++
ByteQueue queue;
// Encode them
{
DERSequenceEncoder outer(queue);
for(unsigned int i = 0; i < count; i += 2)
{
DERSequenceEncoder inner(outer);
vv[i].DEREncode(inner);
vv[i + 1].DEREncode(inner);
inner.MessageEnd();
}
outer.MessageEnd();
}
// Save it to file (use dumpasn1 to view it)
FileSink fs("sequences.der", true);
queue.CopyTo(fs);
fs.MessageEnd();
// Decode them
{
BERSequenceDecoder outer(queue);
// Ensure we break from the loop based on EndReached()
for( ; ; )
{
if(outer.EndReached()) break;
BERSequenceDecoder inner(outer);
Integer i1, i2;
i1.BERDecode(inner);
i2.BERDecode(inner);
cout << "Pair" << endl;
cout << std::hex << " Integer: " << i1 << endl;
cout << std::hex << " Integer: " << i2 << endl;
inner.MessageEnd();
}
outer.MessageEnd();
}
} catch (const Exception& ex) {
cerr << std::dec << ex.what() << endl;
exit (1);
}
return 0;
}
And here's what a run and dump looks like:
$ ./asn1-test.exe 3
Testing 3 integer pairs
Pair
Integer: 301818b3c631h
Integer: 1ff0ebf1ca4bh
Pair
Integer: f97e9d28e9cah
Integer: 94813cab125fh
Pair
Integer: 8a146ea68e7ch
Integer: 60d48ef2462fh
$ dumpasn1 sequences.der
0 57: SEQUENCE {
2 16: SEQUENCE {
4 6: INTEGER 30 18 18 B3 C6 31
12 6: INTEGER 1F F0 EB F1 CA 4B
: }
20 18: SEQUENCE {
22 7: INTEGER 00 F9 7E 9D 28 E9 CA
31 7: INTEGER 00 94 81 3C AB 12 5F
: }
40 17: SEQUENCE {
42 7: INTEGER 00 8A 14 6E A6 8E 7C
51 6: INTEGER 60 D4 8E F2 46 2F
: }
: }
0 warnings, 0 errors.
Here are the includes to save you the trouble of looking them up:
#include <iostream>
using std::ostream;
using std::cin;
using std::cout;
using std::cerr;
using std::endl;
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <sstream>
using std::istringstream;
#include <cryptopp/cryptlib.h>
using CryptoPP::Exception;
#include <cryptopp/filters.h>
using CryptoPP::StringSource;
using CryptoPP::StringSink;
#include <cryptopp/files.h>
using CryptoPP::FileSink;
#include <cryptopp/integer.h>
using CryptoPP::Integer;
#include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;
#include <cryptopp/asn.h>
#include <cryptopp/oids.h>
namespace ASN1 = CryptoPP::ASN1;
using CryptoPP::DERSequenceEncoder;
using CryptoPP::BERSequenceDecoder;
#include <cryptopp/queue.h>
using CryptoPP::ByteQueue;
Upvotes: 5