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#ifndef CHROME_BROWSER_AUTOFILL_CRYPTO_RC4_DECRYPTOR_H_
6#define CHROME_BROWSER_AUTOFILL_CRYPTO_RC4_DECRYPTOR_H_
7
8#include <string>
9#include "base/basictypes.h"
10#include "base/memory/scoped_ptr.h"
11
12// This is modified RC4 decryption used for import of Toolbar autofill data
13// only. The difference from the Crypto Api implementation is twofold:
14// First, it uses a non-standard key size (160 bit), not supported by Microsoft
15// (it supports only 40 and 128 bit for RC4). Second, it codes 128 words with
16// value 0x0020 at the beginning of the code to enhance security.
17// This class used in chrome/browser/autofill/autofill_ie_toolbar_import_win.cc.
18// This class should not be used anywhere else!!!
19class RC4Decryptor {
20 public:
21  explicit RC4Decryptor(wchar_t const* password) {
22    PrepareKey(reinterpret_cast<const uint8 *>(password),
23               wcslen(password) * sizeof(wchar_t));
24    std::wstring data;
25    // First 128 bytes should be spaces.
26    data.resize(128, L' ');
27    Run(data.c_str());
28  }
29
30  // Run the algorithm
31  std::wstring Run(const std::wstring& data) {
32    int data_size = data.length() * sizeof(wchar_t);
33
34    scoped_array<wchar_t> buffer(new wchar_t[data.length() + 1]);
35    memset(buffer.get(), 0, (data.length() + 1) * sizeof(wchar_t));
36    memcpy(buffer.get(), data.c_str(), data_size);
37
38    RunInternal(reinterpret_cast<uint8 *>(buffer.get()), data_size);
39
40    std::wstring result(buffer.get());
41
42    // Clear the memory
43    memset(buffer.get(), 0, data_size);
44    return result;
45  }
46
47 private:
48  static const int kKeyDataSize = 256;
49  struct Rc4Key {
50    uint8 state[kKeyDataSize];
51    uint8 x;
52    uint8 y;
53  };
54
55  void SwapByte(uint8* byte1, uint8* byte2) {
56    uint8 temp = *byte1;
57    *byte1 = *byte2;
58    *byte2 = temp;
59  }
60
61  void PrepareKey(const uint8 *key_data, int key_data_len) {
62    uint8 index1 = 0;
63    uint8 index2 = 0;
64    uint8* state;
65    short counter;
66
67    state = &key_.state[0];
68    for (counter = 0; counter < kKeyDataSize; ++counter)
69      state[counter] = static_cast<uint8>(counter);
70
71    key_.x = key_.y = 0;
72
73    for (counter = 0; counter < kKeyDataSize; counter++) {
74      index2 = (key_data[index1] + state[counter] + index2) % kKeyDataSize;
75      SwapByte(&state[counter], &state[index2]);
76      index1 = (index1 + 1) % key_data_len;
77    }
78  }
79
80  void RunInternal(uint8 *buffer, int buffer_len) {
81    uint8 x, y;
82    uint8 xor_index = 0;
83    uint8* state;
84    int counter;
85
86    x = key_.x;
87    y = key_.y;
88    state = &key_.state[0];
89    for (counter = 0; counter < buffer_len; ++counter) {
90      x = (x + 1) % kKeyDataSize;
91      y = (state[x] + y) % kKeyDataSize;
92      SwapByte(&state[x], &state[y]);
93      xor_index = (state[x] + state[y]) % kKeyDataSize;
94      buffer[counter] ^= state[xor_index];
95    }
96    key_.x = x;
97    key_.y = y;
98  }
99
100  Rc4Key key_;
101};
102
103#endif  // CHROME_BROWSER_AUTOFILL_CRYPTO_RC4_DECRYPTOR_H_
104