Implement QUIC Header Protection
gfe-relnote: Protected by QUIC_VERSION_99
PiperOrigin-RevId: 247137283
Change-Id: I1deb08d304b7739c3c8fa6b995e55fbd8652dc1e
diff --git a/quic/core/crypto/aes_base_encrypter.cc b/quic/core/crypto/aes_base_encrypter.cc
index 49fc71d..cdb21b8 100644
--- a/quic/core/crypto/aes_base_encrypter.cc
+++ b/quic/core/crypto/aes_base_encrypter.cc
@@ -11,7 +11,7 @@
bool AesBaseEncrypter::SetHeaderProtectionKey(QuicStringPiece key) {
if (key.size() != GetKeySize()) {
- QUIC_BUG << "Invalid key size for header protection";
+ QUIC_BUG << "Invalid key size for header protection: " << key.size();
return false;
}
if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key.data()),
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc
index 724f245..57edda0 100644
--- a/quic/core/crypto/crypto_utils.cc
+++ b/quic/core/crypto/crypto_utils.cc
@@ -76,10 +76,14 @@
prf, pp_secret, "quic key", crypter->GetKeySize());
std::vector<uint8_t> iv = CryptoUtils::HkdfExpandLabel(
prf, pp_secret, "quic iv", crypter->GetIVSize());
+ std::vector<uint8_t> pn = CryptoUtils::HkdfExpandLabel(
+ prf, pp_secret, "quic hp", crypter->GetKeySize());
crypter->SetKey(
QuicStringPiece(reinterpret_cast<char*>(key.data()), key.size()));
crypter->SetIV(
QuicStringPiece(reinterpret_cast<char*>(iv.data()), iv.size()));
+ crypter->SetHeaderProtectionKey(
+ QuicStringPiece(reinterpret_cast<char*>(pn.data()), pn.size()));
}
namespace {
@@ -224,15 +228,23 @@
if (perspective == Perspective::IS_SERVER) {
if (!crypters->encrypter->SetKey(hkdf.server_write_key()) ||
!crypters->encrypter->SetNoncePrefix(hkdf.server_write_iv()) ||
+ !crypters->encrypter->SetHeaderProtectionKey(
+ hkdf.server_hp_key()) ||
!crypters->decrypter->SetKey(hkdf.client_write_key()) ||
- !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv())) {
+ !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
+ !crypters->decrypter->SetHeaderProtectionKey(
+ hkdf.client_hp_key())) {
return false;
}
} else {
if (!crypters->encrypter->SetKey(hkdf.client_write_key()) ||
!crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
+ !crypters->encrypter->SetHeaderProtectionKey(
+ hkdf.client_hp_key()) ||
!crypters->decrypter->SetKey(hkdf.server_write_key()) ||
- !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) {
+ !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv()) ||
+ !crypters->decrypter->SetHeaderProtectionKey(
+ hkdf.server_hp_key())) {
return false;
}
}
@@ -246,8 +258,10 @@
if (!crypters->encrypter->SetKey(hkdf.client_write_key()) ||
!crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
+ !crypters->encrypter->SetHeaderProtectionKey(hkdf.client_hp_key()) ||
!crypters->decrypter->SetPreliminaryKey(hkdf.server_write_key()) ||
- !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) {
+ !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv()) ||
+ !crypters->decrypter->SetHeaderProtectionKey(hkdf.server_hp_key())) {
return false;
}
break;
@@ -265,8 +279,10 @@
&nonce_prefix);
if (!crypters->decrypter->SetKey(hkdf.client_write_key()) ||
!crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
+ !crypters->decrypter->SetHeaderProtectionKey(hkdf.client_hp_key()) ||
!crypters->encrypter->SetKey(key) ||
- !crypters->encrypter->SetNoncePrefix(nonce_prefix)) {
+ !crypters->encrypter->SetNoncePrefix(nonce_prefix) ||
+ !crypters->encrypter->SetHeaderProtectionKey(hkdf.server_hp_key())) {
return false;
}
break;
diff --git a/quic/core/crypto/quic_hkdf.cc b/quic/core/crypto/quic_hkdf.cc
index 3754cab..1bd9ad5 100644
--- a/quic/core/crypto/quic_hkdf.cc
+++ b/quic/core/crypto/quic_hkdf.cc
@@ -39,8 +39,8 @@
size_t server_iv_bytes_to_generate,
size_t subkey_secret_bytes_to_generate) {
const size_t material_length =
- client_key_bytes_to_generate + client_iv_bytes_to_generate +
- server_key_bytes_to_generate + server_iv_bytes_to_generate +
+ 2 * client_key_bytes_to_generate + client_iv_bytes_to_generate +
+ 2 * server_key_bytes_to_generate + server_iv_bytes_to_generate +
subkey_secret_bytes_to_generate;
DCHECK_LT(material_length, kMaxKeyMaterialSize);
@@ -85,6 +85,19 @@
if (subkey_secret_bytes_to_generate) {
subkey_secret_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]),
subkey_secret_bytes_to_generate);
+ j += subkey_secret_bytes_to_generate;
+ }
+ // Repeat client and server key bytes for header protection keys.
+ if (client_key_bytes_to_generate) {
+ client_hp_key_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]),
+ client_key_bytes_to_generate);
+ j += client_key_bytes_to_generate;
+ }
+
+ if (server_key_bytes_to_generate) {
+ server_hp_key_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]),
+ server_key_bytes_to_generate);
+ j += server_key_bytes_to_generate;
}
}
diff --git a/quic/core/crypto/quic_hkdf.h b/quic/core/crypto/quic_hkdf.h
index fb80f7b..c57b894 100644
--- a/quic/core/crypto/quic_hkdf.h
+++ b/quic/core/crypto/quic_hkdf.h
@@ -54,6 +54,8 @@
QuicStringPiece server_write_key() const { return server_write_key_; }
QuicStringPiece server_write_iv() const { return server_write_iv_; }
QuicStringPiece subkey_secret() const { return subkey_secret_; }
+ QuicStringPiece client_hp_key() const { return client_hp_key_; }
+ QuicStringPiece server_hp_key() const { return server_hp_key_; }
private:
std::vector<uint8_t> output_;
@@ -63,6 +65,8 @@
QuicStringPiece client_write_iv_;
QuicStringPiece server_write_iv_;
QuicStringPiece subkey_secret_;
+ QuicStringPiece client_hp_key_;
+ QuicStringPiece server_hp_key_;
};
} // namespace quic