繁体   English   中英

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

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

我想通过已知格式的 GET 请求发送 GPG 加密数据。

问题 #1:请求中的数据块大小是有限的(4096 个符号),对于典型的 GPG 消息来说是不够的。 所以,我需要把它分块。

问题 #2:块可能以错误的顺序发送。 每个块必须有一个唯一的消息 ID 和序列号,因此可以将消息放在一起。

GPG 具有以文本格式发送加密数据的方法(装甲)。 RFC 2440 标准允许对装甲消息进行分块:

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

用于多部分消息,其中盔甲被分成 Y 部分,这是 Y 中的第 X 部分。

开始 PGP 消息,第 X 部分

用于多部分消息,其中这是未指定数量部分的第 X 部分。 需要使用 MESSAGE-ID Armor Header。

但是,不幸的是,我没有发现 GPG 中实现了此功能的证据。 并且没有关于公钥分块的消息,实际上,这也可能是巨大的。 所以我拒绝了使用原生 GPG 装甲进行分块的想法。

我目前自制的解决方案:将二进制加密数据拆分成chunk,然后将每个chunk放入一个block中,其中包含UUID(MessageID模拟)、block的序号、block的总数、CRC校验和堵塞。 像那样:

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

将信息从这些块中组合起来是一个更大的挑战,但也是可行的。 但我想要更清晰的解决方案,最好在 C++ 上。

你可以帮帮我吗?

Qt 提供了非常简单的数据序列化方法。 我创建了一个 class 来分块、存储和重建二进制数据,现在我认为我不需要更简单的东西。

但是,如果有人知道更好的解决方案,请与我分享。

#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