Skip to content

Commit

Permalink
Implement AES-CTR for NSS.
Browse files Browse the repository at this point in the history
Implement AES-128-CTR.

BUG=87152
TEST=None

Review URL: http://codereview.chromium.org/7056026

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90425 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
hclam@chromium.org committed Jun 24, 2011
1 parent 93fdd25 commit 2377cde
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 49 deletions.
3 changes: 3 additions & 0 deletions build/build_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,17 @@
#define ARCH_CPU_X86_FAMILY 1
#define ARCH_CPU_X86_64 1
#define ARCH_CPU_64_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(_M_IX86) || defined(__i386__)
#define ARCH_CPU_X86_FAMILY 1
#define ARCH_CPU_X86 1
#define ARCH_CPU_32_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__ARMEL__)
#define ARCH_CPU_ARM_FAMILY 1
#define ARCH_CPU_ARMEL 1
#define ARCH_CPU_32_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
#define WCHAR_T_IS_UNSIGNED 1
#else
#error Please add support for your architecture in build/build_config.h
Expand Down
1 change: 1 addition & 0 deletions crypto/crypto.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
'crypto_module_blocking_password_delegate.h',
'cssm_init.cc',
'cssm_init.h',
'encryptor.cc',
'encryptor.h',
'encryptor_mac.cc',
'encryptor_nss.cc',
Expand Down
120 changes: 120 additions & 0 deletions crypto/encryptor.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) 2011 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 "base/logging.h"
#include "build/build_config.h"

// Include headers to provide bswap for all platforms.
#if defined(COMPILER_MSVC)
#include <stdlib.h>
#define bswap_16(x) _byteswap_ushort(x)
#define bswap_32(x) _byteswap_ulong(x)
#define bswap_64(x) _byteswap_uint64(x)
#elif defined(OS_MACOSX)
#include <libkern/OSByteOrder.h>
#define bswap_16(x) OSSwapInt16(x)
#define bswap_32(x) OSSwapInt32(x)
#define bswap_64(x) OSSwapInt64(x)
#else
#include <byteswap.h>
#endif

#if defined(ARCH_CPU_LITTLE_ENDIAN)
#define ntoh_64(x) bswap_64(x)
#define hton_64(x) bswap_64(x)
#else
#define ntoh_64(x) (x)
#define hton_64(x) (x)
#endif

namespace crypto {

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

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

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

bool Encryptor::Counter::Increment() {
uint64 low_num = ntoh_64(counter_.components64[1]);
uint64 new_low_num = low_num + 1;
counter_.components64[1] = hton_64(new_low_num);

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

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

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

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

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

bool Encryptor::SetCounter(const std::string& 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* 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* plaintext_ptr = reinterpret_cast<const uint8*>(plaintext);
const uint8* mask_ptr = reinterpret_cast<const uint8*>(mask);
uint8* ciphertext_ptr = reinterpret_cast<uint8*>(ciphertext);

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

} // namespace crypto
68 changes: 67 additions & 1 deletion crypto/encryptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include <string>

#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "build/build_config.h"
#include "crypto/crypto_api.h"

Expand All @@ -24,13 +26,41 @@ class SymmetricKey;
class CRYPTO_API Encryptor {
public:
enum Mode {
CBC
CBC,
CTR,
};

// This class implements a 128-bits counter to be used in AES-CTR encryption.
// Only 128-bits counter is supported in this class.
class Counter {
public:
Counter(const std::string& counter);
~Counter();

// Increment the counter value.
bool Increment();

// Write the content of the counter to |buf|. |buf| should have enough
// space for |GetLengthInBytes()|.
void Write(void* buf);

// Return the length of this counter.
size_t GetLengthInBytes() const;

private:
union {
uint32 components32[4];
uint64 components64[2];
} counter_;
};

Encryptor();
virtual ~Encryptor();

// Initializes the encryptor using |key| and |iv|. Returns false if either the
// key or the initialization vector cannot be used.
//
// When |mode| is CTR then |iv| should be empty.
bool Init(SymmetricKey* key, Mode mode, const std::string& iv);

// Encrypts |plaintext| into |ciphertext|.
Expand All @@ -39,18 +69,54 @@ class CRYPTO_API Encryptor {
// Decrypts |ciphertext| into |plaintext|.
bool Decrypt(const std::string& ciphertext, std::string* plaintext);

// Sets the counter value when in CTR mode. Currently only 128-bits
// counter value is supported.
//
// Returns true only if update was successful.
bool SetCounter(const std::string& counter);

// TODO(albertb): Support streaming encryption.

private:
// Generates a mask using |counter_| to be used for encryption in CTR mode.
// Resulting mask will be written to |mask| with |mask_len| bytes.
//
// Make sure there's enough space in mask when calling this method.
// Reserve at least |plaintext_len| + 16 bytes for |mask|.
//
// The generated mask will always have at least |plaintext_len| bytes and
// will be a multiple of the counter length.
//
// This method is used only in CTR mode.
//
// Returns false if this call failed.
bool GenerateCounterMask(size_t plaintext_len,
uint8* mask,
size_t* mask_len);

// Mask the |plaintext| message using |mask|. The output will be written to
// |ciphertext|. |ciphertext| must have at least |plaintext_len| bytes.
void MaskMessage(const void* plaintext,
size_t plaintext_len,
const void* mask,
void* ciphertext) const;

SymmetricKey* key_;
Mode mode_;
scoped_ptr<Counter> counter_;

#if defined(USE_OPENSSL)
bool Crypt(bool encrypt, // Pass true to encrypt, false to decrypt.
const std::string& input,
std::string* output);
std::string iv_;
#elif defined(USE_NSS)
bool Crypt(PK11Context* context,
const std::string& input,
std::string* output);
bool CryptCTR(PK11Context* context,
const std::string& input,
std::string* output);
ScopedPK11Slot slot_;
ScopedSECItem param_;
#elif defined(OS_MACOSX)
Expand Down
Loading

0 comments on commit 2377cde

Please sign in to comment.