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