Skip to content

Commit 95d0848

Browse files
committed
ssh: MLKEM kex ssh
1 parent 77e986d commit 95d0848

8 files changed

Lines changed: 209 additions & 27 deletions

lib/ssh/src/ssh.hrl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ to run any subsystems.
174174
'ecdh-sha2-nistp256' |
175175
'ecdh-sha2-nistp384' |
176176
'ecdh-sha2-nistp521' |
177+
'mlkem768x25519-sha256' |
177178
legacy_kex_alg().
178179

179180
-doc(#{group => <<"Legacy Algorithms">>}).

lib/ssh/src/ssh_connection_handler.erl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,8 @@ set_kex_overload_prefix(Msg = <<?BYTE(Op),_/binary>>, #data{ssh_params=SshParams
16691669
<<"dh_gex",Msg/binary>>;
16701670
"diffie-hellman-group" ++ _ ->
16711671
<<"dh",Msg/binary>>;
1672+
"mlkem768x25519" ++ _ ->
1673+
<<"mlkem",Msg/binary>>;
16721674
_ ->
16731675
Msg
16741676
end;

lib/ssh/src/ssh_fsm_kexinit.erl

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,25 @@ handle_event(internal, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReN
140140
ssh_connection_handler:send_bytes(ExtInfo, D),
141141
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
142142

143+
%%%---- PQ/T Hybrid Key Exchange Method
144+
handle_event(internal, #ssh_msg_kex_hybrid_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
145+
ok = check_kex_strict(Msg, D),
146+
{ok, KexHybridReply, Ssh1} = ssh_transport:handle_kex_hybrid_init(Msg, D#data.ssh_params),
147+
ssh_connection_handler:send_bytes(KexHybridReply, D),
148+
{ok, NewKeys, Ssh2} = ssh_transport:new_keys_message(Ssh1),
149+
ssh_connection_handler:send_bytes(NewKeys, D),
150+
{ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh2),
151+
ssh_connection_handler:send_bytes(ExtInfo, D),
152+
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
153+
154+
handle_event(internal, #ssh_msg_kex_hybrid_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
155+
ok = check_kex_strict(Msg, D),
156+
{ok, NewKeys, Ssh1} = ssh_transport:handle_kex_hybrid_reply(Msg, D#data.ssh_params),
157+
ssh_connection_handler:send_bytes(NewKeys, D),
158+
{ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
159+
ssh_connection_handler:send_bytes(ExtInfo, D),
160+
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
161+
143162
%%% ######## handle KEX strict
144163
handle_event(internal, _Event, {key_exchange,_Role,init},
145164
#data{ssh_params = #ssh{algorithms = #alg{kex_strict_negotiated = true},
@@ -296,7 +315,9 @@ get_alg_group(Kex) when Kex == 'curve25519-sha256';
296315
Kex == 'ecdh-sha2-nistp521';
297316
Kex == 'ecdh-sha2-nistp384';
298317
Kex == 'ecdh-sha2-nistp256' ->
299-
ecdh_alg.
318+
ecdh_alg;
319+
get_alg_group(Kex) when Kex == 'mlkem768x25519-sha256' ->
320+
mlkem_alg.
300321

301322
check_msg_group(_Msg, _AlgGroup, false) -> ok;
302323
check_msg_group(#ssh_msg_kexdh_init{}, dh_alg, true) -> ok;
@@ -308,6 +329,8 @@ check_msg_group(#ssh_msg_kex_dh_gex_init{}, dh_gex_alg, true) -> ok;
308329
check_msg_group(#ssh_msg_kex_dh_gex_reply{}, dh_gex_alg, true) -> ok;
309330
check_msg_group(#ssh_msg_kex_ecdh_init{}, ecdh_alg, true) -> ok;
310331
check_msg_group(#ssh_msg_kex_ecdh_reply{}, ecdh_alg, true) -> ok;
332+
check_msg_group(#ssh_msg_kex_hybrid_init{}, mlkem_alg, true) -> ok;
333+
check_msg_group(#ssh_msg_kex_hybrid_reply{}, mlkem_alg, true) -> ok;
311334
check_msg_group(_Msg, _AlgGroup, _) -> error.
312335

313336
%%%################################################################

lib/ssh/src/ssh_message.erl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,15 @@ encode(#ssh_msg_kex_ecdh_reply{public_host_key = {Key,SigAlg}, q_s = Q_s, h_sig
297297
EncSign = encode_signature(Key, SigAlg, Sign),
298298
<<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Ebinary(Q_s), ?Ebinary(EncSign)>>;
299299

300+
encode(#ssh_msg_kex_hybrid_init{c_init = {C_pk2, C_pk1}}) ->
301+
<<?Ebyte(?SSH_MSG_KEX_HYBRID_INIT), ?Ebinary(<<C_pk2/binary, C_pk1/binary>>)>>;
302+
303+
encode(#ssh_msg_kex_hybrid_reply{public_host_key = {Key,SigAlg}, s_reply = S_reply,
304+
h_sig = Sign}) ->
305+
EncKey = ssh2_pubkey_encode(Key),
306+
EncSign = encode_signature(Key, SigAlg, Sign),
307+
<<?Ebyte(?SSH_MSG_KEX_HYBRID_REPLY), ?Ebinary(EncKey), ?Ebinary(S_reply), ?Ebinary(EncSign)>>;
308+
300309
encode(#ssh_msg_ignore{data = Data}) ->
301310
<<?Ebyte(?SSH_MSG_IGNORE), ?Estring_utf8(Data)>>;
302311

@@ -530,6 +539,19 @@ decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY),
530539
h_sig = decode_signature(Sig)
531540
};
532541

542+
decode(<<"mlkem",?BYTE(?SSH_MSG_KEX_HYBRID_INIT), ?DEC_BIN(C_init,__0)>>) ->
543+
#ssh_msg_kex_hybrid_init{
544+
c_init = C_init
545+
};
546+
547+
decode(<<"mlkem",?BYTE(?SSH_MSG_KEX_HYBRID_REPLY),
548+
?DEC_BIN(Key,__1), ?DEC_BIN(S_reply,__2), ?DEC_BIN(Sig,__3)>>) ->
549+
#ssh_msg_kex_hybrid_reply{
550+
public_host_key = ssh2_pubkey_decode(Key),
551+
s_reply = S_reply,
552+
h_sig = decode_signature(Sig)
553+
};
554+
533555
decode(<<?SSH_MSG_SERVICE_REQUEST, ?DEC_BIN(Service,__0)>>) ->
534556
#ssh_msg_service_request{
535557
name = binary:bin_to_list(Service)

lib/ssh/src/ssh_transport.erl

Lines changed: 131 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@
4747
handle_kexinit_msg/4, handle_kexdh_init/2,
4848
handle_kex_dh_gex_group/2, handle_kex_dh_gex_init/2, handle_kex_dh_gex_reply/2,
4949
handle_new_keys/2, handle_kex_dh_gex_request/2,
50-
handle_kexdh_reply/2,
50+
handle_kexdh_reply/2,
5151
handle_kex_ecdh_init/2,
5252
handle_kex_ecdh_reply/2,
53+
handle_kex_hybrid_init/2,
54+
handle_kex_hybrid_reply/2,
5355
parallell_gen_key/1,
5456
ssh_packet/2, pack/2,
5557
valid_key_sha_alg/3,
@@ -208,6 +210,7 @@ supported_algorithms() -> [{K,supported_algorithms(K)} || K <- algo_classes()].
208210
supported_algorithms(kex) ->
209211
select_crypto_supported(
210212
[
213+
{'mlkem768x25519-sha256', [{kems, mlkem768}, {public_keys,ecdh}, {curves,x25519}, {hashs,sha256}]},
211214
{'curve25519-sha256', [{public_keys,ecdh}, {curves,x25519}, {hashs,sha256}]},
212215
{'[email protected]', [{public_keys,ecdh}, {curves,x25519}, {hashs,sha256}]},
213216
{'curve448-sha512', [{public_keys,ecdh}, {curves,x448}, {hashs,sha512}]},
@@ -573,8 +576,17 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
573576
Curve = ecdh_curve(Kex),
574577
{Public, Private} = generate_key(ecdh, Curve),
575578
{SshPacket, Ssh1} = ssh_packet(#ssh_msg_kex_ecdh_init{q_c=Public}, Ssh0),
576-
{ok, SshPacket,
577-
Ssh1#ssh{keyex_key = {{Public,Private},Curve}}}.
579+
{ok, SshPacket,
580+
Ssh1#ssh{keyex_key = {{Public,Private},Curve}}};
581+
key_exchange_first_msg(Kex, Ssh0) when Kex == 'mlkem768x25519-sha256' ->
582+
Curve = ecdh_curve(Kex),
583+
{C_publickey1, C_privkey1} = generate_key(ecdh, Curve),
584+
{C_publickey2, C_privkey2} = generate_key(mlkem768, []),
585+
{SshPacket, Ssh1} = ssh_packet(
586+
#ssh_msg_kex_hybrid_init{c_init = {C_publickey2, C_publickey1}}, Ssh0),
587+
{ok, SshPacket,
588+
Ssh1#ssh{keyex_key = {{mlkem768, {C_publickey2, C_privkey2}},
589+
{Curve, {C_publickey1, C_privkey1}}}}}.
578590

579591
%%%----------------------------------------------------------------
580592
%%%
@@ -904,6 +916,91 @@ handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey,
904916
[Class,Error], [{chars_limit, ssh_lib:max_log_len(Ssh0)}]))
905917
end.
906918

919+
%%%---- PQ/T Hybrid Key Exchange Method
920+
handle_kex_hybrid_init(#ssh_msg_kex_hybrid_init{c_init = C_init},
921+
Ssh0 = #ssh{algorithms = #alg{kex = Kex,
922+
hkey = SignAlg},
923+
opts = Opts}) ->
924+
%% at server
925+
Curve = ecdh_curve(Kex),
926+
{S_publickey1, S_privkey1} = generate_key(ecdh, Curve),
927+
try
928+
compute_key(hybrid_server, C_init, S_privkey1, Curve)
929+
of
930+
{S_ciphertext2, K_enc} ->
931+
MyPrivHostKey = get_host_key(SignAlg, Opts),
932+
MyPubHostKey = ssh_file:extract_public_key(MyPrivHostKey),
933+
S_reply = <<S_ciphertext2/binary, S_publickey1/binary>>,
934+
H = kex_hash(Ssh0, MyPubHostKey, sha(Curve),
935+
{mlkem, C_init, S_reply, K_enc}),
936+
case sign(H, SignAlg, MyPrivHostKey, Ssh0) of
937+
{ok, H_SIG} ->
938+
{SshPacket, Ssh1} =
939+
ssh_packet(#ssh_msg_kex_hybrid_reply{
940+
public_host_key = {MyPubHostKey,SignAlg},
941+
s_reply = S_reply,
942+
h_sig = H_SIG
943+
},
944+
Ssh0),
945+
{ok, SshPacket, Ssh1#ssh{
946+
shared_secret = K_enc,
947+
exchanged_hash = H,
948+
session_id = sid(Ssh1, H)}};
949+
{error, unsupported_sign_alg} ->
950+
?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
951+
io_lib:format("Unsupported algorithm ~p", [SignAlg],
952+
[{chars_limit, ssh_lib:max_log_len(Opts)}]))
953+
end
954+
catch
955+
Class:Reason0:_Stacktrace ->
956+
Reason = ssh_lib:trim_reason(Reason0),
957+
MsgFun =
958+
fun(debug) ->
959+
io_lib:format("Hybrid compute key failed in server: ~p:~p~n"
960+
"Kex: ~p, Curve: ~p~n"
961+
"C_init: ~p~n",
962+
[Class, Reason, Kex, Curve, C_init],
963+
[{chars_limit, ssh_lib:max_log_len(Ssh0)}]);
964+
(_) ->
965+
io_lib:format("Hybrid compute key failed in server: ~p:~p",
966+
[Class,Reason],
967+
[{chars_limit, ssh_lib:max_log_len(Ssh0)}])
968+
end,
969+
?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, ?SELECT_MSG(MsgFun))
970+
end.
971+
972+
handle_kex_hybrid_reply(#ssh_msg_kex_hybrid_reply{public_host_key = PeerPubHostKey,
973+
s_reply = S_reply,
974+
h_sig = H_SIG},
975+
#ssh{keyex_key =
976+
{{mlkem768, {C_publickey2, C_privkey2}},
977+
{Curve, {C_publickey1, C_privkey1}}}
978+
} = Ssh0
979+
) ->
980+
%% at client
981+
try
982+
compute_key(hybrid_client, S_reply, {C_privkey2, C_privkey1}, Curve)
983+
of
984+
K_enc ->
985+
H = kex_hash(Ssh0, PeerPubHostKey, sha(Curve),
986+
{mlkem, {C_publickey2, C_publickey1}, S_reply, K_enc}),
987+
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
988+
ok ->
989+
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
990+
{ok, SshPacket, install_alg(snd, Ssh#ssh{shared_secret = K_enc,
991+
exchanged_hash = H,
992+
session_id = sid(Ssh, H)})};
993+
Error ->
994+
?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
995+
io_lib:format("Hybrid reply failed. Verify host key: ~p",[Error],
996+
[{chars_limit, ssh_lib:max_log_len(Ssh0)}]))
997+
end
998+
catch
999+
Class:Error:_Stacktrace ->
1000+
?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
1001+
io_lib:format("Peer Hybrid public key seem invalid: ~p:~p",
1002+
[Class,Error], [{chars_limit, ssh_lib:max_log_len(Ssh0)}]))
1003+
end.
9071004

9081005
%%%----------------------------------------------------------------
9091006
handle_new_keys(#ssh_msg_newkeys{}, Ssh0) ->
@@ -1384,8 +1481,6 @@ pack(common, rfc4253, PlainText, DeltaLenTst,
13841481
{Ssh1, CipherPkt} = encrypt(Ssh0, PlainPkt),
13851482
MAC0 = mac(MacAlg, MacKey, SeqNum, PlainPkt),
13861483
{<<CipherPkt/binary,MAC0/binary>>, Ssh1};
1387-
1388-
13891484
pack(common, enc_then_mac, PlainText, DeltaLenTst,
13901485
#ssh{send_sequence = SeqNum,
13911486
send_mac = MacAlg,
@@ -1398,7 +1493,6 @@ pack(common, enc_then_mac, PlainText, DeltaLenTst,
13981493
EncPacketPkt = <<?UINT32(PlainLen), CipherPkt/binary>>,
13991494
MAC0 = mac(MacAlg, MacKey, SeqNum, EncPacketPkt),
14001495
{<<?UINT32(PlainLen), CipherPkt/binary, MAC0/binary>>, Ssh1};
1401-
14021496
pack(aead, _, PlainText, DeltaLenTst, Ssh0) ->
14031497
PadLen = padding_length(1+byte_size(PlainText), Ssh0),
14041498
Pad = ssh_bits:random(PadLen),
@@ -1758,10 +1852,8 @@ encrypt_final(Ssh) ->
17581852
encrypt_ctx = undefined
17591853
}}.
17601854

1761-
17621855
encrypt(#ssh{encrypt = none} = Ssh, Data) ->
17631856
{Ssh, Data};
1764-
17651857
encrypt(#ssh{encrypt = '[email protected]',
17661858
encrypt_keys = {K1,K2},
17671859
send_sequence = Seq} = Ssh,
@@ -1778,7 +1870,6 @@ encrypt(#ssh{encrypt = '[email protected]',
17781870
Ctag = crypto:mac(poly1305, PolyKey, EncBytes),
17791871
%% Result
17801872
{Ssh, {EncBytes,Ctag}};
1781-
17821873
encrypt(#ssh{encrypt = SshCipher,
17831874
encrypt_cipher = CryptoCipher,
17841875
encrypt_keys = K,
@@ -1788,7 +1879,6 @@ encrypt(#ssh{encrypt = SshCipher,
17881879
{Ctext,Ctag} = crypto:crypto_one_time_aead(CryptoCipher, K, IV0, PayloadData, LenData, true),
17891880
IV = next_gcm_iv(IV0),
17901881
{Ssh#ssh{encrypt_ctx = IV}, {<<LenData/binary,Ctext/binary>>,Ctag}};
1791-
17921882
encrypt(#ssh{encrypt_ctx = Ctx0} = Ssh, Data) ->
17931883
Enc = crypto:crypto_update(Ctx0, Data),
17941884
{Ssh, Enc}.
@@ -1843,7 +1933,6 @@ decrypt_final(Ssh) ->
18431933

18441934
decrypt(Ssh, <<>>) ->
18451935
{Ssh, <<>>};
1846-
18471936
decrypt(#ssh{decrypt = '[email protected]',
18481937
decrypt_keys = {K1,K2},
18491938
recv_sequence = Seq} = Ssh, Data) ->
@@ -1866,10 +1955,8 @@ decrypt(#ssh{decrypt = '[email protected]',
18661955
{Ssh,error}
18671956
end
18681957
end;
1869-
18701958
decrypt(#ssh{decrypt = none} = Ssh, Data) ->
18711959
{Ssh, Data};
1872-
18731960
decrypt(#ssh{decrypt = SshCipher,
18741961
decrypt_cipher = CryptoCipher,
18751962
decrypt_keys = K,
@@ -2067,20 +2154,23 @@ kex_plaintext(SSH, Key, Args) ->
20672154
?Ebinary(EncodedKey),
20682155
(kex_alg_dependent(Args))/binary>>.
20692156

2070-
2157+
kex_alg_dependent({mlkem, {C_publickey2, C_publickey1}, S_reply, K_enc}) ->
2158+
%% mlkem client
2159+
C_init = <<C_publickey2/binary, C_publickey1/binary>>,
2160+
kex_alg_dependent({mlkem, C_init, S_reply, K_enc});
2161+
kex_alg_dependent({mlkem, C_init, S_reply, K_enc}) ->
2162+
%% mlkem common
2163+
<<?Ebinary(C_init), ?Ebinary(S_reply), K_enc/binary>>;
20712164
kex_alg_dependent({Q_c, Q_s, K}) when is_binary(Q_c), is_binary(Q_s) ->
20722165
%% ecdh
20732166
<<?Ebinary(Q_c), ?Ebinary(Q_s), ?Empint(K)>>;
2074-
20752167
kex_alg_dependent({E, F, K}) ->
20762168
%% diffie-hellman
20772169
<<?Empint(E), ?Empint(F), ?Empint(K)>>;
2078-
20792170
kex_alg_dependent({-1, NBits, -1, Prime, Gen, E, F, K}) ->
20802171
%% ssh_msg_kex_dh_gex_request_old
20812172
<<?Euint32(NBits),
20822173
?Empint(Prime), ?Empint(Gen), ?Empint(E), ?Empint(F), ?Empint(K)>>;
2083-
20842174
kex_alg_dependent({Min, NBits, Max, Prime, Gen, E, F, K}) ->
20852175
%% diffie-hellman group exchange
20862176
<<?Euint32(Min), ?Euint32(NBits), ?Euint32(Max),
@@ -2156,10 +2246,10 @@ sha('curve25519-sha256' ) -> sha256;
21562246
sha('[email protected]' ) -> sha256;
21572247
sha('curve448-sha512') -> sha512;
21582248
sha(x25519) -> sha256;
2249+
sha('mlkem768x25519-sha256') -> sha256;
21592250
sha(x448) -> sha512;
21602251
sha(Str) when is_list(Str), length(Str)<50 -> sha(list_to_existing_atom(Str)).
21612252

2162-
21632253
mac_key_bytes('hmac-sha1') -> 20;
21642254
mac_key_bytes('[email protected]') -> 20;
21652255
mac_key_bytes('hmac-sha1-96') -> 20;
@@ -2193,7 +2283,6 @@ mac_digest_size(none) -> 0.
21932283
%% Diffie-Hellman utils
21942284
%%
21952285
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2196-
21972286
dh_group('diffie-hellman-group1-sha1') -> ?dh_group1;
21982287
dh_group('diffie-hellman-group14-sha1') -> ?dh_group14;
21992288
dh_group('diffie-hellman-group14-sha256') -> ?dh_group14;
@@ -2207,18 +2296,34 @@ parallell_gen_key(Ssh = #ssh{keyex_key = {x, {G, P}},
22072296
{Public, Private} = generate_key(dh, [P,G,2*Sz]),
22082297
Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}.
22092298

2210-
2299+
generate_key(mlkem768, Args) ->
2300+
crypto:generate_key(mlkem768, Args);
22112301
generate_key(ecdh, Args) ->
22122302
crypto:generate_key(ecdh, Args);
22132303
generate_key(dh, [P,G,Sz2]) ->
22142304
{Public,Private} = crypto:generate_key(dh, [P, G, max(Sz2,?MIN_DH_KEY_SIZE)] ),
22152305
{crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}.
22162306

2217-
2218-
compute_key(Algorithm, OthersPublic, MyPrivate, Args) ->
2219-
Shared = crypto:compute_key(Algorithm, OthersPublic, MyPrivate, Args),
2307+
compute_key(hybrid_server, C_init, S_privkey1, Curve) ->
2308+
<<C_publickey2:1184/binary, C_publickey1:32/binary>> = C_init,
2309+
{K_pq_secret, S_ciphertext2} = crypto:encapsulate_key(mlkem768, C_publickey2),
2310+
SharedSecret = hybrid_common(K_pq_secret, Curve, C_publickey1, S_privkey1),
2311+
{S_ciphertext2, <<?Ebinary(SharedSecret)>>};
2312+
compute_key(hybrid_client, S_reply, {C_privkey2, C_privkey1}, Curve) ->
2313+
<<S_ciphertext2:1088/binary, S_publickey1:32/binary>> = S_reply,
2314+
K_pq_secret = crypto:decapsulate_key(mlkem768, C_privkey2, S_ciphertext2),
2315+
SharedSecret = hybrid_common(K_pq_secret, Curve, S_publickey1, C_privkey1),
2316+
<<?Ebinary(SharedSecret)>>;
2317+
compute_key(Algorithm, PeerPublic, MyPrivate, Args) ->
2318+
Shared = crypto:compute_key(Algorithm, PeerPublic, MyPrivate, Args),
22202319
crypto:bytes_to_integer(Shared).
22212320

2321+
hybrid_common(K_pq_secret, Curve, PeerPublic, MyPrivate) ->
2322+
K_cl_secret = compute_key(ecdh, PeerPublic, MyPrivate, Curve),
2323+
K_cl_secret_mpint = <<?Empint(K_cl_secret)>>,
2324+
K_cl_secret_mpint_trim =
2325+
binary:part(K_cl_secret_mpint, byte_size(K_cl_secret_mpint), -32),
2326+
crypto:hash(sha(Curve), <<K_pq_secret/binary, K_cl_secret_mpint_trim/binary>>).
22222327

22232328
dh_bits(#alg{encrypt = Encrypt,
22242329
send_mac = SendMac}) ->
@@ -2233,8 +2338,9 @@ ecdh_curve('ecdh-sha2-nistp256') -> secp256r1;
22332338
ecdh_curve('ecdh-sha2-nistp384') -> secp384r1;
22342339
ecdh_curve('ecdh-sha2-nistp521') -> secp521r1;
22352340
ecdh_curve('curve448-sha512' ) -> x448;
2236-
ecdh_curve('curve25519-sha256' ) -> x25519;
2237-
ecdh_curve('[email protected]' ) -> x25519.
2341+
ecdh_curve('curve25519-sha256') -> x25519;
2342+
ecdh_curve('mlkem768x25519-sha256') -> x25519;
2343+
ecdh_curve('[email protected]') -> x25519.
22382344

22392345
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
22402346
%%

0 commit comments

Comments
 (0)