/ libi2pd / PostQuantum.cpp
PostQuantum.cpp
  1  /*
  2  * Copyright (c) 2025, The PurpleI2P Project
  3  *
  4  * This file is part of Purple i2pd project and licensed under BSD3
  5  *
  6  * See full license text in LICENSE file at top of project tree
  7  */
  8  
  9  #include "Log.h"
 10  #include "PostQuantum.h"
 11  
 12  #if OPENSSL_PQ
 13  
 14  #include <openssl/param_build.h>
 15  #include <openssl/core_names.h>
 16  
 17  namespace i2p
 18  {
 19  namespace crypto
 20  {
 21  	MLKEMKeys::MLKEMKeys (MLKEMTypes type):
 22  		m_Name (std::get<0>(MLKEMS[type])), m_KeyLen (std::get<1>(MLKEMS[type])), 
 23  		m_CTLen (std::get<2>(MLKEMS[type])), m_Pkey (nullptr)
 24  	{
 25  	}
 26  	
 27  	MLKEMKeys::~MLKEMKeys ()
 28  	{
 29  		if (m_Pkey) EVP_PKEY_free (m_Pkey);
 30  	}	
 31  
 32  	void MLKEMKeys::GenerateKeys ()
 33  	{
 34  		if (m_Pkey) EVP_PKEY_free (m_Pkey);
 35  		m_Pkey = EVP_PKEY_Q_keygen(NULL, NULL, m_Name.c_str ());
 36  	}
 37  
 38  	void MLKEMKeys::GetPublicKey (uint8_t * pub) const
 39  	{	
 40  		if (m_Pkey)
 41  		{	
 42  			size_t len = m_KeyLen;
 43  		    EVP_PKEY_get_octet_string_param (m_Pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, m_KeyLen, &len);
 44  		}	
 45  	}
 46  
 47  	void MLKEMKeys::SetPublicKey (const uint8_t * pub)
 48  	{
 49  		if (m_Pkey)
 50  		{	
 51  			EVP_PKEY_free (m_Pkey);
 52  			m_Pkey = nullptr;
 53  		}	
 54  		OSSL_PARAM params[] =
 55  		{
 56  			OSSL_PARAM_octet_string (OSSL_PKEY_PARAM_PUB_KEY, (uint8_t *)pub, m_KeyLen),
 57  			OSSL_PARAM_END
 58  		};		
 59  		EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, m_Name.c_str (), NULL);
 60  		if (ctx)
 61  		{
 62  			EVP_PKEY_fromdata_init (ctx);
 63  			EVP_PKEY_fromdata (ctx, &m_Pkey, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, params);
 64  			EVP_PKEY_CTX_free (ctx);
 65  		}
 66  		else
 67  			LogPrint (eLogError, "MLKEM can't create PKEY context");
 68  	}
 69  
 70  	void MLKEMKeys::Encaps (uint8_t * ciphertext, uint8_t * shared)
 71  	{
 72  		if (!m_Pkey) return;
 73  		auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL);
 74  		if (ctx)
 75  		{	
 76  			EVP_PKEY_encapsulate_init (ctx, NULL);
 77  			size_t len = m_CTLen, sharedLen = 32;
 78  			EVP_PKEY_encapsulate (ctx, ciphertext, &len, shared, &sharedLen);
 79  			EVP_PKEY_CTX_free (ctx);
 80  		}
 81  		else
 82  			LogPrint (eLogError, "MLKEM can't create PKEY context");
 83  	}	
 84  
 85  	void MLKEMKeys::Decaps (const uint8_t * ciphertext, uint8_t * shared)
 86  	{
 87  		if (!m_Pkey) return;
 88  		auto ctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL);
 89  		if (ctx)
 90  		{	
 91  			EVP_PKEY_decapsulate_init (ctx, NULL);
 92  			size_t sharedLen = 32;
 93  			EVP_PKEY_decapsulate (ctx, shared, &sharedLen, ciphertext, m_CTLen);
 94  			EVP_PKEY_CTX_free (ctx);
 95  		}
 96  		else
 97  			LogPrint (eLogError, "MLKEM can't create PKEY context");
 98  	}	
 99  
