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 //     https://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 #include "securegcm/d2d_crypto_ops.h"
16 
17 #include "gtest/gtest.h"
18 #include "securemessage/crypto_ops.h"
19 #include "securemessage/secure_message_builder.h"
20 
21 namespace securegcm {
22 
23 using securemessage::CryptoOps;
24 using securemessage::HeaderAndBody;
25 using securemessage::SecureMessage;
26 
27 namespace {
28 
29 const char kPayloadData[] = "Test payload";
30 const char kSecretKeyData[] = "secret key must be 32 bytes long";
31 const char kOtherSecretKeyData[] = "other secret key****************";
32 const char kInvalidSigncryptedMessage[] = "Not a protobuf";
33 const int kSupportedProtocolVersion = 1;
34 const int kUnsupportedProtocolVersion = 2;
35 
36 }  // namespace
37 
38 class D2DCryptoOpsTest : public testing::Test {
39  public:
D2DCryptoOpsTest()40   D2DCryptoOpsTest()
41       : payload_(DEVICE_TO_DEVICE_MESSAGE, kPayloadData),
42         secret_key_(kSecretKeyData, CryptoOps::AES_256_KEY) {}
43 
44  protected:
45   const D2DCryptoOps::Payload payload_;
46   const CryptoOps::SecretKey secret_key_;
47 };
48 
TEST_F(D2DCryptoOpsTest,Signcrypt_EmptyPayload)49 TEST_F(D2DCryptoOpsTest, Signcrypt_EmptyPayload) {
50   // Signcrypting an empty payload should fail.
51   D2DCryptoOps::Payload empty_payload(DEVICE_TO_DEVICE_MESSAGE, string());
52   EXPECT_FALSE(D2DCryptoOps::SigncryptPayload(empty_payload, secret_key_));
53 }
54 
TEST_F(D2DCryptoOpsTest,VerifyDecrypt_InvalidMessage)55 TEST_F(D2DCryptoOpsTest, VerifyDecrypt_InvalidMessage) {
56   // VerifyDecrypting an invalid payload should fail.
57   EXPECT_FALSE(D2DCryptoOps::VerifyDecryptPayload(kInvalidSigncryptedMessage,
58                                                   secret_key_));
59 }
60 
TEST_F(D2DCryptoOpsTest,VerifyDecrypt_NoPublicMetadata)61 TEST_F(D2DCryptoOpsTest, VerifyDecrypt_NoPublicMetadata) {
62   std::unique_ptr<string> signcrypted_message =
63       D2DCryptoOps::SigncryptPayload(payload_, secret_key_);
64 
65   // Clear metadata field in header.
66   SecureMessage secure_message;
67   ASSERT_TRUE(secure_message.ParseFromString(*signcrypted_message));
68   HeaderAndBody header_and_body;
69   ASSERT_TRUE(
70       header_and_body.ParseFromString(secure_message.header_and_body()));
71   header_and_body.mutable_header()->clear_public_metadata();
72   secure_message.set_header_and_body(header_and_body.SerializeAsString());
73 
74   // Decrypting the message should now fail.
75   EXPECT_FALSE(D2DCryptoOps::VerifyDecryptPayload(
76       secure_message.SerializeAsString(), secret_key_));
77 }
78 
TEST_F(D2DCryptoOpsTest,VerifyDecrypt_ProtocolVersionNotSupported)79 TEST_F(D2DCryptoOpsTest, VerifyDecrypt_ProtocolVersionNotSupported) {
80   std::unique_ptr<string> signcrypted_message =
81       D2DCryptoOps::SigncryptPayload(payload_, secret_key_);
82 
83   // Change version in metadata field in header to an unsupported version.
84   SecureMessage secure_message;
85   ASSERT_TRUE(secure_message.ParseFromString(*signcrypted_message));
86   HeaderAndBody header_and_body;
87   ASSERT_TRUE(
88       header_and_body.ParseFromString(secure_message.header_and_body()));
89   GcmMetadata metadata;
90   ASSERT_TRUE(
91       metadata.ParseFromString(header_and_body.header().public_metadata()));
92   EXPECT_EQ(kSupportedProtocolVersion, metadata.version());
93   metadata.set_version(kUnsupportedProtocolVersion);
94   header_and_body.mutable_header()->set_public_metadata(
95       metadata.SerializeAsString());
96   secure_message.set_header_and_body(header_and_body.SerializeAsString());
97 
98   // Decrypting the message should now fail.
99   EXPECT_FALSE(D2DCryptoOps::VerifyDecryptPayload(
100       secure_message.SerializeAsString(), secret_key_));
101 }
102 
TEST_F(D2DCryptoOpsTest,SigncryptThenVerifyDecrypt_SuccessWithSameKey)103 TEST_F(D2DCryptoOpsTest, SigncryptThenVerifyDecrypt_SuccessWithSameKey) {
104   // Signcrypt the payload.
105   std::unique_ptr<string> signcrypted_message =
106       D2DCryptoOps::SigncryptPayload(payload_, secret_key_);
107   ASSERT_TRUE(signcrypted_message);
108 
109   // Decrypt the signcrypted message.
110   std::unique_ptr<D2DCryptoOps::Payload> decrypted_payload =
111       D2DCryptoOps::VerifyDecryptPayload(*signcrypted_message, secret_key_);
112   ASSERT_TRUE(decrypted_payload);
113 
114   // Check that decrypted payload is the same.
115   EXPECT_EQ(payload_.type(), decrypted_payload->type());
116   EXPECT_EQ(payload_.message(), decrypted_payload->message());
117 }
118 
TEST_F(D2DCryptoOpsTest,SigncryptThenVerifyDecrypt_FailsWithDifferentKey)119 TEST_F(D2DCryptoOpsTest, SigncryptThenVerifyDecrypt_FailsWithDifferentKey) {
120   CryptoOps::SecretKey other_secret_key(kOtherSecretKeyData,
121                                         CryptoOps::AES_256_KEY);
122 
123   // Signcrypt the payload with first secret key.
124   std::unique_ptr<string> signcrypted_message =
125       D2DCryptoOps::SigncryptPayload(payload_, secret_key_);
126   ASSERT_TRUE(signcrypted_message);
127 
128   // Decrypting the signcrypted message with the other secret key should fail.
129   EXPECT_FALSE(D2DCryptoOps::VerifyDecryptPayload(*signcrypted_message,
130                                                   other_secret_key));
131 }
132 
TEST_F(D2DCryptoOpsTest,DeriveNewKeyForPurpose_ClientServer)133 TEST_F(D2DCryptoOpsTest, DeriveNewKeyForPurpose_ClientServer) {
134   CryptoOps::SecretKey master_key(kSecretKeyData, CryptoOps::AES_256_KEY);
135 
136   std::unique_ptr<CryptoOps::SecretKey> derived_key1 =
137       D2DCryptoOps::DeriveNewKeyForPurpose(master_key, "client");
138   std::unique_ptr<CryptoOps::SecretKey> derived_key2 =
139       D2DCryptoOps::DeriveNewKeyForPurpose(master_key, "server");
140 
141   ASSERT_TRUE(derived_key1);
142   ASSERT_TRUE(derived_key2);
143   EXPECT_EQ(CryptoOps::AES_256_KEY, derived_key1->algorithm());
144   EXPECT_EQ(CryptoOps::AES_256_KEY, derived_key2->algorithm());
145   EXPECT_NE(derived_key1->data().String(), derived_key2->data().String());
146 }
147 
TEST_F(D2DCryptoOpsTest,DeriveNewKeyForPurpose_InvalidMasterKeySize)148 TEST_F(D2DCryptoOpsTest, DeriveNewKeyForPurpose_InvalidMasterKeySize) {
149   CryptoOps::SecretKey master_key("Invalid Size", CryptoOps::AES_256_KEY);
150   EXPECT_FALSE(D2DCryptoOps::DeriveNewKeyForPurpose(master_key, "purpose"));
151 }
152 
TEST_F(D2DCryptoOpsTest,DeriveNewKeyForPurpose_PurposeEmpty)153 TEST_F(D2DCryptoOpsTest, DeriveNewKeyForPurpose_PurposeEmpty) {
154   CryptoOps::SecretKey master_key(kSecretKeyData, CryptoOps::AES_256_KEY);
155   EXPECT_FALSE(D2DCryptoOps::DeriveNewKeyForPurpose(master_key, string()));
156 }
157 
158 }  // namespace securegcm
159