@@ -4727,6 +4727,145 @@ size_t Dsa::getDivisorLength() const {
47274727}
47284728} // namespace ncrypto
47294729
4730+ // ============================================================================
4731+
4732+ size_t Digest::size () const {
4733+ if (md_ == nullptr ) return 0 ;
4734+ return EVP_MD_size (md_);
4735+ }
4736+
4737+ const Digest Digest::MD5 = Digest (EVP_md5 ());
4738+ const Digest Digest::SHA1 = Digest (EVP_sha1 ());
4739+ const Digest Digest::SHA256 = Digest (EVP_sha256 ());
4740+ const Digest Digest::SHA384 = Digest (EVP_sha384 ());
4741+ const Digest Digest::SHA512 = Digest (EVP_sha512 ());
4742+
4743+ const Digest Digest::FromName (const char * name) {
4744+ return ncrypto::getDigestByName (name);
4745+ }
4746+
4747+ // ============================================================================
4748+ // KEM Implementation
4749+ #if OPENSSL_VERSION_MAJOR >= 3
4750+ #if !OPENSSL_VERSION_PREREQ(3, 5)
4751+ bool KEM::SetOperationParameter (EVP_PKEY_CTX* ctx, const EVPKeyPointer& key) {
4752+ const char * operation = nullptr ;
4753+
4754+ switch (EVP_PKEY_id (key.get ())) {
4755+ case EVP_PKEY_RSA:
4756+ operation = OSSL_KEM_PARAM_OPERATION_RSASVE;
4757+ break ;
4758+ #if OPENSSL_VERSION_PREREQ(3, 2)
4759+ case EVP_PKEY_EC:
4760+ case EVP_PKEY_X25519:
4761+ case EVP_PKEY_X448:
4762+ operation = OSSL_KEM_PARAM_OPERATION_DHKEM;
4763+ break ;
4764+ #endif
4765+ default :
4766+ unreachable ();
4767+ }
4768+
4769+ if (operation != nullptr ) {
4770+ OSSL_PARAM params[] = {
4771+ OSSL_PARAM_utf8_string (
4772+ OSSL_KEM_PARAM_OPERATION, const_cast <char *>(operation), 0 ),
4773+ OSSL_PARAM_END};
4774+
4775+ if (EVP_PKEY_CTX_set_params (ctx, params) <= 0 ) {
4776+ return false ;
4777+ }
4778+ }
4779+
4780+ return true ;
4781+ }
4782+ #endif
4783+
4784+ std::optional<KEM::EncapsulateResult> KEM::Encapsulate (
4785+ const EVPKeyPointer& public_key) {
4786+ ClearErrorOnReturn clear_error_on_return;
4787+
4788+ auto ctx = public_key.newCtx ();
4789+ if (!ctx) return std::nullopt ;
4790+
4791+ if (EVP_PKEY_encapsulate_init (ctx.get (), nullptr ) <= 0 ) {
4792+ return std::nullopt ;
4793+ }
4794+
4795+ #if !OPENSSL_VERSION_PREREQ(3, 5)
4796+ if (!SetOperationParameter (ctx.get (), public_key)) {
4797+ return std::nullopt ;
4798+ }
4799+ #endif
4800+
4801+ // Determine output buffer sizes
4802+ size_t ciphertext_len = 0 ;
4803+ size_t shared_key_len = 0 ;
4804+
4805+ if (EVP_PKEY_encapsulate (
4806+ ctx.get (), nullptr , &ciphertext_len, nullptr , &shared_key_len) <= 0 ) {
4807+ return std::nullopt ;
4808+ }
4809+
4810+ auto ciphertext = DataPointer::Alloc (ciphertext_len);
4811+ auto shared_key = DataPointer::Alloc (shared_key_len);
4812+ if (!ciphertext || !shared_key) return std::nullopt ;
4813+
4814+ if (EVP_PKEY_encapsulate (ctx.get (),
4815+ static_cast <unsigned char *>(ciphertext.get ()),
4816+ &ciphertext_len,
4817+ static_cast <unsigned char *>(shared_key.get ()),
4818+ &shared_key_len) <= 0 ) {
4819+ return std::nullopt ;
4820+ }
4821+
4822+ return EncapsulateResult (std::move (ciphertext), std::move (shared_key));
4823+ }
4824+
4825+ DataPointer KEM::Decapsulate (const EVPKeyPointer& private_key,
4826+ const Buffer<const void >& ciphertext) {
4827+ ClearErrorOnReturn clear_error_on_return;
4828+
4829+ auto ctx = private_key.newCtx ();
4830+ if (!ctx) return {};
4831+
4832+ if (EVP_PKEY_decapsulate_init (ctx.get (), nullptr ) <= 0 ) {
4833+ return {};
4834+ }
4835+
4836+ #if !OPENSSL_VERSION_PREREQ(3, 5)
4837+ if (!SetOperationParameter (ctx.get (), private_key)) {
4838+ return {};
4839+ }
4840+ #endif
4841+
4842+ // First pass: determine shared secret size
4843+ size_t shared_key_len = 0 ;
4844+ if (EVP_PKEY_decapsulate (ctx.get (),
4845+ nullptr ,
4846+ &shared_key_len,
4847+ static_cast <const unsigned char *>(ciphertext.data ),
4848+ ciphertext.len ) <= 0 ) {
4849+ return {};
4850+ }
4851+
4852+ auto shared_key = DataPointer::Alloc (shared_key_len);
4853+ if (!shared_key) return {};
4854+
4855+ if (EVP_PKEY_decapsulate (ctx.get (),
4856+ static_cast <unsigned char *>(shared_key.get ()),
4857+ &shared_key_len,
4858+ static_cast <const unsigned char *>(ciphertext.data ),
4859+ ciphertext.len ) <= 0 ) {
4860+ return {};
4861+ }
4862+
4863+ return shared_key;
4864+ }
4865+
4866+ #endif // OPENSSL_VERSION_MAJOR >= 3
4867+
4868+ } // namespace ncrypto
47304869// ===========================================================================
47314870#ifdef NCRYPTO_BSSL_NEEDS_DH_PRIMES
47324871// While newer versions of BoringSSL have these primes, older versions do not,
0 commit comments