1/*
2 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#ifndef _WEBRTC_BASE_CRYPTSTRING_H_
12#define _WEBRTC_BASE_CRYPTSTRING_H_
13
14#include <string.h>
15
16#include <string>
17#include <vector>
18
19#include "webrtc/base/linked_ptr.h"
20#include "webrtc/base/scoped_ptr.h"
21
22namespace rtc {
23
24class CryptStringImpl {
25public:
26  virtual ~CryptStringImpl() {}
27  virtual size_t GetLength() const = 0;
28  virtual void CopyTo(char * dest, bool nullterminate) const = 0;
29  virtual std::string UrlEncode() const = 0;
30  virtual CryptStringImpl * Copy() const = 0;
31  virtual void CopyRawTo(std::vector<unsigned char> * dest) const = 0;
32};
33
34class EmptyCryptStringImpl : public CryptStringImpl {
35public:
36  virtual ~EmptyCryptStringImpl() {}
37  virtual size_t GetLength() const { return 0; }
38  virtual void CopyTo(char * dest, bool nullterminate) const {
39    if (nullterminate) {
40      *dest = '\0';
41    }
42  }
43  virtual std::string UrlEncode() const { return ""; }
44  virtual CryptStringImpl * Copy() const { return new EmptyCryptStringImpl(); }
45  virtual void CopyRawTo(std::vector<unsigned char> * dest) const {
46    dest->clear();
47  }
48};
49
50class CryptString {
51public:
52  CryptString() : impl_(new EmptyCryptStringImpl()) {}
53  size_t GetLength() const { return impl_->GetLength(); }
54  void CopyTo(char * dest, bool nullterminate) const { impl_->CopyTo(dest, nullterminate); }
55  CryptString(const CryptString & other) : impl_(other.impl_->Copy()) {}
56  explicit CryptString(const CryptStringImpl & impl) : impl_(impl.Copy()) {}
57  CryptString & operator=(const CryptString & other) {
58    if (this != &other) {
59      impl_.reset(other.impl_->Copy());
60    }
61    return *this;
62  }
63  void Clear() { impl_.reset(new EmptyCryptStringImpl()); }
64  std::string UrlEncode() const { return impl_->UrlEncode(); }
65  void CopyRawTo(std::vector<unsigned char> * dest) const {
66    return impl_->CopyRawTo(dest);
67  }
68
69private:
70  scoped_ptr<const CryptStringImpl> impl_;
71};
72
73
74// Used for constructing strings where a password is involved and we
75// need to ensure that we zero memory afterwards
76class FormatCryptString {
77public:
78  FormatCryptString() {
79    storage_ = new char[32];
80    capacity_ = 32;
81    length_ = 0;
82    storage_[0] = 0;
83  }
84
85  void Append(const std::string & text) {
86    Append(text.data(), text.length());
87  }
88
89  void Append(const char * data, size_t length) {
90    EnsureStorage(length_ + length + 1);
91    memcpy(storage_ + length_, data, length);
92    length_ += length;
93    storage_[length_] = '\0';
94  }
95
96  void Append(const CryptString * password) {
97    size_t len = password->GetLength();
98    EnsureStorage(length_ + len + 1);
99    password->CopyTo(storage_ + length_, true);
100    length_ += len;
101  }
102
103  size_t GetLength() {
104    return length_;
105  }
106
107  const char * GetData() {
108    return storage_;
109  }
110
111
112  // Ensures storage of at least n bytes
113  void EnsureStorage(size_t n) {
114    if (capacity_ >= n) {
115      return;
116    }
117
118    size_t old_capacity = capacity_;
119    char * old_storage = storage_;
120
121    for (;;) {
122      capacity_ *= 2;
123      if (capacity_ >= n)
124        break;
125    }
126
127    storage_ = new char[capacity_];
128
129    if (old_capacity) {
130      memcpy(storage_, old_storage, length_);
131
132      // zero memory in a way that an optimizer won't optimize it out
133      old_storage[0] = 0;
134      for (size_t i = 1; i < old_capacity; i++) {
135        old_storage[i] = old_storage[i - 1];
136      }
137      delete[] old_storage;
138    }
139  }
140
141  ~FormatCryptString() {
142    if (capacity_) {
143      storage_[0] = 0;
144      for (size_t i = 1; i < capacity_; i++) {
145        storage_[i] = storage_[i - 1];
146      }
147    }
148    delete[] storage_;
149  }
150private:
151  char * storage_;
152  size_t capacity_;
153  size_t length_;
154};
155
156class InsecureCryptStringImpl : public CryptStringImpl {
157 public:
158  std::string& password() { return password_; }
159  const std::string& password() const { return password_; }
160
161  virtual ~InsecureCryptStringImpl() {}
162  virtual size_t GetLength() const { return password_.size(); }
163  virtual void CopyTo(char * dest, bool nullterminate) const {
164    memcpy(dest, password_.data(), password_.size());
165    if (nullterminate) dest[password_.size()] = 0;
166  }
167  virtual std::string UrlEncode() const { return password_; }
168  virtual CryptStringImpl * Copy() const {
169    InsecureCryptStringImpl * copy = new InsecureCryptStringImpl;
170    copy->password() = password_;
171    return copy;
172  }
173  virtual void CopyRawTo(std::vector<unsigned char> * dest) const {
174    dest->resize(password_.size());
175    memcpy(&dest->front(), password_.data(), password_.size());
176  }
177 private:
178  std::string password_;
179};
180
181}
182
183#endif  // _WEBRTC_BASE_CRYPTSTRING_H_
184