Skip to content

Commit

Permalink
Merge pull request #16825 from michael-redpanda/crypto-lib2
Browse files Browse the repository at this point in the history
Crypto lib
  • Loading branch information
michael-redpanda authored Mar 5, 2024
2 parents f9af041 + ec0b9ac commit 3fa20fe
Show file tree
Hide file tree
Showing 26 changed files with 2,040 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ licenses @emaxerrno @dswang
/install-dependencies.sh @redpanda-data/devprod
/.yapfignore @redpanda-data/devprod

#
# crypto
#
/src/v/crypto @michael-redpanda

#
# rpk
#
Expand Down
1 change: 1 addition & 0 deletions src/v/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ add_subdirectory(wasm)
add_subdirectory(transform)
add_subdirectory(container)
add_subdirectory(strings)
add_subdirectory(crypto)

option(ENABLE_GIT_VERSION "Build with Git metadata" OFF)

Expand Down
6 changes: 5 additions & 1 deletion src/v/base/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
v_cc_library(NAME base)
v_cc_library(
NAME base
DEPS
Seastar::seastar
)
add_subdirectory(tests)
3 changes: 3 additions & 0 deletions src/v/bytes/include/bytes/bytes.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <cstdint>
#include <iosfwd>
#include <span>

// cannot be a `std::byte` because that's not sizeof(char)
constexpr size_t bytes_inline_size = 31;
Expand All @@ -32,6 +33,8 @@ using bytes = ss::basic_sstring<

using bytes_view = std::basic_string_view<uint8_t>;
using bytes_opt = std::optional<bytes>;
template<std::size_t Extent = std::dynamic_extent>
using bytes_span = std::span<bytes::value_type, Extent>;

struct bytes_type_hash {
using is_transparent = std::true_type;
Expand Down
19 changes: 19 additions & 0 deletions src/v/crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
find_package(OpenSSL 3.0.9 EXACT REQUIRED)

v_cc_library(
NAME crypto
SRCS
crypto.cc
digest.cc
hmac.cc
key.cc
random.cc
signature.cc
ssl_utils.cc
DEPS
absl::node_hash_set
v::bytes
OpenSSL::SSL
)

add_subdirectory(test)
150 changes: 150 additions & 0 deletions src/v/crypto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Redpanda Crypto Library

The Redpanda crypto library provides a convenient API for any subsystem that
desires to use a cryptographic function. It will abstract away the actual
implementation (OpenSSL).

This library provides the following implementations:

* RSA PKCSv1.5 signature verification
* HMAC
* MD5, SHA256 and SHA512 digest generation
* Cryptographically secure DRBG
* Base64 decoding

## Cryptographic Secure Digest

This library currently supports the following digest types:

* MD5
* SHA256
* SHA512

There are two ways of performing a digest: one-shot and multi-part.

For one-shot, you can do the following:

```c++
#include "crypto/crypto.h"

bytes msg = {...};
auto digest = crypto::digest(crypto::digest_type::SHA256, msg);
```
For multi-part operation, you can do the following:
```c++
#include "crypto/crypto.h"
bytes msg = {...};
crypto::digest_ctx ctx(crypto::digest_type::SHA256);
ctx.update(msg);
auto digest = std::move(ctx).final();
```

## HMAC

Like digests, this library can perform HMAC two ways: one-shot and multi-part.

For one-shot:

```c++
#include "crypto/crypto.h"

bytes key = {...};
bytes msg = {...};

auto sig = crypto::hmac(crypto::digest_type::SHA256, key, msg);
```
For multi-part:
```c++
#include "crypto/crypto.h"
bytes key = {...};
bytes msg = {...};
crypto::hmac_ctx ctx(crypto::digest_type::SHA256, key);
ctx.update(msg);
auto sig = std::move(ctx).final();
```

## Asymmetric Key Handling

Currently, this library only supports RSA keys. There are two ways of loading a
key from a buffer.

First, if the key is held within a buffer in PKCS8 format, you can use
`crypto::load_key`:

```c++
#include "crypto/crypto.h"

bytes rsa_priv_key {...};

auto key = crypto::key::load_key(
rsa_priv_key,
crypto::format_type::PEM,
crypto::is_private_key_t::yes);
```
The above function can determine the type of key held in the buffer but the
caller is responsible for indicating the format the key is in (PEM or DER) and
whether or not it's the public half of the key or the private key.
The other way of loading a key is by its parts. Currently only RSA public key
loading is available:
```c++
#include "crypto/crypto.h"
bytes modulus {...};
bytes public_exponent {...};
auto key = crypto::key::load_rsa_public_key(modulus, public_exponent);
```

## Signature Verification

Performing signature verification can be done either one-shot or multi part.

One-shot:

```c++
#include "crypto/crypto.h"

auto key = {...};
bytes msg {...};
bytes sig {...};

auto sig_verified = crypto::verify_signature(
crypto::digest_type::SHA256,
key,
msg,
sig
);
```
For multi-part:
```c++
#include "crypto/crypto.h"
auto key = {...};
bytes msg {...};
bytes sig {...};
crypto::verify_ctx ctx(crypto::digest_type::SHA256, key);
ctx.update(msg);
bool verified = std::move(ctx).final(sig);
```

## RNG Generation

To get cryptographically secure random data, please use
`crypto::generate_random`. There are two functions you can use. One will
place random data into the provided buffer and another will return an allocated
buffer with random data. Both functions also have a flag to indicate if the caller
wants to use the 'private' DRBG. For more information on this please refer to
OpenSSL's [documentation](https://www.openssl.org/docs/man3.0/man3/RAND_priv_bytes.html)
on this.
43 changes: 43 additions & 0 deletions src/v/crypto/crypto.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2024 Redpanda Data, Inc.
*
* Use of this software is governed by the Business Source License
* included in the file licenses/BSL.md
*
* As of the Change Date specified in that file, in accordance with
* the Business Source License, use of this software will be governed
* by the Apache License, Version 2.0
*/

#include "crypto/crypto.h"

namespace crypto {
std::ostream& operator<<(std::ostream& os, digest_type type) {
switch (type) {
case digest_type::MD5:
return os << "MD5";
case digest_type::SHA256:
return os << "SHA256";
case digest_type::SHA512:
return os << "SHA512";
}

return os;
}

std::ostream& operator<<(std::ostream& os, key_type type) {
switch (type) {
case key_type::RSA:
return os << "RSA";
}
}

std::ostream& operator<<(std::ostream& os, format_type type) {
switch (type) {
case format_type::PEM:
return os << "PEM";
case format_type::DER:
return os << "DER";
}
}
} // namespace crypto
Loading

0 comments on commit 3fa20fe

Please sign in to comment.