diff options
Diffstat (limited to 'chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h')
-rw-r--r-- | chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h b/chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h new file mode 100644 index 00000000000..1332708e0d9 --- /dev/null +++ b/chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h @@ -0,0 +1,167 @@ +// 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 two versions of ietf-webpush-encryption. The user +// of this class must pass in the version to use when constructing an instance. +// +// https://tools.ietf.org/html/draft-ietf-webpush-encryption-03 +// https://tools.ietf.org/html/draft-ietf-webpush-encryption-08 (WGLC) +// +// 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: + // Size, in bytes, of the authentication tag included in the messages. + static const size_t kAuthenticationTagBytes; + + // 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, + + // https://tools.ietf.org/html/draft-ietf-webpush-encryption-08 (WGLC) + DRAFT_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& recipient_public_key, + const base::StringPiece& sender_public_key, + 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; + + // Validates that the |ciphertext_size| is valid following the scheme. + virtual bool ValidateCiphertextSize(size_t ciphertext_size, + size_t record_size) = 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); + + 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_ |