1 // Copyright 2020 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 /////////////////////////////////////////////////////////////////////////////// 16 17 #ifndef TINK_EXPERIMENTAL_PQCRYPTO_KEM_SUBTLE_CECPQ2_HKDF_SENDER_KEM_BORINGSSL_H_ 18 #define TINK_EXPERIMENTAL_PQCRYPTO_KEM_SUBTLE_CECPQ2_HKDF_SENDER_KEM_BORINGSSL_H_ 19 20 #include <memory> 21 #include <string> 22 #include <utility> 23 24 #include "absl/strings/string_view.h" 25 #include "openssl/curve25519.h" 26 #include "openssl/ec.h" 27 #include "openssl/hrss.h" 28 #include "tink/internal/fips_utils.h" 29 #include "tink/subtle/common_enums.h" 30 #include "tink/util/secret_data.h" 31 #include "tink/util/statusor.h" 32 33 namespace crypto { 34 namespace tink { 35 namespace subtle { 36 37 // This class implements the CECPQ2 hybrid KEM from the sender's perspective, 38 // using Boring SSL for the underlying cryptographic operations. 39 // This class is made generic enough so that extending the ECC algorithm to 40 // support other curves is trivial. As of now, the only supported curve is 41 // Curve25519. 42 // 43 // CECPQ2 combines both X25519 KEM and NTRU-HRSS KEM into a single hybrid KEM. 44 // The NTRU-HRSS is a structured lattice-based key encapsulation mechanism. It 45 // was originally proposed in [1] and submitted to the NIST Post-Quantum 46 // Cryptography standardization process [2]. 47 // 48 // During the course of the NIST PQC standardization process, the NTRU-HRSS 49 // proposal merged with another proposal (NTRUEncrypt). The resulting scheme, 50 // simply called NTRU [3], is a 3rd round finalist of the NIST PQC 51 // standardization process. 52 // 53 // The implementation available in BoringSSL is based on [1] but it 54 // uses a different KEM construction based on [4]. Similar path has been taken 55 // by the NTRU team in the NIST competition which later adopted [4] as their 56 // QROM security proof approach. Note that the BoringSSL implementation is *not* 57 // compatible with the 3rd Round finalist NTRU running in the NIST Post-Quantum 58 // Cryptography standardization process [5]. 59 // 60 // References: 61 // [1]: https://eprint.iacr.org/2017/667.pdf 62 // [2]: https://csrc.nist.gov/Projects/post-quantum-cryptography/ 63 // [3]: https://ntru.org/ 64 // [4]: https://eprint.iacr.org/2017/1005.pdf 65 // [5]: https://ntru.org/release/NIST-PQ-Submission-NTRU-20201016.tar.gz 66 class Cecpq2HkdfSenderKemBoringSsl { 67 public: 68 // Container for the generated key and associated kem_bytes data. 69 class KemKey { 70 public: 71 KemKey() = default; KemKey(std::string kem_bytes,util::SecretData symmetric_key)72 explicit KemKey(std::string kem_bytes, util::SecretData symmetric_key) 73 : kem_bytes_(std::move(kem_bytes)), 74 symmetric_key_(std::move(symmetric_key)) {} get_kem_bytes()75 const std::string& get_kem_bytes() const { return kem_bytes_; } get_symmetric_key()76 const util::SecretData& get_symmetric_key() const { return symmetric_key_; } 77 78 private: 79 // The kem_bytes variable stores both X25519 and HRSS kem_bytes in a 80 // contiguous form. We note that for X25519, the kem_bytes consists of the 81 // X25519 public key, while for HRSS it is the encrypted shared secret. 82 std::string kem_bytes_; 83 util::SecretData symmetric_key_; 84 }; 85 86 // Constructs a sender CECPQ2 KEM for recipient's ECC public key, which must 87 // be a big-endian byte array, and recipient's HRSS public key. This method is 88 // made generic enough so that extending the ECC algorithm to support other 89 // curves is trivial. 90 static crypto::tink::util::StatusOr< 91 std::unique_ptr<const Cecpq2HkdfSenderKemBoringSsl>> 92 New(EllipticCurveType curve, absl::string_view ec_pubx, 93 absl::string_view ec_puby, absl::string_view marshalled_hrss_pub); 94 95 // Generates ephemeral key pairs, computes ECC's shared secret based on 96 // generated ephemeral key and recipient's public key, generate a random 97 // shared secret and encapsulates it using recipient's HRSS public key. 98 // Then it uses HKDF to derive the symmetric key from both shared secrets, 99 // 'hkdf_info' and hkdf_salt. This method is made generic enough so that 100 // extending the ECC algorithm to support other curves is trivial. 101 virtual crypto::tink::util::StatusOr<std::unique_ptr<const KemKey>> 102 GenerateKey(HashType hash, absl::string_view hkdf_salt, 103 absl::string_view hkdf_info, uint32_t key_size_in_bytes, 104 EcPointFormat point_format) const = 0; 105 106 virtual ~Cecpq2HkdfSenderKemBoringSsl() = default; 107 }; 108 109 // Implementation of Cecpq2HkdfSenderKemBoringSsl for X25519 and HRSS. 110 class Cecpq2HkdfX25519SenderKemBoringSsl : public Cecpq2HkdfSenderKemBoringSsl { 111 public: 112 // Constructs a sender CECPQ2 KEM for recipient's X25519 public key, which 113 // must be a big-endian byte array, and recipient's HRSS public key. 114 static crypto::tink::util::StatusOr< 115 std::unique_ptr<const Cecpq2HkdfSenderKemBoringSsl>> 116 New(EllipticCurveType curve, absl::string_view pubx, absl::string_view puby, 117 absl::string_view marshalled_hrss_pub); 118 119 // Generates an ephemeral X25519 key pair, computes the X25519's shared secret 120 // based on the ephemeral key and recipient's public key, generates a random 121 // shared secret and encapsulates it using the recipient's HRSS public key. 122 // Then it uses HKDF to derive the symmetric key from both shared secrets, 123 // 'hkdf_info' and hkdf_salt. 124 crypto::tink::util::StatusOr<std::unique_ptr<const KemKey>> GenerateKey( 125 HashType hash, absl::string_view hkdf_salt, absl::string_view hkdf_info, 126 uint32_t key_size_in_bytes, EcPointFormat point_format) const override; 127 128 // Flag to indicate CECPQ2 is not FIPS compliant 129 static constexpr crypto::tink::internal::FipsCompatibility kFipsStatus = 130 crypto::tink::internal::FipsCompatibility::kNotFips; 131 132 private: 133 // The private constructor only takes the X25519 and HRSS public keys. The 134 // curve is not provided as a parameter here because the curve validation has 135 // already been made in the New() method defined above. 136 explicit Cecpq2HkdfX25519SenderKemBoringSsl( 137 absl::string_view peer_ec_pubx, absl::string_view marshalled_hrss_pub); 138 139 // X25519 and HRSS public key containers. We note that the BoringSSL 140 // implementation of HRSS requires that the HRSS public key is stored in the 141 // *marshalled* format. This is done by calling the HRSS_marshal_public_key 142 // function from BoringSSL (see the tests available in cecpq2_hkdf_sender_kem 143 // _boringssl_test.cc file that demonstrate this process). If this process is 144 // not done, the internal raw HRSS public key representation (using the struct 145 // HRSS_public_key data structure) might cause padding problems depending on 146 // the compiler options. 147 // X25519 public key of size X25519_PUBLIC_VALUE_LEN 148 std::string peer_public_key_x25519_; 149 // HRSS public key of size HRSS_PUBLIC_KEY_BYTES 150 std::string peer_marshalled_public_key_hrss_; 151 }; 152 153 } // namespace subtle 154 } // namespace tink 155 } // namespace crypto 156 157 #endif // TINK_EXPERIMENTAL_PQCRYPTO_KEM_SUBTLE_CECPQ2_HKDF_SENDER_KEM_BORINGSSL_H_ 158