简体   繁体   English

将加密的消息拆分成块并再次组合在一起

[英]Split encrypted messages into chunks and put them together again

I want to send GPG encrypted data via GET request of known format.我想通过已知格式的 GET 请求发送 GPG 加密数据。

Issue #1: Data block size in the request is limited (4096 symbols), and it is not enough for a typical GPG message.问题 #1:请求中的数据块大小是有限的(4096 个符号),对于典型的 GPG 消息来说是不够的。 So, I need to chunk it.所以,我需要把它分块。

Issue #2: Chunks may be sent in the wrong order.问题 #2:块可能以错误的顺序发送。 Each chunk must have a unique message ID and serial number, so the messages can be put together.每个块必须有一个唯一的消息 ID 和序列号,因此可以将消息放在一起。

GPG has the method to send encrypted data in text format (armoring). GPG 具有以文本格式发送加密数据的方法(装甲)。 RFC 2440 standard allows chunking armored messages: RFC 2440 标准允许对装甲消息进行分块:

BEGIN PGP MESSAGE, PART X/Y开始 PGP 消息,第 X/Y 部分

Used for multi-part messages, where the armor is split amongst Y parts, and this is the Xth part out of Y.用于多部分消息,其中盔甲被分成 Y 部分,这是 Y 中的第 X 部分。

BEGIN PGP MESSAGE, PART X开始 PGP 消息,第 X 部分

Used for multi-part messages, where this is the Xth part of an unspecified number of parts.用于多部分消息,其中这是未指定数量部分的第 X 部分。 Requires the MESSAGE-ID Armor Header to be used.需要使用 MESSAGE-ID Armor Header。

But, unfortunately, I've found no evidence that this feature is implemented in GPG.但是,不幸的是,我没有发现 GPG 中实现了此功能的证据。 And no word about chunking of public keys, which, actually, can be huge too.并且没有关于公钥分块的消息,实际上,这也可能是巨大的。 So I turned down the idea of using native GPG armors for chunking.所以我拒绝了使用原生 GPG 装甲进行分块的想法。

My current home-made solution: binary encrypted data are splitted into chunks, then each chunk is put into a block, which contains UUID (MessageID analog), the serial number of the block, the total number of blocks, and CRC checksum of the block.我目前自制的解决方案:将二进制加密数据拆分成chunk,然后将每个chunk放入一个block中,其中包含UUID(MessageID模拟)、block的序号、block的总数、CRC校验和堵塞。 Like that:像那样:

[ UUID ][ Number ][ Total ][ Chunk of encrypted data ][ Checksum ]

Putting the message together out of that blocks is a bigger challenge, but doable as well.将信息从这些块中组合起来是一个更大的挑战,但也是可行的。 But I want more clear solution, preferably on C++.但我想要更清晰的解决方案,最好在 C++ 上。

Could you help me?你可以帮帮我吗?

Qt provides very simple methods for data serialization. Qt 提供了非常简单的数据序列化方法。 I created a class to chunk, store, and rebuild binary data, and for now I don't think I need something more simple.我创建了一个 class 来分块、存储和重建二进制数据,现在我认为我不需要更简单的东西。

But, if someone knows a better solution, please share it with me.但是,如果有人知道更好的解决方案,请与我分享。

#include <QByteArrayView>
#include <QDataStream>
#include <QException>
#include <QUuid>

enum CHUNKER {
    MESSAGE_READY = 0,
    BLOCK_ADDED
};

struct ChunkedMessage {
    QUuid UUID;
    QByteArray Data;
};

class Chunker {
public:
    Chunker();
    ~Chunker();
    static quint16 GetChecksum(QByteArray *Block);
    static QByteArrayList ArmorData(QByteArray *Data, qsizetype *ChunkSize);
    CHUNKER AddBlock(QByteArray *Block, ChunkedMessage *Message);
private:
    struct MessageBlock {
        QUuid UUID;
        quint32 Number;
        quint32 Total;
        QByteArray Data;
    };
    QMap<QUuid, quint32> Sizes;
    QMap<QUuid, QMap<quint32, Chunker::MessageBlock>*> Stack;
    MessageBlock DearmorChunk(QByteArray *Block);
    bool CheckIntegrity(QUuid *UUID, QByteArray *Reconstructed);
};

