blob: 52402c39fe010968e2ccb554e096f9b122e26023 [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 <memory>
#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. We support the third draft of ietf-webpush-encryption:
//
// https://tools.ietf.org/html/draft-ietf-webpush-encryption-03
//
// 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.
//
// 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;
// Version of the encryption scheme desired by the consumer.
enum class Version {
// https://tools.ietf.org/html/draft-ietf-webpush-encryption-03
DRAFT_03
// TODO(peter): Add support for ietf-webpush-encryption-08.
};
// Interface that different versions of the encryption scheme must implement.
class EncryptionScheme {
public:
virtual ~EncryptionScheme() {}
// Type of encoding to produce in GenerateInfoForContentEncoding().
enum class EncodingType { CONTENT_ENCRYPTION_KEY, NONCE };
// Derives the pseudo random key (PRK) to use for deriving the content
// encryption key and the nonce.
virtual std::string DerivePseudoRandomKey(
const base::StringPiece& ecdh_shared_secret,
const base::StringPiece& auth_secret) = 0;
// Generates the info string used for generating the content encryption key
// and the nonce used for the cryptographic transformation.
virtual std::string GenerateInfoForContentEncoding(
EncodingType type,
const base::StringPiece& recipient_public_key,
const base::StringPiece& sender_public_key) = 0;
// Creates an encryption record to contain the given |plaintext|.
virtual std::string CreateRecord(const base::StringPiece& plaintext) = 0;
// Verifies that the padding included in |record| is valid and removes it
// from the StringPiece. Returns whether the padding was valid.
virtual bool ValidateAndRemovePadding(base::StringPiece& record) = 0;
};
// Creates a new cryptographer for |version| of the encryption scheme.
explicit GCMMessageCryptographer(Version version);
~GCMMessageCryptographer();
// Encrypts the |plaintext| in accordance with the Web Push Encryption scheme
// this cryptographer represents, storing the result in |*record_size| and
// |*ciphertext|. Returns whether encryption was successful.
//
// |recipient_public_key|: Recipient's key as an uncompressed P-256 EC point.
// |sender_public_key|: Sender's key as an uncompressed P-256 EC point.
// |ecdh_shared_secret|: 32-byte shared secret between the key pairs.
// |auth_secret|: 16-byte prearranged secret between recipient and sender.
// |salt|: 16-byte cryptographically secure salt unique to the message.
// |plaintext|: The plaintext that is to be encrypted.
// |*record_size|: Out parameter in which the record size will be written.
// |*ciphertext|: Out parameter in which the ciphertext will be written.
bool Encrypt(const base::StringPiece& recipient_public_key,
const base::StringPiece& sender_public_key,
const base::StringPiece& ecdh_shared_secret,
const base::StringPiece& auth_secret,
const base::StringPiece& salt,
const base::StringPiece& plaintext,
size_t* record_size,
std::string* ciphertext) const WARN_UNUSED_RESULT;
// Decrypts the |ciphertext| in accordance with the Web Push Encryption scheme
// this cryptographer represents, storing the result in |*plaintext|. Returns
// whether decryption was successful.
//
// |recipient_public_key|: Recipient's key as an uncompressed P-256 EC point.
// |sender_public_key|: Sender's key as an uncompressed P-256 EC point.
// |ecdh_shared_secret|: 32-byte shared secret between the key pairs.
// |auth_secret|: 16-byte prearranged secret between recipient and sender.
// |salt|: 16-byte cryptographically secure salt unique to the message.
// |ciphertext|: The ciphertext that is to be decrypted.
// |record_size|: Size of a single record. Must be larger than or equal to
// len(plaintext) plus the ciphertext's overhead (18 bytes).
// |*plaintext|: Out parameter in which the plaintext will be written.
bool Decrypt(const base::StringPiece& recipient_public_key,
const base::StringPiece& sender_public_key,
const base::StringPiece& ecdh_shared_secret,
const base::StringPiece& auth_secret,
const base::StringPiece& salt,
const base::StringPiece& ciphertext,
size_t record_size,
std::string* plaintext) const WARN_UNUSED_RESULT;
private:
FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, AuthSecretAffectsPRK);
FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, InvalidRecordPadding);
// Size, in bytes, of the authentication tag included in the messages.
static const size_t kAuthenticationTagBytes;
enum class Direction { ENCRYPT, DECRYPT };
// Derives the content encryption key from |ecdh_shared_secret| and |salt|.
std::string DeriveContentEncryptionKey(
const base::StringPiece& recipient_public_key,
const base::StringPiece& sender_public_key,
const base::StringPiece& ecdh_shared_secret,
const base::StringPiece& salt) const;
// Derives the nonce from |ecdh_shared_secret| and |salt|.
std::string DeriveNonce(const base::StringPiece& recipient_public_key,
const base::StringPiece& sender_public_key,
const base::StringPiece& ecdh_shared_secret,
const base::StringPiece& salt) const;
// Private implementation of the encryption and decryption routines.
bool TransformRecord(Direction direction,
const base::StringPiece& input,
const base::StringPiece& key,
const base::StringPiece& nonce,
std::string* output) const;
// Implementation of the encryption scheme. Set in the constructor depending
// on the version requested by the consumer.
std::unique_ptr<EncryptionScheme> encryption_scheme_;
};
} // namespace gcm
#endif // COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_