summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibCrypto/Cipher/AES.h
blob: 796c653167964bf67e2631bbeae84c3fdd26c2b3 (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
/*
 * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
 *
 * 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(const u8* 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(const u8* 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

    const u32* round_keys() const
    {
        return (const u32*)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 { }

    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 const AESCipherKey& key() const override { return m_key; };
    virtual AESCipherKey& key() override { return m_key; };

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

    virtual String class_name() const override { return "AES"; }

protected:
    AESCipherKey m_key;
};

}
}