Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 96 additions & 152 deletions include/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/kdf.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
Expand All @@ -16,17 +17,13 @@
#include <openssl/aead.h>
#endif

#include <stdint.h>
#include <cstddef>
#include <cstdio>
#include <functional>
#include <list>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>

#if NCRYPTO_DEVELOPMENT_CHECKS
#include <iostream>
Expand Down Expand Up @@ -92,7 +89,10 @@ inline bool EqualNoCase(const std::string_view a, const std::string_view b) {
#define NCRYPTO_STR(x) #x
#define NCRYPTO_REQUIRE(EXPR) \
{ \
if (!(EXPR) { abort(); }) }
if (!(EXPR)) { \
abort(); \
} \
}

#define NCRYPTO_FAIL(MESSAGE) \
do { \
Expand Down Expand Up @@ -269,8 +269,6 @@ class ECKeyPointer;
class Dsa;
class Rsa;
class Ec;
class Aead;
class AeadCtxPointer;

struct StackOfXASN1Deleter {
void operator()(STACK_OF(ASN1_OBJECT) * p) const {
Expand Down Expand Up @@ -325,25 +323,7 @@ DataPointer xofHashDigest(const Buffer<const unsigned char>& data,
const EVP_MD* md,
size_t length);

template <typename T>
class ModeMixin {
public:
std::string_view getModeLabel() const;

bool isGcmMode() const { return self().getMode() == EVP_CIPH_GCM_MODE; }
bool isWrapMode() const { return self().getMode() == EVP_CIPH_WRAP_MODE; }
bool isCtrMode() const { return self().getMode() == EVP_CIPH_CTR_MODE; }
bool isCcmMode() const { return self().getMode() == EVP_CIPH_CCM_MODE; }
bool isOcbMode() const { return self().getMode() == EVP_CIPH_OCB_MODE; }
bool isStreamMode() const {
return self().getMode() == EVP_CIPH_STREAM_CIPHER;
}

private:
const T& self() const { return static_cast<const T&>(*this); }
};

class Cipher final : public ModeMixin<Cipher> {
class Cipher final {
public:
static constexpr size_t MAX_KEY_LENGTH = EVP_MAX_KEY_LENGTH;
static constexpr size_t MAX_IV_LENGTH = EVP_MAX_IV_LENGTH;
Expand All @@ -352,10 +332,12 @@ class Cipher final : public ModeMixin<Cipher> {
#else
static constexpr size_t MAX_AUTH_TAG_LENGTH = 16;
#endif
// FIXME: These constants are not available in all OpenSSL/BoringSSL versions
// static_assert(EVP_GCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH &&
// EVP_CCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH &&
// EVP_CHACHAPOLY_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH);
static_assert(EVP_GCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH
#ifndef OPENSSL_IS_BORINGSSL
&& EVP_CCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH &&
EVP_CHACHAPOLY_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH
#endif
);

Cipher() = default;
Cipher(const EVP_CIPHER* cipher) : cipher_(cipher) {}
Expand All @@ -376,9 +358,15 @@ class Cipher final : public ModeMixin<Cipher> {
int getIvLength() const;
int getKeyLength() const;
int getBlockSize() const;

std::string_view getModeLabel() const;
const char* getName() const;

bool isGcmMode() const;
bool isWrapMode() const;
bool isCtrMode() const;
bool isCcmMode() const;
bool isOcbMode() const;
bool isStreamMode() const;
bool isChaCha20Poly1305() const;

bool isSupportedAuthenticatedMode() const;
Expand Down Expand Up @@ -471,78 +459,8 @@ class Dsa final {
OSSL3_CONST DSA* dsa_;
};

class BignumPointer final {
public:
BignumPointer() = default;
explicit BignumPointer(BIGNUM* bignum);
explicit BignumPointer(const unsigned char* data, size_t len);
BignumPointer(BignumPointer&& other) noexcept;
BignumPointer& operator=(BignumPointer&& other) noexcept;
NCRYPTO_DISALLOW_COPY(BignumPointer)
~BignumPointer();

int operator<=>(const BignumPointer& other) const noexcept;
int operator<=>(const BIGNUM* other) const noexcept;
inline operator bool() const { return bn_ != nullptr; }
inline BIGNUM* get() const noexcept { return bn_.get(); }
void reset(BIGNUM* bn = nullptr);
void reset(const unsigned char* data, size_t len);
BIGNUM* release();

bool isZero() const;
bool isOne() const;

bool setWord(unsigned long w); // NOLINT(runtime/int)
unsigned long getWord() const; // NOLINT(runtime/int)

size_t byteLength() const;
size_t bitLength() const;

DataPointer toHex() const;
DataPointer encode() const;
DataPointer encodePadded(size_t size) const;
size_t encodeInto(unsigned char* out) const;
size_t encodePaddedInto(unsigned char* out, size_t size) const;

using PrimeCheckCallback = std::function<bool(int, int)>;
int isPrime(int checks,
PrimeCheckCallback cb = defaultPrimeCheckCallback) const;
struct PrimeConfig {
int bits;
bool safe = false;
const BignumPointer& add;
const BignumPointer& rem;
};

static BignumPointer NewPrime(
const PrimeConfig& params,
PrimeCheckCallback cb = defaultPrimeCheckCallback);

bool generate(const PrimeConfig& params,
PrimeCheckCallback cb = defaultPrimeCheckCallback) const;

static BignumPointer New();
static BignumPointer NewSecure();
static BignumPointer NewSub(const BignumPointer& a, const BignumPointer& b);
static BignumPointer NewLShift(size_t length);

static DataPointer Encode(const BIGNUM* bn);
static DataPointer EncodePadded(const BIGNUM* bn, size_t size);
static size_t EncodePaddedInto(const BIGNUM* bn,
unsigned char* out,
size_t size);
static int GetBitCount(const BIGNUM* bn);
static int GetByteCount(const BIGNUM* bn);
static unsigned long GetWord(const BIGNUM* bn); // NOLINT(runtime/int)
static const BIGNUM* One();

BignumPointer clone();

private:
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;

static bool defaultPrimeCheckCallback(int, int) { return 1; }
};
// ============================================================================
// RSA

class Rsa final {
public:
Expand Down Expand Up @@ -604,10 +522,6 @@ class Ec final {

const EC_GROUP* getGroup() const;
int getCurve() const;
uint32_t getDegree() const;
std::string getCurveName() const;
const EC_POINT* getPublicKey() const;
const BIGNUM* getPrivateKey() const;

inline operator bool() const { return ec_ != nullptr; }
inline operator OSSL3_CONST EC_KEY*() const { return ec_; }
Expand All @@ -617,16 +531,8 @@ class Ec final {
using GetCurveCallback = std::function<bool(const char*)>;
static bool GetCurves(GetCurveCallback callback);

inline const BignumPointer& getX() const { return x_; }
inline const BignumPointer& getY() const { return y_; }
inline const BignumPointer& getD() const { return d_; }

private:
OSSL3_CONST EC_KEY* ec_ = nullptr;
// Affine coordinates for the EC_KEY.
BignumPointer x_;
BignumPointer y_;
BignumPointer d_;
};

// A managed pointer to a buffer of data. When destroyed the underlying
Expand Down Expand Up @@ -757,6 +663,78 @@ class BIOPointer final {
mutable DeleteFnPtr<BIO, BIO_free_all> bio_;
};

class BignumPointer final {
public:
BignumPointer() = default;
explicit BignumPointer(BIGNUM* bignum);
explicit BignumPointer(const unsigned char* data, size_t len);
BignumPointer(BignumPointer&& other) noexcept;
BignumPointer& operator=(BignumPointer&& other) noexcept;
NCRYPTO_DISALLOW_COPY(BignumPointer)
~BignumPointer();

int operator<=>(const BignumPointer& other) const noexcept;
int operator<=>(const BIGNUM* other) const noexcept;
inline operator bool() const { return bn_ != nullptr; }
inline BIGNUM* get() const noexcept { return bn_.get(); }
void reset(BIGNUM* bn = nullptr);
void reset(const unsigned char* data, size_t len);
BIGNUM* release();

bool isZero() const;
bool isOne() const;

bool setWord(unsigned long w); // NOLINT(runtime/int)
unsigned long getWord() const; // NOLINT(runtime/int)

size_t byteLength() const;

DataPointer toHex() const;
DataPointer encode() const;
DataPointer encodePadded(size_t size) const;
size_t encodeInto(unsigned char* out) const;
size_t encodePaddedInto(unsigned char* out, size_t size) const;

using PrimeCheckCallback = std::function<bool(int, int)>;
int isPrime(int checks,
PrimeCheckCallback cb = defaultPrimeCheckCallback) const;
struct PrimeConfig {
int bits;
bool safe = false;
const BignumPointer& add;
const BignumPointer& rem;
};

static BignumPointer NewPrime(
const PrimeConfig& params,
PrimeCheckCallback cb = defaultPrimeCheckCallback);

bool generate(const PrimeConfig& params,
PrimeCheckCallback cb = defaultPrimeCheckCallback) const;

static BignumPointer New();
static BignumPointer NewSecure();
static BignumPointer NewSub(const BignumPointer& a, const BignumPointer& b);
static BignumPointer NewLShift(size_t length);

static DataPointer Encode(const BIGNUM* bn);
static DataPointer EncodePadded(const BIGNUM* bn, size_t size);
static size_t EncodePaddedInto(const BIGNUM* bn,
unsigned char* out,
size_t size);
static int GetBitCount(const BIGNUM* bn);
static int GetByteCount(const BIGNUM* bn);
static unsigned long GetWord(const BIGNUM* bn); // NOLINT(runtime/int)
static const BIGNUM* One();

BignumPointer clone();

private:
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;

static bool defaultPrimeCheckCallback(int, int) { return 1; }
};

class CipherCtxPointer final {
public:
static CipherCtxPointer New();
Expand Down Expand Up @@ -998,15 +976,12 @@ class EVPKeyPointer final {
int getDefaultSignPadding() const;
operator Rsa() const;
operator Dsa() const;
operator Ec() const;

bool isRsaVariant() const;
bool isOneShotVariant() const;
bool isSigVariant() const;
bool validateDsaParameters() const;

EVPKeyPointer clone() const;

private:
DeleteFnPtr<EVP_PKEY, EVP_PKEY_free> pkey_;
};
Expand Down Expand Up @@ -1635,19 +1610,11 @@ bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext);
// ============================================================================
// SPKAC

[[deprecated("Use the version that takes a Buffer")]] bool VerifySpkac(
const char* input, size_t length);

[[deprecated("Use the version that takes a Buffer")]] BIOPointer
ExportPublicKey(const char* input, size_t length);
bool VerifySpkac(const char* input, size_t length);
BIOPointer ExportPublicKey(const char* input, size_t length);

// The caller takes ownership of the returned Buffer<char>
[[deprecated("Use the version that takes a Buffer")]] Buffer<char>
ExportChallenge(const char* input, size_t length);

bool VerifySpkac(const Buffer<const char>& buf);
BIOPointer ExportPublicKey(const Buffer<const char>& buf);
DataPointer ExportChallenge(const Buffer<const char>& buf);
Buffer<char> ExportChallenge(const char* input, size_t length);

// ============================================================================
// KDF
Expand All @@ -1664,13 +1631,6 @@ bool extractP1363(const Buffer<const unsigned char>& buf,
unsigned char* dest,
size_t n);

bool hkdfInfo(const Digest& md,
const Buffer<const unsigned char>& key,
const Buffer<const unsigned char>& info,
const Buffer<const unsigned char>& salt,
size_t length,
Buffer<unsigned char>* out);

DataPointer hkdf(const Digest& md,
const Buffer<const unsigned char>& key,
const Buffer<const unsigned char>& info,
Expand All @@ -1679,15 +1639,6 @@ DataPointer hkdf(const Digest& md,

bool checkScryptParams(uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem);

bool scryptInto(const Buffer<const char>& pass,
const Buffer<const unsigned char>& salt,
uint64_t N,
uint64_t r,
uint64_t p,
uint64_t maxmem,
size_t length,
Buffer<unsigned char>* out);

DataPointer scrypt(const Buffer<const char>& pass,
const Buffer<const unsigned char>& salt,
uint64_t N,
Expand All @@ -1696,13 +1647,6 @@ DataPointer scrypt(const Buffer<const char>& pass,
uint64_t maxmem,
size_t length);

bool pbkdf2Into(const Digest& md,
const Buffer<const char>& pass,
const Buffer<const unsigned char>& salt,
uint32_t iterations,
size_t length,
Buffer<unsigned char>* out);

DataPointer pbkdf2(const Digest& md,
const Buffer<const char>& pass,
const Buffer<const unsigned char>& salt,
Expand Down
Loading
Loading