Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "crypto/symmetric_key.h"
      6 
      7 #include <string>
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/string_number_conversions.h"
     11 #include "base/string_util.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 TEST(SymmetricKeyTest, GenerateRandomKey) {
     15   scoped_ptr<crypto::SymmetricKey> key(
     16       crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256));
     17   ASSERT_TRUE(NULL != key.get());
     18   std::string raw_key;
     19   EXPECT_TRUE(key->GetRawKey(&raw_key));
     20   EXPECT_EQ(32U, raw_key.size());
     21 
     22   // Do it again and check that the keys are different.
     23   // (Note: this has a one-in-10^77 chance of failure!)
     24   scoped_ptr<crypto::SymmetricKey> key2(
     25       crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256));
     26   ASSERT_TRUE(NULL != key2.get());
     27   std::string raw_key2;
     28   EXPECT_TRUE(key2->GetRawKey(&raw_key2));
     29   EXPECT_EQ(32U, raw_key2.size());
     30   EXPECT_NE(raw_key, raw_key2);
     31 }
     32 
     33 TEST(SymmetricKeyTest, ImportGeneratedKey) {
     34   scoped_ptr<crypto::SymmetricKey> key1(
     35       crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256));
     36   ASSERT_TRUE(NULL != key1.get());
     37   std::string raw_key1;
     38   EXPECT_TRUE(key1->GetRawKey(&raw_key1));
     39 
     40   scoped_ptr<crypto::SymmetricKey> key2(
     41       crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key1));
     42   ASSERT_TRUE(NULL != key2.get());
     43 
     44   std::string raw_key2;
     45   EXPECT_TRUE(key2->GetRawKey(&raw_key2));
     46 
     47   EXPECT_EQ(raw_key1, raw_key2);
     48 }
     49 
     50 TEST(SymmetricKeyTest, ImportDerivedKey) {
     51   scoped_ptr<crypto::SymmetricKey> key1(
     52       crypto::SymmetricKey::DeriveKeyFromPassword(
     53           crypto::SymmetricKey::HMAC_SHA1, "password", "somesalt", 1024, 160));
     54   ASSERT_TRUE(NULL != key1.get());
     55   std::string raw_key1;
     56   EXPECT_TRUE(key1->GetRawKey(&raw_key1));
     57 
     58   scoped_ptr<crypto::SymmetricKey> key2(
     59       crypto::SymmetricKey::Import(crypto::SymmetricKey::HMAC_SHA1, raw_key1));
     60   ASSERT_TRUE(NULL != key2.get());
     61 
     62   std::string raw_key2;
     63   EXPECT_TRUE(key2->GetRawKey(&raw_key2));
     64 
     65   EXPECT_EQ(raw_key1, raw_key2);
     66 }
     67 
     68 struct PBKDF2TestVector {
     69   crypto::SymmetricKey::Algorithm algorithm;
     70   const char* password;
     71   const char* salt;
     72   unsigned int rounds;
     73   unsigned int key_size_in_bits;
     74   const char* expected;  // ASCII encoded hex bytes
     75 };
     76 
     77 class SymmetricKeyDeriveKeyFromPasswordTest
     78     : public testing::TestWithParam<PBKDF2TestVector> {
     79 };
     80 
     81 TEST_P(SymmetricKeyDeriveKeyFromPasswordTest, DeriveKeyFromPassword) {
     82   PBKDF2TestVector test_data(GetParam());
     83 #if defined(OS_MACOSX)
     84   // The OS X crypto libraries have minimum salt and iteration requirements
     85   // so some of the tests below will cause them to barf. Skip these.
     86   if (strlen(test_data.salt) < 8 || test_data.rounds < 1000) {
     87     VLOG(1) << "Skipped test vector for " << test_data.expected;
     88     return;
     89   }
     90 #endif  // OS_MACOSX
     91 
     92   scoped_ptr<crypto::SymmetricKey> key(
     93       crypto::SymmetricKey::DeriveKeyFromPassword(
     94           test_data.algorithm,
     95           test_data.password, test_data.salt,
     96           test_data.rounds, test_data.key_size_in_bits));
     97   ASSERT_TRUE(NULL != key.get());
     98 
     99   std::string raw_key;
    100   key->GetRawKey(&raw_key);
    101   EXPECT_EQ(test_data.key_size_in_bits / 8, raw_key.size());
    102   EXPECT_EQ(test_data.expected,
    103             StringToLowerASCII(base::HexEncode(raw_key.data(),
    104                                                raw_key.size())));
    105 }
    106 
    107 static const PBKDF2TestVector kTestVectors[] = {
    108   // These tests come from
    109   // http://www.ietf.org/id/draft-josefsson-pbkdf2-test-vectors-00.txt
    110   {
    111     crypto::SymmetricKey::HMAC_SHA1,
    112     "password",
    113     "salt",
    114     1,
    115     160,
    116     "0c60c80f961f0e71f3a9b524af6012062fe037a6",
    117   },
    118   {
    119     crypto::SymmetricKey::HMAC_SHA1,
    120     "password",
    121     "salt",
    122     2,
    123     160,
    124     "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957",
    125   },
    126   {
    127     crypto::SymmetricKey::HMAC_SHA1,
    128     "password",
    129     "salt",
    130     4096,
    131     160,
    132     "4b007901b765489abead49d926f721d065a429c1",
    133   },
    134   // This test takes over 30s to run on the trybots.
    135 #if 0
    136   {
    137     crypto::SymmetricKey::HMAC_SHA1,
    138     "password",
    139     "salt",
    140     16777216,
    141     160,
    142     "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984",
    143   },
    144 #endif
    145 
    146   // These tests come from RFC 3962, via BSD source code at
    147   // http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/bioctl/pbkdf2.c?rev=HEAD&content-type=text/plain
    148   {
    149     crypto::SymmetricKey::HMAC_SHA1,
    150     "password",
    151     "ATHENA.MIT.EDUraeburn",
    152     1,
    153     160,
    154     "cdedb5281bb2f801565a1122b25635150ad1f7a0",
    155   },
    156   {
    157     crypto::SymmetricKey::HMAC_SHA1,
    158     "password",
    159     "ATHENA.MIT.EDUraeburn",
    160     2,
    161     160,
    162     "01dbee7f4a9e243e988b62c73cda935da05378b9",
    163   },
    164   {
    165     crypto::SymmetricKey::HMAC_SHA1,
    166     "password",
    167     "ATHENA.MIT.EDUraeburn",
    168     1200,
    169     160,
    170     "5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddb",
    171   },
    172   {
    173     crypto::SymmetricKey::HMAC_SHA1,
    174     "password",
    175     "\0224VxxV4\022", /* 0x1234567878563412 */
    176     5,
    177     160,
    178     "d1daa78615f287e6a1c8b120d7062a493f98d203",
    179   },
    180   {
    181     crypto::SymmetricKey::HMAC_SHA1,
    182     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    183     "pass phrase equals block size",
    184     1200,
    185     160,
    186     "139c30c0966bc32ba55fdbf212530ac9c5ec59f1",
    187   },
    188   {
    189     crypto::SymmetricKey::HMAC_SHA1,
    190     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    191     "pass phrase exceeds block size",
    192     1200,
    193     160,
    194     "9ccad6d468770cd51b10e6a68721be611a8b4d28",
    195   },
    196   {
    197     crypto::SymmetricKey::HMAC_SHA1,
    198     "\360\235\204\236", /* g-clef (0xf09d849e) */
    199     "EXAMPLE.COMpianist",
    200     50,
    201     160,
    202     "6b9cf26d45455a43a5b8bb276a403b39e7fe37a0",
    203   },
    204 
    205   // Regression tests for AES keys, derived from the Linux NSS implementation.
    206   {
    207     crypto::SymmetricKey::AES,
    208     "A test password",
    209     "saltsalt",
    210     1,
    211     256,
    212     "44899a7777f0e6e8b752f875f02044b8ac593de146de896f2e8a816e315a36de",
    213   },
    214   {
    215     crypto::SymmetricKey::AES,
    216     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    217     "pass phrase exceeds block size",
    218     20,
    219     256,
    220     "e0739745dc28b8721ba402e05214d2ac1eab54cf72bee1fba388297a09eb493c",
    221   },
    222 };
    223 
    224 INSTANTIATE_TEST_CASE_P(, SymmetricKeyDeriveKeyFromPasswordTest,
    225                         testing::ValuesIn(kTestVectors));
    226