| // Copyright 2017 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "starboard/cryptography.h" |
| |
| #include "starboard/common/log.h" |
| #include "starboard/common/scoped_ptr.h" |
| #include "starboard/nplb/cryptography_helpers.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace starboard { |
| namespace nplb { |
| namespace { |
| |
| class Aes : public ::testing::TestWithParam<SbCryptographyBlockCipherMode> { |
| protected: |
| SbCryptographyBlockCipherMode GetMode() { return GetParam(); } |
| |
| bool ShouldSetIvAtInitialization() { |
| return GetIvMode() == kIvModeSetAtInitialization || |
| GetIvMode() == kIvModeSetAnyTime; |
| } |
| |
| bool ShouldSetIvAfterInitialization() { |
| return GetIvMode() == kIvModeSetAfterInitialization || |
| GetIvMode() == kIvModeSetAnyTime; |
| } |
| |
| bool ShouldSetAuthenticatedData() { |
| switch (GetMode()) { |
| case kSbCryptographyBlockCipherModeGcm: |
| return true; |
| case kSbCryptographyBlockCipherModeEcb: |
| case kSbCryptographyBlockCipherModeCtr: |
| case kSbCryptographyBlockCipherModeCbc: |
| case kSbCryptographyBlockCipherModeCfb: |
| case kSbCryptographyBlockCipherModeOfb: |
| return false; |
| default: |
| ADD_FAILURE() << "Unrecognized SbCryptographyBlockCipherMode " |
| << GetMode(); |
| return false; |
| } |
| } |
| |
| const char* GetExpectedEncryptedValueHex() { |
| switch (GetMode()) { |
| case kSbCryptographyBlockCipherModeGcm: |
| return "6a7b6e871f851db21a29f6aef579cfb77238d34b2f099404f20bb44c6b2d4d2" |
| "0a2788f8ffc0a36eba4cd8e69ee95e973b5eb52d1e218ee991ccc0ee1ba2fa7" |
| "d1dc83a5d2e3c317e5637b67c2524bd073ec6fe547edf6044111e2e16c239ed" |
| "e845d4b7b235f24fbdb2673dbdd1c5d5c46d7b69059ff4b1566b01bec4f4ca6" |
| "a4c500"; |
| |
| case kSbCryptographyBlockCipherModeEcb: |
| return "36aa40499dccc9f25bb3c1abcf4b73cf5993dc6127c534e7491a31a54f09bc4" |
| "8e9fc157e380ca1457dedac9147e158be1c8eba2ec679d6bdc54cb2878cd2ab" |
| "6736aa40499dccc9f25bb3c1abcf4b73cf5993dc6127c534e7491a31a54f09b" |
| "c48e9fc157e380ca1457dedac9147e158beae602e043e0572ed2f71acf5438c" |
| "e78200"; |
| |
| case kSbCryptographyBlockCipherModeCtr: |
| return "f32f8a813cea30e0f4c6e2efeab52ab92976cc06fa5f69409c3358ef2f3782d" |
| "daff201f56acd9b61fea4c3e4739deab176ad764da16d1248d59337962c7ab0" |
| "f2cd4c292ed34ae4125d8fb142344b2d2fc4ff533b80f5e8e311cde700ceaed" |
| "a613c6f27f72a0602e6e4891e6b4f5a0a64e795998a40544d88363d124d5294" |
| "c91700"; |
| |
| case kSbCryptographyBlockCipherModeCbc: |
| return "eaa929d637cde55115d43257e920ff8d39d1dec8240255a5db79a0cf79501a1" |
| "4bc62c4d16fc45dd7fa9d15b3346a74301260dfeb96e22259787344d7e47047" |
| "3eb4187eeac16a74afd1c5fdc67fb145cc494667ea4b16dccc83cc1cc1b2c36" |
| "2f2a03e90d6c3a9adbf53c4cb8e4987719928ef7c47c4403f0cfe5a0ff77325" |
| "6eaa00"; |
| |
| case kSbCryptographyBlockCipherModeCfb: |
| case kSbCryptographyBlockCipherModeOfb: |
| ADD_FAILURE() << "Unsupported SbCryptographyBlockCipherMode " |
| << GetMode(); |
| return ""; |
| default: |
| ADD_FAILURE() << "Unrecognized SbCryptographyBlockCipherMode " |
| << GetMode(); |
| return ""; |
| } |
| } |
| |
| private: |
| enum IvMode { |
| kIvModeNotUsed, |
| kIvModeSetAtInitialization, |
| kIvModeSetAfterInitialization, |
| kIvModeSetAnyTime, |
| }; |
| |
| IvMode GetIvMode() { |
| switch (GetMode()) { |
| case kSbCryptographyBlockCipherModeEcb: |
| return kIvModeNotUsed; |
| case kSbCryptographyBlockCipherModeGcm: |
| return kIvModeSetAfterInitialization; |
| case kSbCryptographyBlockCipherModeCtr: |
| return kIvModeSetAnyTime; |
| case kSbCryptographyBlockCipherModeCbc: |
| case kSbCryptographyBlockCipherModeCfb: |
| case kSbCryptographyBlockCipherModeOfb: |
| return kIvModeSetAtInitialization; |
| default: |
| ADD_FAILURE() << "Unrecognized SbCryptographyBlockCipherMode " |
| << GetMode(); |
| return kIvModeNotUsed; |
| } |
| } |
| }; |
| |
| const int kBlockSizeBits = 128; |
| const int kBlockSizeBytes = kBlockSizeBits / 8; |
| |
| const char kClearText[] = |
| "This test text is designed to be a multiple of 128 bits, huzzah-" |
| "This test text is designed to be a multiple of 128 bits, huzzah!"; |
| const char kAdditionalDataString[] = "000000000000000000000000"; |
| const char kInitializationVector[kBlockSizeBytes + 1] = "0123456789ABCDEF"; |
| const char kKey[kBlockSizeBytes + 1] = "Rijndael"; |
| |
| TEST_P(Aes, SunnyDayIdentity) { |
| SbCryptographyBlockCipherMode mode = GetMode(); |
| |
| SbCryptographyTransformer encrypter = SbCryptographyCreateTransformer( |
| kSbCryptographyAlgorithmAes, kBlockSizeBits, |
| kSbCryptographyDirectionEncode, mode, |
| ShouldSetIvAtInitialization() ? kInitializationVector : NULL, |
| ShouldSetIvAtInitialization() ? kBlockSizeBytes : 0, kKey, |
| kBlockSizeBytes); |
| |
| if (!SbCryptographyIsTransformerValid(encrypter)) { |
| SB_LOG(WARNING) << "Skipping test, as there is no implementation."; |
| // Test over if there's no implementation. |
| return; |
| } |
| |
| if (ShouldSetIvAfterInitialization()) { |
| SbCryptographySetInitializationVector(encrypter, kInitializationVector, |
| kBlockSizeBytes); |
| } |
| |
| if (ShouldSetAuthenticatedData()) { |
| scoped_array<uint8_t> aad; |
| int aad_len = 0; |
| DecodeHex(&aad, &aad_len, kAdditionalDataString, GetMode(), "aad"); |
| SbCryptographySetAuthenticatedData(encrypter, aad.get(), aad_len); |
| } |
| |
| const int kInputSize = static_cast<int>(SbStringGetLength(kClearText)); |
| const int kBufferSize = static_cast<int>(sizeof(kClearText)); |
| char* cipher_text = new char[kBufferSize]; |
| SbMemorySet(cipher_text, 0, kBufferSize); |
| int count = |
| SbCryptographyTransform(encrypter, kClearText, kInputSize, cipher_text); |
| EXPECT_EQ(kInputSize, count); |
| EXPECT_NE(0, SbStringCompare(kClearText, cipher_text, kBufferSize)); |
| |
| EXPECT_STREQ(GetExpectedEncryptedValueHex(), |
| HexDump(cipher_text, kBufferSize).c_str()); |
| |
| SbCryptographyTransformer decrypter = SbCryptographyCreateTransformer( |
| kSbCryptographyAlgorithmAes, kBlockSizeBits, |
| kSbCryptographyDirectionDecode, mode, |
| ShouldSetIvAtInitialization() ? kInitializationVector : NULL, |
| ShouldSetIvAtInitialization() ? kBlockSizeBytes : 0, kKey, |
| kBlockSizeBytes); |
| |
| ASSERT_TRUE(SbCryptographyIsTransformerValid(decrypter)) |
| << "Cryptographic support for a set of parameters must be symmetrical."; |
| |
| if (ShouldSetIvAfterInitialization()) { |
| SbCryptographySetInitializationVector(decrypter, kInitializationVector, |
| kBlockSizeBytes); |
| } |
| |
| if (ShouldSetAuthenticatedData()) { |
| scoped_array<uint8_t> aad; |
| int aad_len = 0; |
| DecodeHex(&aad, &aad_len, kAdditionalDataString, GetMode(), "aad"); |
| SbCryptographySetAuthenticatedData(decrypter, aad.get(), aad_len); |
| } |
| |
| char* decrypted_text = new char[kBufferSize]; |
| SbMemorySet(decrypted_text, 0, kBufferSize); |
| count = SbCryptographyTransform(decrypter, cipher_text, kInputSize, |
| decrypted_text); |
| |
| EXPECT_EQ(kInputSize, count); |
| EXPECT_EQ(kInputSize, SbStringGetLength(decrypted_text)); |
| EXPECT_STREQ(kClearText, decrypted_text); |
| |
| delete[] decrypted_text; |
| delete[] cipher_text; |
| SbCryptographyDestroyTransformer(decrypter); |
| SbCryptographyDestroyTransformer(encrypter); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(SbCryptographyTransform, |
| Aes, |
| ::testing::Values(kSbCryptographyBlockCipherModeCbc, |
| kSbCryptographyBlockCipherModeCfb, |
| kSbCryptographyBlockCipherModeCtr, |
| kSbCryptographyBlockCipherModeEcb, |
| kSbCryptographyBlockCipherModeOfb, |
| kSbCryptographyBlockCipherModeGcm)); |
| |
| } // namespace |
| } // namespace nplb |
| } // namespace starboard |