summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibCrypto/Cipher/AES.h
blob: 4aa94bf6ddb0a077877afd21bc539df31012d0f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
 * Copyright (c) 2022, the SerenityOS developers.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Vector.h>
#include <LibCrypto/Cipher/Cipher.h>
#include <LibCrypto/Cipher/Mode/CBC.h>
#include <LibCrypto/Cipher/Mode/CTR.h>
#include <LibCrypto/Cipher/Mode/GCM.h>

#ifndef KERNEL
#    include <AK/String.h>
#endif

namespace Crypto {
namespace Cipher {

struct AESCipherBlock : public CipherBlock {
public:
    static constexpr size_t BlockSizeInBits = 128;

    explicit AESCipherBlock(PaddingMode mode = PaddingMode::CMS)
        : CipherBlock(mode)
    {
    }
    AESCipherBlock(u8 const* data, size_t length, PaddingMode mode = PaddingMode::CMS)
        : AESCipherBlock(mode)
    {
        CipherBlock::overwrite(data, length);
    }

    constexpr static size_t block_size() { return BlockSizeInBits / 8; };

    virtual ReadonlyBytes bytes() const override { return ReadonlyBytes { m_data, sizeof(m_data) }; }
    virtual Bytes bytes() override { return Bytes { m_data, sizeof(m_data) }; }

    virtual void overwrite(ReadonlyBytes) override;
    virtual void overwrite(u8 const* data, size_t size) override { overwrite({ data, size }); }

    virtual void apply_initialization_vector(ReadonlyBytes ivec) override
    {
        for (size_t i = 0; i < min(block_size(), ivec.size()); ++i)
            m_data[i] ^= ivec[i];
    }

#ifndef KERNEL
    String to_string() const;
#endif

private:
    constexpr static size_t data_size() { return sizeof(m_data); }

    u8 m_data[BlockSizeInBits / 8] {};
};

struct AESCipherKey : public CipherKey {
    virtual ReadonlyBytes bytes() const override { return ReadonlyBytes { m_rd_keys, sizeof(m_rd_keys) }; };
    virtual void expand_encrypt_key(ReadonlyBytes user_key, size_t bits) override;
    virtual void expand_decrypt_key(ReadonlyBytes user_key, size_t bits) override;
    static bool is_valid_key_size(size_t bits) { return bits == 128 || bits == 192 || bits == 256; };

#ifndef KERNEL
    String to_string() const;
#endif

    u32 const* round_keys() const
    {
        return (u32 const*)m_rd_keys;
    }

    AESCipherKey(ReadonlyBytes user_key, size_t key_bits, Intent intent)
        : m_bits(key_bits)
    {
        if (intent == Intent::Encryption)
            expand_encrypt_key(user_key, key_bits);
        else
            expand_decrypt_key(user_key, key_bits);
    }

    virtual ~AESCipherKey() override = default;

    size_t rounds() const { return m_rounds; }
    size_t length() const { return m_bits / 8; }

protected:
    u32* round_keys()
    {
        return (u32*)m_rd_keys;
    }

private:
    static constexpr size_t MAX_ROUND_COUNT = 14;
    u32 m_rd_keys[(MAX_ROUND_COUNT + 1) * 4] { 0 };
    size_t m_rounds;
    size_t m_bits;
};

class AESCipher final : public Cipher<AESCipherKey, AESCipherBlock> {
public:
    using CBCMode = CBC<AESCipher>;
    using CTRMode = CTR<AESCipher>;
    using GCMMode = GCM<AESCipher>;

    constexpr static size_t BlockSizeInBits = BlockType::BlockSizeInBits;

    AESCipher(ReadonlyBytes user_key, size_t key_bits, Intent intent = Intent::Encryption, PaddingMode mode = PaddingMode::CMS)
        : Cipher<AESCipherKey, AESCipherBlock>(mode)
        , m_key(user_key, key_bits, intent)
    {
    }

    virtual AESCipherKey const& key() const override { return m_key; };
    virtual AESCipherKey& key() override { return m_key; };

    virtual void encrypt_block(BlockType const& in, BlockType& out) override;
    virtual void decrypt_block(BlockType const& in, BlockType& out) override;

#ifndef KERNEL
    virtual String class_name() const override
    {
        return "AES";
    }
#endif

protected:
    AESCipherKey m_key;
};

}
}