Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_ | 5 #ifndef COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_ |
| 6 #define COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_ | 6 #define COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 #include <memory> | |
| 10 #include <string> | 11 #include <string> |
| 11 | 12 |
| 12 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 13 #include "base/gtest_prod_util.h" | 14 #include "base/gtest_prod_util.h" |
| 14 #include "base/strings/string_piece.h" | 15 #include "base/strings/string_piece.h" |
| 15 | 16 |
| 16 namespace gcm { | 17 namespace gcm { |
| 17 | 18 |
| 18 // Messages delivered through GCM may be encrypted according to the IETF Web | 19 // Messages delivered through GCM may be encrypted according to the IETF Web |
| 19 // Push protocol, as described in draft-ietf-webpush-encryption: | 20 // Push protocol. We support the third draft of ietf-webpush-encryption: |
| 20 // | 21 // |
| 21 // https://tools.ietf.org/html/draft-ietf-webpush-encryption | 22 // https://tools.ietf.org/html/draft-ietf-webpush-encryption-03 |
| 22 // | 23 // |
| 23 // This class implements the ability to encrypt or decrypt such messages using | 24 // This class implements the ability to encrypt or decrypt such messages using |
| 24 // AEAD_AES_128_GCM with a 16-octet authentication tag. The encrypted payload | 25 // AEAD_AES_128_GCM with a 16-octet authentication tag. The encrypted payload |
| 25 // will be stored in a single record as described in | 26 // will be stored in a single record. |
| 26 // draft-thomson-http-encryption: | |
| 27 // | |
| 28 // https://tools.ietf.org/html/draft-thomson-http-encryption | |
| 29 // | 27 // |
| 30 // Note that while this class is not responsible for creating or storing the | 28 // Note that while this class is not responsible for creating or storing the |
| 31 // actual keys, it uses a key derivation function for the actual message | 29 // actual keys, it uses a key derivation function for the actual message |
| 32 // encryption/decryption, thus allowing for the safe re-use of keys in multiple | 30 // encryption/decryption, thus allowing for the safe re-use of keys in multiple |
| 33 // messages provided that a cryptographically-strong random salt is used. | 31 // messages provided that a cryptographically-strong random salt is used. |
| 34 class GCMMessageCryptographer { | 32 class GCMMessageCryptographer { |
| 35 public: | 33 public: |
| 36 // Salt size, in bytes, that will be used together with the key to create a | 34 // Salt size, in bytes, that will be used together with the key to create a |
| 37 // unique content encryption key for a given message. | 35 // unique content encryption key for a given message. |
| 38 static const size_t kSaltSize; | 36 static const size_t kSaltSize; |
| 39 | 37 |
| 40 // Creates a new cryptographer, identifying the group used for the key | 38 // Version of the encryption scheme desired by the consumer. |
| 41 // agreement, and the public keys of both the recipient and sender. | 39 enum class Version { |
| 42 GCMMessageCryptographer(const base::StringPiece& recipient_public_key, | 40 // https://tools.ietf.org/html/draft-ietf-webpush-encryption-03 |
| 43 const base::StringPiece& sender_public_key, | 41 DRAFT_03 |
| 44 const std::string& auth_secret); | |
| 45 | 42 |
| 43 // TODO(peter): Add support for ietf-webpush-encryption-08. | |
| 44 }; | |
| 45 | |
| 46 // Interface that different versions of the encryption scheme must implement. | |
| 47 class EncryptionScheme { | |
| 48 public: | |
| 49 virtual ~EncryptionScheme() {} | |
| 50 | |
| 51 // Type of encoding to produce in GenerateInfoForContentEncoding(). | |
| 52 enum class EncodingType { CONTENT_ENCRYPTION_KEY, NONCE }; | |
| 53 | |
| 54 // Derives the pseuro random key (PRK) to use for deriving the content | |
|
martijnc
2017/03/28 16:26:36
typo: pseudo
Peter Beverloo
2017/04/07 17:48:22
Done.
| |
| 55 // encryption key and the nonce. | |
| 56 virtual std::string DerivePseudoRandomKey( | |
| 57 const base::StringPiece& ecdh_shared_secret, | |
| 58 const base::StringPiece& auth_secret) = 0; | |
| 59 | |
| 60 // Generates the info string used for generating the content encryption key | |
| 61 // and the nonce used for the cryptographic transformation. | |
| 62 virtual std::string GenerateInfoForContentEncoding( | |
| 63 EncodingType type, | |
| 64 const base::StringPiece& recipient_public_key, | |
| 65 const base::StringPiece& sender_public_key) = 0; | |
| 66 | |
| 67 // Creates an encryption record to contain the given |plaintext|. | |
| 68 virtual std::string CreateRecord(const base::StringPiece& plaintext) = 0; | |
| 69 | |
| 70 // Verifies that the padding included in |record| is valid and removes it | |
| 71 // from the StringPiece. Returns whether the padding was valid. | |
| 72 virtual bool ValidateAndRemovePadding(base::StringPiece& record) = 0; | |
| 73 }; | |
| 74 | |
| 75 // Creates a new cryptographer for |version| of the encryption scheme. | |
| 76 explicit GCMMessageCryptographer(Version version); | |
| 46 ~GCMMessageCryptographer(); | 77 ~GCMMessageCryptographer(); |
| 47 | 78 |
| 48 // Encrypts |plaintext| using the |ikm| and the |salt|, both of which must be | 79 // Encrypts the |plaintext| in accordance with the Web Push Encryption scheme |
| 49 // 16 octets in length. The |plaintext| will be written to a single record, | 80 // this cryptographer represents, storing the result in |*record_size| and |
| 50 // and will include a 16 octet authentication tag. The encrypted result will | 81 // |*ciphertext|. Returns whether encryption was successful. |
| 51 // be written to |ciphertext|, the record size to |record_size|. This | 82 // |
| 52 // implementation does not support prepending padding to the |plaintext|. | 83 // |recipient_public_key|: Recipient's key as an uncompressed P-256 EC point. |
| 53 bool Encrypt(const base::StringPiece& plaintext, | 84 // |sender_public_key|: Sender's key as an uncompressed P-256 EC point. |
| 54 const base::StringPiece& ikm, | 85 // |ecdh_shared_secret|: 32-byte shared secret between the key pairs. |
| 86 // |auth_secret|: 16-byte prearranged secret between recipient and sender. | |
| 87 // |salt|: 16-byte cryptographically secure salt unique to the message. | |
| 88 // |plaintext|: The plaintext that is to be encrypted. | |
| 89 // |*record_size|: Out parameter in which the record size will be written. | |
| 90 // |*ciphertext|: Out parameter in which the ciphertext will be written. | |
| 91 bool Encrypt(const base::StringPiece& recipient_public_key, | |
| 92 const base::StringPiece& sender_public_key, | |
| 93 const base::StringPiece& ecdh_shared_secret, | |
| 94 const base::StringPiece& auth_secret, | |
| 55 const base::StringPiece& salt, | 95 const base::StringPiece& salt, |
| 96 const base::StringPiece& plaintext, | |
| 56 size_t* record_size, | 97 size_t* record_size, |
| 57 std::string* ciphertext) const WARN_UNUSED_RESULT; | 98 std::string* ciphertext) const WARN_UNUSED_RESULT; |
| 58 | 99 |
| 59 // Decrypts |ciphertext| using the |ikm| and the |salt|, both of which must be | 100 // Decrypts the |ciphertext| in accordance with the Web Push Encryption scheme |
| 60 // 16 octets in length. The result will be stored in |plaintext|. Note that | 101 // this cryptographer represents, storing the result in |*plaintext|. Returns |
| 61 // there must only be a single record, per draft-thomson-http-encryption-01. | 102 // whether decryption was successful. |
| 62 bool Decrypt(const base::StringPiece& ciphertext, | 103 // |
| 63 const base::StringPiece& ikm, | 104 // |recipient_public_key|: Recipient's key as an uncompressed P-256 EC point. |
| 105 // |sender_public_key|: Sender's key as an uncompressed P-256 EC point. | |
| 106 // |ecdh_shared_secret|: 32-byte shared secret between the key pairs. | |
| 107 // |auth_secret|: 16-byte prearranged secret between recipient and sender. | |
| 108 // |salt|: 16-byte cryptographically secure salt unique to the message. | |
| 109 // |ciphertext|: The ciphertext that is to be decrypted. | |
| 110 // |record_size|: Size of a single record. Must be larger than or equal to | |
| 111 // len(plaintext) plus the ciphertext's overhead (18 bytes). | |
| 112 // |*plaintext|: Out parameter in which the plaintext will be written. | |
| 113 bool Decrypt(const base::StringPiece& recipient_public_key, | |
| 114 const base::StringPiece& sender_public_key, | |
| 115 const base::StringPiece& ecdh_shared_secret, | |
| 116 const base::StringPiece& auth_secret, | |
| 64 const base::StringPiece& salt, | 117 const base::StringPiece& salt, |
| 118 const base::StringPiece& ciphertext, | |
| 65 size_t record_size, | 119 size_t record_size, |
| 66 std::string* plaintext) const WARN_UNUSED_RESULT; | 120 std::string* plaintext) const WARN_UNUSED_RESULT; |
| 67 | 121 |
| 68 private: | 122 private: |
| 69 FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, AuthSecretAffectsIKM); | 123 FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, AuthSecretAffectsPRK); |
| 70 FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, InvalidRecordPadding); | 124 FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, InvalidRecordPadding); |
| 71 FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, NonceGeneration); | |
| 72 friend class GCMMessageCryptographerReferenceTest; | |
| 73 | 125 |
| 74 // Size, in bytes, of the authentication tag included in the messages. | 126 // Size, in bytes, of the authentication tag included in the messages. |
| 75 static const size_t kAuthenticationTagBytes; | 127 static const size_t kAuthenticationTagBytes; |
| 76 | 128 |
| 77 enum Mode { ENCRYPT, DECRYPT }; | 129 enum class Direction { ENCRYPT, DECRYPT }; |
| 78 | 130 |
| 79 // Private implementation of the encryption and decryption routines, provided | 131 // Derives the content encryption key from |ecdh_shared_secret| and |salt|. |
| 80 // by BoringSSL. | 132 std::string DeriveContentEncryptionKey( |
| 81 bool EncryptDecryptRecordInternal(Mode mode, | 133 const base::StringPiece& recipient_public_key, |
| 82 const base::StringPiece& input, | 134 const base::StringPiece& sender_public_key, |
| 83 const base::StringPiece& key, | 135 const base::StringPiece& ecdh_shared_secret, |
| 84 const base::StringPiece& nonce, | 136 const base::StringPiece& salt) const; |
| 85 std::string* output) const; | |
| 86 | 137 |
| 87 // Derives the pseuro random key (PRK) to use for deriving the content | 138 // Derives the nonce from |ecdh_shared_secret| and |salt|. |
| 88 // encryption key and the nonce. If |auth_secret_| is not the empty string, | 139 std::string DeriveNonce(const base::StringPiece& recipient_public_key, |
| 89 // another HKDF will be invoked between the |key| and the |auth_secret_|. | 140 const base::StringPiece& sender_public_key, |
| 90 std::string DerivePseudoRandomKey(const base::StringPiece& ikm) const; | 141 const base::StringPiece& ecdh_shared_secret, |
| 91 | |
| 92 // Derives the content encryption key from |prk| and |salt|. | |
| 93 std::string DeriveContentEncryptionKey(const base::StringPiece& prk, | |
| 94 const base::StringPiece& salt) const; | |
| 95 | |
| 96 // Derives the nonce from |prk| and |salt|. | |
| 97 std::string DeriveNonce(const base::StringPiece& prk, | |
| 98 const base::StringPiece& salt) const; | 142 const base::StringPiece& salt) const; |
| 99 | 143 |
| 100 // The info parameters to the HKDFs used for deriving the content encryption | 144 // Private implementation of the encryption and decryption routines. |
| 101 // key and the nonce. These contain the label of the used curve, as well as | 145 bool TransformRecord(Direction direction, |
| 102 // the sender and recipient's public keys. | 146 const base::StringPiece& input, |
| 103 std::string content_encryption_key_info_; | 147 const base::StringPiece& key, |
| 104 std::string nonce_info_; | 148 const base::StringPiece& nonce, |
| 149 std::string* output) const; | |
| 105 | 150 |
| 106 // The pre-shared authentication secret associated with the subscription. | 151 // Implementation of the encryption scheme. Set in the constructor depending |
| 107 std::string auth_secret_; | 152 // on the version requested by the consumer. |
| 108 | 153 std::unique_ptr<EncryptionScheme> encryption_scheme_; |
| 109 // Whether an empty auth secret is acceptable when deriving the IKM. This only | |
| 110 // is the case when running tests against the reference vectors. | |
| 111 bool allow_empty_auth_secret_for_tests_ = false; | |
| 112 | |
| 113 void set_allow_empty_auth_secret_for_tests(bool value) { | |
| 114 allow_empty_auth_secret_for_tests_ = value; | |
| 115 } | |
| 116 }; | 154 }; |
| 117 | 155 |
| 118 } // namespace gcm | 156 } // namespace gcm |
| 119 | 157 |
| 120 #endif // COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_ | 158 #endif // COMPONENTS_GCM_DRIVER_CRYPTO_GCM_MESSAGE_CRYPTOGRAPHER_H_ |
| OLD | NEW |