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
14TEST(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
33TEST(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
50TEST(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
68struct 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
77class SymmetricKeyDeriveKeyFromPasswordTest
78    : public testing::TestWithParam<PBKDF2TestVector> {
79};
80
81TEST_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
107static 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
224INSTANTIATE_TEST_CASE_P(, SymmetricKeyDeriveKeyFromPasswordTest,
225                        testing::ValuesIn(kTestVectors));
226