aboutsummaryrefslogtreecommitdiff
path: root/src/cryptography/noscrypt_cipher.hpp
blob: 04bdbf2623e6dd81f1b30941b8ff2b413fe2c21b (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#pragma once

#include <memory>

#include <noscrypt.h>
#include <noscryptutil.h>
#include "../internal/noscrypt_logger.hpp"

namespace nostr
{
namespace cryptography
{

enum NoscryptCipherMode : uint32_t
{
    CIPHER_MODE_ENCRYPT = NC_UTIL_CIPHER_MODE_ENCRYPT,
    CIPHER_MODE_DECRYPT = NC_UTIL_CIPHER_MODE_DECRYPT,
};
  
enum NoscryptCipherVersion : uint32_t
{
	NIP04 = NC_ENC_VERSION_NIP04,
	NIP44 = NC_ENC_VERSION_NIP44,
};

class NoscryptCipherContext
{
private:
    NCUtilCipherContext* _cipher;

public:

    NoscryptCipherContext(NoscryptCipherVersion version, NoscryptCipherMode mode)
    {
        /*
        * Create a new cipher context with the specified
        * version and mode that will live for the duration of the
        * instance.
        *
        * The user is expected to use the noscryptutil mode for
        * setting encryption/decryption modes.
        *
        * The cipher will zero out the memory when it is freed.
        *
        * For decryption, by default the mac is verified before
        * decryption occurs.
        *
        * NOTE: The ciper is set to reusable mode, so encrypt/decrypt
        * can be called multiple times although it's not recommended,
        * its just the more predictable way for users to handle it.
        */

        _cipher = NCUtilCipherAlloc(
            (uint32_t)version,
            ((uint32_t)mode) | NC_UTIL_CIPHER_ZERO_ON_FREE | NC_UTIL_CIPHER_REUSEABLE
        );

    //TODO, may fail to allocate memory.
    }

    ~NoscryptCipherContext()
    {
        //Free the cipher context (will also zero any data/pointers)
        NCUtilCipherFree(_cipher);
    }

    NCResult update(
        const std::shared_ptr<const NCContext> libContext,
        const std::shared_ptr<const NCSecretKey> localKey,
        const std::shared_ptr<const NCPublicKey> remoteKey
    ) const
    {
        return NCUtilCipherUpdate(_cipher, libContext.get(), localKey.get(), remoteKey.get());
    }

    NCResult setIV(std::vector<uint8_t>& iv) const
    {
        return NCUtilCipherSetProperty(_cipher, NC_ENC_SET_IV, iv.data(), (uint32_t)iv.size());
    }

    size_t ivSize() const
    {
        NCResult size = NCUtilCipherGetIvSize(_cipher);

        if (size <= 0)
        {
            //TODO Implement error handling
            return 0;
        }

        return size;
    }

    NCResult outputSize() const
    {
        return NCUtilCipherGetOutputSize(_cipher);
    }

    uint32_t flags() const
    {
        NCResult result = NCUtilCipherGetFlags(_cipher);

        if (result <= 0)
        {
            //TODO Implement error handling
            return 0;
        }

        return (uint32_t)result;
    }

    NoscryptCipherMode mode() const
    {
		//Mode bit is lsb so just mask off the rest of the flags and convert back to enum
		return (NoscryptCipherMode)(flags() & NC_UTIL_CIPHER_MODE);
    }

    NCResult readOutput(std::vector<uint8_t>& output) const
    {
        return NCUtilCipherReadOutput(_cipher, output.data(), (uint32_t)output.size());
    }

    NCResult setInput(const std::vector<uint8_t>& input) const
    {
        /*
        * Assign and validate input string. Init can be only called multiple times
        * without side effects when the reusable flag is set. (currently set)
        */

        return NCUtilCipherInit(_cipher, input.data(), input.size());
    }
};

class NoscryptCipher
{

private:
    const NoscryptCipherContext _cipher;
    /*
     * Stores the initialziation vector (aka nonce for nip44) for the cipher.
     * Noscrypt needs a memory buffer to store the iv, as it only holds pointers.
     * 
     * This buffer must always point to valid memory after the cipher is created.
     */
    std::vector<uint8_t> _ivBuffer;

public:
    NoscryptCipher(NoscryptCipherVersion version, NoscryptCipherMode mode);

    /*
     * @brief Performs the cipher operation on the input data. Depending on the mode
     * the cipher was initialized as, this will either encrypt or decrypt the data.
     * @param libContext The noscrypt library context.
     * @param localKey The local secret key used to encrypt/decrypt the data.
     * @param remoteKey The remote public key used to encrypt/decrypt the data.
     * @param input The data to encrypt/decrypt.
     * @returns The opposite of the input data.
     * @remark This cipher function follows the nostr nips format and will use do it's
     * best to
     */
    std::string update(
        const std::shared_ptr<const NCContext> libContext,
        const std::shared_ptr<const NCSecretKey> localKey,
        const std::shared_ptr<const NCPublicKey> remoteKey,
        const std::string& input
    );

    /**
     * @brief Computes the length of a base64 encoded string.
     * @param n The length of the string to be encoded.
     * @return The length of the resulting base64 encoded string.
     */
    inline static size_t base64EncodedSize(const size_t n)
    {
        return (((n + 2) / 3) << 2) + 1;
    };

    /**
     * @brief Computes the length of a string decoded from base64.
     * @param n The length of the base64 encoded string.
     * @return The length of the decoded string.
     */
    inline static size_t base64DecodedSize(const size_t n)
    {
        return (n * 3) >> 2;
    };

    static std::string naiveEncodeBase64(const std::string& str);

    static std::string naiveDecodeBase64(const std::string& str);
};
} // namespace cryptography
} // namespace nostr