std.crypto.tls: fix x25519_ml_kem768 key share

This is mostly nfc cleanup as I was bisecting the client hello to find
the problematic part, and the only bug fix ended up being

    key_share.x25519_kp.public_key ++
    key_share.ml_kem768_kp.public_key.toBytes()

to

    key_share.ml_kem768_kp.public_key.toBytes() ++
    key_share.x25519_kp.public_key)

and the same swap in `KeyShare.exchange` as per some random blog that
says "a hybrid keyshare, constructed by concatenating the public KEM key
with the public X25519 key".  I also note that based on the same blog
post, there was a draft version of this method that indeed had these
values swapped, and that used to be supported by this code, but it was
not properly fixed up when this code was updated from the draft spec.

Closes #21747
This commit is contained in:
Jacob Young 2024-11-02 02:45:12 -04:00
parent 7f20c78c95
commit 7afb277725
2 changed files with 135 additions and 138 deletions

View File

@ -291,6 +291,12 @@ pub const NamedGroup = enum(u16) {
_,
};
pub const PskKeyExchangeMode = enum(u8) {
psk_ke = 0,
psk_dhe_ke = 1,
_,
};
pub const CipherSuite = enum(u16) {
RSA_WITH_AES_128_CBC_SHA = 0x002F,
DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033,
@ -407,6 +413,11 @@ pub const CipherSuite = enum(u16) {
}
};
pub const CompressionMethod = enum(u8) {
null = 0,
_,
};
pub const CertificateType = enum(u8) {
X509 = 0,
RawPublicKey = 2,
@ -419,6 +430,11 @@ pub const KeyUpdateRequest = enum(u8) {
_,
};
pub const ChangeCipherSpecType = enum(u8) {
change_cipher_spec = 1,
_,
};
pub fn HandshakeCipherT(comptime AeadType: type, comptime HashType: type, comptime explicit_iv_length: comptime_int) type {
return struct {
pub const A = ApplicationCipherT(AeadType, HashType, explicit_iv_length);
@ -560,34 +576,38 @@ pub fn hmac(comptime Hmac: type, message: []const u8, key: [Hmac.key_length]u8)
return result;
}
pub inline fn extension(comptime et: ExtensionType, bytes: anytype) [2 + 2 + bytes.len]u8 {
return int2(@intFromEnum(et)) ++ array(1, bytes);
pub inline fn extension(et: ExtensionType, bytes: anytype) [2 + 2 + bytes.len]u8 {
return int(u16, @intFromEnum(et)) ++ array(u16, u8, bytes);
}
pub inline fn array(comptime elem_size: comptime_int, bytes: anytype) [2 + bytes.len]u8 {
comptime assert(bytes.len % elem_size == 0);
return int2(bytes.len) ++ bytes;
}
pub inline fn enum_array(comptime E: type, comptime tags: []const E) [2 + @sizeOf(E) * tags.len]u8 {
assert(@sizeOf(E) == 2);
var result: [tags.len * 2]u8 = undefined;
for (tags, 0..) |elem, i| {
result[i * 2] = @as(u8, @truncate(@intFromEnum(elem) >> 8));
result[i * 2 + 1] = @as(u8, @truncate(@intFromEnum(elem)));
pub inline fn array(
comptime Len: type,
comptime Elem: type,
elems: anytype,
) [@divExact(@bitSizeOf(Len), 8) + @divExact(@bitSizeOf(Elem), 8) * elems.len]u8 {
const len_size = @divExact(@bitSizeOf(Len), 8);
const elem_size = @divExact(@bitSizeOf(Elem), 8);
var arr: [len_size + elem_size * elems.len]u8 = undefined;
std.mem.writeInt(Len, arr[0..len_size], @intCast(elem_size * elems.len), .big);
const ElemInt = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Elem) } });
for (0.., @as([elems.len]Elem, elems)) |index, elem| {
std.mem.writeInt(
ElemInt,
arr[len_size + elem_size * index ..][0..elem_size],
switch (@typeInfo(Elem)) {
.int => @as(Elem, elem),
.@"enum" => @intFromEnum(@as(Elem, elem)),
else => @bitCast(@as(Elem, elem)),
},
.big,
);
}
return array(2, result);
}
pub inline fn int2(int: u16) [2]u8 {
var arr: [2]u8 = undefined;
std.mem.writeInt(u16, &arr, int, .big);
return arr;
}
pub inline fn int3(int: u24) [3]u8 {
var arr: [3]u8 = undefined;
std.mem.writeInt(u24, &arr, int, .big);
pub inline fn int(comptime Int: type, val: Int) [@divExact(@bitSizeOf(Int), 8)]u8 {
var arr: [@divExact(@bitSizeOf(Int), 8)]u8 = undefined;
std.mem.writeInt(Int, &arr, val, .big);
return arr;
}
@ -670,9 +690,8 @@ pub const Decoder = struct {
else => @compileError("unsupported int type: " ++ @typeName(T)),
},
.@"enum" => |info| {
const int = d.decode(info.tag_type);
if (info.is_exhaustive) @compileError("exhaustive enum cannot be used");
return @as(T, @enumFromInt(int));
return @enumFromInt(d.decode(info.tag_type));
},
else => @compileError("unsupported type: " ++ @typeName(T)),
}

View File

@ -10,10 +10,8 @@ const Certificate = std.crypto.Certificate;
const max_ciphertext_len = tls.max_ciphertext_len;
const hmacExpandLabel = tls.hmacExpandLabel;
const hkdfExpandLabel = tls.hkdfExpandLabel;
const int2 = tls.int2;
const int3 = tls.int3;
const int = tls.int;
const array = tls.array;
const enum_array = tls.enum_array;
tls_version: tls.ProtocolVersion,
read_seq: u64,
@ -156,70 +154,62 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
error.IdentityElement => return error.InsufficientEntropy,
};
const extensions_payload =
tls.extension(.supported_versions, [_]u8{2 + 2} ++ // byte length of supported versions
int2(@intFromEnum(tls.ProtocolVersion.tls_1_3)) ++
int2(@intFromEnum(tls.ProtocolVersion.tls_1_2))) ++
tls.extension(.signature_algorithms, enum_array(tls.SignatureScheme, &.{
const extensions_payload = tls.extension(.supported_versions, array(u8, tls.ProtocolVersion, .{
.tls_1_3,
.tls_1_2,
})) ++ tls.extension(.signature_algorithms, array(u16, tls.SignatureScheme, .{
.ecdsa_secp256r1_sha256,
.ecdsa_secp384r1_sha384,
.rsa_pss_rsae_sha256,
.rsa_pss_rsae_sha384,
.rsa_pss_rsae_sha512,
.ed25519,
})) ++ tls.extension(.supported_groups, enum_array(tls.NamedGroup, &.{
})) ++ tls.extension(.supported_groups, array(u16, tls.NamedGroup, .{
.x25519_ml_kem768,
.secp256r1,
.x25519,
})) ++ tls.extension(
.key_share,
array(1, int2(@intFromEnum(tls.NamedGroup.x25519)) ++
array(1, key_share.x25519_kp.public_key) ++
int2(@intFromEnum(tls.NamedGroup.secp256r1)) ++
array(1, key_share.secp256r1_kp.public_key.toUncompressedSec1()) ++
int2(@intFromEnum(tls.NamedGroup.x25519_ml_kem768)) ++
array(1, key_share.x25519_kp.public_key ++ key_share.ml_kem768_kp.public_key.toBytes())),
) ++
int2(@intFromEnum(tls.ExtensionType.server_name)) ++
int2(host_len + 5) ++ // byte length of this extension payload
int2(host_len + 3) ++ // server_name_list byte count
[1]u8{0x00} ++ // name_type
int2(host_len);
})) ++ tls.extension(.psk_key_exchange_modes, array(u8, tls.PskKeyExchangeMode, .{
.psk_dhe_ke,
})) ++ tls.extension(.key_share, array(
u16,
u8,
int(u16, @intFromEnum(tls.NamedGroup.x25519_ml_kem768)) ++
array(u16, u8, key_share.ml_kem768_kp.public_key.toBytes() ++ key_share.x25519_kp.public_key) ++
int(u16, @intFromEnum(tls.NamedGroup.secp256r1)) ++
array(u16, u8, key_share.secp256r1_kp.public_key.toUncompressedSec1()) ++
int(u16, @intFromEnum(tls.NamedGroup.x25519)) ++
array(u16, u8, key_share.x25519_kp.public_key),
)) ++ int(u16, @intFromEnum(tls.ExtensionType.server_name)) ++
int(u16, 2 + 1 + 2 + host_len) ++ // byte length of this extension payload
int(u16, 1 + 2 + host_len) ++ // server_name_list byte count
.{0x00} ++ // name_type
int(u16, host_len);
const extensions_header =
int2(@intCast(extensions_payload.len + host_len)) ++
int(u16, @intCast(extensions_payload.len + host_len)) ++
extensions_payload;
const legacy_compression_methods = 0x0100;
const client_hello =
int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
client_hello_rand ++
[1]u8{32} ++ legacy_session_id ++
cipher_suites ++
int2(legacy_compression_methods) ++
array(u8, tls.CompressionMethod, .{.null}) ++
extensions_header;
const out_handshake =
[_]u8{@intFromEnum(tls.HandshakeType.client_hello)} ++
int3(@intCast(client_hello.len + host_len)) ++
const out_handshake = .{@intFromEnum(tls.HandshakeType.client_hello)} ++
int(u24, @intCast(client_hello.len + host_len)) ++
client_hello;
const cleartext_header = [_]u8{@intFromEnum(tls.ContentType.handshake)} ++
int2(@intFromEnum(tls.ProtocolVersion.tls_1_0)) ++ // legacy_record_version
int2(@intCast(out_handshake.len + host_len)) ++
const cleartext_header = .{@intFromEnum(tls.ContentType.handshake)} ++
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_0)) ++
int(u16, @intCast(out_handshake.len + host_len)) ++
out_handshake;
{
var iovecs = [_]std.posix.iovec_const{
.{
.base = &cleartext_header,
.len = cleartext_header.len,
},
.{
.base = host.ptr,
.len = host.len,
},
.{ .base = &cleartext_header, .len = cleartext_header.len },
.{ .base = host.ptr, .len = host.len },
};
try stream.writevAll(&iovecs);
}
@ -526,7 +516,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
},
.change_cipher_spec => {
try ctd.ensure(1);
if (ctd.decode(u8) != 0x01) return error.TlsIllegalParameter;
if (ctd.decode(tls.ChangeCipherSpecType) != .change_cipher_spec) return error.TlsIllegalParameter;
cipher_state = pending_cipher_state;
},
.handshake => while (true) {
@ -648,20 +638,13 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
if (handshake_state != .server_hello_done) return error.TlsUnexpectedMessage;
handshake_state = .finished;
const client_key_exchange_msg =
[_]u8{@intFromEnum(tls.ContentType.handshake)} ++ // record content type
int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
int2(0x46) ++ // record length
.{@intFromEnum(tls.HandshakeType.client_key_exchange)} ++ // handshake type
int3(0x42) ++ // params length
.{0x41} ++ // pubkey length
key_share.secp256r1_kp.public_key.toUncompressedSec1();
// This message is to trick buggy proxies into behaving correctly.
const client_change_cipher_spec_msg =
[_]u8{@intFromEnum(tls.ContentType.change_cipher_spec)} ++ // record content type
int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
int2(1) ++ // record length
.{0x01};
const client_key_exchange_msg = .{@intFromEnum(tls.ContentType.handshake)} ++
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
array(u16, u8, .{@intFromEnum(tls.HandshakeType.client_key_exchange)} ++
array(u24, u8, array(u8, u8, key_share.secp256r1_kp.public_key.toUncompressedSec1())));
const client_change_cipher_spec_msg = .{@intFromEnum(tls.ContentType.change_cipher_spec)} ++
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
array(u16, tls.ChangeCipherSpecType, .{.change_cipher_spec});
const pre_master_secret = key_share.getSharedSecret().?;
switch (handshake_cipher) {
inline else => |*p| {
@ -680,10 +663,13 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
@sizeOf(P.Tls_1_2),
);
const verify_data_len = 12;
const client_verify_cleartext =
[_]u8{@intFromEnum(tls.HandshakeType.finished)} ++ // handshake type
int3(verify_data_len) ++ // verify data length
hmacExpandLabel(P.Hmac, &master_secret, &.{ "client finished", &p.transcript_hash.peek() }, verify_data_len);
const client_verify_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++
array(u24, u8, hmacExpandLabel(
P.Hmac,
&master_secret,
&.{ "client finished", &p.transcript_hash.peek() },
verify_data_len,
));
p.transcript_hash.update(&client_verify_cleartext);
p.version = .{ .tls_1_2 = .{
.server_verify_data = hmacExpandLabel(
@ -709,25 +695,23 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
const operand: V = pad ++ @as([8]u8, @bitCast(big(write_seq)));
break :nonce @as(V, pv.app_cipher.client_write_IV ++ pv.app_cipher.client_salt) ^ operand;
};
var client_verify_msg = [_]u8{@intFromEnum(tls.ContentType.handshake)} ++ // record content type
int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
int2(P.record_iv_length + client_verify_cleartext.len + P.mac_length) ++ // record length
nonce[P.fixed_iv_length..].* ++
@as([client_verify_cleartext.len + P.mac_length]u8, undefined);
var client_verify_msg = .{@intFromEnum(tls.ContentType.handshake)} ++
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
array(u16, u8, nonce[P.fixed_iv_length..].* ++
@as([client_verify_cleartext.len + P.mac_length]u8, undefined));
P.AEAD.encrypt(
client_verify_msg[client_verify_msg.len - P.mac_length -
client_verify_cleartext.len ..][0..client_verify_cleartext.len],
client_verify_msg[client_verify_msg.len - P.mac_length ..][0..P.mac_length],
&client_verify_cleartext,
std.mem.toBytes(big(write_seq)) ++ client_verify_msg[0 .. 1 + 2] ++ int2(client_verify_cleartext.len),
std.mem.toBytes(big(write_seq)) ++ client_verify_msg[0 .. 1 + 2] ++ int(u16, client_verify_cleartext.len),
nonce,
pv.app_cipher.client_write_key,
);
const all_msgs = client_key_exchange_msg ++ client_change_cipher_spec_msg ++ client_verify_msg;
var all_msgs_vec = [_]std.posix.iovec_const{.{
.base = &all_msgs,
.len = all_msgs.len,
}};
var all_msgs_vec = [_]std.posix.iovec_const{
.{ .base = &all_msgs, .len = all_msgs.len },
};
try stream.writevAll(&all_msgs_vec);
},
}
@ -755,11 +739,9 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
if (cipher_state == .cleartext) return error.TlsUnexpectedMessage;
if (handshake_state != .finished) return error.TlsUnexpectedMessage;
// This message is to trick buggy proxies into behaving correctly.
const client_change_cipher_spec_msg =
[_]u8{@intFromEnum(tls.ContentType.change_cipher_spec)} ++
int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
int2(1) ++ // length
.{0x01};
const client_change_cipher_spec_msg = .{@intFromEnum(tls.ContentType.change_cipher_spec)} ++
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
array(u16, tls.ChangeCipherSpecType, .{.change_cipher_spec});
const app_cipher = app_cipher: switch (handshake_cipher) {
inline else => |*p, tag| switch (tls_version) {
.tls_1_3 => {
@ -771,17 +753,15 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
if (!mem.eql(u8, &expected_server_verify_data, hsd.buf)) return error.TlsDecryptError;
const handshake_hash = p.transcript_hash.finalResult();
const verify_data = tls.hmac(P.Hmac, &handshake_hash, pv.client_finished_key);
const out_cleartext = [_]u8{
@intFromEnum(tls.HandshakeType.finished),
0, 0, verify_data.len, // length
} ++ verify_data ++ [1]u8{@intFromEnum(tls.ContentType.handshake)};
const out_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++
array(u24, u8, verify_data) ++
.{@intFromEnum(tls.ContentType.handshake)};
const wrapped_len = out_cleartext.len + P.AEAD.tag_length;
var finished_msg = [_]u8{@intFromEnum(tls.ContentType.application_data)} ++
int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
int2(wrapped_len) ++ // byte length of encrypted record
@as([wrapped_len]u8, undefined);
var finished_msg = .{@intFromEnum(tls.ContentType.application_data)} ++
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
array(u16, u8, @as([wrapped_len]u8, undefined));
const ad = finished_msg[0..tls.record_header_len];
const ciphertext = finished_msg[tls.record_header_len..][0..out_cleartext.len];
@ -790,10 +770,9 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
P.AEAD.encrypt(ciphertext, auth_tag, &out_cleartext, ad, nonce, pv.client_handshake_key);
const all_msgs = client_change_cipher_spec_msg ++ finished_msg;
var all_msgs_vec = [_]std.posix.iovec_const{.{
.base = &all_msgs,
.len = all_msgs.len,
}};
var all_msgs_vec = [_]std.posix.iovec_const{
.{ .base = &all_msgs, .len = all_msgs.len },
};
try stream.writevAll(&all_msgs_vec);
const client_secret = hkdfExpandLabel(P.Hkdf, pv.master_secret, "c ap traffic", &handshake_hash, P.Hash.digest_length);
@ -965,10 +944,9 @@ fn prepareCiphertextRecord(
const record_start = ciphertext_end;
const ad = ciphertext_buf[ciphertext_end..][0..tls.record_header_len];
ad.* =
[_]u8{@intFromEnum(tls.ContentType.application_data)} ++
int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
int2(ciphertext_len + P.AEAD.tag_length);
ad.* = .{@intFromEnum(tls.ContentType.application_data)} ++
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
int(u16, ciphertext_len + P.AEAD.tag_length);
ciphertext_end += ad.len;
const ciphertext = ciphertext_buf[ciphertext_end..][0..ciphertext_len];
ciphertext_end += ciphertext_len;
@ -1023,10 +1001,10 @@ fn prepareCiphertextRecord(
const record_start = ciphertext_end;
const record_header = ciphertext_buf[ciphertext_end..][0..tls.record_header_len];
ciphertext_end += tls.record_header_len;
record_header.* = [_]u8{@intFromEnum(inner_content_type)} ++
int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
int2(P.record_iv_length + message_len + P.mac_length);
const ad = std.mem.toBytes(big(c.write_seq)) ++ record_header[0 .. 1 + 2] ++ int2(message_len);
record_header.* = .{@intFromEnum(inner_content_type)} ++
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
int(u16, P.record_iv_length + message_len + P.mac_length);
const ad = std.mem.toBytes(big(c.write_seq)) ++ record_header[0 .. 1 + 2] ++ int(u16, message_len);
const record_iv = ciphertext_buf[ciphertext_end..][0..P.record_iv_length];
ciphertext_end += P.record_iv_length;
const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
@ -1569,25 +1547,17 @@ const KeyShare = struct {
) error{ TlsIllegalParameter, TlsDecryptFailure }!void {
switch (named_group) {
.x25519_ml_kem768 => {
const xksl = crypto.dh.X25519.public_length;
const hksl = xksl + crypto.kem.ml_kem.MLKem768.ciphertext_length;
if (server_pub_key.len != hksl) return error.TlsIllegalParameter;
const hksl = crypto.kem.ml_kem.MLKem768.ciphertext_length;
const xksl = hksl + crypto.dh.X25519.public_length;
if (server_pub_key.len != xksl) return error.TlsIllegalParameter;
const xsk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[0..xksl].*) catch
const hsk = ks.ml_kem768_kp.secret_key.decaps(server_pub_key[0..hksl]) catch
return error.TlsDecryptFailure;
const hsk = ks.ml_kem768_kp.secret_key.decaps(server_pub_key[xksl..hksl]) catch
const xsk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[hksl..xksl].*) catch
return error.TlsDecryptFailure;
@memcpy(ks.sk_buf[0..xsk.len], &xsk);
@memcpy(ks.sk_buf[xsk.len..][0..hsk.len], &hsk);
ks.sk_len = xsk.len + hsk.len;
},
.x25519 => {
const ksl = crypto.dh.X25519.public_length;
if (server_pub_key.len != ksl) return error.TlsIllegalParameter;
const sk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[0..ksl].*) catch
return error.TlsDecryptFailure;
@memcpy(ks.sk_buf[0..sk.len], &sk);
ks.sk_len = sk.len;
@memcpy(ks.sk_buf[0..hsk.len], &hsk);
@memcpy(ks.sk_buf[hsk.len..][0..xsk.len], &xsk);
ks.sk_len = hsk.len + xsk.len;
},
.secp256r1 => {
const PublicKey = crypto.sign.ecdsa.EcdsaP256Sha256.PublicKey;
@ -1598,6 +1568,14 @@ const KeyShare = struct {
@memcpy(ks.sk_buf[0..sk.len], &sk);
ks.sk_len = sk.len;
},
.x25519 => {
const ksl = crypto.dh.X25519.public_length;
if (server_pub_key.len != ksl) return error.TlsIllegalParameter;
const sk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[0..ksl].*) catch
return error.TlsDecryptFailure;
@memcpy(ks.sk_buf[0..sk.len], &sk);
ks.sk_len = sk.len;
},
else => return error.TlsIllegalParameter,
}
}
@ -1877,7 +1855,7 @@ fn limitVecs(iovecs: []std.posix.iovec, len: usize) []std.posix.iovec {
/// aes128-gcm: 138 MiB/s
/// aes256-gcm: 120 MiB/s
const cipher_suites = if (crypto.core.aes.has_hardware_support)
enum_array(tls.CipherSuite, &.{
array(u16, tls.CipherSuite, .{
.AEGIS_128L_SHA256,
.AEGIS_256_SHA512,
.AES_128_GCM_SHA256,
@ -1888,7 +1866,7 @@ const cipher_suites = if (crypto.core.aes.has_hardware_support)
.ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
})
else
enum_array(tls.CipherSuite, &.{
array(u16, tls.CipherSuite, .{
.CHACHA20_POLY1305_SHA256,
.ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
.AEGIS_128L_SHA256,