100  	std::unique_ptr<MLKEMKeys> CreateMLKEMKeys (i2p::data::CryptoKeyType type)
101  	{
102  		if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ||
103  		    type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)MLKEMS.size ()) return nullptr;
104  		return std::make_unique<MLKEMKeys>((MLKEMTypes)(type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1));
105  	}	
106  
107  	static constexpr std::array NoiseIKInitMLKEMKeys =
108  	{
109  		std::make_pair
110  		(
111  			std::array<uint8_t, 32>
112  		 	{
113  				0xb0, 0x8f, 0xb1, 0x73, 0x92, 0x66, 0xc9, 0x90, 0x45, 0x7f, 0xdd, 0xc6, 0x4e, 0x55, 0x40, 0xd8, 
114  				0x0a, 0x37, 0x99, 0x06, 0x92, 0x2a, 0x78, 0xc4, 0xb1, 0xef, 0x86, 0x06, 0xd0, 0x15, 0x9f, 0x4d
115  			}, // SHA256("Noise_IKhfselg2_25519+MLKEM512_ChaChaPoly_SHA256")
116  			std::array<uint8_t, 32>
117  		 	{
118  				0x95, 0x8d, 0xf6, 0x6c, 0x95, 0xce, 0xa9, 0xf7, 0x42, 0xfc, 0xfa, 0x62, 0x71, 0x36, 0x1e, 0xa7,
119  				0xdc, 0x7a, 0xc0, 0x75, 0x01, 0xcf, 0xf9, 0xfc, 0x9f, 0xdb, 0x4c, 0x68, 0x3a, 0x53, 0x49, 0xeb
120  			} // SHA256 (first)
121  		),
122  		std::make_pair
123  		(
124  			std::array<uint8_t, 32>
125  		 	{
126  				0x36, 0x03, 0x90, 0x2d, 0xf9, 0xa2, 0x2a, 0x5e, 0xc9, 0x3d, 0xdb, 0x8f, 0xa8, 0x1b, 0xdb, 0x4b,
127  				0xae, 0x9d, 0x93, 0x9c, 0xdf, 0xaf, 0xde, 0x55, 0x49, 0x13, 0xfe, 0x98, 0xf8, 0x4a, 0xd4, 0xbd
128  			}, // SHA256("Noise_IKhfselg2_25519+MLKEM768_ChaChaPoly_SHA256")
129  		 	std::array<uint8_t, 32>
130  		 	{
131  				0x15, 0x44, 0x89, 0xbf, 0x30, 0xf0, 0xc9, 0x77, 0x66, 0x10, 0xcb, 0xb1, 0x57, 0x3f, 0xab, 0x68,
132  				0x79, 0x57, 0x39, 0x57, 0x0a, 0xe7, 0xc0, 0x31, 0x8a, 0xa2, 0x96, 0xef, 0xbf, 0xa9, 0x6a, 0xbb
133  			} // SHA256 (first)
134  		),
135  		std::make_pair
136  		(
137  			std::array<uint8_t, 32>
138  		 	{
139  				0x86, 0xa5, 0x36, 0x44, 0xc6, 0x12, 0xd5, 0x71, 0xa1, 0x2d, 0xd8, 0xb6, 0x0a, 0x00, 0x9f, 0x2c,
140  				0x1a, 0xa8, 0x7d, 0x22, 0xa4, 0xff, 0x2b, 0xcd, 0x61, 0x34, 0x97, 0x6d, 0xa1, 0x49, 0xeb, 0x4a
141  			}, // SHA256("Noise_IKhfselg2_25519+MLKEM1024_ChaChaPoly_SHA256")
142  		 	std::array<uint8_t, 32>
143  		 	{
144  				0x42, 0x0d, 0xc2, 0x1c, 0x7b, 0x18, 0x61, 0xb7, 0x4a, 0x04, 0x3d, 0xae, 0x0f, 0xdc, 0xf2, 0x71,
145  				0xb9, 0xba, 0x19, 0xbb, 0xbd, 0x5f, 0xd4, 0x9c, 0x3f, 0x4b, 0x01, 0xed, 0x6d, 0x13, 0x1d, 0xa2
146  			} // SHA256 (first)
147  		)
148  	};
149  		
150  	void InitNoiseIKStateMLKEM (NoiseSymmetricState& state, i2p::data::CryptoKeyType type, const uint8_t * pub)
151  	{
152  		if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ||
153  		    type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)NoiseIKInitMLKEMKeys.size ()) return;
154  		auto ind = type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1;
155  		state.Init (NoiseIKInitMLKEMKeys[ind].first.data(), NoiseIKInitMLKEMKeys[ind].second.data(), pub);
156  	}
157  
158  	static constexpr std::array NoiseXKInitMLKEMKeys =
159  	{
160  		std::make_pair
161  		(
162  			std::array<uint8_t, 32>
163  		 	{
164  				0xf9, 0x9f, 0x6c, 0x60, 0xea, 0x06, 0x78, 0x7f, 0x8d, 0xc2, 0x3f, 0xa3, 0xe9, 0xf7, 0xc0, 0xa5,
165  				0x34, 0x77, 0x10, 0xc1, 0x1d, 0x99, 0xe0, 0xe9, 0x9c, 0xe3, 0x90, 0x2b, 0x92, 0x32, 0x07, 0x20
166  			}, // SHA256("Noise_XKhfsaesobfse+hs2+hs3_25519+MLKEM512_ChaChaPoly_SHA256")
167  			std::array<uint8_t, 32>
168  		 	{
169  				0x6a, 0xc4, 0x2c, 0xd8, 0x31, 0xeb, 0xd3, 0x0c, 0xdf, 0x90, 0x2e, 0x67, 0xf4, 0x66, 0x39, 0xab,
170  				0x85, 0xcf, 0xac, 0x0f, 0x77, 0xba, 0x79, 0x58, 0x61, 0xe9, 0x56, 0x97, 0x44, 0x99, 0xad, 0xe1
171  			} // SHA256 (first)
172  		),
173  		std::make_pair
174  		(
175  			std::array<uint8_t, 32>
176  		 	{
177  				0xb9, 0xc3, 0x44, 0x56, 0x11, 0xcc, 0x80, 0xec, 0xca, 0x15, 0xde, 0x37, 0xa4, 0x1a, 0xb6, 0xc6,
178  				0xfb, 0x59, 0xdb, 0x83, 0xeb, 0x1e, 0x9d, 0x7e, 0x27, 0x63, 0xa8, 0xa5, 0x34, 0xec, 0x53, 0xd1
179  			}, // SHA256("Noise_XKhfsaesobfse+hs2+hs3_25519+MLKEM768_ChaChaPoly_SHA256")
180  			std::array<uint8_t, 32>
181  		 	{
182  				0x0b, 0xcd, 0x38, 0xaf, 0xcf, 0xb7, 0xaa, 0xeb, 0x25, 0x73, 0xb8, 0x4f, 0x74, 0x83, 0x02, 0x94,
183  				0x8b, 0x53, 0xf5, 0x42, 0xce, 0x3f, 0x23, 0xdc, 0xcc, 0x9a, 0xe9, 0xb0, 0x21, 0xab, 0x48, 0xff
184  			} // SHA256 (first)
185  		),
186  		std::make_pair
187  		(
188  			std::array<uint8_t, 32>
189  		 	{
190  				0x97, 0xe6, 0x8d, 0x27, 0x49, 0x41, 0x50, 0xea, 0x80, 0x54, 0x8e, 0x73, 0x04, 0x45, 0x3f, 0x61,
191  				0x29, 0xbc, 0x07, 0x8b, 0x14, 0x05, 0x13, 0xbe, 0x9a, 0x55, 0xb2, 0x07, 0xa2, 0xda, 0x37, 0x0c
192  			}, // SHA256("Noise_XKhfsaesobfse+hs2+hs3_25519+MLKEM1024_ChaChaPoly_SHA256")
193  			std::array<uint8_t, 32>
194  		 	{
195  				0x59, 0x50, 0x1a, 0x59, 0x87, 0x82, 0x65, 0x55, 0x58, 0x09, 0x9b, 0xec, 0xab, 0x2a, 0x64, 0x1d,
196  				0xf1, 0x7b, 0xca, 0xe7, 0xb3, 0x5d, 0x6d, 0xa7, 0x8c, 0x6e, 0x79, 0x7e, 0xab, 0xf3, 0x57, 0x3f
197  			} // SHA256 (first)
198  		)
199  	};
200  
201  	void InitNoiseXKStateMLKEM (NoiseSymmetricState& state, i2p::data::CryptoKeyType type, const uint8_t * pub)
202  	{
203  		if (type <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ||
204  		    type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD > (int)NoiseXKInitMLKEMKeys.size ()) return;
205  		auto ind = type - i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD - 1;
206  		state.Init (NoiseXKInitMLKEMKeys[ind].first.data(), NoiseXKInitMLKEMKeys[ind].second.data(), pub);
207  	}	
208  }	
209  }	
210  
211  #endif