diff options
Diffstat (limited to 'src/core/crypto/ctr_encryption_layer.cpp')
-rw-r--r-- | src/core/crypto/ctr_encryption_layer.cpp | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp new file mode 100644 index 000000000..8799496e2 --- /dev/null +++ b/src/core/crypto/ctr_encryption_layer.cpp @@ -0,0 +1,56 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "core/crypto/ctr_encryption_layer.h" + +namespace Crypto { +CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset) + : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR), + iv(16, 0) {} + +size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const { + if (length == 0) + return 0; + + const auto sector_offset = offset & 0xF; + if (sector_offset == 0) { + UpdateIV(base_offset + offset); + std::vector<u8> raw = base->ReadBytes(length, offset); + if (raw.size() != length) + return Read(data, raw.size(), offset); + cipher.Transcode(raw.data(), length, data, Op::DECRYPT); + return length; + } + + // offset does not fall on block boundary (0x10) + std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset); + UpdateIV(base_offset + offset - sector_offset); + cipher.Transcode(block.data(), block.size(), block.data(), Op::DECRYPT); + size_t read = 0x10 - sector_offset; + + if (length + sector_offset < 0x10) { + memcpy_s(data, length, block.data() + sector_offset, std::min<u64>(length, read)); + return read; + } + + memcpy_s(data, length, block.data() + sector_offset, read); + return read + Read(data + read, length - read, offset + read); +} + +void CTREncryptionLayer::SetIV(std::vector<u8> iv_) { + const auto length = std::min<size_t>(iv_.size(), iv.size()); + for (size_t i = 0; i < length; ++i) + iv[i] = iv_[i]; +} + +void CTREncryptionLayer::UpdateIV(size_t offset) const { + offset >>= 4; + for (size_t i = 0; i < 8; ++i) { + iv[16 - i - 1] = offset & 0xFF; + offset >>= 8; + } + cipher.SetIV(iv); +} +} // namespace Crypto |