gcm_message_cryptographer.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_
  5. #define COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <memory>
  9. #include <string>
  10. #include "base/gtest_prod_util.h"
  11. #include "base/strings/string_piece.h"
  12. namespace gcm {
  13. // Messages delivered through GCM may be encrypted according to the IETF Web
  14. // Push protocol. We support two versions of ietf-webpush-encryption. The user
  15. // of this class must pass in the version to use when constructing an instance.
  16. //
  17. // https://tools.ietf.org/html/draft-ietf-webpush-encryption-03
  18. // https://tools.ietf.org/html/draft-ietf-webpush-encryption-08 (WGLC)
  19. //
  20. // This class implements the ability to encrypt or decrypt such messages using
  21. // AEAD_AES_128_GCM with a 16-octet authentication tag. The encrypted payload
  22. // will be stored in a single record.
  23. //
  24. // Note that while this class is not responsible for creating or storing the
  25. // actual keys, it uses a key derivation function for the actual message
  26. // encryption/decryption, thus allowing for the safe re-use of keys in multiple
  27. // messages provided that a cryptographically-strong random salt is used.
  28. class GCMMessageCryptographer {
  29. public:
  30. // Size, in bytes, of the authentication tag included in the messages.
  31. static const size_t kAuthenticationTagBytes;
  32. // Salt size, in bytes, that will be used together with the key to create a
  33. // unique content encryption key for a given message.
  34. static const size_t kSaltSize;
  35. // Version of the encryption scheme desired by the consumer.
  36. enum class Version {
  37. // https://tools.ietf.org/html/draft-ietf-webpush-encryption-03
  38. DRAFT_03,
  39. // https://tools.ietf.org/html/draft-ietf-webpush-encryption-08 (WGLC)
  40. DRAFT_08
  41. };
  42. // Interface that different versions of the encryption scheme must implement.
  43. class EncryptionScheme {
  44. public:
  45. virtual ~EncryptionScheme() {}
  46. // Type of encoding to produce in GenerateInfoForContentEncoding().
  47. enum class EncodingType { CONTENT_ENCRYPTION_KEY, NONCE };
  48. // Derives the pseudo random key (PRK) to use for deriving the content
  49. // encryption key and the nonce.
  50. virtual std::string DerivePseudoRandomKey(
  51. const base::StringPiece& recipient_public_key,
  52. const base::StringPiece& sender_public_key,
  53. const base::StringPiece& ecdh_shared_secret,
  54. const base::StringPiece& auth_secret) = 0;
  55. // Generates the info string used for generating the content encryption key
  56. // and the nonce used for the cryptographic transformation.
  57. virtual std::string GenerateInfoForContentEncoding(
  58. EncodingType type,
  59. const base::StringPiece& recipient_public_key,
  60. const base::StringPiece& sender_public_key) = 0;
  61. // Creates an encryption record to contain the given |plaintext|.
  62. virtual std::string CreateRecord(const base::StringPiece& plaintext) = 0;
  63. // Validates that the |ciphertext_size| is valid following the scheme.
  64. virtual bool ValidateCiphertextSize(size_t ciphertext_size,
  65. size_t record_size) = 0;
  66. // Verifies that the padding included in |record| is valid and removes it
  67. // from the StringPiece. Returns whether the padding was valid.
  68. virtual bool ValidateAndRemovePadding(base::StringPiece& record) = 0;
  69. };
  70. // Creates a new cryptographer for |version| of the encryption scheme.
  71. explicit GCMMessageCryptographer(Version version);
  72. ~GCMMessageCryptographer();
  73. // Encrypts the |plaintext| in accordance with the Web Push Encryption scheme
  74. // this cryptographer represents, storing the result in |*record_size| and
  75. // |*ciphertext|. Returns whether encryption was successful.
  76. //
  77. // |recipient_public_key|: Recipient's key as an uncompressed P-256 EC point.
  78. // |sender_public_key|: Sender's key as an uncompressed P-256 EC point.
  79. // |ecdh_shared_secret|: 32-byte shared secret between the key pairs.
  80. // |auth_secret|: 16-byte prearranged secret between recipient and sender.
  81. // |salt|: 16-byte cryptographically secure salt unique to the message.
  82. // |plaintext|: The plaintext that is to be encrypted.
  83. // |*record_size|: Out parameter in which the record size will be written.
  84. // |*ciphertext|: Out parameter in which the ciphertext will be written.
  85. [[nodiscard]] bool Encrypt(const base::StringPiece& recipient_public_key,
  86. const base::StringPiece& sender_public_key,
  87. const base::StringPiece& ecdh_shared_secret,
  88. const base::StringPiece& auth_secret,
  89. const base::StringPiece& salt,
  90. const base::StringPiece& plaintext,
  91. size_t* record_size,
  92. std::string* ciphertext) const;
  93. // Decrypts the |ciphertext| in accordance with the Web Push Encryption scheme
  94. // this cryptographer represents, storing the result in |*plaintext|. Returns
  95. // whether decryption was successful.
  96. //
  97. // |recipient_public_key|: Recipient's key as an uncompressed P-256 EC point.
  98. // |sender_public_key|: Sender's key as an uncompressed P-256 EC point.
  99. // |ecdh_shared_secret|: 32-byte shared secret between the key pairs.
  100. // |auth_secret|: 16-byte prearranged secret between recipient and sender.
  101. // |salt|: 16-byte cryptographically secure salt unique to the message.
  102. // |ciphertext|: The ciphertext that is to be decrypted.
  103. // |record_size|: Size of a single record. Must be larger than or equal to
  104. // len(plaintext) plus the ciphertext's overhead (18 bytes).
  105. // |*plaintext|: Out parameter in which the plaintext will be written.
  106. [[nodiscard]] bool Decrypt(const base::StringPiece& recipient_public_key,
  107. const base::StringPiece& sender_public_key,
  108. const base::StringPiece& ecdh_shared_secret,
  109. const base::StringPiece& auth_secret,
  110. const base::StringPiece& salt,
  111. const base::StringPiece& ciphertext,
  112. size_t record_size,
  113. std::string* plaintext) const;
  114. private:
  115. FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, AuthSecretAffectsPRK);
  116. FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, InvalidRecordPadding);
  117. enum class Direction { ENCRYPT, DECRYPT };
  118. // Derives the content encryption key from |ecdh_shared_secret| and |salt|.
  119. std::string DeriveContentEncryptionKey(
  120. const base::StringPiece& recipient_public_key,
  121. const base::StringPiece& sender_public_key,
  122. const base::StringPiece& ecdh_shared_secret,
  123. const base::StringPiece& salt) const;
  124. // Derives the nonce from |ecdh_shared_secret| and |salt|.
  125. std::string DeriveNonce(const base::StringPiece& recipient_public_key,
  126. const base::StringPiece& sender_public_key,
  127. const base::StringPiece& ecdh_shared_secret,
  128. const base::StringPiece& salt) const;
  129. // Private implementation of the encryption and decryption routines.
  130. bool TransformRecord(Direction direction,
  131. const base::StringPiece& input,
  132. const base::StringPiece& key,
  133. const base::StringPiece& nonce,
  134. std::string* output) const;
  135. // Implementation of the encryption scheme. Set in the constructor depending
  136. // on the version requested by the consumer.
  137. std::unique_ptr<EncryptionScheme> encryption_scheme_;
  138. };
  139. } // namespace gcm
  140. #endif // COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_