From f3629f863d1a842f61c134b794402a3a7daa598d Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sun, 23 Feb 2020 17:34:30 -0800 Subject: [PATCH] crypto: implement RSA-2048-PSS --- .../libvapours/include/vapours/crypto.hpp | 3 +- .../vapours/crypto/crypto_rsa_calculator.hpp | 60 +++++++++ .../crypto/crypto_rsa_pss_sha256_verifier.hpp | 53 ++++++++ .../crypto/crypto_rsa_pss_verifier.hpp | 109 ++++++++++++++++ .../crypto/crypto_sha256_generator.hpp | 61 +++++++++ .../vapours/crypto/impl/crypto_bignum.hpp | 4 +- .../crypto/impl/crypto_hash_function.hpp | 37 ++++++ .../crypto/impl/crypto_rsa_pss_impl.hpp | 120 +++++++++++++++++ .../crypto/impl/crypto_sha256_impl.hpp | 54 ++++++++ libraries/libvapours/include/vapours/util.hpp | 1 + .../include/vapours/util/util_endian.hpp | 121 ++++++++++++++++++ .../source/crypto/crypto_sha256_generator.cpp | 28 ++++ .../impl/crypto_sha256_impl.arch.arm64.cpp | 44 +++++++ 13 files changed, 692 insertions(+), 3 deletions(-) create mode 100644 libraries/libvapours/include/vapours/crypto/crypto_rsa_calculator.hpp create mode 100644 libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_sha256_verifier.hpp create mode 100644 libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_verifier.hpp create mode 100644 libraries/libvapours/include/vapours/crypto/crypto_sha256_generator.hpp create mode 100644 libraries/libvapours/include/vapours/crypto/impl/crypto_hash_function.hpp create mode 100644 libraries/libvapours/include/vapours/crypto/impl/crypto_rsa_pss_impl.hpp create mode 100644 libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl.hpp create mode 100644 libraries/libvapours/include/vapours/util/util_endian.hpp create mode 100644 libraries/libvapours/source/crypto/crypto_sha256_generator.cpp create mode 100644 libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.arm64.cpp diff --git a/libraries/libvapours/include/vapours/crypto.hpp b/libraries/libvapours/include/vapours/crypto.hpp index a468ee98a..7e90f8ce1 100644 --- a/libraries/libvapours/include/vapours/crypto.hpp +++ b/libraries/libvapours/include/vapours/crypto.hpp @@ -19,4 +19,5 @@ #include #include -#include +#include +#include diff --git a/libraries/libvapours/include/vapours/crypto/crypto_rsa_calculator.hpp b/libraries/libvapours/include/vapours/crypto/crypto_rsa_calculator.hpp new file mode 100644 index 000000000..e377084e9 --- /dev/null +++ b/libraries/libvapours/include/vapours/crypto/crypto_rsa_calculator.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include +#include +#include + +namespace ams::crypto { + + template + class RsaCalculator { + NON_COPYABLE(RsaCalculator); + NON_MOVEABLE(RsaCalculator); + public: + static constexpr inline size_t RequiredWorkBufferSize = 0x10 * ModulusSize; + private: + impl::StaticBigNum modulus; + impl::StaticBigNum exponent; + public: + RsaCalculator() { /* ... */ } + ~RsaCalculator() { this->exponent.ClearToZero(); } + + bool Initialize(const void *mod, size_t mod_size, const void *exp, size_t exp_size) { + if (!this->modulus.Import(mod, mod_size) || this->modulus.IsZero()) { + return false; + } + if (!this->exponent.Import(exp, exp_size) || this->exponent.IsZero()) { + return false; + } + return true; + } + + bool ExpMod(void *dst, const void *src, size_t size, void *work_buf, size_t work_buf_size) { + AMS_ASSERT(work_buf_size >= RequiredWorkBufferSize); + + return this->modulus.ExpMod(dst, src, size, this->exponent, static_cast(work_buf), work_buf_size); + } + + bool ExpMod(void *dst, const void *src, size_t size) { + u32 work_buf[RequiredWorkBufferSize / sizeof(u32)]; + return this->ExpMod(dst, src, size, work_buf, sizeof(work_buf)); + } + }; + +} diff --git a/libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_sha256_verifier.hpp b/libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_sha256_verifier.hpp new file mode 100644 index 000000000..a2136e98f --- /dev/null +++ b/libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_sha256_verifier.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include +#include +#include +#include +#include + +namespace ams::crypto { + + namespace impl { + + template + using RsaNPssSha256Verifier = ::ams::crypto::RsaPssVerifier; + + } + + using Rsa2048PssSha256Verifier = ::ams::crypto::impl::RsaNPssSha256Verifier<2048>; + using Rsa4096PssSha256Verifier = ::ams::crypto::impl::RsaNPssSha256Verifier<4096>; + + inline bool VerifyRsa2048PssSha256(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size) { + return Rsa2048PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size); + } + + inline bool VerifyRsa2048PssSha256(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size, void *work_buf, size_t work_buf_size) { + return Rsa2048PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size, work_buf, work_buf_size); + } + + inline bool VerifyRsa4096PssSha256(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size) { + return Rsa4096PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size); + } + + inline bool VerifyRsa4096PssSha256(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size, void *work_buf, size_t work_buf_size) { + return Rsa4096PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size, work_buf, work_buf_size); + } + +} diff --git a/libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_verifier.hpp b/libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_verifier.hpp new file mode 100644 index 000000000..61b4a4de8 --- /dev/null +++ b/libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_verifier.hpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include +#include +#include +#include + +namespace ams::crypto { + + template /* requires HashFunction */ + class RsaPssVerifier { + NON_COPYABLE(RsaPssVerifier); + NON_MOVEABLE(RsaPssVerifier); + public: + static constexpr size_t HashSize = Hash::HashSize; + static constexpr size_t SaltSize = Hash::HashSize; + static constexpr size_t SignatureSize = ModulusSize; + static constexpr size_t MaximumExponentSize = 3; + static constexpr size_t RequiredWorkBufferSize = RsaCalculator::RequiredWorkBufferSize; + private: + enum class State { + None, + Initialized, + Done, + }; + private: + RsaCalculator calculator; + Hash hash; + State state; + public: + RsaPssVerifier() : state(State::None) { /* ... */ } + ~RsaPssVerifier() { } + + bool Initialize(const void *mod, size_t mod_size, const void *exp, size_t exp_size) { + this->hash.Initialize(); + if (this->calculator.Initialize(mod, mod_size, exp, exp_size)) { + this->state = State::Initialized; + return true; + } else { + return false; + } + } + + void Update(const void *data, size_t size) { + return this->hash.Update(data, size); + } + + bool Verify(const void *signature, size_t size) { + AMS_ASSERT(this->state == State::Initialized); + AMS_ASSERT(size == SignatureSize); + ON_SCOPE_EXIT { this->state = State::Done; }; + + impl::RsaPssImpl impl; + u8 message[SignatureSize]; + ON_SCOPE_EXIT { ClearMemory(message, sizeof(message)); }; + + return this->calculator.ExpMod(message, signature, SignatureSize) && + impl.Verify(message, sizeof(message), std::addressof(this->hash)); + } + + bool Verify(const void *signature, size_t size, void *work_buf, size_t work_buf_size) { + AMS_ASSERT(this->state == State::Initialized); + AMS_ASSERT(size == SignatureSize); + ON_SCOPE_EXIT { this->state = State::Done; }; + + impl::RsaPssImpl impl; + u8 message[SignatureSize]; + ON_SCOPE_EXIT { ClearMemory(message, sizeof(message)); }; + + return this->calculator.ExpMod(message, signature, SignatureSize, work_buf, work_buf_size) && + impl.Verify(message, sizeof(message), std::addressof(this->hash)); + } + + static bool Verify(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size) { + RsaPssVerifier verifier; + if (!verifier.Initialize(mod, mod_size, exp, exp_size)) { + return false; + } + verifier.Update(msg, msg_size); + return verifier.Verify(sig, sig_size); + } + + static bool Verify(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size, void *work_buf, size_t work_buf_size) { + RsaPssVerifier verifier; + if (!verifier.Initialize(mod, mod_size, exp, exp_size)) { + return false; + } + verifier.Update(msg, msg_size); + return verifier.Verify(sig, sig_size, work_buf, work_buf_size); + } + }; + +} diff --git a/libraries/libvapours/include/vapours/crypto/crypto_sha256_generator.hpp b/libraries/libvapours/include/vapours/crypto/crypto_sha256_generator.hpp new file mode 100644 index 000000000..9b6a54773 --- /dev/null +++ b/libraries/libvapours/include/vapours/crypto/crypto_sha256_generator.hpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include +#include +#include + +namespace ams::crypto { + + class Sha256Generator { + private: + using Impl = impl::Sha256Impl; + public: + static constexpr size_t HashSize = Impl::HashSize; + static constexpr size_t BlockSize = Impl::BlockSize; + + static constexpr inline u8 Asn1Identifier[] = { + 0x30, 0x31, /* Sequence, size 0x31 */ + 0x30, 0x0D, /* Sequence, size 0x0D */ + 0x06, 0x09, /* Object Identifier */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* SHA-256 */ + 0x00, /* Null */ + 0x04, 0x20, /* Octet string, size 0x20 */ + }; + static constexpr size_t Asn1IdentifierSize = util::size(Asn1Identifier); + private: + Impl impl; + public: + Sha256Generator() { /* ... */ } + + void Initialize() { + this->impl.Initialize(); + } + + void Update(const void *data, size_t size) { + this->impl.Update(data, size); + } + + void GetHash(void *dst, size_t size) { + this->impl.GetHash(dst, size); + } + }; + + void GenerateSha256Hash(void *dst, size_t dst_size, const void *src, size_t src_size); + +} diff --git a/libraries/libvapours/include/vapours/crypto/impl/crypto_bignum.hpp b/libraries/libvapours/include/vapours/crypto/impl/crypto_bignum.hpp index 585e41975..37cea25bc 100644 --- a/libraries/libvapours/include/vapours/crypto/impl/crypto_bignum.hpp +++ b/libraries/libvapours/include/vapours/crypto/impl/crypto_bignum.hpp @@ -147,7 +147,7 @@ namespace ams::crypto::impl { }; template - class StackBigNum : public BigNum { + class StaticBigNum : public BigNum { public: static constexpr size_t NumBits = Bits; static constexpr size_t NumWords = util::AlignUp(NumBits, BitsPerWord) / BitsPerWord; @@ -155,7 +155,7 @@ namespace ams::crypto::impl { private: Word word_buf[NumWords]; public: - constexpr StackBigNum() : word_buf() { + constexpr StaticBigNum() : word_buf() { this->ReserveStatic(word_buf, NumWords); } }; diff --git a/libraries/libvapours/include/vapours/crypto/impl/crypto_hash_function.hpp b/libraries/libvapours/include/vapours/crypto/impl/crypto_hash_function.hpp new file mode 100644 index 000000000..b598b46f6 --- /dev/null +++ b/libraries/libvapours/include/vapours/crypto/impl/crypto_hash_function.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include +#include +#include +#include + +namespace ams::crypto::impl { + + /* TODO: C++20 + template + concept HashFunction = requires(T &t, const void *cv, void *v, size_t sz) { + { T::HashSize } -> std::same_as; + { T::BlockSize } -> std::same_as; + { t.Initialize() } -> std::same_as; + { t.Update(cv, sz) } -> std::same_as; + { t.GetHash(v, sz) } -> std::same_as; + }; + */ + +} diff --git a/libraries/libvapours/include/vapours/crypto/impl/crypto_rsa_pss_impl.hpp b/libraries/libvapours/include/vapours/crypto/impl/crypto_rsa_pss_impl.hpp new file mode 100644 index 000000000..5a17ff4e5 --- /dev/null +++ b/libraries/libvapours/include/vapours/crypto/impl/crypto_rsa_pss_impl.hpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include +#include +#include + +namespace ams::crypto::impl { + + template /* requires HashFunction */ + 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, 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(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, Hash *hash) { + /* Validate sanity byte. */ + if (buf[size - 1] != TailMagic) { + return false; + } + + /* 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 = -1; + for (size_t i = 0; i < db_len; i++) { + if (db[i] != 0) { + salt_ofs = static_cast(i) + 1; + break; + } + } + if (salt_ofs == -1) { + return false; + } + if (db[salt_ofs - 1] != 1) { + return false; + } + + /* Verify salt. */ + const u8 *salt = db + salt_ofs; + const size_t salt_size = db_len - salt_ofs; + if (salt_size == 0) { + return false; + } + + /* Verify hash. */ + u8 cmp_hash[HashSize]; + ON_SCOPE_EXIT { ClearMemory(cmp_hash, sizeof(cmp_hash)); }; + + ComputeHashWithPadding(cmp_hash, hash, salt, salt_size); + return IsSameBytes(cmp_hash, h, HashSize); + } + }; + +} diff --git a/libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl.hpp b/libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl.hpp new file mode 100644 index 000000000..4fa60ca2d --- /dev/null +++ b/libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include +#include +#include +#include + +namespace ams::crypto::impl { + + class Sha256Impl { + public: + static constexpr size_t HashSize = 0x20; + static constexpr size_t BlockSize = 0x40; + private: + struct State { + u32 intermediate_hash[HashSize / sizeof(u32)]; + u8 buffer[BlockSize]; + u64 bits_consumed; + size_t num_buffered; + bool finalized; + }; + private: + State state; + public: + Sha256Impl() { /* ... */ } + ~Sha256Impl() { + static_assert(std::is_trivially_destructible::value); + ClearMemory(std::addressof(this->state), sizeof(this->state)); + } + + void Initialize(); + void Update(const void *data, size_t size); + void GetHash(void *dst, size_t size); + }; + + /* static_assert(HashFunction); */ + +} diff --git a/libraries/libvapours/include/vapours/util.hpp b/libraries/libvapours/include/vapours/util.hpp index c59ea8afb..e3018fa6e 100644 --- a/libraries/libvapours/include/vapours/util.hpp +++ b/libraries/libvapours/include/vapours/util.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include diff --git a/libraries/libvapours/include/vapours/util/util_endian.hpp b/libraries/libvapours/include/vapours/util/util_endian.hpp new file mode 100644 index 000000000..c91b72558 --- /dev/null +++ b/libraries/libvapours/include/vapours/util/util_endian.hpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include + +namespace ams::util { + + /* TODO: C++20 std::endian */ + + constexpr bool IsLittleEndian() { + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return true; + #else + return false; + #endif + } + + constexpr bool IsBigEndian() { + #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return true; + #else + return false; + #endif + } + + static_assert(IsLittleEndian() ^ IsBigEndian()); + + template /* requires unsigned_integral */ + constexpr ALWAYS_INLINE U SwapBytes(const U u) { + static_assert(BITSIZEOF(u8) == 8); + constexpr U ByteMask = 0xFFu; + if constexpr (std::is_same::value) { + return ((u & (ByteMask << 56)) >> 56) | + ((u & (ByteMask << 48)) >> 40) | + ((u & (ByteMask << 40)) >> 24) | + ((u & (ByteMask << 32)) >> 8) | + ((u & (ByteMask << 24)) << 8) | + ((u & (ByteMask << 16)) << 24) | + ((u & (ByteMask << 8)) << 40) | + ((u & (ByteMask << 0)) << 56); + + } else if constexpr (std::is_same::value) { + return ((u & (ByteMask << 24)) >> 24) | + ((u & (ByteMask << 16)) >> 8) | + ((u & (ByteMask << 8)) << 8) | + ((u & (ByteMask << 0)) << 24); + + } else if constexpr (std::is_same::value) { + return ((u & (ByteMask << 8)) >> 8) | + ((u & (ByteMask << 0)) << 8); + + } else if constexpr (std::is_same::value) { + return u; + } else { + static_assert(!std::is_same::value); + } + } + + template /* requires integral */ + constexpr ALWAYS_INLINE void SwapBytes(T *ptr) { + using U = typename std::make_unsigned::type; + + *ptr = static_cast(SwapBytes(static_cast(*ptr))); + } + + template + constexpr ALWAYS_INLINE T ConvertToBigEndian(const T val) { + if constexpr (IsBigEndian()) { + return val; + } else { + static_assert(IsLittleEndian()); + return SwapBytes(val); + } + } + + template + constexpr ALWAYS_INLINE T ConvertToLittleEndian(const T val) { + if constexpr (IsBigEndian()) { + return SwapBytes(val); + } else { + static_assert(IsLittleEndian()); + return val; + } + } + + template /* requires integral */ + constexpr ALWAYS_INLINE T LoadBigEndian(T *ptr) { + return ConvertToBigEndian(*ptr); + } + + template /* requires integral */ + constexpr ALWAYS_INLINE T LoadLittleEndian(T *ptr) { + return ConvertToLittleEndian(*ptr); + } + + template + constexpr ALWAYS_INLINE void StoreBigEndian(T *ptr, T val) { + *ptr = ConvertToBigEndian(val); + } + + template + constexpr ALWAYS_INLINE void StoreLittleEndian(T *ptr, T val) { + *ptr = ConvertToLittleEndian(val); + } + +} diff --git a/libraries/libvapours/source/crypto/crypto_sha256_generator.cpp b/libraries/libvapours/source/crypto/crypto_sha256_generator.cpp new file mode 100644 index 000000000..41e963214 --- /dev/null +++ b/libraries/libvapours/source/crypto/crypto_sha256_generator.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#include + +namespace ams::crypto { + + void GenerateSha256Hash(void *dst, size_t dst_size, const void *src, size_t src_size) { + Sha256Generator gen; + + gen.Initialize(); + gen.Update(src, src_size); + gen.GetHash(dst, dst_size); + } + +} diff --git a/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.arm64.cpp b/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.arm64.cpp new file mode 100644 index 000000000..e68933354 --- /dev/null +++ b/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.arm64.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#include + +namespace ams::crypto::impl { + +#ifdef ATMOSPHERE_IS_STRATOSPHERE + + void Sha256Impl::Initialize() { + static_assert(sizeof(this->state) == sizeof(::Sha256Context)); + ::sha256ContextCreate(reinterpret_cast<::Sha256Context *>(std::addressof(this->state))); + } + + void Sha256Impl::Update(const void *data, size_t size) { + static_assert(sizeof(this->state) == sizeof(::Sha256Context)); + ::sha256ContextUpdate(reinterpret_cast<::Sha256Context *>(std::addressof(this->state)), data, size); + } + + void Sha256Impl::GetHash(void *dst, size_t size) { + static_assert(sizeof(this->state) == sizeof(::Sha256Context)); + AMS_ASSERT(size >= HashSize); + ::sha256ContextGetHash(reinterpret_cast<::Sha256Context *>(std::addressof(this->state)), dst); + } + +#else + + /* TODO: Non-EL0 implementation. */ + +#endif + +} \ No newline at end of file