1/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef _TALK_BASE_CRYPTSTRING_H_
29#define _TALK_BASE_CRYPTSTRING_H_
30
31#include <cstring>
32#include <string>
33#include <vector>
34#include "talk/base/linked_ptr.h"
35#include "talk/base/scoped_ptr.h"
36
37namespace talk_base {
38
39class CryptStringImpl {
40public:
41  virtual ~CryptStringImpl() {}
42  virtual size_t GetLength() const = 0;
43  virtual void CopyTo(char * dest, bool nullterminate) const = 0;
44  virtual std::string UrlEncode() const = 0;
45  virtual CryptStringImpl * Copy() const = 0;
46  virtual void CopyRawTo(std::vector<unsigned char> * dest) const = 0;
47};
48
49class EmptyCryptStringImpl : public CryptStringImpl {
50public:
51  virtual ~EmptyCryptStringImpl() {}
52  virtual size_t GetLength() const { return 0; }
53  virtual void CopyTo(char * dest, bool nullterminate) const {
54    if (nullterminate) {
55      *dest = '\0';
56    }
57  }
58  virtual std::string UrlEncode() const { return ""; }
59  virtual CryptStringImpl * Copy() const { return new EmptyCryptStringImpl(); }
60  virtual void CopyRawTo(std::vector<unsigned char> * dest) const {
61    dest->clear();
62  }
63};
64
65class CryptString {
66public:
67  CryptString() : impl_(new EmptyCryptStringImpl()) {}
68  size_t GetLength() const { return impl_->GetLength(); }
69  void CopyTo(char * dest, bool nullterminate) const { impl_->CopyTo(dest, nullterminate); }
70  CryptString(const CryptString & other) : impl_(other.impl_->Copy()) {}
71  explicit CryptString(const CryptStringImpl & impl) : impl_(impl.Copy()) {}
72  CryptString & operator=(const CryptString & other) {
73    if (this != &other) {
74      impl_.reset(other.impl_->Copy());
75    }
76    return *this;
77  }
78  void Clear() { impl_.reset(new EmptyCryptStringImpl()); }
79  std::string UrlEncode() const { return impl_->UrlEncode(); }
80  void CopyRawTo(std::vector<unsigned char> * dest) const {
81    return impl_->CopyRawTo(dest);
82  }
83
84private:
85  scoped_ptr<const CryptStringImpl> impl_;
86};
87
88
89// Used for constructing strings where a password is involved and we
90// need to ensure that we zero memory afterwards
91class FormatCryptString {
92public:
93  FormatCryptString() {
94    storage_ = new char[32];
95    capacity_ = 32;
96    length_ = 0;
97    storage_[0] = 0;
98  }
99
100  void Append(const std::string & text) {
101    Append(text.data(), text.length());
102  }
103
104  void Append(const char * data, size_t length) {
105    EnsureStorage(length_ + length + 1);
106    memcpy(storage_ + length_, data, length);
107    length_ += length;
108    storage_[length_] = '\0';
109  }
110
111  void Append(const CryptString * password) {
112    size_t len = password->GetLength();
113    EnsureStorage(length_ + len + 1);
114    password->CopyTo(storage_ + length_, true);
115    length_ += len;
116  }
117
118  size_t GetLength() {
119    return length_;
120  }
121
122  const char * GetData() {
123    return storage_;
124  }
125
126
127  // Ensures storage of at least n bytes
128  void EnsureStorage(size_t n) {
129    if (capacity_ >= n) {
130      return;
131    }
132
133    size_t old_capacity = capacity_;
134    char * old_storage = storage_;
135
136    for (;;) {
137      capacity_ *= 2;
138      if (capacity_ >= n)
139        break;
140    }
141
142    storage_ = new char[capacity_];
143
144    if (old_capacity) {
145      memcpy(storage_, old_storage, length_);
146
147      // zero memory in a way that an optimizer won't optimize it out
148      old_storage[0] = 0;
149      for (size_t i = 1; i < old_capacity; i++) {
150        old_storage[i] = old_storage[i - 1];
151      }
152      delete[] old_storage;
153    }
154  }
155
156  ~FormatCryptString() {
157    if (capacity_) {
158      storage_[0] = 0;
159      for (size_t i = 1; i < capacity_; i++) {
160        storage_[i] = storage_[i - 1];
161      }
162    }
163    delete[] storage_;
164  }
165private:
166  char * storage_;
167  size_t capacity_;
168  size_t length_;
169};
170
171class InsecureCryptStringImpl : public CryptStringImpl {
172 public:
173  std::string& password() { return password_; }
174  const std::string& password() const { return password_; }
175
176  virtual ~InsecureCryptStringImpl() {}
177  virtual size_t GetLength() const { return password_.size(); }
178  virtual void CopyTo(char * dest, bool nullterminate) const {
179    memcpy(dest, password_.data(), password_.size());
180    if (nullterminate) dest[password_.size()] = 0;
181  }
182  virtual std::string UrlEncode() const { return password_; }
183  virtual CryptStringImpl * Copy() const {
184    InsecureCryptStringImpl * copy = new InsecureCryptStringImpl;
185    copy->password() = password_;
186    return copy;
187  }
188  virtual void CopyRawTo(std::vector<unsigned char> * dest) const {
189    dest->resize(password_.size());
190    memcpy(&dest->front(), password_.data(), password_.size());
191  }
192 private:
193  std::string password_;
194};
195
196}
197
198#endif  // _TALK_BASE_CRYPTSTRING_H_
199