blob: 5aaf083cc27eec05cd3afddd6623a63e29897de7 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_
#define COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_
#include <stddef.h>
#include <stdint.h>
#include <string>
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/strings/string_piece.h"
namespace gcm {
// Messages delivered through GCM may be encrypted according to the IETF Web
// Push protocol, as described in draft-ietf-webpush-encryption:
//
// https://tools.ietf.org/html/draft-ietf-webpush-encryption
//
// This class implements the ability to encrypt or decrypt such messages using
// AEAD_AES_128_GCM with a 16-octet authentication tag. The encrypted payload
// will be stored in a single record as described in
// draft-thomson-http-encryption:
//
// https://tools.ietf.org/html/draft-thomson-http-encryption
//
// Note that while this class is not responsible for creating or storing the
// actual keys, it uses a key derivation function for the actual message
// encryption/decryption, thus allowing for the safe re-use of keys in multiple
// messages provided that a cryptographically-strong random salt is used.
class GCMMessageCryptographer {
public:
// Salt size, in bytes, that will be used together with the key to create a
// unique content encryption key for a given message.
static const size_t kSaltSize;
// Creates a new cryptographer, identifying the group used for the key
// agreement, and the public keys of both the recipient and sender.
GCMMessageCryptographer(const base::StringPiece& recipient_public_key,
const base::StringPiece& sender_public_key,
const std::string& auth_secret);
~GCMMessageCryptographer();
// Encrypts |plaintext| using the |ikm| and the |salt|, both of which must be
// 16 octets in length. The |plaintext| will be written to a single record,
// and will include a 16 octet authentication tag. The encrypted result will
// be written to |ciphertext|, the record size to |record_size|. This
// implementation does not support prepending padding to the |plaintext|.
bool Encrypt(const base::StringPiece& plaintext,
const base::StringPiece& ikm,
const base::StringPiece& salt,
size_t* record_size,
std::string* ciphertext) const WARN_UNUSED_RESULT;
// Decrypts |ciphertext| using the |ikm| and the |salt|, both of which must be
// 16 octets in length. The result will be stored in |plaintext|. Note that
// there must only be a single record, per draft-thomson-http-encryption-01.
bool Decrypt(const base::StringPiece& ciphertext,
const base::StringPiece& ikm,
const base::StringPiece& salt,
size_t record_size,
std::string* plaintext) const WARN_UNUSED_RESULT;
private:
FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, AuthSecretAffectsIKM);
FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, InvalidRecordPadding);
FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, NonceGeneration);
friend class GCMMessageCryptographerReferenceTest;
// Size, in bytes, of the authentication tag included in the messages.
static const size_t kAuthenticationTagBytes;
enum Mode { ENCRYPT, DECRYPT };
// Private implementation of the encryption and decryption routines, provided
// by BoringSSL.
bool EncryptDecryptRecordInternal(Mode mode,
const base::StringPiece& input,
const base::StringPiece& key,
const base::StringPiece& nonce,
std::string* output) const;
// Derives the pseuro random key (PRK) to use for deriving the content
// encryption key and the nonce. If |auth_secret_| is not the empty string,
// another HKDF will be invoked between the |key| and the |auth_secret_|.
std::string DerivePseudoRandomKey(const base::StringPiece& ikm) const;
// Derives the content encryption key from |prk| and |salt|.
std::string DeriveContentEncryptionKey(const base::StringPiece& prk,
const base::StringPiece& salt) const;
// Derives the nonce from |prk| and |salt|.
std::string DeriveNonce(const base::StringPiece& prk,
const base::StringPiece& salt) const;
// The info parameters to the HKDFs used for deriving the content encryption
// key and the nonce. These contain the label of the used curve, as well as
// the sender and recipient's public keys.
std::string content_encryption_key_info_;
std::string nonce_info_;
// The pre-shared authentication secret associated with the subscription.
std::string auth_secret_;
// Whether an empty auth secret is acceptable when deriving the IKM. This only
// is the case when running tests against the reference vectors.
bool allow_empty_auth_secret_for_tests_ = false;
void set_allow_empty_auth_secret_for_tests(bool value) {
allow_empty_auth_secret_for_tests_ = value;
}
};
} // namespace gcm
#endif // COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_