Skip to content

Commit 5eed8df

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

14 files changed

+651
-477
lines changed

deps/ncrypto/ncrypto.cc

Lines changed: 436 additions & 22 deletions
Large diffs are not rendered by default.

deps/ncrypto/ncrypto.h

Lines changed: 82 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,91 @@ 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:
195248
BignumPointer() = default;
196249
explicit BignumPointer(BIGNUM* bignum);
250+
explicit BignumPointer(const unsigned char* data, size_t len);
197251
BignumPointer(BignumPointer&& other) noexcept;
198252
BignumPointer& operator=(BignumPointer&& other) noexcept;
199253
NCRYPTO_DISALLOW_COPY(BignumPointer)
200254
~BignumPointer();
201255

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; }
256+
int operator<=>(const BignumPointer& other) const noexcept;
257+
int operator<=>(const BIGNUM* other) const noexcept;
205258
inline operator bool() const { return bn_ != nullptr; }
206259
inline BIGNUM* get() const noexcept { return bn_.get(); }
207260
void reset(BIGNUM* bn = nullptr);
261+
void reset(const unsigned char* data, size_t len);
208262
BIGNUM* release();
209263

210-
size_t byteLength();
264+
bool isZero() const;
265+
bool isOne() const;
266+
267+
bool setWord(unsigned long w);
268+
unsigned long getWord() const;
269+
270+
size_t byteLength() const;
211271

212-
std::vector<uint8_t> encode();
213-
std::vector<uint8_t> encodePadded(size_t size);
272+
DataPointer toHex() const;
273+
DataPointer encode() const;
274+
DataPointer encodePadded(size_t size) const;
275+
size_t encodeInto(unsigned char* out) const;
276+
size_t encodePaddedInto(unsigned char* out, size_t size) const;
214277

215-
static std::vector<uint8_t> encode(const BIGNUM* bn);
216-
static std::vector<uint8_t> encodePadded(const BIGNUM* bn, size_t size);
278+
static BignumPointer New();
279+
static BignumPointer NewSecure();
280+
static DataPointer Encode(const BIGNUM* bn);
281+
static DataPointer EncodePadded(const BIGNUM* bn, size_t size);
282+
static size_t EncodePaddedInto(const BIGNUM* bn, unsigned char* out, size_t size);
283+
static int GetBitCount(const BIGNUM* bn);
284+
static int GetByteCount(const BIGNUM* bn);
285+
static unsigned long GetWord(const BIGNUM* bn);
286+
static const BIGNUM* One();
217287

218288
private:
219289
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;
@@ -269,11 +339,6 @@ bool testFipsEnabled();
269339
// ============================================================================
270340
// Various utilities
271341

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

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

286351
int PasswordCallback(char* buf, int size, int rwflag, void* u);
287352

353+
bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext);
354+
bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext);
355+
288356
// ============================================================================
289357
// Version metadata
290358
#define NCRYPTO_VERSION "0.0.1"

src/crypto/crypto_aes.cc

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,7 @@ 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, byte_length);
192189
}
193190

194191
unsigned int byte_length =
@@ -199,7 +196,7 @@ BignumPointer GetCounter(const AESCipherConfig& params) {
199196
data + params.iv.size());
200197
counter[0] &= ~(0xFF << remainder);
201198

202-
return BignumPointer(BN_bin2bn(counter.data(), counter.size(), nullptr));
199+
return BignumPointer(counter.data(), counter.size());
203200
}
204201

205202
std::vector<unsigned char> BlockWithZeroedCounter(
@@ -269,23 +266,22 @@ WebCryptoCipherStatus AES_CTR_Cipher(
269266
const AESCipherConfig& params,
270267
const ByteSource& in,
271268
ByteSource* out) {
272-
BignumPointer num_counters(BN_new());
273-
if (!BN_lshift(num_counters.get(), BN_value_one(), params.length))
269+
auto num_counters = BignumPointer::New();
270+
if (!BN_lshift(num_counters.get(), BignumPointer::One(), params.length))
274271
return WebCryptoCipherStatus::FAILED;
275272

276273
BignumPointer current_counter = GetCounter(params);
277274

278-
BignumPointer num_output(BN_new());
275+
auto num_output = BignumPointer::New();
279276

280-
if (!BN_set_word(num_output.get(), CeilDiv(in.size(), kAesBlockSize)))
277+
if (!num_output.setWord(CeilDiv(in.size(), kAesBlockSize)))
281278
return WebCryptoCipherStatus::FAILED;
282279

283280
// Just like in chromium's implementation, if the counter will
284281
// be incremented more than there are counter values, we fail.
285-
if (BN_cmp(num_output.get(), num_counters.get()) > 0)
286-
return WebCryptoCipherStatus::FAILED;
282+
if (num_output > num_counters) return WebCryptoCipherStatus::FAILED;
287283

288-
BignumPointer remaining_until_reset(BN_new());
284+
auto remaining_until_reset = BignumPointer::New();
289285
if (!BN_sub(remaining_until_reset.get(),
290286
num_counters.get(),
291287
current_counter.get())) {
@@ -298,7 +294,7 @@ WebCryptoCipherStatus AES_CTR_Cipher(
298294
// Also just like in chromium's implementation, if we can process
299295
// the input without wrapping the counter, we'll do it as a single
300296
// 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) {
297+
if (remaining_until_reset >= num_output) {
302298
auto status = AES_CTR_Cipher2(key_data,
303299
cipher_mode,
304300
params,
@@ -309,8 +305,7 @@ WebCryptoCipherStatus AES_CTR_Cipher(
309305
return status;
310306
}
311307

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

315310
// Encrypt the first part...
316311
auto status =

0 commit comments

Comments
 (0)