Add ECB-mode decryptor draft implementation.
Chaos Ci / test (push) Successful in 2m59s
Chaos Ci / benchmark (push) Successful in 1m31s

This commit is contained in:
hashlag
2026-07-29 02:25:51 +03:00
parent 78ab3a8c27
commit 6ae4df4bfc
2 changed files with 675 additions and 0 deletions
+146
View File
@@ -106,6 +106,152 @@ public:
return written;
}
};
class Decryptor
{
public:
Decryptor(const typename CipherT::Key & key)
: Decryptor_(key)
, BlockBytesPacked_(0)
, PreviousBlockSaved_(false)
{ }
static constexpr uint64_t PredictMaxUpdateOutput(uint64_t in)
{
return in + CipherT::BlockSize - 1;
}
static constexpr uint64_t PredictMaxFinishOutput()
{
return CipherT::BlockSize;
}
template<typename OutputIt, typename InputIt>
uint64_t Update(OutputIt outBegin, OutputIt outEnd,
InputIt inBegin, InputIt inEnd)
{
return UpdateImpl(outBegin, outEnd, inBegin, inEnd);
}
template<typename OutputIt>
uint64_t Finish(OutputIt outBegin, OutputIt outEnd)
{
if (BlockBytesPacked_ != 0)
{
throw Service::ChaosException("EcbMode<>::Decryptor: ciphertext size "
"is not a multiple of the algorithm's "
"block size");
}
if (!PreviousBlockSaved_)
{
return 0;
}
auto unpadResult = PadderT::ComputeUnpad(PreviousBlock_.Begin(),
PreviousBlock_.End());
if (!unpadResult.IsOkay_)
{
throw Service::ChaosException("EcbMode<>::Decryptor: invalid ciphertext");
}
const uint64_t lastChunkSize = CipherT::BlockSize - unpadResult.PadSize_;
EnsureCopy(outBegin, outEnd,
PreviousBlock_.Begin(),
PreviousBlock_.Begin() + lastChunkSize);
return lastChunkSize;
}
private:
using BlockArray = Service::SeArray<uint8_t, CipherT::BlockSize>;
typename CipherT::Decryptor Decryptor_;
uint64_t BlockBytesPacked_;
BlockArray Block_;
BlockArray DecryptedBlock_;
bool PreviousBlockSaved_;
BlockArray PreviousBlock_;
template<typename OutputIt, typename InputIt>
static OutputIt EnsureCopy(OutputIt outBegin, OutputIt outEnd,
InputIt inBegin, InputIt inEnd)
{
OutputIt out = outBegin;
InputIt in = inBegin;
for (; out != outEnd && in != inEnd; ++out, ++in)
{
*out = *in;
}
if (out == outEnd && in != inEnd)
{
throw Service::ChaosException("EcbMode<>::Decryptor: insufficient output "
"buffer size");
}
return out;
}
template<typename OutputIt>
struct DelayedFlushResult
{
OutputIt Next_;
uint64_t Written_;
};
template<typename OutputIt>
DelayedFlushResult<OutputIt> DelayedFlush(OutputIt outBegin, OutputIt outEnd)
{
if (PreviousBlockSaved_)
{
OutputIt result = EnsureCopy(outBegin, outEnd,
PreviousBlock_.Begin(), PreviousBlock_.End());
PreviousBlock_ = DecryptedBlock_;
return { .Next_ = result, .Written_ = CipherT::BlockSize };
}
else
{
PreviousBlock_ = DecryptedBlock_;
PreviousBlockSaved_ = true;
return { .Next_ = outBegin, .Written_ = 0 };
}
}
template<typename OutputIt, typename InputIt>
uint64_t UpdateImpl(OutputIt outBegin, OutputIt outEnd,
InputIt inBegin, InputIt inEnd)
{
uint64_t written = 0;
OutputIt out = outBegin;
for (InputIt in = inBegin; in != inEnd; ++in)
{
Block_[BlockBytesPacked_++] = *in;
if (BlockBytesPacked_ == Block_.Size())
{
BlockBytesPacked_ = 0;
Decryptor_.DecryptBlock(DecryptedBlock_.Begin(), DecryptedBlock_.End(),
Block_.Begin(), Block_.End());
auto result = DelayedFlush(out, outEnd);
out = result.Next_;
written += result.Written_;
}
}
return written;
}
};
};
} // namespace Chaos::Cipher::Block::Mode