// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0 > or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT >, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use neqo_crypto::{
constants::{
Cipher, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA25
6,
TLS_VERSION_1_3,
},
hkdf, SymKey,
};
use test_fixture::fixture_init;
const SALT: &[u8] = &[
0 x00, 0 x01, 0 x02, 0 x03, 0 x04, 0 x05, 0 x06, 0 x07, 0 x08, 0 x09, 0 x0a, 0 x0b, 0 x0c, 0 x0d, 0 x0e, 0 x0f,
0 x10, 0 x11, 0 x12, 0 x13, 0 x14, 0 x15, 0 x16, 0 x17, 0 x18, 0 x19, 0 x1a, 0 x1b, 0 x1c, 0 x1d, 0 x1e, 0 x1f,
0 x20, 0 x21, 0 x22, 0 x23, 0 x24, 0 x25, 0 x26, 0 x27, 0 x28, 0 x29, 0 x2a, 0 x2b, 0 x2c, 0 x2d, 0 x2e, 0 x2f,
];
const IKM: &[u8] = &[
0 x01, 0 x01, 0 x02, 0 x03, 0 x04, 0 x05, 0 x06, 0 x07, 0 x08, 0 x09, 0 x0a, 0 x0b, 0 x0c, 0 x0d, 0 x0e, 0 x0f,
0 x10, 0 x11, 0 x12, 0 x13, 0 x14, 0 x15, 0 x16, 0 x17, 0 x18, 0 x19, 0 x1a, 0 x1b, 0 x1c, 0 x1d, 0 x1e, 0 x1f,
0 x20, 0 x21, 0 x22, 0 x23, 0 x24, 0 x25, 0 x26, 0 x27, 0 x28, 0 x29, 0 x2a, 0 x2b, 0 x2c, 0 x2d, 0 x2e, 0 x2f,
];
const SESSION_HASH: &[u8] = &[
0 xf0, 0 xf1, 0 xf2, 0 xf3, 0 xf4, 0 xf5, 0 xf6, 0 xf7, 0 xf8, 0 xf9, 0 xfa, 0 xfb, 0 xfc, 0 xfd, 0 xfe, 0 xff,
0 xe0, 0 xe1, 0 xe2, 0 xe3, 0 xe4, 0 xe5, 0 xe6, 0 xe7, 0 xe8, 0 xe9, 0 xea, 0 xeb, 0 xec, 0 xed, 0 xee, 0 xef,
0 xd0, 0 xd1, 0 xd2, 0 xd3, 0 xd4, 0 xd5, 0 xd6, 0 xd7, 0 xd8, 0 xd9, 0 xda, 0 xdb, 0 xdc, 0 xdd, 0 xde, 0 xdf,
0 xe0, 0 xe1, 0 xe2, 0 xe3, 0 xe4, 0 xe5, 0 xe6, 0 xe7, 0 xe8, 0 xe9, 0 xea, 0 xeb, 0 xec, 0 xed, 0 xee, 0 xef,
];
fn cipher_hash_len(cipher: Cipher) -> usize {
match cipher {
TLS_AES_128_GCM_SHA256 | TLS_CHACHA20_POLY1305_SHA256 => 32 ,
TLS_AES_256_GCM_SHA384 => 48 ,
_ => unreachable!(),
}
}
fn import_keys(cipher: Cipher) -> (SymKey, SymKey) {
let l = cipher_hash_len(cipher);
(
hkdf::import_key(TLS_VERSION_1_3, &SALT[0 ..l]).expect("import salt" ),
hkdf::import_key(TLS_VERSION_1_3, &IKM[0 ..l]).expect("import IKM" ),
)
}
fn extract(cipher: Cipher, expected: &[u8]) {
fixture_init();
let (salt, ikm) = import_keys(cipher);
let prk = hkdf::extract(TLS_VERSION_1_3, cipher, Some(&salt), &ikm)
.expect("HKDF Extract should work" );
let raw_prk = prk.as_bytes().expect("key should have bytes" );
assert_eq!(raw_prk, expected);
}
#[ test]
fn extract_sha256() {
const EXPECTED: &[u8] = &[
0 xa5, 0 x68, 0 x02, 0 x5a, 0 x95, 0 xc9, 0 x7f, 0 x55, 0 x38, 0 xbc, 0 xf7, 0 x97, 0 xcc, 0 x0f, 0 xd5,
0 xf6, 0 xa8, 0 x8d, 0 x15, 0 xbc, 0 x0e, 0 x85, 0 x74, 0 x70, 0 x3c, 0 xa3, 0 x65, 0 xbd, 0 x76, 0 xcf,
0 x9f, 0 xd3,
];
extract(TLS_AES_128_GCM_SHA256, EXPECTED);
extract(TLS_CHACHA20_POLY1305_SHA256, EXPECTED);
}
#[ test]
fn extract_sha384() {
extract(
TLS_AES_256_GCM_SHA384,
&[
0 x01, 0 x93, 0 xc0, 0 x07, 0 x3f, 0 x6a, 0 x83, 0 x0e, 0 x2e, 0 x4f, 0 xb2, 0 x58, 0 xe4, 0 x00,
0 x08, 0 x5c, 0 x68, 0 x9c, 0 x37, 0 x32, 0 x00, 0 x37, 0 xff, 0 xc3, 0 x1c, 0 x5b, 0 x98, 0 x0b,
0 x02, 0 x92, 0 x3f, 0 xfd, 0 x73, 0 x5a, 0 x6f, 0 x2a, 0 x95, 0 xa3, 0 xee, 0 xf6, 0 xd6, 0 x8e,
0 x6f, 0 x86, 0 xea, 0 x63, 0 xf8, 0 x33,
],
);
}
fn derive_secret(cipher: Cipher, expected: &[u8]) {
fixture_init();
// Here we only use the salt as the PRK.
let (prk, _) = import_keys(cipher);
let secret = hkdf::expand_label(TLS_VERSION_1_3, cipher, &prk, &[], "master secret" )
.expect("HKDF-Expand-Label should work" );
let raw_secret = secret.as_bytes().expect("key should have bytes" );
assert_eq!(raw_secret, expected);
}
#[ test]
fn derive_secret_sha256() {
const EXPECTED: &[u8] = &[
0 xb7, 0 x08, 0 x00, 0 xe3, 0 x8e, 0 x48, 0 x68, 0 x91, 0 xb1, 0 x0f, 0 x5e, 0 x6f, 0 x22, 0 x53, 0 x6b,
0 x84, 0 x69, 0 x75, 0 xaa, 0 xa3, 0 x2a, 0 xe7, 0 xde, 0 xaa, 0 xc3, 0 xd1, 0 xb4, 0 x05, 0 x22, 0 x5c,
0 x68, 0 xf5,
];
derive_secret(TLS_AES_128_GCM_SHA256, EXPECTED);
derive_secret(TLS_CHACHA20_POLY1305_SHA256, EXPECTED);
}
#[ test]
fn derive_secret_sha384() {
derive_secret(
TLS_AES_256_GCM_SHA384,
&[
0 x13, 0 xd3, 0 x36, 0 x9f, 0 x3c, 0 x78, 0 xa0, 0 x32, 0 x40, 0 xee, 0 x16, 0 xe9, 0 x11, 0 x12,
0 x66, 0 xc7, 0 x51, 0 xad, 0 xd8, 0 x3c, 0 xa1, 0 xa3, 0 x97, 0 x74, 0 xd7, 0 x45, 0 xff, 0 xa7,
0 x88, 0 x9e, 0 x52, 0 x17, 0 x2e, 0 xaa, 0 x3a, 0 xd2, 0 x35, 0 xd8, 0 xd5, 0 x35, 0 xfd, 0 x65,
0 x70, 0 x9f, 0 xa9, 0 xf9, 0 xfa, 0 x23,
],
);
}
fn expand_label(cipher: Cipher, expected: &[u8]) {
fixture_init();
let l = cipher_hash_len(cipher);
let (prk, _) = import_keys(cipher);
let secret = hkdf::expand_label(
TLS_VERSION_1_3,
cipher,
&prk,
&SESSION_HASH[0 ..l],
"master secret" ,
)
.expect("HKDF-Expand-Label should work" );
let raw_secret = secret.as_bytes().expect("key should have bytes" );
assert_eq!(raw_secret, expected);
}
#[ test]
fn expand_label_sha256() {
const EXPECTED: &[u8] = &[
0 x3e, 0 x4e, 0 x6e, 0 xd0, 0 xbc, 0 xc4, 0 xf4, 0 xff, 0 xf0, 0 xf5, 0 x69, 0 xd0, 0 x6c, 0 x1e, 0 x0e,
0 x10, 0 x32, 0 xaa, 0 xd7, 0 xa3, 0 xef, 0 xf6, 0 xa8, 0 x65, 0 x8e, 0 xbe, 0 xee, 0 xc7, 0 x1f, 0 x01,
0 x6d, 0 x3c,
];
expand_label(TLS_AES_128_GCM_SHA256, EXPECTED);
expand_label(TLS_CHACHA20_POLY1305_SHA256, EXPECTED);
}
#[ test]
fn expand_label_sha384() {
expand_label(
TLS_AES_256_GCM_SHA384,
&[
0 x41, 0 xea, 0 x77, 0 x09, 0 x8c, 0 x90, 0 x04, 0 x10, 0 xec, 0 xbc, 0 x37, 0 xd8, 0 x5b, 0 x54,
0 xcd, 0 x7b, 0 x08, 0 x15, 0 x13, 0 x20, 0 xed, 0 x1e, 0 x3f, 0 x54, 0 x74, 0 xf7, 0 x8b, 0 x06,
0 x38, 0 x28, 0 x06, 0 x37, 0 x75, 0 x23, 0 xa2, 0 xb7, 0 x34, 0 xb1, 0 x72, 0 x2e, 0 x59, 0 x6d,
0 x5a, 0 x31, 0 xf5, 0 x53, 0 xab, 0 x99,
],
);
}
Messung V0.5 in Prozent C=90 H=98 G=94
¤ Dauer der Verarbeitung: 0.0 Sekunden
(vorverarbeitet am 2026-06-18)
¤
*© Formatika GbR, Deutschland