Как декодировать неключевые данные ASN1?

Можно ли использовать библиотеку crypto++ для декодирования произвольных данных ASN1 (которые имеют пару последовательностей и целых чисел), которые у меня есть в массиве байтов. ash.h содержит методы, которые все принимают BufferedTransformation в качестве входных данных, но этот класс является интерфейсом для различных шифров и хэшей, что, похоже, вообще не связано с моим простым случаем. Я также нашел ASN1Object в cryptlib.h, но это другой интерфейс, и мне не удалось найти какие-либо реализующие классы.

Думал ли я, что это слишком сложно для себя, или действительно сложно декодировать произвольные данные ASN1?

На самом деле я использую это в приложении Swift/objective-c iOS, поэтому, если у кого-то есть простое решение с любым другим инструментом, дайте мне знать.

РЕДАКТИРОВАТЬ: добавление примера структуры данных

SEQUENCE
    SEQUENCE
        INTEGER
        INTEGER
    SEQUENCE
        INTEGER
        INTEGER

Всегда есть родительская последовательность, которая содержит от 1 до n последовательностей, каждая из которых содержит 2 целых числа (пару шифрования elgamal (g ^ r, mh ^ r)).


person Kelo    schedule 15.04.2015    source источник
comment
Короткий ответ МОЖЕТ БЫТЬ, и это зависит от базовых типов ASN.1. Можете ли вы привести пример того, что вы пытаетесь расшифровать? Опишите его в тексте и используйте отступ, чтобы показать типичную иерархию, связанную со структурами ASN.1. Это поможет нам показать вам, как выглядит решение. Добавьте пример к своему вопросу, нажав Изменить (не добавляйте его в комментарии).   -  person jww    schedule 15.04.2015
comment
Я обновил сообщение, не уверен, что это то, что вы имели в виду, или это слишком упрощено.   -  person Kelo    schedule 16.04.2015


Ответы (1)


SEQUENCE
    SEQUENCE
        INTEGER
        INTEGER
    SEQUENCE
        INTEGER
        INTEGER

Для этого вам нужно что-то вроде:

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();

которые содержат 2 целых числа (пара шифрования elgamal (g ^ r, mh ^ r)).

Когда у вас есть параметры (см. ниже), вы должны вызвать одну из Initialize функций с параметрами. Не вызывайте те, которые принимают PRNG, потому что они создают параметры и ключи.

См. gfpcrypt.h для некоторых соответствующих определений классов. См. также ElGamal — Crypto++ Wiki.


Вот пример, который генерирует пары целых чисел и упаковывает их в структуры ASN.1, как вы хотите. Затем он считывает их обратно и останавливается, когда нечего потреблять (т. Е. Внутренние пары целых чисел являются необязательными).

Вы бы запустили его как ./asn1-test.exe или ./asn1-test.exe 3 или ./asn1-test.exe 6 или ./asn1-test.exe 128. Размер всего 48 бит, поэтому вы не тратите время на создание целых чисел, которые вам не нужны.

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;
}

А вот как выглядит run and dump:

$ ./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.

Вот включения, чтобы избавить вас от необходимости искать их:

#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;
person jww    schedule 16.04.2015
comment
Большое спасибо. Мне кажется, это работает и без MessageEnd() вызовов. Это очень важно, поскольку мои собственные данные не включают их. - person Kelo; 20.04.2015
comment
@Kelo - вы можете избежать вызовов MessageEnd() в этом примере, но не делайте это привычкой. В конце концов вы обнаружите, что вам не хватает данных, потому что данные не были сброшены. См., например, HexEncoder и отсутствующие данные. Это известная проблема с фильтрами. (На самом деле, это сделано по замыслу и потому, что фильтр ждет, когда вы скажете ему сбросить частичные данные, которые он буферизировал). - person jww; 20.04.2015