[英]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.