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