Skip to content

Commit 5d75ed7

Browse files
committed
src: shift more crypto impl details to ncrypto
1 parent c79a674 commit 5d75ed7

14 files changed

+639
-456
lines changed

deps/ncrypto/ncrypto.cc

Lines changed: 433 additions & 19 deletions
Large diffs are not rendered by default.

deps/ncrypto/ncrypto.h

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#pragma once
22

3+
#include <cstddef>
34
#include <list>
45
#include <memory>
56
#include <optional>
67
#include <string>
78
#include <string_view>
8-
#include <vector>
99
#include "openssl/bn.h"
1010
#include <openssl/x509.h>
1111
#include <openssl/dh.h>
@@ -82,6 +82,15 @@ namespace ncrypto {
8282
void* operator new(size_t) = delete; \
8383
void operator delete(void*) = delete;
8484

85+
[[noreturn]] inline void unreachable() {
86+
#ifdef __GNUC__
87+
__builtin_unreachable();
88+
#elif defined(_MSC_VER)
89+
__assume(false);
90+
#else
91+
#endif
92+
}
93+
8594
// ============================================================================
8695
// Error handling utilities
8796

@@ -190,30 +199,92 @@ using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
190199
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
191200
using X509Pointer = DeleteFnPtr<X509, X509_free>;
192201

202+
// An unowned, unmanaged pointer to a buffer of data.
203+
struct Buffer {
204+
void* data;
205+
size_t len;
206+
};
207+
208+
// A managed pointer to a buffer of data. When destroyed the underlying
209+
// buffer will be freed.
210+
class DataPointer final {
211+
public:
212+
static DataPointer Alloc(size_t len);
213+
214+
DataPointer() = default;
215+
explicit DataPointer(void* data, size_t len);
216+
explicit DataPointer(const Buffer& buffer);
217+
DataPointer(DataPointer&& other) noexcept;
218+
DataPointer& operator=(DataPointer&& other) noexcept;
219+
NCRYPTO_DISALLOW_COPY(DataPointer)
220+
~DataPointer();
221+
222+
inline bool operator==(std::nullptr_t) noexcept { return data_ == nullptr; }
223+
inline operator bool() const { return data_ != nullptr; }
224+
inline void* get() const noexcept { return data_; }
225+
inline size_t size() const noexcept { return len_; }
226+
void reset(void* data = nullptr, size_t len = 0);
227+
void reset(const Buffer& buffer);
228+
229+
// Releases ownership of the underlying data buffer. It is the caller's
230+
// responsibility to ensure the buffer is appropriately freed.
231+
Buffer release();
232+
233+
// Returns a Buffer struct that is a view of the underlying data.
234+
inline operator const Buffer() const {
235+
return {
236+
.data = data_,
237+
.len = len_,
238+
};
239+
}
240+
241+
private:
242+
void* data_ = nullptr;
243+
size_t len_ = 0;
244+
};
245+
193246
class BignumPointer final {
194247
public:
248+
static BignumPointer Create();
249+
static BignumPointer CreateSecure();
250+
195251
BignumPointer() = default;
196252
explicit BignumPointer(BIGNUM* bignum);
253+
explicit BignumPointer(const unsigned char* data, size_t len);
197254
BignumPointer(BignumPointer&& other) noexcept;
198255
BignumPointer& operator=(BignumPointer&& other) noexcept;
199256
NCRYPTO_DISALLOW_COPY(BignumPointer)
200257
~BignumPointer();
201258

202-
bool operator==(const BignumPointer& other) noexcept;
203-
bool operator==(const BIGNUM* other) noexcept;
204-
inline bool operator==(std::nullptr_t) noexcept { return bn_ == nullptr; }
259+
int operator<=>(const BignumPointer& other) const noexcept;
260+
int operator<=>(const BIGNUM* other) const noexcept;
205261
inline operator bool() const { return bn_ != nullptr; }
206262
inline BIGNUM* get() const noexcept { return bn_.get(); }
207263
void reset(BIGNUM* bn = nullptr);
264+
void reset(const unsigned char* data, size_t len);
208265
BIGNUM* release();
209266

210-
size_t byteLength();
267+
bool isZero() const;
268+
bool isOne() const;
269+
270+
bool setWord(unsigned long w);
271+
unsigned long getWord() const;
272+
273+
size_t byteLength() const;
211274

212-
std::vector<uint8_t> encode();
213-
std::vector<uint8_t> encodePadded(size_t size);
275+
DataPointer toHex() const;
276+
DataPointer encode() const;
277+
DataPointer encodePadded(size_t size) const;
278+
size_t encodeInto(unsigned char* out) const;
279+
size_t encodePaddedInto(unsigned char* out, size_t size) const;
214280

215-
static std::vector<uint8_t> encode(const BIGNUM* bn);
216-
static std::vector<uint8_t> encodePadded(const BIGNUM* bn, size_t size);
281+
static DataPointer encode(const BIGNUM* bn);
282+
static DataPointer encodePadded(const BIGNUM* bn, size_t size);
283+
static size_t encodePaddedInto(const BIGNUM* bn, unsigned char* out, size_t size);
284+
static int getBitCount(const BIGNUM* bn);
285+
static int getByteCount(const BIGNUM* bn);
286+
static unsigned long getWord(const BIGNUM* bn);
287+
static const BIGNUM* one();
217288

218289
private:
219290
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;
@@ -269,11 +340,6 @@ bool testFipsEnabled();
269340
// ============================================================================
270341
// Various utilities
271342

272-
struct Buffer {
273-
const void* data;
274-
size_t len;
275-
};
276-
277343
bool CSPRNG(void* buffer, size_t length) NCRYPTO_MUST_USE_RESULT;
278344

279345
// This callback is used to avoid the default passphrase callback in OpenSSL
@@ -285,6 +351,9 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
285351

286352
int PasswordCallback(char* buf, int size, int rwflag, void* u);
287353

354+
bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext);
355+
bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext);
356+
288357
// ============================================================================
289358
// Version metadata
290359
#define NCRYPTO_VERSION "0.0.1"

