summaryrefslogtreecommitdiffstats
path: root/crypto/encryptor.cc
blob: 7872774e301c6995505f6f922a64a7bff74f4fb7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "crypto/encryptor.h"

#include <stddef.h>
#include <stdint.h>

#include "base/logging.h"
#include "base/sys_byteorder.h"

namespace crypto {

/////////////////////////////////////////////////////////////////////////////
// Encyptor::Counter Implementation.
Encryptor::Counter::Counter(const base::StringPiece& counter) {
  CHECK(sizeof(counter_) == counter.length());

  memcpy(&counter_, counter.data(), sizeof(counter_));
}

Encryptor::Counter::~Counter() {
}

bool Encryptor::Counter::Increment() {
  uint64_t low_num = base::NetToHost64(counter_.components64[1]);
  uint64_t new_low_num = low_num + 1;
  counter_.components64[1] = base::HostToNet64(new_low_num);

  // If overflow occured then increment the most significant component.
  if (new_low_num < low_num) {
    counter_.components64[0] =
        base::HostToNet64(base::NetToHost64(counter_.components64[0]) + 1);
  }

  // TODO(hclam): Return false if counter value overflows.
  return true;
}

void Encryptor::Counter::Write(void* buf) {
  uint8_t* buf_ptr = reinterpret_cast<uint8_t*>(buf);
  memcpy(buf_ptr, &counter_, sizeof(counter_));
}

size_t Encryptor::Counter::GetLengthInBytes() const {
  return sizeof(counter_);
}

/////////////////////////////////////////////////////////////////////////////
// Partial Encryptor Implementation.

bool Encryptor::SetCounter(const base::StringPiece& counter) {
  if (mode_ != CTR)
    return false;
  if (counter.length() != 16u)
    return false;

  counter_.reset(new Counter(counter));
  return true;
}

bool Encryptor::GenerateCounterMask(size_t plaintext_len,
                                    uint8_t* mask,
                                    size_t* mask_len) {
  DCHECK_EQ(CTR, mode_);
  CHECK(mask);
  CHECK(mask_len);

  const size_t kBlockLength = counter_->GetLengthInBytes();
  size_t blocks = (plaintext_len + kBlockLength - 1) / kBlockLength;
  CHECK(blocks);

  *mask_len = blocks * kBlockLength;

  for (size_t i = 0; i < blocks; ++i) {
    counter_->Write(mask);
    mask += kBlockLength;

    bool ret = counter_->Increment();
    if (!ret)
      return false;
  }
  return true;
}

void Encryptor::MaskMessage(const void* plaintext,
                            size_t plaintext_len,
                            const void* mask,
                            void* ciphertext) const {
  DCHECK_EQ(CTR, mode_);
  const uint8_t* plaintext_ptr = reinterpret_cast<const uint8_t*>(plaintext);
  const uint8_t* mask_ptr = reinterpret_cast<const uint8_t*>(mask);
  uint8_t* ciphertext_ptr = reinterpret_cast<uint8_t*>(ciphertext);

  for (size_t i = 0; i < plaintext_len; ++i)
    ciphertext_ptr[i] = plaintext_ptr[i] ^ mask_ptr[i];
}

}  // namespace crypto