/src/serenity/Userland/Libraries/LibCrypto/Cipher/AES.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org> |
3 | | * Copyright (c) 2022, the SerenityOS developers. |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #pragma once |
9 | | |
10 | | #include <AK/CPUFeatures.h> |
11 | | #include <AK/Vector.h> |
12 | | #include <LibCrypto/Cipher/Cipher.h> |
13 | | #include <LibCrypto/Cipher/Mode/CBC.h> |
14 | | #include <LibCrypto/Cipher/Mode/CTR.h> |
15 | | #include <LibCrypto/Cipher/Mode/GCM.h> |
16 | | |
17 | | #ifndef KERNEL |
18 | | # include <AK/ByteString.h> |
19 | | #endif |
20 | | |
21 | | namespace Crypto::Cipher { |
22 | | |
23 | | struct AESCipherBlock : public CipherBlock { |
24 | | public: |
25 | | static constexpr size_t BlockSizeInBits = 128; |
26 | | |
27 | | explicit AESCipherBlock(PaddingMode mode = PaddingMode::CMS) |
28 | 0 | : CipherBlock(mode) |
29 | 0 | { |
30 | 0 | } |
31 | | AESCipherBlock(u8 const* data, size_t length, PaddingMode mode = PaddingMode::CMS) |
32 | | : AESCipherBlock(mode) |
33 | 0 | { |
34 | 0 | CipherBlock::overwrite(data, length); |
35 | 0 | } |
36 | | |
37 | 0 | constexpr static size_t block_size() { return BlockSizeInBits / 8; } |
38 | | |
39 | 0 | virtual ReadonlyBytes bytes() const override { return ReadonlyBytes { m_data, sizeof(m_data) }; } |
40 | 0 | virtual Bytes bytes() override { return Bytes { m_data, sizeof(m_data) }; } |
41 | | |
42 | | virtual void overwrite(ReadonlyBytes) override; |
43 | 0 | virtual void overwrite(u8 const* data, size_t size) override { overwrite({ data, size }); } |
44 | | |
45 | | virtual void apply_initialization_vector(ReadonlyBytes ivec) override |
46 | 0 | { |
47 | 0 | for (size_t i = 0; i < min(block_size(), ivec.size()); ++i) |
48 | 0 | m_data[i] ^= ivec[i]; |
49 | 0 | } |
50 | | |
51 | | #ifndef KERNEL |
52 | | ByteString to_byte_string() const; |
53 | | #endif |
54 | | |
55 | | private: |
56 | 0 | constexpr static size_t data_size() { return sizeof(m_data); } |
57 | | |
58 | | u8 m_data[BlockSizeInBits / 8] {}; |
59 | | }; |
60 | | |
61 | | struct AESCipherKey : public CipherKey { |
62 | 0 | virtual ReadonlyBytes bytes() const override { return ReadonlyBytes { m_rd_keys, sizeof(m_rd_keys) }; } |
63 | 0 | virtual void expand_encrypt_key(ReadonlyBytes user_key, size_t bits) override { return (this->*expand_encrypt_key_dispatched)(user_key, bits); } |
64 | 0 | virtual void expand_decrypt_key(ReadonlyBytes user_key, size_t bits) override { return (this->*expand_decrypt_key_dispatched)(user_key, bits); } |
65 | 0 | static bool is_valid_key_size(size_t bits) { return bits == 128 || bits == 192 || bits == 256; } |
66 | | |
67 | | #ifndef KERNEL |
68 | | ByteString to_byte_string() const; |
69 | | #endif |
70 | | |
71 | | u32 const* round_keys() const |
72 | 0 | { |
73 | 0 | return (u32 const*)m_rd_keys; |
74 | 0 | } |
75 | | |
76 | | AESCipherKey(ReadonlyBytes user_key, size_t key_bits, Intent intent) |
77 | 0 | : m_bits(key_bits) |
78 | 0 | { |
79 | 0 | if (intent == Intent::Encryption) |
80 | 0 | expand_encrypt_key(user_key, key_bits); |
81 | 0 | else |
82 | 0 | expand_decrypt_key(user_key, key_bits); |
83 | 0 | } |
84 | | |
85 | | virtual ~AESCipherKey() override = default; |
86 | | |
87 | 0 | size_t rounds() const { return m_rounds; } |
88 | 0 | size_t length() const { return m_bits / 8; } |
89 | | |
90 | | protected: |
91 | | u32* round_keys() |
92 | 0 | { |
93 | 0 | return (u32*)m_rd_keys; |
94 | 0 | } |
95 | | |
96 | | private: |
97 | | template<CPUFeatures> |
98 | | void expand_encrypt_key_impl(ReadonlyBytes user_key, size_t bits); |
99 | | template<CPUFeatures> |
100 | | void expand_decrypt_key_impl(ReadonlyBytes user_key, size_t bits); |
101 | | |
102 | | static void (AESCipherKey::* const expand_encrypt_key_dispatched)(ReadonlyBytes user_key, size_t bits); |
103 | | static void (AESCipherKey::* const expand_decrypt_key_dispatched)(ReadonlyBytes user_key, size_t bits); |
104 | | |
105 | | static constexpr size_t MAX_ROUND_COUNT = 14; |
106 | | u32 m_rd_keys[(MAX_ROUND_COUNT + 1) * 4] { 0 }; |
107 | | size_t m_rounds; |
108 | | size_t m_bits; |
109 | | }; |
110 | | |
111 | | class AESCipher final : public Cipher<AESCipherKey, AESCipherBlock> { |
112 | | public: |
113 | | using CBCMode = CBC<AESCipher>; |
114 | | using CTRMode = CTR<AESCipher>; |
115 | | using GCMMode = GCM<AESCipher>; |
116 | | |
117 | | constexpr static size_t BlockSizeInBits = BlockType::BlockSizeInBits; |
118 | | |
119 | | AESCipher(ReadonlyBytes user_key, size_t key_bits, Intent intent = Intent::Encryption, PaddingMode mode = PaddingMode::CMS) |
120 | 0 | : Cipher<AESCipherKey, AESCipherBlock>(mode) |
121 | 0 | , m_key(user_key, key_bits, intent) |
122 | 0 | { |
123 | 0 | } |
124 | | |
125 | 0 | virtual AESCipherKey const& key() const override { return m_key; } |
126 | 0 | virtual AESCipherKey& key() override { return m_key; } |
127 | | |
128 | 0 | virtual void encrypt_block(BlockType const& in, BlockType& out) override { return (this->*encrypt_block_dispatched)(in, out); } |
129 | 0 | virtual void decrypt_block(BlockType const& in, BlockType& out) override { return (this->*decrypt_block_dispatched)(in, out); } |
130 | | |
131 | | #ifndef KERNEL |
132 | | virtual ByteString class_name() const override |
133 | 0 | { |
134 | 0 | return "AES"; |
135 | 0 | } |
136 | | #endif |
137 | | |
138 | | protected: |
139 | | AESCipherKey m_key; |
140 | | |
141 | | private: |
142 | | template<CPUFeatures> |
143 | | void encrypt_block_impl(BlockType const& in, BlockType& out); |
144 | | template<CPUFeatures> |
145 | | void decrypt_block_impl(BlockType const& in, BlockType& out); |
146 | | |
147 | | static void (AESCipher::* const encrypt_block_dispatched)(BlockType const& in, BlockType& out); |
148 | | static void (AESCipher::* const decrypt_block_dispatched)(BlockType const& in, BlockType& out); |
149 | | }; |
150 | | |
151 | | } |