How to decode non-key ASN1 data?

2019-07-20 12:43发布

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.

1条回答
对你真心纯属浪费
2楼-- · 2019-07-20 13:37
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;
查看更多
登录 后发表回答