Chunker::Chunker() { }

Chunker::~Chunker() { }

quint16 Chunker::GetChecksum(QByteArray *Block) { return qChecksum(QByteArrayView(*Block), Qt::ChecksumIso3309); }

QByteArrayList Chunker::ArmorData(QByteArray *Data, qsizetype *ChunkSize) {
    QByteArrayList Result;
    QUuid UUID = QUuid::createUuid();
    qsizetype RealChunkSize = (*ChunkSize) - sizeof(UUID.toRfc4122()) - sizeof(quint32) - sizeof(quint32) - sizeof(quint16);
    const quint32 ChunkCount = ((*Data).length() / RealChunkSize) + 1;
    for (auto Pos = 0; Pos < ChunkCount; Pos++) {
        QByteArray Block;
        QDataStream Stream(&Block, QIODeviceBase::WriteOnly);
        Stream << UUID.toRfc4122() << (Pos + 1) << ChunkCount << (*Data).mid(Pos * RealChunkSize, RealChunkSize);
        Stream << Chunker::GetChecksum(&Block);
        Result.push_back(Block);
    }
    return Result;
}

Chunker::MessageBlock Chunker::DearmorChunk(QByteArray *Block) {
    Chunker::MessageBlock Result;
    QDataStream Stream(Block, QIODeviceBase::ReadOnly);
    QByteArray ClearBlock = (*Block).chopped(sizeof(quint16));
    QByteArray BytesUUID;
    quint16 Checksum;
    Stream >> BytesUUID >> Result.Number >> Result.Total >> Result.Data >> Checksum;
    Result.UUID = QUuid::fromRfc4122(QByteArrayView(BytesUUID));
    if (Chunker::GetChecksum(&ClearBlock) != Checksum) throw std::runtime_error("Checksums are not equal");
    return Result;
}

bool Chunker::CheckIntegrity(QUuid *UUID, QByteArray *Reconstructed) {
    quint32 Size = this->Sizes[*UUID];
    if (this->Stack[*UUID]->size() > Size) throw std::runtime_error("Corrupted message blocks");
    if (this->Stack[*UUID]->size() < Size) return false;
    for (quint32 Counter = 0; Counter < Size; Counter++) {
        if (!(this->Stack[*UUID]->contains(Counter + 1))) return false;
        (*Reconstructed).append((*(this->Stack[*UUID]))[Counter + 1].Data);
    }
    return true;
}

CHUNKER Chunker::AddBlock(QByteArray *Block, ChunkedMessage *Message) {
    Chunker::MessageBlock DecodedBlock = Chunker::DearmorChunk(Block);
    if (!this->Sizes.contains(DecodedBlock.UUID)) {
        this->Sizes[(QUuid)DecodedBlock.UUID] = (quint32)DecodedBlock.Total;
        this->Stack[(QUuid)DecodedBlock.UUID] = new QMap<quint32, Chunker::MessageBlock>;
    }
    (*(this->Stack[DecodedBlock.UUID]))[(quint32)(DecodedBlock.Number)] = Chunker::MessageBlock(DecodedBlock);
    QByteArray ReconstructedData;
    if (this->CheckIntegrity(&DecodedBlock.UUID, &ReconstructedData)) {
        (*Message).UUID = (QUuid)(DecodedBlock.UUID);
        (*Message).Data = (QByteArray)ReconstructedData;
        this->Sizes.remove(DecodedBlock.UUID);
        delete this->Stack[DecodedBlock.UUID];
        this->Stack.remove(DecodedBlock.UUID);
        return CHUNKER::MESSAGE_READY;
    }
    return CHUNKER::BLOCK_ADDED;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM