File: Crypto.h

package info (click to toggle)
i2pd 2.58.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,612 kB
  • sloc: cpp: 59,663; makefile: 224; sh: 138
file content (278 lines) | stat: -rw-r--r-- 7,361 bytes parent folder | download
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/*
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/

#ifndef CRYPTO_H__
#define CRYPTO_H__

#include <inttypes.h>
#include <string>
#include <string_view>
#include <vector>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/aes.h>
#include <openssl/dsa.h>
#include <openssl/ecdsa.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/opensslv.h>

#include "Base.h"
#include "Tag.h"

// recognize openssl version and features
#if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL
#	define OPENSSL_SIPHASH 1
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0
#	define OPENSSL_PQ 1
#endif

namespace i2p
{
namespace crypto
{
	bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);

	// DSA
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
	EVP_PKEY * CreateDSA (BIGNUM * pubKey = nullptr, BIGNUM * privKey = nullptr);
#else
	DSA * CreateDSA ();
#endif	

	// RSA
	const BIGNUM * GetRSAE ();

	// x25519
	class X25519Keys
	{
		public:

			X25519Keys ();
			X25519Keys (const uint8_t * priv, const uint8_t * pub); // if pub is null, derive from priv
			~X25519Keys ();

			void GenerateKeys ();
			const uint8_t * GetPublicKey () const { return m_PublicKey; };
			void GetPrivateKey (uint8_t * priv) const;
			void SetPrivateKey (const uint8_t * priv, bool calculatePublic = false);
			bool Agree (const uint8_t * pub, uint8_t * shared);

			bool IsElligatorIneligible () const { return m_IsElligatorIneligible; }
			void SetElligatorIneligible () { m_IsElligatorIneligible = true; }

		private:

			uint8_t m_PublicKey[32];
			EVP_PKEY_CTX * m_Ctx;
			EVP_PKEY * m_Pkey;
			bool m_IsElligatorIneligible = false; // true if definitely ineligible
	};

	// ElGamal
	void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted
	bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data
	void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub);

	// ECIES
	void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted
	bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data
	void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);

	// AES
	typedef i2p::data::Tag<32> AESKey;
	
	class ECBEncryption
	{
		public:

			ECBEncryption ();
			~ECBEncryption ();
			
			void SetKey (const uint8_t * key) { m_Key = key; };
			void Encrypt(const uint8_t * in, uint8_t * out);

		private:

			AESKey m_Key;
			EVP_CIPHER_CTX * m_Ctx;	
	};

	class ECBDecryption
	{
		public:

			ECBDecryption ();
			~ECBDecryption ();
			
			void SetKey (const uint8_t * key) { m_Key = key; };
			void Decrypt (const uint8_t * in, uint8_t * out);
			
		private:
			
			AESKey m_Key;
			EVP_CIPHER_CTX * m_Ctx;	
	};

	class CBCEncryption
	{
		public:

			CBCEncryption ();
			~CBCEncryption ();

			void SetKey (const uint8_t * key) { m_Key = key; }; // 32 bytes		
			void Encrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out);
			
		private:

			AESKey m_Key;
			EVP_CIPHER_CTX * m_Ctx;	
	};

	class CBCDecryption
	{
		public:

			CBCDecryption ();
			~CBCDecryption ();
			
			void SetKey (const uint8_t * key) { m_Key = key; }; // 32 bytes
			void Decrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out);

		private:

			AESKey m_Key;
			EVP_CIPHER_CTX * m_Ctx;	
	};

	class TunnelEncryption // with double IV encryption
	{
		public:

			void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
			{
				m_LayerEncryption.SetKey (layerKey);
				m_IVEncryption.SetKey (ivKey);
			}

			void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)

		private:

			ECBEncryption m_IVEncryption;
			CBCEncryption m_LayerEncryption;
	};

	class TunnelDecryption // with double IV encryption
	{
		public:

			void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
			{
				m_LayerDecryption.SetKey (layerKey);
				m_IVDecryption.SetKey (ivKey);
			}

			void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)

		private:

			ECBDecryption m_IVDecryption;
			CBCDecryption m_LayerDecryption;
	};

// AEAD/ChaCha20/Poly1305

	class AEADChaCha20Poly1305Encryptor
	{
		public:

			AEADChaCha20Poly1305Encryptor ();
			~AEADChaCha20Poly1305Encryptor ();

			bool Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
				const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); // msgLen is len without tag

			void Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad
			
		private:

			EVP_CIPHER_CTX * m_Ctx;	
	};	

	class AEADChaCha20Poly1305Decryptor
	{
		public:

			AEADChaCha20Poly1305Decryptor ();
			~AEADChaCha20Poly1305Decryptor ();

			bool Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
				const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); // msgLen is len without tag
			
		private:

			EVP_CIPHER_CTX * m_Ctx;	
	};	
	
	bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
		const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag
	
// ChaCha20
	void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out);

	class ChaCha20Context
	{
		public:

			ChaCha20Context ();
			~ChaCha20Context ();
			void operator ()(const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out);
			
		private:

			EVP_CIPHER_CTX * m_Ctx;	
	};
	
// HKDF

	void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, std::string_view info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32

// Noise

	struct NoiseSymmetricState
	{
		uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/;
		uint64_t m_N;

		void Init (const uint8_t * ck, const uint8_t * hh, const uint8_t * pub);
		
		void MixHash (const uint8_t * buf, size_t len);
		void MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs);
		void MixKey (const uint8_t * sharedSecret);

		bool Encrypt (const uint8_t * in, uint8_t * out, size_t len); // out length = len + 16
		bool Decrypt (const uint8_t * in, uint8_t * out, size_t len); // len without 16 bytes tag
	};

	void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_N (tunnels, router)
	void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2)
	void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (SSU2)
	void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
	
// init and terminate
	void InitCrypto (bool precomputation);
	void TerminateCrypto ();
}
}

#endif