Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"
This reverts commit 15b7df8ef1.
This commit is contained in:
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_block_cipher.hpp>
|
||||
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<size_t _KeySize>
|
||||
class AesImpl {
|
||||
public:
|
||||
static constexpr size_t KeySize = _KeySize;
|
||||
static constexpr size_t BlockSize = 16;
|
||||
static constexpr s32 RoundCount = (KeySize / 4) + 6;
|
||||
static constexpr size_t RoundKeySize = BlockSize * (RoundCount + 1);
|
||||
private:
|
||||
#ifdef ATMOSPHERE_IS_EXOSPHERE
|
||||
int m_slot;
|
||||
#endif
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
u32 m_round_keys[RoundKeySize / sizeof(u32)];
|
||||
#endif
|
||||
public:
|
||||
~AesImpl();
|
||||
|
||||
void Initialize(const void *key, size_t key_size, bool is_encrypt);
|
||||
void EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const;
|
||||
void DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const;
|
||||
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
const u8 *GetRoundKey() const {
|
||||
return reinterpret_cast<const u8 *>(m_round_keys);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static_assert(BlockCipher<AesImpl<16>>);
|
||||
static_assert(BlockCipher<AesImpl<24>>);
|
||||
static_assert(BlockCipher<AesImpl<32>>);
|
||||
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_memory_compare.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
class BigNum {
|
||||
NON_COPYABLE(BigNum);
|
||||
NON_MOVEABLE(BigNum);
|
||||
public:
|
||||
using HalfWord = u16;
|
||||
using Word = u32;
|
||||
using DoubleWord = u64;
|
||||
|
||||
static constexpr size_t MaxBits = 4096;
|
||||
static constexpr size_t BitsPerWord = sizeof(Word) * CHAR_BIT;
|
||||
static constexpr Word MaxWord = std::numeric_limits<Word>::max();
|
||||
static constexpr Word MaxHalfWord = std::numeric_limits<HalfWord>::max();
|
||||
|
||||
class WordAllocator {
|
||||
NON_COPYABLE(WordAllocator);
|
||||
NON_MOVEABLE(WordAllocator);
|
||||
public:
|
||||
class Allocation {
|
||||
NON_COPYABLE(Allocation);
|
||||
NON_MOVEABLE(Allocation);
|
||||
private:
|
||||
friend class WordAllocator;
|
||||
private:
|
||||
WordAllocator *m_allocator;
|
||||
Word *m_buffer;
|
||||
size_t m_count;
|
||||
private:
|
||||
constexpr ALWAYS_INLINE Allocation(WordAllocator *a, Word *w, size_t c) : m_allocator(a), m_buffer(w), m_count(c) { /* ... */ }
|
||||
public:
|
||||
ALWAYS_INLINE ~Allocation() { if (m_allocator) { m_allocator->Free(m_buffer, m_count); } }
|
||||
|
||||
constexpr ALWAYS_INLINE Word *GetBuffer() const { return m_buffer; }
|
||||
constexpr ALWAYS_INLINE size_t GetCount() const { return m_count; }
|
||||
constexpr ALWAYS_INLINE bool IsValid() const { return m_buffer != nullptr; }
|
||||
};
|
||||
|
||||
friend class Allocation;
|
||||
private:
|
||||
Word *m_buffer;
|
||||
size_t m_count;
|
||||
size_t m_max_count;
|
||||
size_t m_min_count;
|
||||
private:
|
||||
ALWAYS_INLINE void Free(void *words, size_t num) {
|
||||
m_buffer -= num;
|
||||
m_count += num;
|
||||
|
||||
AMS_ASSERT(words == m_buffer);
|
||||
AMS_UNUSED(words);
|
||||
}
|
||||
public:
|
||||
constexpr ALWAYS_INLINE WordAllocator(Word *buf, size_t c) : m_buffer(buf), m_count(c), m_max_count(c), m_min_count(c) { /* ... */ }
|
||||
|
||||
ALWAYS_INLINE Allocation Allocate(size_t num) {
|
||||
if (num <= m_count) {
|
||||
Word *allocated = m_buffer;
|
||||
|
||||
m_buffer += num;
|
||||
m_count -= num;
|
||||
m_min_count = std::min(m_count, m_min_count);
|
||||
|
||||
return Allocation(this, allocated, num);
|
||||
} else {
|
||||
return Allocation(nullptr, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE size_t GetMaxUsedSize() const {
|
||||
return (m_max_count - m_min_count) * sizeof(Word);
|
||||
}
|
||||
};
|
||||
private:
|
||||
Word *m_words;
|
||||
size_t m_num_words;
|
||||
size_t m_max_words;
|
||||
private:
|
||||
static void ImportImpl(Word *out, size_t out_size, const u8 *src, size_t src_size);
|
||||
static void ExportImpl(u8 *out, size_t out_size, const Word *src, size_t src_size);
|
||||
public:
|
||||
constexpr BigNum() : m_words(), m_num_words(), m_max_words() { /* ... */ }
|
||||
~BigNum() { /* ... */ }
|
||||
|
||||
constexpr void ReserveStatic(Word *buf, size_t capacity) {
|
||||
m_words = buf;
|
||||
m_max_words = capacity;
|
||||
}
|
||||
|
||||
bool Import(const void *src, size_t src_size);
|
||||
void Export(void *dst, size_t dst_size);
|
||||
|
||||
size_t GetSize() const;
|
||||
|
||||
bool IsZero() const {
|
||||
return m_num_words == 0;
|
||||
}
|
||||
|
||||
bool ExpMod(void *dst, const void *src, size_t size, const BigNum &exp, u32 *work_buf, size_t work_buf_size) const;
|
||||
void ClearToZero();
|
||||
void UpdateCount();
|
||||
public:
|
||||
/* Utility. */
|
||||
static bool IsZero(const Word *w, size_t num_words);
|
||||
static int Compare(const Word *lhs, const Word *rhs, size_t num_words);
|
||||
static size_t CountWords(const Word *w, size_t num_words);
|
||||
static size_t CountSignificantBits(Word w);
|
||||
static void ClearToZero(Word *w, size_t num_words);
|
||||
static void SetToWord(Word *w, size_t num_words, Word v);
|
||||
static void Copy(Word *dst, const Word *src, size_t num_words);
|
||||
|
||||
/* Arithmetic. */
|
||||
static bool ExpMod(Word *dst, const Word *src, const Word *exp, size_t exp_num_words, const Word *mod, size_t mod_num_words, WordAllocator *allocator);
|
||||
static bool MultMod(Word *dst, const Word *src, const Word *mult, const Word *mod, size_t num_words, WordAllocator *allocator);
|
||||
static bool Mod(Word *dst, const Word *src, size_t src_words, const Word *mod, size_t mod_words, WordAllocator *allocator);
|
||||
static bool DivMod(Word *quot, Word *rem, const Word *top, size_t top_words, const Word *bot, size_t bot_words, WordAllocator *allocator);
|
||||
static bool Mult(Word *dst, const Word *lhs, const Word *rhs, size_t num_words, WordAllocator *allocator);
|
||||
|
||||
static Word LeftShift(Word *dst, const Word *w, size_t num_words, const size_t shift);
|
||||
static Word RightShift(Word *dst, const Word *w, size_t num_words, const size_t shift);
|
||||
static Word Add(Word *dst, const Word *lhs, const Word *rhs, size_t num_words);
|
||||
static Word Sub(Word *dst, const Word *lhs, const Word *rhs, size_t num_words);
|
||||
static Word MultAdd(Word *dst, const Word *w, size_t num_words, Word mult);
|
||||
static Word MultSub(Word *dst, const Word *w, const Word *v, size_t num_words, Word mult);
|
||||
};
|
||||
|
||||
template<size_t Bits>
|
||||
class StaticBigNum : public BigNum {
|
||||
public:
|
||||
static constexpr size_t NumBits = Bits;
|
||||
static constexpr size_t NumWords = util::AlignUp(NumBits, BitsPerWord) / BitsPerWord;
|
||||
static constexpr size_t NumBytes = NumWords * sizeof(Word);
|
||||
private:
|
||||
Word m_word_buf[NumWords];
|
||||
public:
|
||||
constexpr StaticBigNum() : m_word_buf() {
|
||||
this->ReserveStatic(m_word_buf, NumWords);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_memory_compare.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<typename T>
|
||||
concept BlockCipher = requires(T &t, const void *cv, void *v, size_t sz, bool b) {
|
||||
{ T::BlockSize } -> std::convertible_to<size_t>;
|
||||
{ t.EncryptBlock(v, sz, cv, sz) } -> std::same_as<void>;
|
||||
{ t.DecryptBlock(v, sz, cv, sz) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
#include <vapours/crypto/crypto_aes_encryptor.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
class CbcMacImpl {
|
||||
NON_COPYABLE(CbcMacImpl);
|
||||
NON_MOVEABLE(CbcMacImpl);
|
||||
public:
|
||||
static constexpr size_t BlockSize = 0x10;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_Initialized,
|
||||
State_Done,
|
||||
};
|
||||
private:
|
||||
u8 m_mac[BlockSize];
|
||||
u8 m_buffer[BlockSize];
|
||||
size_t m_buffered_bytes;
|
||||
const void *m_cipher_context;
|
||||
void (*m_cipher_function)(void *dst, const void *src, const void *ctx);
|
||||
State m_state;
|
||||
public:
|
||||
CbcMacImpl() : m_buffered_bytes(0), m_state(State_None) { /* ... */ }
|
||||
|
||||
~CbcMacImpl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
void Initialize(const BlockCipher *block_cipher) {
|
||||
static_assert(BlockCipher::BlockSize == BlockSize);
|
||||
|
||||
/* Set our context. */
|
||||
m_cipher_context = block_cipher;
|
||||
m_cipher_function = &EncryptBlockCallback<BlockCipher>;
|
||||
m_buffered_bytes = 0;
|
||||
|
||||
std::memset(m_mac, 0, sizeof(m_mac));
|
||||
|
||||
m_state = State_Initialized;
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
void Update(const void *data, size_t size) {
|
||||
this->UpdateGeneric(data, size);
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
void ProcessBlocks(const void *data, size_t size) {
|
||||
this->ProcessBlocksGeneric(data, size);
|
||||
}
|
||||
|
||||
size_t GetBlockSize() const {
|
||||
return BlockSize;
|
||||
}
|
||||
|
||||
size_t GetBufferedDataSize() const {
|
||||
return m_buffered_bytes;
|
||||
}
|
||||
|
||||
void UpdateGeneric(const void *data, size_t size);
|
||||
void ProcessBlocksGeneric(const void *data, size_t num_blocks);
|
||||
void ProcessPartialData(const void *data, size_t size);
|
||||
void ProcessRemainingData(const void *data, size_t size);
|
||||
|
||||
void GetMac(void *mac, size_t mac_size);
|
||||
void MaskBufferedData(const void *data, size_t size);
|
||||
private:
|
||||
void ProcessBlock(const void *data);
|
||||
|
||||
template<typename BlockCipher>
|
||||
static void EncryptBlockCallback(void *dst, const void *src, const void *cipher) {
|
||||
static_assert(BlockCipher::BlockSize == BlockSize);
|
||||
static_cast<const BlockCipher *>(cipher)->EncryptBlock(dst, BlockCipher::BlockSize, src, BlockCipher::BlockSize);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
void CbcMacImpl::Update<AesEncryptor128>(const void *data, size_t size);
|
||||
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
#include <vapours/crypto/crypto_aes_encryptor.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<typename BlockCipher>
|
||||
class CbcModeImpl {
|
||||
NON_COPYABLE(CbcModeImpl);
|
||||
NON_MOVEABLE(CbcModeImpl);
|
||||
public:
|
||||
static constexpr size_t KeySize = BlockCipher::KeySize;
|
||||
static constexpr size_t BlockSize = BlockCipher::BlockSize;
|
||||
static constexpr size_t IvSize = BlockCipher::BlockSize;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_Initialized,
|
||||
};
|
||||
private:
|
||||
const BlockCipher *m_block_cipher;
|
||||
u8 m_iv[IvSize];
|
||||
u8 m_buffer[BlockSize];
|
||||
size_t m_buffered_bytes;
|
||||
State m_state;
|
||||
public:
|
||||
CbcModeImpl() : m_state(State_None) { /* ... */ }
|
||||
|
||||
~CbcModeImpl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void Initialize(const BlockCipher *block_cipher, const void *iv, size_t iv_size) {
|
||||
AMS_ASSERT(iv_size == IvSize);
|
||||
AMS_UNUSED(iv_size);
|
||||
|
||||
m_block_cipher = block_cipher;
|
||||
std::memcpy(m_iv, iv, IvSize);
|
||||
m_buffered_bytes = 0;
|
||||
|
||||
m_state = State_Initialized;
|
||||
}
|
||||
|
||||
size_t GetBufferedDataSize() const {
|
||||
return m_buffered_bytes;
|
||||
}
|
||||
|
||||
size_t UpdateEncryption(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
AMS_ASSERT(dst_size >= ((src_size + this->GetBufferedDataSize()) / BlockSize) * BlockSize);
|
||||
AMS_ASSERT(m_state == State_Initialized);
|
||||
|
||||
return this->Update(dst, dst_size, src, src_size, [&] (u8 *d, u8 *i, const u8 *s, size_t n) ALWAYS_INLINE_LAMBDA {
|
||||
this->EncryptBlocks(d, i, s, n);
|
||||
});
|
||||
}
|
||||
|
||||
size_t UpdateDecryption(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
AMS_ASSERT(dst_size >= ((src_size + this->GetBufferedDataSize()) / BlockSize) * BlockSize);
|
||||
AMS_ASSERT(m_state == State_Initialized);
|
||||
|
||||
return this->Update(dst, dst_size, src, src_size, [&] (u8 *d, u8 *i, const u8 *s, size_t n) ALWAYS_INLINE_LAMBDA {
|
||||
this->DecryptBlocks(d, i, s, n);
|
||||
});
|
||||
}
|
||||
private:
|
||||
size_t Update(void *_dst, size_t dst_size, const void *_src, size_t src_size, auto ProcessBlocks) {
|
||||
AMS_UNUSED(dst_size);
|
||||
|
||||
u8 *dst = static_cast<u8 *>(_dst);
|
||||
const u8 *src = static_cast<const u8 *>(_src);
|
||||
size_t remaining = src_size;
|
||||
size_t processed = 0;
|
||||
|
||||
if (m_buffered_bytes > 0) {
|
||||
const size_t copy_size = std::min(BlockSize - m_buffered_bytes, remaining);
|
||||
|
||||
std::memcpy(m_buffer + m_buffered_bytes, src, copy_size);
|
||||
src += copy_size;
|
||||
remaining -= copy_size;
|
||||
m_buffered_bytes += copy_size;
|
||||
|
||||
if (m_buffered_bytes == BlockSize) {
|
||||
ProcessBlocks(dst, m_iv, m_buffer, 1);
|
||||
processed += BlockSize;
|
||||
dst += BlockSize;
|
||||
|
||||
m_buffered_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (remaining >= BlockSize) {
|
||||
const size_t num_blocks = remaining / BlockSize;
|
||||
|
||||
ProcessBlocks(dst, m_iv, src, num_blocks);
|
||||
|
||||
const size_t processed_size = num_blocks * BlockSize;
|
||||
dst += processed_size;
|
||||
src += processed_size;
|
||||
remaining -= processed_size;
|
||||
processed += processed_size;
|
||||
}
|
||||
|
||||
if (remaining > 0) {
|
||||
std::memcpy(m_buffer, src, remaining);
|
||||
m_buffered_bytes = remaining;
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
void EncryptBlocks(u8 *dst, u8 *iv, const u8 *src, size_t num_blocks) {
|
||||
const u8 *cur_iv = iv;
|
||||
|
||||
u8 block[BlockSize];
|
||||
while (num_blocks--) {
|
||||
for (size_t i = 0; i < BlockSize; ++i) {
|
||||
block[i] = src[i] ^ cur_iv[i];
|
||||
}
|
||||
|
||||
m_block_cipher->EncryptBlock(dst, BlockSize, block, BlockSize);
|
||||
|
||||
cur_iv = dst;
|
||||
src += BlockSize;
|
||||
dst += BlockSize;
|
||||
}
|
||||
|
||||
if (iv != cur_iv) {
|
||||
std::memcpy(iv, cur_iv, BlockSize);
|
||||
}
|
||||
}
|
||||
|
||||
void DecryptBlocks(u8 *dst, u8 *iv, const u8 *src, size_t num_blocks) {
|
||||
u8 next_iv[BlockSize];
|
||||
std::memcpy(next_iv, src + ((num_blocks - 1) * BlockSize), BlockSize);
|
||||
|
||||
if (src == dst) {
|
||||
src = src + ((num_blocks - 1) * BlockSize);
|
||||
dst = dst + ((num_blocks - 1) * BlockSize);
|
||||
|
||||
const u8 *cur_iv = (num_blocks == 1) ? iv : src - BlockSize;
|
||||
|
||||
while (num_blocks-- > 1) {
|
||||
m_block_cipher->DecryptBlock(dst, BlockSize, src, BlockSize);
|
||||
|
||||
for (size_t i = 0; i < BlockSize; ++i) {
|
||||
dst[i] ^= cur_iv[i];
|
||||
}
|
||||
|
||||
cur_iv -= BlockSize;
|
||||
src -= BlockSize;
|
||||
dst -= BlockSize;
|
||||
}
|
||||
|
||||
m_block_cipher->DecryptBlock(dst, BlockSize, src, BlockSize);
|
||||
|
||||
for (size_t i = 0; i < BlockSize; ++i) {
|
||||
dst[i] ^= iv[i];
|
||||
}
|
||||
} else {
|
||||
const u8 *cur_iv = iv;
|
||||
|
||||
while (num_blocks-- > 0) {
|
||||
m_block_cipher->DecryptBlock(dst, BlockSize, src, BlockSize);
|
||||
|
||||
for (size_t i = 0; i < BlockSize; ++i) {
|
||||
dst[i] ^= cur_iv[i];
|
||||
}
|
||||
|
||||
cur_iv = src;
|
||||
src += BlockSize;
|
||||
dst += BlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
std::memcpy(iv, next_iv, BlockSize);
|
||||
}
|
||||
};
|
||||
|
||||
/* TODO: Optimized AES cbc impl specializations. */
|
||||
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
#include <vapours/crypto/impl/crypto_ctr_mode_impl.hpp>
|
||||
#include <vapours/crypto/impl/crypto_cbc_mac_impl.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<typename BlockCipher>
|
||||
class CcmModeImpl {
|
||||
NON_COPYABLE(CcmModeImpl);
|
||||
NON_MOVEABLE(CcmModeImpl);
|
||||
public:
|
||||
static constexpr size_t KeySize = BlockCipher::KeySize;
|
||||
static constexpr size_t BlockSize = BlockCipher::BlockSize;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_ProcessingAad,
|
||||
State_ProcessingData,
|
||||
State_DataInputDone,
|
||||
State_Done,
|
||||
};
|
||||
private:
|
||||
u8 m_mac[BlockSize];
|
||||
s64 m_given_data_size;
|
||||
s64 m_given_aad_size;
|
||||
size_t m_given_mac_size;
|
||||
s64 m_processed_data_size;
|
||||
s64 m_processed_aad_size;
|
||||
State m_state;
|
||||
CtrModeImpl<BlockCipher> m_ctr_mode_impl;
|
||||
CbcMacImpl m_cbc_mac_impl;
|
||||
public:
|
||||
CcmModeImpl() : m_state(State_None) { /* ... */ }
|
||||
|
||||
~CcmModeImpl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void Initialize(const BlockCipher *cipher, const void *nonce, size_t nonce_size, s64 aad_size, s64 data_size, size_t mac_size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(7 <= nonce_size && nonce_size <= 13);
|
||||
AMS_ASSERT(4 <= mac_size && mac_size <= 16 && (mac_size % 2) == 0);
|
||||
AMS_ASSERT(aad_size >= 0);
|
||||
AMS_ASSERT(data_size >= 0);
|
||||
if (nonce_size == 7) {
|
||||
AMS_ASSERT(data_size <= std::numeric_limits<s64>::max());
|
||||
} else {
|
||||
AMS_ASSERT(data_size < (INT64_C(1) << ((15 - nonce_size) * 8)));
|
||||
}
|
||||
|
||||
/* Set various size fields. */
|
||||
m_given_aad_size = aad_size;
|
||||
m_given_data_size = data_size;
|
||||
m_given_mac_size = mac_size;
|
||||
m_processed_aad_size = 0;
|
||||
m_processed_data_size = 0;
|
||||
|
||||
/* Make the initial counter. */
|
||||
u8 tmp[BlockSize];
|
||||
MakeInitialCounter(tmp, nonce, nonce_size);
|
||||
|
||||
/* Encrypt the block. */
|
||||
cipher->EncryptBlock(m_mac, BlockSize, tmp, BlockSize);
|
||||
|
||||
/* Initialize our ctr mode impl. */
|
||||
m_ctr_mode_impl.Initialize(cipher, tmp, BlockSize);
|
||||
m_ctr_mode_impl.IncrementCounter();
|
||||
|
||||
/* Make the header block. */
|
||||
MakeHeaderBlock(tmp, nonce, nonce_size, aad_size, data_size, mac_size);
|
||||
|
||||
/* Initialize our cbc mac impl. */
|
||||
m_cbc_mac_impl.Initialize(cipher);
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(tmp, BlockSize);
|
||||
|
||||
/* Process aad size block. */
|
||||
if (aad_size > 0) {
|
||||
this->ProcessEncodedAadSize();
|
||||
m_state = State_ProcessingAad;
|
||||
} else {
|
||||
m_state = State_ProcessingData;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAad(const void *aad, size_t aad_size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_state == State_ProcessingAad);
|
||||
AMS_ASSERT(m_processed_aad_size + static_cast<s64>(aad_size) <= m_given_aad_size);
|
||||
|
||||
/* Update on the aad. */
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(aad, aad_size);
|
||||
m_processed_aad_size += aad_size;
|
||||
|
||||
/* Check if we're done with aad. */
|
||||
if (m_processed_aad_size == m_given_aad_size) {
|
||||
/* Pad the aad to block size. */
|
||||
this->ProcessPadding();
|
||||
|
||||
/* Update our state. */
|
||||
if (m_given_data_size > 0) {
|
||||
m_state = State_ProcessingData;
|
||||
} else {
|
||||
m_state = State_DataInputDone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t UpdateEncryption(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_state == State_ProcessingData);
|
||||
AMS_ASSERT(m_processed_data_size + static_cast<s64>(src_size) <= m_given_data_size);
|
||||
AMS_ASSERT(dst_size >= src_size);
|
||||
|
||||
/* Update mac on decrypted data. */
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(src, src_size);
|
||||
|
||||
/* Encrypt. */
|
||||
const size_t processed = m_ctr_mode_impl.Update(dst, dst_size, src, src_size);
|
||||
m_processed_data_size += src_size;
|
||||
|
||||
/* Check if we're done with data. */
|
||||
if (m_processed_data_size == m_given_data_size) {
|
||||
/* Pad the data to block size. */
|
||||
this->ProcessPadding();
|
||||
|
||||
m_state = State_DataInputDone;
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
size_t UpdateDecryption(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_state == State_ProcessingData);
|
||||
AMS_ASSERT(m_processed_data_size + static_cast<s64>(src_size) <= m_given_data_size);
|
||||
AMS_ASSERT(dst_size >= src_size);
|
||||
|
||||
/* Decrypt. */
|
||||
const size_t processed = m_ctr_mode_impl.Update(dst, dst_size, src, src_size);
|
||||
m_processed_data_size += src_size;
|
||||
|
||||
/* Update mac on decrypted data. */
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(dst, dst_size);
|
||||
|
||||
/* Check if we're done with data. */
|
||||
if (m_processed_data_size == m_given_data_size) {
|
||||
/* Pad the data to block size. */
|
||||
this->ProcessPadding();
|
||||
|
||||
m_state = State_DataInputDone;
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
void GetMac(void *mac, size_t mac_size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_state == State_DataInputDone || m_state == State_Done);
|
||||
AMS_ASSERT(mac_size >= m_given_mac_size);
|
||||
AMS_UNUSED(mac_size);
|
||||
|
||||
/* Generate the mac, if we haven't already. */
|
||||
if (m_state == State_DataInputDone) {
|
||||
this->GenerateMac();
|
||||
m_state = State_Done;
|
||||
}
|
||||
|
||||
/* Copy out the mac. */
|
||||
std::memcpy(mac, m_mac, m_given_mac_size);
|
||||
}
|
||||
private:
|
||||
void MakeInitialCounter(void *dst, const void *nonce, size_t nonce_size) {
|
||||
/* Clear the counter. */
|
||||
u8 *ctr = static_cast<u8 *>(dst);
|
||||
std::memset(ctr, 0, BlockSize);
|
||||
|
||||
/* Set the nonce. */
|
||||
ctr[0] = (((BlockSize - 1 - nonce_size) & 0xFF) - 1) & 0x07;
|
||||
std::memcpy(ctr + 1, nonce, nonce_size);
|
||||
}
|
||||
|
||||
void MakeHeaderBlock(void *dst, const void *nonce, size_t nonce_size, s64 aad_size, s64 data_size, size_t mac_size) {
|
||||
/* Clear the block. */
|
||||
u8 *hdr = static_cast<u8 *>(dst);
|
||||
std::memset(hdr, 0, BlockSize);
|
||||
|
||||
/* Encode the flags. */
|
||||
hdr[0] = (((BlockSize - 1 - nonce_size) & 0xFF) - 1) & 0x07;
|
||||
hdr[0] |= (((mac_size - 2) / 2) & 0x07) << 3;
|
||||
hdr[0] |= (aad_size > 0) ? 0x40 : 0x00;
|
||||
|
||||
/* Encode the data size. */
|
||||
for (size_t i = 0; i < sizeof(s64); ++i) {
|
||||
hdr[BlockSize - 1 - i] = static_cast<u64>(data_size) >> (BITSIZEOF(u8) * i);
|
||||
}
|
||||
|
||||
/* Copy the nonce. */
|
||||
std::memcpy(hdr + 1, nonce, nonce_size);
|
||||
}
|
||||
|
||||
void ProcessEncodedAadSize() {
|
||||
u8 encoded_aad[10];
|
||||
size_t encoded_aad_size;
|
||||
|
||||
if (m_given_aad_size < ((1 << 16) - (1 << 8))) {
|
||||
encoded_aad[0] = (m_given_aad_size >> (BITSIZEOF(u8) * 1)) & 0xFF;
|
||||
encoded_aad[1] = (m_given_aad_size >> (BITSIZEOF(u8) * 0)) & 0xFF;
|
||||
encoded_aad_size = 2;
|
||||
} else if (m_given_aad_size <= 0xFFFFFFFFu) {
|
||||
encoded_aad[0] = 0xFF;
|
||||
encoded_aad[1] = 0xFE;
|
||||
encoded_aad[2] = (m_given_aad_size >> (BITSIZEOF(u8) * 3)) & 0xFF;
|
||||
encoded_aad[3] = (m_given_aad_size >> (BITSIZEOF(u8) * 2)) & 0xFF;
|
||||
encoded_aad[4] = (m_given_aad_size >> (BITSIZEOF(u8) * 1)) & 0xFF;
|
||||
encoded_aad[5] = (m_given_aad_size >> (BITSIZEOF(u8) * 0)) & 0xFF;
|
||||
encoded_aad_size = 6;
|
||||
} else {
|
||||
encoded_aad[0] = 0xFF;
|
||||
encoded_aad[1] = 0xFE;
|
||||
encoded_aad[2] = (static_cast<u64>(m_given_aad_size) >> (BITSIZEOF(u8) * 7)) & 0xFF;
|
||||
encoded_aad[3] = (static_cast<u64>(m_given_aad_size) >> (BITSIZEOF(u8) * 6)) & 0xFF;
|
||||
encoded_aad[4] = (static_cast<u64>(m_given_aad_size) >> (BITSIZEOF(u8) * 5)) & 0xFF;
|
||||
encoded_aad[5] = (static_cast<u64>(m_given_aad_size) >> (BITSIZEOF(u8) * 4)) & 0xFF;
|
||||
encoded_aad[6] = (static_cast<u64>(m_given_aad_size) >> (BITSIZEOF(u8) * 3)) & 0xFF;
|
||||
encoded_aad[7] = (static_cast<u64>(m_given_aad_size) >> (BITSIZEOF(u8) * 2)) & 0xFF;
|
||||
encoded_aad[8] = (static_cast<u64>(m_given_aad_size) >> (BITSIZEOF(u8) * 1)) & 0xFF;
|
||||
encoded_aad[9] = (static_cast<u64>(m_given_aad_size) >> (BITSIZEOF(u8) * 0)) & 0xFF;
|
||||
encoded_aad_size = 10;
|
||||
}
|
||||
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(encoded_aad, encoded_aad_size);
|
||||
}
|
||||
|
||||
void ProcessPadding() {
|
||||
/* Process any remaining padding. */
|
||||
if (const auto buffered = m_cbc_mac_impl.GetBufferedDataSize(); buffered > 0) {
|
||||
u8 zeros[BlockSize] = {};
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(zeros, BlockSize - buffered);
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateMac() {
|
||||
/* Get the cbc mac. */
|
||||
u8 tmp[BlockSize];
|
||||
m_cbc_mac_impl.GetMac(tmp, BlockSize);
|
||||
|
||||
/* Xor into our mac. */
|
||||
for (size_t i = 0; i < BlockSize; ++i) {
|
||||
m_mac[i] ^= tmp[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
#include <vapours/crypto/impl/crypto_cbc_mac_impl.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<typename BlockCipher>
|
||||
class CmacImpl {
|
||||
NON_COPYABLE(CmacImpl);
|
||||
NON_MOVEABLE(CmacImpl);
|
||||
public:
|
||||
static constexpr size_t BlockSize = BlockCipher::BlockSize;
|
||||
static constexpr size_t MacSize = BlockSize;
|
||||
static_assert(BlockSize == 0x10); /* TODO: Should this be supported? */
|
||||
private:
|
||||
enum State {
|
||||
State_None = 0,
|
||||
State_Initialized = 1,
|
||||
State_Done = 2,
|
||||
};
|
||||
private:
|
||||
CbcMacImpl m_cbc_mac_impl;
|
||||
u8 m_sub_key[BlockSize];
|
||||
State m_state;
|
||||
public:
|
||||
CmacImpl() : m_state(State_None) { /* ... */ }
|
||||
~CmacImpl() {
|
||||
/* Clear everything. */
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void Initialize(const BlockCipher *cipher);
|
||||
void Update(const void *data, size_t data_size);
|
||||
void GetMac(void *dst, size_t dst_size);
|
||||
private:
|
||||
static void MultiplyOneOverGF128(u8 *data) {
|
||||
/* Determine the carry bit. */
|
||||
const u8 carry = data[0] & 0x80;
|
||||
|
||||
/* Shift all bytes by one bit. */
|
||||
for (size_t i = 0; i < BlockSize - 1; ++i) {
|
||||
data[i] = (data[i] << 1) | (data[i + 1] >> 7);
|
||||
}
|
||||
data[BlockSize - 1] <<= 1;
|
||||
|
||||
/* Adjust based on carry. */
|
||||
if (carry) {
|
||||
data[BlockSize - 1] ^= 0x87;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename BlockCipher>
|
||||
inline void CmacImpl<BlockCipher>::Initialize(const BlockCipher *cipher) {
|
||||
/* Clear the key storage. */
|
||||
std::memset(m_sub_key, 0, sizeof(m_sub_key));
|
||||
|
||||
/* Set the key storage. */
|
||||
cipher->EncryptBlock(m_sub_key, BlockSize, m_sub_key, BlockSize);
|
||||
MultiplyOneOverGF128(m_sub_key);
|
||||
|
||||
/* Initialize the cbc-mac impl. */
|
||||
m_cbc_mac_impl.Initialize(cipher);
|
||||
|
||||
/* Mark initialized. */
|
||||
m_state = State_Initialized;
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
inline void CmacImpl<BlockCipher>::Update(const void *data, size_t data_size) {
|
||||
AMS_ASSERT(m_state == State_Initialized);
|
||||
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(data, data_size);
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
inline void CmacImpl<BlockCipher>::GetMac(void *dst, size_t dst_size) {
|
||||
AMS_ASSERT(m_state == State_Initialized || m_state == State_Done);
|
||||
AMS_ASSERT(dst_size >= MacSize);
|
||||
AMS_UNUSED(dst_size);
|
||||
|
||||
/* If we're not already finalized, get the final mac. */
|
||||
if (m_state == State_Initialized) {
|
||||
/* Process padding as needed. */
|
||||
if (m_cbc_mac_impl.GetBufferedDataSize() != BlockSize) {
|
||||
/* Determine the remaining size. */
|
||||
const size_t remaining = BlockSize - m_cbc_mac_impl.GetBufferedDataSize();
|
||||
|
||||
/* Update with padding. */
|
||||
static constexpr u8 s_padding[BlockSize] = { 0x80, /* ... */ };
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(s_padding, remaining);
|
||||
|
||||
/* Update our subkey. */
|
||||
MultiplyOneOverGF128(m_sub_key);
|
||||
}
|
||||
|
||||
/* Mask the subkey. */
|
||||
m_cbc_mac_impl.MaskBufferedData(m_sub_key, BlockSize);
|
||||
|
||||
/* Set our state as done. */
|
||||
m_state = State_Done;
|
||||
}
|
||||
|
||||
/* Get the mac. */
|
||||
m_cbc_mac_impl.GetMac(dst, dst_size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
#include <vapours/crypto/crypto_aes_encryptor.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<typename BlockCipher>
|
||||
class CtrModeImpl {
|
||||
NON_COPYABLE(CtrModeImpl);
|
||||
NON_MOVEABLE(CtrModeImpl);
|
||||
public:
|
||||
static constexpr size_t KeySize = BlockCipher::KeySize;
|
||||
static constexpr size_t BlockSize = BlockCipher::BlockSize;
|
||||
static constexpr size_t IvSize = BlockCipher::BlockSize;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_Initialized,
|
||||
};
|
||||
private:
|
||||
const BlockCipher *m_block_cipher;
|
||||
u8 m_counter[IvSize];
|
||||
u8 m_encrypted_counter[BlockSize];
|
||||
size_t m_buffer_offset;
|
||||
State m_state;
|
||||
public:
|
||||
CtrModeImpl() : m_state(State_None) { /* ... */ }
|
||||
|
||||
~CtrModeImpl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void Initialize(const BlockCipher *block_cipher, const void *iv, size_t iv_size) {
|
||||
this->Initialize(block_cipher, iv, iv_size, 0);
|
||||
}
|
||||
|
||||
void Initialize(const BlockCipher *block_cipher, const void *iv, size_t iv_size, s64 offset) {
|
||||
AMS_ASSERT(iv_size == IvSize);
|
||||
AMS_ASSERT(offset >= 0);
|
||||
|
||||
m_block_cipher = block_cipher;
|
||||
m_state = State_Initialized;
|
||||
|
||||
this->SwitchMessage(iv, iv_size);
|
||||
|
||||
if (offset >= 0) {
|
||||
u64 ctr_offset = offset / BlockSize;
|
||||
if (ctr_offset > 0) {
|
||||
this->IncrementCounter(ctr_offset);
|
||||
}
|
||||
|
||||
if (size_t remaining = static_cast<size_t>(offset % BlockSize); remaining != 0) {
|
||||
m_block_cipher->EncryptBlock(m_encrypted_counter, sizeof(m_encrypted_counter), m_counter, sizeof(m_counter));
|
||||
this->IncrementCounter();
|
||||
|
||||
m_buffer_offset = remaining;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchMessage(const void *iv, size_t iv_size) {
|
||||
AMS_ASSERT(m_state == State_Initialized);
|
||||
AMS_ASSERT(iv_size == IvSize);
|
||||
|
||||
std::memcpy(m_counter, iv, iv_size);
|
||||
m_buffer_offset = 0;
|
||||
}
|
||||
|
||||
void IncrementCounter() {
|
||||
for (s32 i = IvSize - 1; i >= 0; --i) {
|
||||
if (++m_counter[i] != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Update(void *_dst, size_t dst_size, const void *_src, size_t src_size) {
|
||||
AMS_ASSERT(m_state == State_Initialized);
|
||||
AMS_ASSERT(dst_size >= src_size);
|
||||
AMS_UNUSED(dst_size);
|
||||
|
||||
u8 *dst = static_cast<u8 *>(_dst);
|
||||
const u8 *src = static_cast<const u8 *>(_src);
|
||||
size_t remaining = src_size;
|
||||
|
||||
if (m_buffer_offset > 0) {
|
||||
const size_t xor_size = std::min(BlockSize - m_buffer_offset, remaining);
|
||||
|
||||
const u8 *ctr = m_encrypted_counter + m_buffer_offset;
|
||||
for (size_t i = 0; i < xor_size; i++) {
|
||||
dst[i] = src[i] ^ ctr[i];
|
||||
}
|
||||
|
||||
src += xor_size;
|
||||
dst += xor_size;
|
||||
remaining -= xor_size;
|
||||
m_buffer_offset += xor_size;
|
||||
|
||||
if (m_buffer_offset == BlockSize) {
|
||||
m_buffer_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (remaining >= BlockSize) {
|
||||
const size_t num_blocks = remaining / BlockSize;
|
||||
|
||||
this->ProcessBlocks(dst, src, num_blocks);
|
||||
|
||||
const size_t processed_size = num_blocks * BlockSize;
|
||||
dst += processed_size;
|
||||
src += processed_size;
|
||||
remaining -= processed_size;
|
||||
}
|
||||
|
||||
if (remaining > 0) {
|
||||
this->ProcessBlock(dst, src, remaining);
|
||||
m_buffer_offset = remaining;
|
||||
}
|
||||
|
||||
return src_size;
|
||||
}
|
||||
private:
|
||||
void IncrementCounter(u64 count) {
|
||||
u64 _block[IvSize / sizeof(u64)] = {};
|
||||
util::StoreBigEndian(std::addressof(_block[(IvSize / sizeof(u64)) - 1]), count);
|
||||
|
||||
u16 acc = 0;
|
||||
const u8 *block = reinterpret_cast<const u8 *>(_block);
|
||||
for (s32 i = IvSize - 1; i >= 0; --i) {
|
||||
acc += (m_counter[i] + block[i]);
|
||||
m_counter[i] = acc & 0xFF;
|
||||
acc >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessBlock(u8 *dst, const u8 *src, size_t src_size) {
|
||||
m_block_cipher->EncryptBlock(m_encrypted_counter, BlockSize, m_counter, IvSize);
|
||||
this->IncrementCounter();
|
||||
|
||||
for (size_t i = 0; i < src_size; i++) {
|
||||
dst[i] = src[i] ^ m_encrypted_counter[i];
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks);
|
||||
};
|
||||
|
||||
template<typename BlockCipher>
|
||||
inline void CtrModeImpl<BlockCipher>::ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks) {
|
||||
while (num_blocks--) {
|
||||
this->ProcessBlock(dst, src, BlockSize);
|
||||
dst += BlockSize;
|
||||
src += BlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
template<> void CtrModeImpl<AesEncryptor128>::ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks);
|
||||
|
||||
/* TODO: Optimized x64 CTR-192/256? */
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
template<> void CtrModeImpl<AesEncryptor192>::ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks);
|
||||
template<> void CtrModeImpl<AesEncryptor256>::ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
#include <vapours/crypto/crypto_aes_encryptor.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<typename BlockCipher>
|
||||
class GcmModeImpl {
|
||||
NON_COPYABLE(GcmModeImpl);
|
||||
NON_MOVEABLE(GcmModeImpl);
|
||||
public:
|
||||
static constexpr size_t KeySize = BlockCipher::KeySize;
|
||||
static constexpr size_t BlockSize = BlockCipher::BlockSize;
|
||||
static constexpr size_t MacSize = BlockCipher::BlockSize;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_Initialized,
|
||||
State_ProcessingAad,
|
||||
State_Encrypting,
|
||||
State_Decrypting,
|
||||
State_Done,
|
||||
};
|
||||
|
||||
struct Block128 {
|
||||
u64 hi;
|
||||
u64 lo;
|
||||
|
||||
ALWAYS_INLINE void Clear() {
|
||||
this->hi = 0;
|
||||
this->lo = 0;
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<Block128>::value);
|
||||
static_assert(sizeof(Block128) == 0x10);
|
||||
|
||||
union Block {
|
||||
Block128 block_128;
|
||||
u32 block_32[4];
|
||||
u8 block_8[16];
|
||||
};
|
||||
static_assert(util::is_pod<Block>::value);
|
||||
static_assert(sizeof(Block) == 0x10);
|
||||
|
||||
using CipherFunction = void (*)(void *dst_block, const void *src_block, const void *ctx);
|
||||
private:
|
||||
State m_state;
|
||||
const BlockCipher *m_block_cipher;
|
||||
CipherFunction m_cipher_func;
|
||||
u8 m_pad[sizeof(u64)];
|
||||
Block m_block_x;
|
||||
Block m_block_y;
|
||||
Block m_block_ek;
|
||||
Block m_block_ek0;
|
||||
Block m_block_tmp;
|
||||
size_t m_aad_size;
|
||||
size_t m_msg_size;
|
||||
u32 m_aad_remaining;
|
||||
u32 m_msg_remaining;
|
||||
u32 m_counter;
|
||||
Block m_h_mult_blocks[16];
|
||||
public:
|
||||
GcmModeImpl() : m_state(State_None) { /* ... */ }
|
||||
|
||||
~GcmModeImpl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void Initialize(const BlockCipher *block_cipher);
|
||||
|
||||
void Reset(const void *iv, size_t iv_size);
|
||||
|
||||
void UpdateAad(const void *aad, size_t aad_size);
|
||||
size_t UpdateEncrypt(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
size_t UpdateDecrypt(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
void GetMac(void *dst, size_t dst_size);
|
||||
private:
|
||||
static void ProcessBlock(void *dst_block, const void *src_block, const void *ctx) {
|
||||
static_cast<const BlockCipher *>(ctx)->EncryptBlock(dst_block, BlockSize, src_block, BlockSize);
|
||||
}
|
||||
|
||||
void InitializeHashKey();
|
||||
void ComputeMac(bool encrypt);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_memory_compare.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<typename T>
|
||||
concept HashFunction = requires(T &t, const void *cv, void *v, size_t sz) {
|
||||
{ T::HashSize } -> std::convertible_to<size_t>;
|
||||
{ T::BlockSize } -> std::convertible_to<size_t>;
|
||||
{ t.Initialize() } -> std::same_as<void>;
|
||||
{ t.Update(cv, sz) } -> std::same_as<void>;
|
||||
{ t.GetHash(v, sz) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<HashFunction Hash>
|
||||
class HmacImpl {
|
||||
NON_COPYABLE(HmacImpl);
|
||||
NON_MOVEABLE(HmacImpl);
|
||||
public:
|
||||
static constexpr size_t MacSize = Hash::HashSize;
|
||||
static constexpr size_t BlockSize = Hash::BlockSize;
|
||||
private:
|
||||
static constexpr u32 IpadMagic = 0x36363636;
|
||||
static constexpr u32 OpadMagic = 0x5c5c5c5c;
|
||||
|
||||
static constexpr u32 IpadMagicXorOpadMagic = IpadMagic ^ OpadMagic;
|
||||
static_assert(IpadMagicXorOpadMagic == 0x6a6a6a6a);
|
||||
private:
|
||||
enum State {
|
||||
State_None = 0,
|
||||
State_Initialized = 1,
|
||||
State_Done = 2,
|
||||
};
|
||||
private:
|
||||
Hash m_hash_function;
|
||||
u32 m_key[BlockSize / sizeof(u32)];
|
||||
u32 m_mac[MacSize / sizeof(u32)];
|
||||
State m_state;
|
||||
public:
|
||||
HmacImpl() : m_state(State_None) { /* ... */ }
|
||||
~HmacImpl() {
|
||||
static_assert(AMS_OFFSETOF(HmacImpl, m_hash_function) == 0);
|
||||
|
||||
/* Clear everything except for the hash function. */
|
||||
ClearMemory(reinterpret_cast<u8 *>(this) + sizeof(m_hash_function), sizeof(*this) - sizeof(m_hash_function));
|
||||
}
|
||||
|
||||
void Initialize(const void *key, size_t key_size);
|
||||
void Update(const void *data, size_t data_size);
|
||||
void GetMac(void *dst, size_t dst_size);
|
||||
};
|
||||
|
||||
template<HashFunction Hash>
|
||||
inline void HmacImpl<Hash>::Initialize(const void *key, size_t key_size) {
|
||||
/* Clear the key storage. */
|
||||
std::memset(m_key, 0, sizeof(m_key));
|
||||
|
||||
/* Set the key storage. */
|
||||
if (key_size > BlockSize) {
|
||||
m_hash_function.Initialize();
|
||||
m_hash_function.Update(key, key_size);
|
||||
m_hash_function.GetHash(m_key, m_hash_function.HashSize);
|
||||
} else {
|
||||
std::memcpy(m_key, key, key_size);
|
||||
}
|
||||
|
||||
/* Xor the key with the ipad. */
|
||||
for (size_t i = 0; i < util::size(m_key); i++) {
|
||||
m_key[i] ^= IpadMagic;
|
||||
}
|
||||
|
||||
/* Update the hash function with the xor'd key. */
|
||||
m_hash_function.Initialize();
|
||||
m_hash_function.Update(m_key, BlockSize);
|
||||
|
||||
/* Mark initialized. */
|
||||
m_state = State_Initialized;
|
||||
}
|
||||
|
||||
template<HashFunction Hash>
|
||||
inline void HmacImpl<Hash>::Update(const void *data, size_t data_size) {
|
||||
AMS_ASSERT(m_state == State_Initialized);
|
||||
|
||||
m_hash_function.Update(data, data_size);
|
||||
}
|
||||
|
||||
template<HashFunction Hash>
|
||||
inline void HmacImpl<Hash>::GetMac(void *dst, size_t dst_size) {
|
||||
AMS_ASSERT(m_state == State_Initialized || m_state == State_Done);
|
||||
AMS_ASSERT(dst_size >= MacSize);
|
||||
AMS_UNUSED(dst_size);
|
||||
|
||||
/* If we're not already finalized, get the final mac. */
|
||||
if (m_state == State_Initialized) {
|
||||
/* Get the hash of ((key ^ ipad) || data). */
|
||||
m_hash_function.GetHash(m_mac, MacSize);
|
||||
|
||||
/* Xor the key with the opad. */
|
||||
for (size_t i = 0; i < util::size(m_key); i++) {
|
||||
m_key[i] ^= IpadMagicXorOpadMagic;
|
||||
}
|
||||
|
||||
/* Calculate the final mac as hash of ((key ^ opad) || hash((key ^ ipad) || data)) */
|
||||
m_hash_function.Initialize();
|
||||
m_hash_function.Update(m_key, BlockSize);
|
||||
m_hash_function.Update(m_mac, MacSize);
|
||||
m_hash_function.GetHash(m_mac, MacSize);
|
||||
|
||||
/* Set our state as done. */
|
||||
m_state = State_Done;
|
||||
}
|
||||
|
||||
std::memcpy(dst, m_mac, MacSize);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
class Md5Impl {
|
||||
public:
|
||||
static constexpr size_t HashSize = 0x10;
|
||||
static constexpr size_t BlockSize = 0x40;
|
||||
private:
|
||||
enum State {
|
||||
State_None = 0,
|
||||
State_Initialized = 1,
|
||||
State_Done = 2,
|
||||
};
|
||||
private:
|
||||
union {
|
||||
struct {
|
||||
u32 a, b, c, d;
|
||||
} p;
|
||||
u32 state[4];
|
||||
} m_x;
|
||||
alignas(8) u8 m_y[BlockSize];
|
||||
size_t m_size;
|
||||
State m_state;
|
||||
public:
|
||||
Md5Impl() : m_state(State_None) { /* ... */ }
|
||||
~Md5Impl() { ClearMemory(this, sizeof(*this)); }
|
||||
|
||||
void Initialize();
|
||||
void Update(const void *data, size_t size);
|
||||
void GetHash(void *dst, size_t size);
|
||||
private:
|
||||
void ProcessBlock();
|
||||
void ProcessLastBlock();
|
||||
};
|
||||
|
||||
static_assert(HashFunction<Md5Impl>);
|
||||
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<HashFunction Hash>
|
||||
class RsaOaepImpl {
|
||||
NON_COPYABLE(RsaOaepImpl);
|
||||
NON_MOVEABLE(RsaOaepImpl);
|
||||
public:
|
||||
static constexpr size_t HashSize = Hash::HashSize;
|
||||
private:
|
||||
static constexpr u8 HeadMagic = 0x00;
|
||||
private:
|
||||
static void ComputeHashWithPadding(void *dst, Hash *hash, const void *salt, size_t salt_size) {
|
||||
/* Initialize our buffer. */
|
||||
u8 buf[8 + HashSize];
|
||||
std::memset(buf, 0, 8);
|
||||
hash->GetHash(buf + 8, HashSize);
|
||||
ON_SCOPE_EXIT { ClearMemory(buf, sizeof(buf)); };
|
||||
|
||||
|
||||
/* Calculate our hash. */
|
||||
hash->Initialize();
|
||||
hash->Update(buf, sizeof(buf));
|
||||
hash->Update(salt, salt_size);
|
||||
hash->GetHash(dst, HashSize);
|
||||
}
|
||||
|
||||
static void ApplyMGF1(u8 *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
u8 buf[HashSize];
|
||||
ON_SCOPE_EXIT { ClearMemory(buf, sizeof(buf)); };
|
||||
|
||||
const size_t required_iters = (dst_size + HashSize - 1) / HashSize;
|
||||
for (size_t i = 0; i < required_iters; i++) {
|
||||
Hash hash;
|
||||
hash.Initialize();
|
||||
hash.Update(src, src_size);
|
||||
|
||||
const u32 tmp = util::ConvertToBigEndian(static_cast<u32>(i));
|
||||
hash.Update(std::addressof(tmp), sizeof(tmp));
|
||||
|
||||
hash.GetHash(buf, HashSize);
|
||||
|
||||
const size_t start = HashSize * i;
|
||||
const size_t end = std::min(dst_size, start + HashSize);
|
||||
for (size_t j = start; j < end; j++) {
|
||||
dst[j] ^= buf[j - start];
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
RsaOaepImpl() { /* ... */ }
|
||||
|
||||
void Encode(void *dst, size_t dst_size, Hash *hash, const void *src, size_t src_size, const void *salt, size_t salt_size) {
|
||||
u8 label_digest[HashSize];
|
||||
ON_SCOPE_EXIT { ClearMemory(label_digest, HashSize); };
|
||||
|
||||
hash->GetHash(label_digest, HashSize);
|
||||
return this->Encode(dst, dst_size, label_digest, sizeof(label_digest), src, src_size, salt, salt_size);
|
||||
}
|
||||
|
||||
void Encode(void *dst, size_t dst_size, const void *label_digest, size_t label_digest_size, const void *src, size_t src_size, const void *salt, size_t salt_size) {
|
||||
/* Check our preconditions. */
|
||||
AMS_ASSERT(dst_size >= 2 * HashSize + 2 + src_size);
|
||||
AMS_ASSERT(salt_size > 0);
|
||||
AMS_ASSERT(salt_size == HashSize);
|
||||
AMS_ASSERT(label_digest_size == HashSize);
|
||||
AMS_UNUSED(salt_size, label_digest_size);
|
||||
|
||||
u8 *buf = static_cast<u8 *>(dst);
|
||||
buf[0] = HeadMagic;
|
||||
|
||||
u8 *seed = buf + 1;
|
||||
std::memcpy(seed, salt, HashSize);
|
||||
|
||||
u8 *db = seed + HashSize;
|
||||
std::memcpy(db, label_digest, HashSize);
|
||||
std::memset(db + HashSize, 0, dst_size - 2 * HashSize - 2 - src_size);
|
||||
|
||||
u8 *msg = buf + dst_size - src_size - 1;
|
||||
*(msg++) = 0x01;
|
||||
std::memcpy(msg, src, src_size);
|
||||
|
||||
ApplyMGF1(db, dst_size - (1 + HashSize), seed, HashSize);
|
||||
ApplyMGF1(seed, HashSize, db, dst_size - (1 + HashSize));
|
||||
}
|
||||
|
||||
size_t Decode(void *dst, size_t dst_size, const void *label_digest, size_t label_digest_size, u8 *buf, size_t buf_size) {
|
||||
/* Check our preconditions. */
|
||||
AMS_ABORT_UNLESS(dst_size > 0);
|
||||
AMS_ABORT_UNLESS(buf_size >= 2 * HashSize + 3);
|
||||
AMS_ABORT_UNLESS(label_digest_size == HashSize);
|
||||
AMS_UNUSED(label_digest_size);
|
||||
|
||||
/* Validate sanity byte. */
|
||||
bool is_valid = buf[0] == HeadMagic;
|
||||
|
||||
/* Decrypt seed and masked db. */
|
||||
size_t db_len = buf_size - HashSize - 1;
|
||||
u8 *seed = buf + 1;
|
||||
u8 *db = seed + HashSize;
|
||||
ApplyMGF1(seed, HashSize, db, db_len);
|
||||
ApplyMGF1(db, db_len, seed, HashSize);
|
||||
|
||||
/* Check the label digest. */
|
||||
is_valid &= IsSameBytes(label_digest, db, HashSize);
|
||||
|
||||
/* Skip past the label digest. */
|
||||
db += HashSize;
|
||||
db_len -= HashSize;
|
||||
|
||||
/* Verify that DB is of the form 0000...0001 < message > */
|
||||
s32 msg_ofs = 0;
|
||||
{
|
||||
int looking_for_one = 1;
|
||||
int invalid_db_padding = 0;
|
||||
int is_zero;
|
||||
int is_one;
|
||||
for (size_t i = 0; i < db_len; /* ... */) {
|
||||
is_zero = (db[i] == 0);
|
||||
is_one = (db[i] == 1);
|
||||
msg_ofs += (looking_for_one & is_one) * (static_cast<s32>(++i));
|
||||
looking_for_one &= ~is_one;
|
||||
invalid_db_padding |= (looking_for_one & ~is_zero);
|
||||
}
|
||||
|
||||
is_valid &= (invalid_db_padding == 0);
|
||||
}
|
||||
|
||||
/* If we're invalid, return zero size. */
|
||||
const size_t valid_msg_size = db_len - msg_ofs;
|
||||
const size_t msg_size = std::min(dst_size, static_cast<size_t>(is_valid) * valid_msg_size);
|
||||
|
||||
/* Copy to output. */
|
||||
std::memcpy(dst, db + msg_ofs, msg_size);
|
||||
|
||||
/* Return copied size. */
|
||||
return msg_size;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<HashFunction Hash>
|
||||
class RsaPkcs1Impl {
|
||||
NON_COPYABLE(RsaPkcs1Impl);
|
||||
NON_MOVEABLE(RsaPkcs1Impl);
|
||||
public:
|
||||
static constexpr size_t HashSize = Hash::HashSize;
|
||||
public:
|
||||
RsaPkcs1Impl() { /* ... */ }
|
||||
~RsaPkcs1Impl() { /* ... */ }
|
||||
|
||||
void BuildPad(void *out_block, size_t block_size, Hash *hash) {
|
||||
AMS_ASSERT(block_size >= 2 + 1 + sizeof(Hash::Asn1Identifier) + HashSize);
|
||||
|
||||
u8 *dst = static_cast<u8 *>(out_block);
|
||||
*(dst++) = 0x00;
|
||||
*(dst++) = 0x01;
|
||||
|
||||
const size_t pad_len = block_size - (2 + 1 + sizeof(Hash::Asn1Identifier) + HashSize);
|
||||
std::memset(dst, 0xFF, pad_len);
|
||||
dst += pad_len;
|
||||
|
||||
*(dst++) = 0x00;
|
||||
|
||||
std::memcpy(dst, Hash::Asn1Identifier, sizeof(Hash::Asn1Identifier));
|
||||
dst += sizeof(Hash::Asn1Identifier);
|
||||
|
||||
hash->GetHash(dst, HashSize);
|
||||
}
|
||||
|
||||
bool CheckPad(const u8 *src, size_t block_size, Hash *hash) {
|
||||
/* Check that block size is minimally big enough. */
|
||||
if (block_size < 2 + 1 + sizeof(Hash::Asn1Identifier) + HashSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check that the padding if correctly of form 0001FF..FF00 */
|
||||
if (*(src++) != 0x00) {
|
||||
return false;
|
||||
}
|
||||
if (*(src++) != 0x01) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t pad_len = block_size - (2 + 1 + sizeof(Hash::Asn1Identifier) + HashSize);
|
||||
for (size_t i = 0; i < pad_len; ++i) {
|
||||
if (*(src++) != 0xFF) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (*(src++) != 0x00) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check that the asn1 identifier matches. */
|
||||
if (std::memcmp(src, Hash::Asn1Identifier, sizeof(Hash::Asn1Identifier)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
src += sizeof(Hash::Asn1Identifier);
|
||||
|
||||
/* Check the hash. */
|
||||
u8 calc_hash[HashSize];
|
||||
hash->GetHash(calc_hash, sizeof(calc_hash));
|
||||
|
||||
return std::memcmp(calc_hash, src, HashSize) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<HashFunction Hash>
|
||||
class RsaPssImpl {
|
||||
NON_COPYABLE(RsaPssImpl);
|
||||
NON_MOVEABLE(RsaPssImpl);
|
||||
public:
|
||||
static constexpr size_t HashSize = Hash::HashSize;
|
||||
private:
|
||||
static constexpr u8 TailMagic = 0xBC;
|
||||
private:
|
||||
static void ComputeHashWithPadding(void *dst, const u8 *user_hash, size_t user_hash_size, const void *salt, size_t salt_size) {
|
||||
AMS_ASSERT(user_hash_size == HashSize);
|
||||
AMS_UNUSED(user_hash_size);
|
||||
|
||||
/* Initialize our buffer. */
|
||||
u8 buf[8 + HashSize];
|
||||
std::memset(buf, 0, 8);
|
||||
std::memcpy(buf + 8, user_hash, HashSize);
|
||||
ON_SCOPE_EXIT { ClearMemory(buf, sizeof(buf)); };
|
||||
|
||||
|
||||
/* Calculate our hash. */
|
||||
Hash hash;
|
||||
hash.Initialize();
|
||||
hash.Update(buf, sizeof(buf));
|
||||
hash.Update(salt, salt_size);
|
||||
hash.GetHash(dst, HashSize);
|
||||
}
|
||||
|
||||
static void ApplyMGF1(u8 *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
u8 buf[HashSize];
|
||||
ON_SCOPE_EXIT { ClearMemory(buf, sizeof(buf)); };
|
||||
|
||||
const size_t required_iters = (dst_size + HashSize - 1) / HashSize;
|
||||
for (size_t i = 0; i < required_iters; i++) {
|
||||
Hash hash;
|
||||
hash.Initialize();
|
||||
hash.Update(src, src_size);
|
||||
|
||||
const u32 tmp = util::ConvertToBigEndian(static_cast<u32>(i));
|
||||
hash.Update(std::addressof(tmp), sizeof(tmp));
|
||||
|
||||
hash.GetHash(buf, HashSize);
|
||||
|
||||
const size_t start = HashSize * i;
|
||||
const size_t end = std::min(dst_size, start + HashSize);
|
||||
for (size_t j = start; j < end; j++) {
|
||||
dst[j] ^= buf[j - start];
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
RsaPssImpl() { /* ... */ }
|
||||
|
||||
bool Verify(u8 *buf, size_t size, const u8 *hash, size_t hash_size) {
|
||||
/* Validate sanity byte. */
|
||||
bool is_valid = buf[size - 1] == TailMagic;
|
||||
|
||||
/* Decrypt maskedDB */
|
||||
const size_t db_len = size - HashSize - 1;
|
||||
u8 *db = buf;
|
||||
u8 *h = db + db_len;
|
||||
ApplyMGF1(db, db_len, h, HashSize);
|
||||
|
||||
/* Apply lmask. */
|
||||
db[0] &= 0x7F;
|
||||
|
||||
/* Verify that DB is of the form 0000...0001 */
|
||||
s32 salt_ofs = 0;
|
||||
{
|
||||
int looking_for_one = 1;
|
||||
int invalid_db_padding = 0;
|
||||
int is_zero;
|
||||
int is_one;
|
||||
for (size_t i = 0; i < db_len; /* ... */) {
|
||||
is_zero = (db[i] == 0);
|
||||
is_one = (db[i] == 1);
|
||||
salt_ofs += (looking_for_one & is_one) * (static_cast<s32>(++i));
|
||||
looking_for_one &= ~is_one;
|
||||
invalid_db_padding |= (looking_for_one & ~is_zero);
|
||||
}
|
||||
|
||||
is_valid &= (invalid_db_padding == 0);
|
||||
}
|
||||
|
||||
/* Verify salt. */
|
||||
const u8 *salt = db + salt_ofs;
|
||||
const size_t salt_size = db_len - salt_ofs;
|
||||
is_valid &= (salt_size != 0);
|
||||
is_valid &= (salt_size != db_len);
|
||||
|
||||
/* Verify hash. */
|
||||
u8 cmp_hash[HashSize];
|
||||
ON_SCOPE_EXIT { ClearMemory(cmp_hash, sizeof(cmp_hash)); };
|
||||
|
||||
ComputeHashWithPadding(cmp_hash, hash, hash_size, salt, salt_size);
|
||||
is_valid &= IsSameBytes(cmp_hash, h, HashSize);
|
||||
|
||||
/* Succeed if all our checks succeeded. */
|
||||
return is_valid;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
class Sha1Impl {
|
||||
public:
|
||||
static constexpr size_t HashSize = 0x14;
|
||||
static constexpr size_t BlockSize = 0x40;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_Initialized,
|
||||
State_Done,
|
||||
};
|
||||
private:
|
||||
u32 m_intermediate_hash[HashSize / sizeof(u32)];
|
||||
u8 m_buffer[BlockSize];
|
||||
size_t m_buffered_bytes;
|
||||
u64 m_bits_consumed;
|
||||
State m_state;
|
||||
public:
|
||||
Sha1Impl() : m_state(State_None) { /* ... */ }
|
||||
~Sha1Impl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
void Update(const void *data, size_t size);
|
||||
void GetHash(void *dst, size_t size);
|
||||
private:
|
||||
void ProcessBlock(const void *data);
|
||||
void ProcessBlocks(const u8 *data, size_t block_count);
|
||||
void ProcessLastBlock();
|
||||
};
|
||||
|
||||
static_assert(HashFunction<Sha1Impl>);
|
||||
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
namespace ams::crypto {
|
||||
|
||||
struct Sha256Context;
|
||||
|
||||
}
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
class Sha256Impl {
|
||||
public:
|
||||
static constexpr size_t HashSize = 0x20;
|
||||
static constexpr size_t BlockSize = 0x40;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_Initialized,
|
||||
State_Done,
|
||||
};
|
||||
private:
|
||||
u32 m_intermediate_hash[HashSize / sizeof(u32)];
|
||||
u8 m_buffer[BlockSize];
|
||||
size_t m_buffered_bytes;
|
||||
u64 m_bits_consumed;
|
||||
State m_state;
|
||||
public:
|
||||
Sha256Impl() : m_state(State_None) { /* ... */ }
|
||||
~Sha256Impl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
void Update(const void *data, size_t size);
|
||||
void GetHash(void *dst, size_t size);
|
||||
|
||||
void InitializeWithContext(const Sha256Context *context);
|
||||
size_t GetContext(Sha256Context *context) const;
|
||||
|
||||
size_t GetBufferedDataSize() const { return m_buffered_bytes; }
|
||||
|
||||
void GetBufferedData(void *dst, size_t dst_size) const {
|
||||
AMS_ASSERT(dst_size >= this->GetBufferedDataSize());
|
||||
AMS_UNUSED(dst_size);
|
||||
|
||||
std::memcpy(dst, m_buffer, m_buffered_bytes);
|
||||
}
|
||||
private:
|
||||
void ProcessBlock(const void *data);
|
||||
void ProcessBlocks(const u8 *data, size_t block_count);
|
||||
void ProcessLastBlock();
|
||||
};
|
||||
|
||||
static_assert(HashFunction<Sha256Impl>);
|
||||
|
||||
}
|
||||
@@ -1,296 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
class Sha256CompileTimeImpl {
|
||||
public:
|
||||
static constexpr size_t HashSize = 0x20;
|
||||
static constexpr size_t BlockSize = 0x40;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_Initialized,
|
||||
State_Done,
|
||||
};
|
||||
private:
|
||||
u32 m_intermediate_hash[HashSize / sizeof(u32)];
|
||||
u8 m_buffer[BlockSize];
|
||||
size_t m_buffered_bytes;
|
||||
u64 m_bits_consumed;
|
||||
State m_state;
|
||||
public:
|
||||
constexpr Sha256CompileTimeImpl() : m_intermediate_hash(), m_buffer(), m_buffered_bytes(), m_bits_consumed(), m_state(State_None) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr void Initialize() {
|
||||
/* Reset buffered bytes/bits. */
|
||||
m_buffered_bytes = 0;
|
||||
m_bits_consumed = 0;
|
||||
|
||||
/* Set intermediate hash. */
|
||||
m_intermediate_hash[0] = 0x6A09E667;
|
||||
m_intermediate_hash[1] = 0xBB67AE85;
|
||||
m_intermediate_hash[2] = 0x3C6EF372;
|
||||
m_intermediate_hash[3] = 0xA54FF53A;
|
||||
m_intermediate_hash[4] = 0x510E527F;
|
||||
m_intermediate_hash[5] = 0x9B05688C;
|
||||
m_intermediate_hash[6] = 0x1F83D9AB;
|
||||
m_intermediate_hash[7] = 0x5BE0CD19;
|
||||
|
||||
/* Set state. */
|
||||
m_state = State_Initialized;
|
||||
}
|
||||
|
||||
template<typename T, typename = typename std::enable_if<std::same_as<T, u8> || std::same_as<T, s8> || std::same_as<T, char> || std::same_as<T, unsigned char>>::type>
|
||||
constexpr void Update(const T *data, size_t size) {
|
||||
static_assert(sizeof(T) == 1);
|
||||
|
||||
/* Verify we're in a state to update. */
|
||||
AMS_ASSERT(m_state == State_Initialized);
|
||||
|
||||
/* Advance our input bit count. */
|
||||
m_bits_consumed += BITSIZEOF(u8) * (((m_buffered_bytes + size) / BlockSize) * BlockSize);
|
||||
|
||||
/* Process anything we have buffered. */
|
||||
size_t remaining = size;
|
||||
|
||||
if (m_buffered_bytes > 0) {
|
||||
const size_t copy_size = std::min(BlockSize - m_buffered_bytes, remaining);
|
||||
for (size_t i = 0; i < copy_size; ++i) {
|
||||
m_buffer[m_buffered_bytes + i] = static_cast<u8>(data[i]);
|
||||
}
|
||||
|
||||
data += copy_size;
|
||||
remaining -= copy_size;
|
||||
m_buffered_bytes += copy_size;
|
||||
|
||||
/* Process a block, if we filled one. */
|
||||
if (m_buffered_bytes == BlockSize) {
|
||||
this->ProcessBlock(m_buffer);
|
||||
m_buffered_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process blocks, if we have any. */
|
||||
while (remaining >= BlockSize) {
|
||||
u8 block[BlockSize] = {};
|
||||
for (size_t i = 0; i < BlockSize; ++i) {
|
||||
block[i] = static_cast<u8>(data[i]);
|
||||
}
|
||||
this->ProcessBlock(block);
|
||||
|
||||
data += BlockSize;
|
||||
remaining -= BlockSize;
|
||||
}
|
||||
|
||||
/* Copy any leftover data to our buffer. */
|
||||
if (remaining > 0) {
|
||||
m_buffered_bytes = remaining;
|
||||
for (size_t i = 0; i < remaining; ++i) {
|
||||
m_buffer[i] = static_cast<u8>(data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void GetHash(u8 *dst, size_t size) {
|
||||
/* Verify we're in a state to get hash. */
|
||||
AMS_ASSERT(m_state == State_Initialized || m_state == State_Done);
|
||||
AMS_ASSERT(size >= HashSize);
|
||||
AMS_UNUSED(size);
|
||||
|
||||
/* If we need to, process the last block. */
|
||||
if (m_state == State_Initialized) {
|
||||
this->ProcessLastBlock();
|
||||
m_state = State_Done;
|
||||
}
|
||||
|
||||
/* Copy the output hash. */
|
||||
for (size_t i = 0; i < HashSize / sizeof(u32); ++i) {
|
||||
const u32 v = m_intermediate_hash[i];
|
||||
|
||||
dst[sizeof(u32) * i + 3] = static_cast<u8>(v >> (BITSIZEOF(u8) * 0));
|
||||
dst[sizeof(u32) * i + 2] = static_cast<u8>(v >> (BITSIZEOF(u8) * 1));
|
||||
dst[sizeof(u32) * i + 1] = static_cast<u8>(v >> (BITSIZEOF(u8) * 2));
|
||||
dst[sizeof(u32) * i + 0] = static_cast<u8>(v >> (BITSIZEOF(u8) * 3));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t GetBufferedDataSize() const { return m_buffered_bytes; }
|
||||
|
||||
constexpr void GetBufferedData(u8 *dst, size_t dst_size) const {
|
||||
AMS_ASSERT(dst_size >= this->GetBufferedDataSize());
|
||||
AMS_UNUSED(dst_size);
|
||||
|
||||
for (size_t i = 0; i < m_buffered_bytes; ++i) {
|
||||
dst[i] = m_buffer[i];
|
||||
}
|
||||
}
|
||||
private:
|
||||
static constexpr ALWAYS_INLINE u32 Choose(u32 x, u32 y, u32 z) {
|
||||
return (x & y) ^ ((~x) & z);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 Majority(u32 x, u32 y, u32 z) {
|
||||
return (x & y) ^ (x & z) ^ (y & z);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 LargeSigma0(u32 x) {
|
||||
return util::RotateRight<u32>(x, 2) ^ util::RotateRight<u32>(x, 13) ^ util::RotateRight<u32>(x, 22);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 LargeSigma1(u32 x) {
|
||||
return util::RotateRight<u32>(x, 6) ^ util::RotateRight<u32>(x, 11) ^ util::RotateRight<u32>(x, 25);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 SmallSigma0(u32 x) {
|
||||
return util::RotateRight<u32>(x, 7) ^ util::RotateRight<u32>(x, 18) ^ (x >> 3);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 SmallSigma1(u32 x) {
|
||||
return util::RotateRight<u32>(x, 17) ^ util::RotateRight<u32>(x, 19) ^ (x >> 10);
|
||||
}
|
||||
|
||||
constexpr void ProcessBlock(const u8 *data) {
|
||||
/* Load work variables. */
|
||||
u32 a = m_intermediate_hash[0];
|
||||
u32 b = m_intermediate_hash[1];
|
||||
u32 c = m_intermediate_hash[2];
|
||||
u32 d = m_intermediate_hash[3];
|
||||
u32 e = m_intermediate_hash[4];
|
||||
u32 f = m_intermediate_hash[5];
|
||||
u32 g = m_intermediate_hash[6];
|
||||
u32 h = m_intermediate_hash[7];
|
||||
u32 tmp[2]{};
|
||||
size_t i = 0;
|
||||
|
||||
/* Copy the input. */
|
||||
u32 w[64]{};
|
||||
for (size_t i = 0; i < BlockSize / sizeof(u32); ++i) {
|
||||
u32 v = 0;
|
||||
v |= static_cast<u32>(data[sizeof(u32) * i + 0]) << (BITSIZEOF(u8) * 3);
|
||||
v |= static_cast<u32>(data[sizeof(u32) * i + 1]) << (BITSIZEOF(u8) * 2);
|
||||
v |= static_cast<u32>(data[sizeof(u32) * i + 2]) << (BITSIZEOF(u8) * 1);
|
||||
v |= static_cast<u32>(data[sizeof(u32) * i + 3]) << (BITSIZEOF(u8) * 0);
|
||||
|
||||
w[i] = v;
|
||||
}
|
||||
|
||||
/* Initialize the rest of w. */
|
||||
for (i = BlockSize / sizeof(u32); i < util::size(w); ++i) {
|
||||
const u32 *prev = w + (i - BlockSize / sizeof(u32));
|
||||
w[i] = prev[0] + SmallSigma0(prev[1]) + prev[9] + SmallSigma1(prev[14]);
|
||||
}
|
||||
|
||||
/* Perform rounds. */
|
||||
{
|
||||
const u32 RoundConstants[0x40] = {
|
||||
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
|
||||
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
|
||||
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
|
||||
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
|
||||
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
|
||||
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
|
||||
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
|
||||
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
|
||||
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
|
||||
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
|
||||
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
|
||||
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
|
||||
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
|
||||
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
|
||||
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
|
||||
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
|
||||
};
|
||||
|
||||
for (i = 0; i < 64; ++i) {
|
||||
tmp[0] = h + LargeSigma1(e) + Choose(e, f, g) + RoundConstants[i] + w[i];
|
||||
tmp[1] = LargeSigma0(a) + Majority(a, b, c);
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + tmp[0];
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = tmp[0] + tmp[1];
|
||||
}
|
||||
}
|
||||
|
||||
/* Update intermediate hash. */
|
||||
m_intermediate_hash[0] += a;
|
||||
m_intermediate_hash[1] += b;
|
||||
m_intermediate_hash[2] += c;
|
||||
m_intermediate_hash[3] += d;
|
||||
m_intermediate_hash[4] += e;
|
||||
m_intermediate_hash[5] += f;
|
||||
m_intermediate_hash[6] += g;
|
||||
m_intermediate_hash[7] += h;
|
||||
}
|
||||
|
||||
constexpr void ProcessLastBlock() {
|
||||
/* Setup the final block. */
|
||||
constexpr const auto BlockSizeWithoutSizeField = BlockSize - sizeof(u64);
|
||||
|
||||
/* Increment our bits consumed. */
|
||||
m_bits_consumed += BITSIZEOF(u8) * m_buffered_bytes;
|
||||
|
||||
/* Add 0x80 terminator. */
|
||||
m_buffer[m_buffered_bytes++] = 0x80;
|
||||
|
||||
/* If we can process the size field directly, do so, otherwise set up to process it. */
|
||||
if (m_buffered_bytes <= BlockSizeWithoutSizeField) {
|
||||
/* Clear up to size field. */
|
||||
for (size_t i = 0; i < BlockSizeWithoutSizeField - m_buffered_bytes; ++i) {
|
||||
m_buffer[m_buffered_bytes + i] = 0;
|
||||
}
|
||||
} else {
|
||||
/* Consume full block */
|
||||
for (size_t i = 0; i < BlockSize - m_buffered_bytes; ++i) {
|
||||
m_buffer[m_buffered_bytes + i] = 0;
|
||||
}
|
||||
|
||||
this->ProcessBlock(m_buffer);
|
||||
|
||||
/* Clear up to size field. */
|
||||
for (size_t i = 0; i < BlockSizeWithoutSizeField; ++i) {
|
||||
m_buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store the size field. */
|
||||
m_buffer[BlockSizeWithoutSizeField + 0] = static_cast<u8>((m_bits_consumed >> (BITSIZEOF(u8) * 7)) & 0xFF);
|
||||
m_buffer[BlockSizeWithoutSizeField + 1] = static_cast<u8>((m_bits_consumed >> (BITSIZEOF(u8) * 6)) & 0xFF);
|
||||
m_buffer[BlockSizeWithoutSizeField + 2] = static_cast<u8>((m_bits_consumed >> (BITSIZEOF(u8) * 5)) & 0xFF);
|
||||
m_buffer[BlockSizeWithoutSizeField + 3] = static_cast<u8>((m_bits_consumed >> (BITSIZEOF(u8) * 4)) & 0xFF);
|
||||
m_buffer[BlockSizeWithoutSizeField + 4] = static_cast<u8>((m_bits_consumed >> (BITSIZEOF(u8) * 3)) & 0xFF);
|
||||
m_buffer[BlockSizeWithoutSizeField + 5] = static_cast<u8>((m_bits_consumed >> (BITSIZEOF(u8) * 2)) & 0xFF);
|
||||
m_buffer[BlockSizeWithoutSizeField + 6] = static_cast<u8>((m_bits_consumed >> (BITSIZEOF(u8) * 1)) & 0xFF);
|
||||
m_buffer[BlockSizeWithoutSizeField + 7] = static_cast<u8>((m_bits_consumed >> (BITSIZEOF(u8) * 0)) & 0xFF);
|
||||
|
||||
/* Process the final block. */
|
||||
this->ProcessBlock(m_buffer);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
namespace ams::crypto {
|
||||
|
||||
struct Sha3Context;
|
||||
|
||||
}
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<size_t _HashSize>
|
||||
class Sha3Impl {
|
||||
public:
|
||||
static constexpr size_t InternalStateSize = 200;
|
||||
static constexpr size_t HashSize = _HashSize;
|
||||
static constexpr size_t BlockSize = InternalStateSize - 2 * HashSize;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_Initialized,
|
||||
State_Done,
|
||||
};
|
||||
private:
|
||||
u64 m_internal_state[InternalStateSize / sizeof(u64)];
|
||||
size_t m_buffered_bytes;
|
||||
State m_state;
|
||||
public:
|
||||
Sha3Impl() : m_state(State_None) { /* ... */ }
|
||||
~Sha3Impl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
void Update(const void *data, size_t size);
|
||||
void GetHash(void *dst, size_t size);
|
||||
|
||||
void InitializeWithContext(const Sha3Context *context);
|
||||
void GetContext(Sha3Context *context) const;
|
||||
private:
|
||||
void ProcessBlock();
|
||||
void ProcessLastBlock();
|
||||
};
|
||||
|
||||
static_assert(HashFunction<Sha3Impl<224 / BITSIZEOF(u8)>>);
|
||||
static_assert(HashFunction<Sha3Impl<256 / BITSIZEOF(u8)>>);
|
||||
static_assert(HashFunction<Sha3Impl<384 / BITSIZEOF(u8)>>);
|
||||
static_assert(HashFunction<Sha3Impl<512 / BITSIZEOF(u8)>>);
|
||||
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
#include <vapours/crypto/crypto_aes_encryptor.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
class XtsModeImpl {
|
||||
NON_COPYABLE(XtsModeImpl);
|
||||
NON_MOVEABLE(XtsModeImpl);
|
||||
public:
|
||||
/* TODO: More generic support. */
|
||||
static constexpr size_t BlockSize = 16;
|
||||
static constexpr size_t IvSize = 16;
|
||||
private:
|
||||
enum State {
|
||||
State_None,
|
||||
State_Initialized,
|
||||
State_Processing,
|
||||
State_Done
|
||||
};
|
||||
private:
|
||||
u8 m_buffer[BlockSize];
|
||||
u8 m_tweak[BlockSize];
|
||||
u8 m_last_block[BlockSize];
|
||||
size_t m_num_buffered;
|
||||
const void *m_cipher_ctx;
|
||||
void (*m_cipher_func)(void *dst_block, const void *src_block, const void *cipher_ctx);
|
||||
State m_state;
|
||||
public:
|
||||
XtsModeImpl() : m_num_buffered(0), m_state(State_None) { /* ... */ }
|
||||
|
||||
~XtsModeImpl() {
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
private:
|
||||
template<typename BlockCipher>
|
||||
static void EncryptBlockCallback(void *dst_block, const void *src_block, const void *cipher) {
|
||||
return static_cast<const BlockCipher *>(cipher)->EncryptBlock(dst_block, BlockCipher::BlockSize, src_block, BlockCipher::BlockSize);
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
static void DecryptBlockCallback(void *dst_block, const void *src_block, const void *cipher) {
|
||||
return static_cast<const BlockCipher *>(cipher)->DecryptBlock(dst_block, BlockCipher::BlockSize, src_block, BlockCipher::BlockSize);
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
void Initialize(const BlockCipher *cipher, const void *tweak, size_t tweak_size) {
|
||||
AMS_ASSERT(tweak_size == IvSize);
|
||||
AMS_UNUSED(tweak_size);
|
||||
|
||||
cipher->EncryptBlock(m_tweak, IvSize, tweak, IvSize);
|
||||
|
||||
m_num_buffered = 0;
|
||||
m_state = State_Initialized;
|
||||
}
|
||||
|
||||
void ProcessBlock(u8 *dst, const u8 *src);
|
||||
public:
|
||||
template<typename BlockCipher1, typename BlockCipher2>
|
||||
void InitializeEncryption(const BlockCipher1 *cipher1, const BlockCipher2 *cipher2, const void *tweak, size_t tweak_size) {
|
||||
static_assert(BlockCipher1::BlockSize == BlockSize);
|
||||
static_assert(BlockCipher2::BlockSize == BlockSize);
|
||||
|
||||
m_cipher_ctx = cipher1;
|
||||
m_cipher_func = EncryptBlockCallback<BlockCipher1>;
|
||||
|
||||
this->Initialize(cipher2, tweak, tweak_size);
|
||||
}
|
||||
|
||||
template<typename BlockCipher1, typename BlockCipher2>
|
||||
void InitializeDecryption(const BlockCipher1 *cipher1, const BlockCipher2 *cipher2, const void *tweak, size_t tweak_size) {
|
||||
static_assert(BlockCipher1::BlockSize == BlockSize);
|
||||
static_assert(BlockCipher2::BlockSize == BlockSize);
|
||||
|
||||
m_cipher_ctx = cipher1;
|
||||
m_cipher_func = DecryptBlockCallback<BlockCipher1>;
|
||||
|
||||
this->Initialize(cipher2, tweak, tweak_size);
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
size_t Update(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
return this->UpdateGeneric(dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
size_t ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks) {
|
||||
return this->ProcessBlocksGeneric(dst, src, num_blocks);
|
||||
}
|
||||
|
||||
size_t GetBufferedDataSize() const {
|
||||
return m_num_buffered;
|
||||
}
|
||||
|
||||
constexpr size_t GetBlockSize() const {
|
||||
return BlockSize;
|
||||
}
|
||||
|
||||
size_t FinalizeEncryption(void *dst, size_t dst_size);
|
||||
size_t FinalizeDecryption(void *dst, size_t dst_size);
|
||||
|
||||
size_t UpdateGeneric(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
size_t ProcessBlocksGeneric(u8 *dst, const u8 *src, size_t num_blocks);
|
||||
|
||||
size_t ProcessPartialData(u8 *dst, const u8 *src, size_t size);
|
||||
size_t ProcessRemainingData(u8 *dst, const u8 *src, size_t size);
|
||||
};
|
||||
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
template<> size_t XtsModeImpl::Update<AesEncryptor128>(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
template<> size_t XtsModeImpl::Update<AesEncryptor192>(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
template<> size_t XtsModeImpl::Update<AesEncryptor256>(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
template<> size_t XtsModeImpl::Update<AesDecryptor128>(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
template<> size_t XtsModeImpl::Update<AesDecryptor192>(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
template<> size_t XtsModeImpl::Update<AesDecryptor256>(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
#endif
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user