src/crypto/crypto_aes.cc

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,8 @@ BignumPointer GetCounter(const AESCipherConfig& params) {
185185

186186
if (remainder == 0) {
187187
unsigned int byte_length = params.length / CHAR_BIT;
188-
return BignumPointer(BN_bin2bn(
189-
data + params.iv.size() - byte_length,
190-
byte_length,
191-
nullptr));
188+
return BignumPointer(data + params.iv.size() - byte_length,
189+
byte_length);
192190
}
193191

194192
unsigned int byte_length =
@@ -199,7 +197,7 @@ BignumPointer GetCounter(const AESCipherConfig& params) {
199197
data + params.iv.size());
200198
counter[0] &= ~(0xFF << remainder);
201199

202-
return BignumPointer(BN_bin2bn(counter.data(), counter.size(), nullptr));
200+
return BignumPointer(counter.data(), counter.size());
203201
}
204202

205203
std::vector<unsigned char> BlockWithZeroedCounter(
@@ -269,23 +267,23 @@ WebCryptoCipherStatus AES_CTR_Cipher(
269267
const AESCipherConfig& params,
270268
const ByteSource& in,
271269
ByteSource* out) {
272-
BignumPointer num_counters(BN_new());
273-
if (!BN_lshift(num_counters.get(), BN_value_one(), params.length))
270+
auto num_counters = BignumPointer::Create();
271+
if (!BN_lshift(num_counters.get(), BignumPointer::one(), params.length))
274272
return WebCryptoCipherStatus::FAILED;
275273

276274
BignumPointer current_counter = GetCounter(params);
277275

278-
BignumPointer num_output(BN_new());
276+
auto num_output = BignumPointer::Create();
279277

280-
if (!BN_set_word(num_output.get(), CeilDiv(in.size(), kAesBlockSize)))
278+
if (!num_output.setWord(CeilDiv(in.size(), kAesBlockSize)))
281279
return WebCryptoCipherStatus::FAILED;
282280

283281
// Just like in chromium's implementation, if the counter will
284282
// be incremented more than there are counter values, we fail.
285-
if (BN_cmp(num_output.get(), num_counters.get()) > 0)
283+
if (num_output > num_counters)
286284
return WebCryptoCipherStatus::FAILED;
287285

288-
BignumPointer remaining_until_reset(BN_new());
286+
auto remaining_until_reset = BignumPointer::Create();
289287
if (!BN_sub(remaining_until_reset.get(),
290288
num_counters.get(),
291289
current_counter.get())) {
@@ -298,7 +296,7 @@ WebCryptoCipherStatus AES_CTR_Cipher(
298296
// Also just like in chromium's implementation, if we can process
299297
// the input without wrapping the counter, we'll do it as a single
300298
// call here. If we can't, we'll fallback to the a two-step approach
301-
if (BN_cmp(remaining_until_reset.get(), num_output.get()) >= 0) {
299+
if (remaining_until_reset >= num_output) {
302300
auto status = AES_CTR_Cipher2(key_data,
303301
cipher_mode,
304302
params,
@@ -309,8 +307,7 @@ WebCryptoCipherStatus AES_CTR_Cipher(
309307
return status;
310308
}
311309

312-
BN_ULONG blocks_part1 = BN_get_word(remaining_until_reset.get());
313-
BN_ULONG input_size_part1 = blocks_part1 * kAesBlockSize;
310+
BN_ULONG input_size_part1 = remaining_until_reset.getWord() * kAesBlockSize;
314311

315312
// Encrypt the first part...
316313
auto status =

0 commit comments

Comments
 (0)