| // 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_ |