Commit cc5485f8 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot 5

Wrappers for some of OpenSSL's crypto hash functions

Summary:
[Folly] Wrappers for some of OpenSSL's crypto hash functions.

Wraps some of the OpenSSL crypto hash functions with variants that take `ByteRange` for input and `MutableByteRange` for output, and also variants that take `const IOBuf&` for input as well.

These are a bit nicer to use than passing pointers and lengths separately.

Reviewed By: ivmaykov

Differential Revision: D3434562

fbshipit-source-id: 3688ef11680a029b7664ac417a7781e70f9c6926
parent b57cfc00
......@@ -294,6 +294,7 @@ nobase_follyinclude_HEADERS = \
SpinLock.h \
SpookyHashV1.h \
SpookyHashV2.h \
ssl/OpenSSLHash.h \
stats/BucketedTimeSeries-defs.h \
stats/BucketedTimeSeries.h \
stats/Histogram-defs.h \
......@@ -432,6 +433,7 @@ libfolly_la_SOURCES = \
SocketAddress.cpp \
SpookyHashV1.cpp \
SpookyHashV2.cpp \
ssl/OpenSSLHash.cpp \
stats/Instantiations.cpp \
Subprocess.cpp \
ThreadCachedArena.cpp \
......
/*
* Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/ssl/OpenSSLHash.h>
#include <folly/Format.h>
namespace folly {
namespace ssl {
void OpenSSLHash::check_out_size_throw(size_t size, MutableByteRange out) {
throw std::invalid_argument(folly::sformat(
"expected out of size {} but was of size {}", size, out.size()));
}
void OpenSSLHash::check_libssl_result_throw() {
throw std::runtime_error("openssl crypto function failed");
}
}
}
/*
* Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <folly/Range.h>
#include <folly/io/IOBuf.h>
namespace folly {
namespace ssl {
/// Warning:
/// These functions are not thread-safe unless you initialize OpenSSL.
class OpenSSLHash {
public:
class Digest {
public:
Digest() {
EVP_MD_CTX_init(&ctx_);
}
~Digest() {
EVP_MD_CTX_cleanup(&ctx_);
}
void hash_init(const EVP_MD* md) {
md_ = md;
check_libssl_result(1, EVP_DigestInit_ex(&ctx_, md, nullptr));
}
void hash_update(ByteRange data) {
check_libssl_result(1, EVP_DigestUpdate(&ctx_, data.data(), data.size()));
}
void hash_update(const IOBuf& data) {
for (auto r : data) {
hash_update(r);
}
}
void hash_final(MutableByteRange out) {
const auto size = EVP_MD_size(md_);
check_out_size(size, out);
unsigned int len = 0;
check_libssl_result(1, EVP_DigestFinal_ex(&ctx_, out.data(), &len));
check_libssl_result(size, len);
md_ = nullptr;
}
private:
const EVP_MD* md_ = nullptr;
EVP_MD_CTX ctx_;
};
static void hash(
MutableByteRange out,
const EVP_MD* md,
ByteRange data) {
Digest hash;
hash.hash_init(md);
hash.hash_update(data);
hash.hash_final(out);
}
static void hash(
MutableByteRange out,
const EVP_MD* md,
const IOBuf& data) {
Digest hash;
hash.hash_init(md);
hash.hash_update(data);
hash.hash_final(out);
}
static void sha1(MutableByteRange out, ByteRange data) {
hash(out, EVP_sha1(), data);
}
static void sha1(MutableByteRange out, const IOBuf& data) {
hash(out, EVP_sha1(), data);
}
static void sha256(MutableByteRange out, ByteRange data) {
hash(out, EVP_sha256(), data);
}
static void sha256(MutableByteRange out, const IOBuf& data) {
hash(out, EVP_sha256(), data);
}
class Hmac {
public:
Hmac() {
HMAC_CTX_init(&ctx_);
}
~Hmac() {
HMAC_CTX_cleanup(&ctx_);
}
void hash_init(const EVP_MD* md, ByteRange key) {
md_ = md;
check_libssl_result(
1, HMAC_Init_ex(&ctx_, key.data(), key.size(), md_, nullptr));
}
void hash_update(ByteRange data) {
check_libssl_result(1, HMAC_Update(&ctx_, data.data(), data.size()));
}
void hash_update(const IOBuf& data) {
for (auto r : data) {
hash_update(r);
}
}
void hash_final(MutableByteRange out) {
const auto size = EVP_MD_size(md_);
check_out_size(size, out);
unsigned int len = 0;
check_libssl_result(1, HMAC_Final(&ctx_, out.data(), &len));
check_libssl_result(size, len);
md_ = nullptr;
}
private:
const EVP_MD* md_ = nullptr;
HMAC_CTX ctx_;
};
static void hmac(
MutableByteRange out,
const EVP_MD* md,
ByteRange key,
ByteRange data) {
Hmac hmac;
hmac.hash_init(md, key);
hmac.hash_update(data);
hmac.hash_final(out);
};
static void hmac(
MutableByteRange out,
const EVP_MD* md,
ByteRange key,
const IOBuf& data) {
Hmac hmac;
hmac.hash_init(md, key);
hmac.hash_update(data);
hmac.hash_final(out);
}
static void hmac_sha1(
MutableByteRange out, ByteRange key, ByteRange data) {
hmac(out, EVP_sha1(), key, data);
}
static void hmac_sha1(
MutableByteRange out, ByteRange key, const IOBuf& data) {
hmac(out, EVP_sha1(), key, data);
}
static void hmac_sha256(
MutableByteRange out, ByteRange key, ByteRange data) {
hmac(out, EVP_sha256(), key, data);
}
static void hmac_sha256(
MutableByteRange out, ByteRange key, const IOBuf& data) {
hmac(out, EVP_sha256(), key, data);
}
private:
static inline void check_out_size(size_t size, MutableByteRange out) {
if (LIKELY(size == out.size())) {
return;
}
check_out_size_throw(size, out);
}
static void check_out_size_throw(size_t size, MutableByteRange out);
static inline void check_libssl_result(int expected, int result) {
if (LIKELY(result == expected)) {
return;
}
check_libssl_result_throw();
}
static void check_libssl_result_throw();
};
}
}
/*
* Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/ssl/OpenSSLHash.h>
#include <gtest/gtest.h>
#include <folly/io/IOBufQueue.h>
using namespace std;
using namespace folly;
using namespace folly::ssl;
namespace {
class OpenSSLHashTest : public testing::Test {};
}
TEST_F(OpenSSLHashTest, sha256) {
IOBuf buf;
buf.prependChain(IOBuf::wrapBuffer(ByteRange(StringPiece("foo"))));
buf.prependChain(IOBuf::wrapBuffer(ByteRange(StringPiece("bar"))));
EXPECT_EQ(3, buf.countChainElements());
EXPECT_EQ(6, buf.computeChainDataLength());
auto expected = vector<uint8_t>(32);
auto combined = ByteRange(StringPiece("foobar"));
SHA256(combined.data(), combined.size(), expected.data());
auto out = vector<uint8_t>(32);
OpenSSLHash::sha256(range(out), buf);
EXPECT_EQ(expected, out);
}
TEST_F(OpenSSLHashTest, hmac_sha256) {
auto key = ByteRange(StringPiece("qwerty"));
IOBuf buf;
buf.prependChain(IOBuf::wrapBuffer(ByteRange(StringPiece("foo"))));
buf.prependChain(IOBuf::wrapBuffer(ByteRange(StringPiece("bar"))));
EXPECT_EQ(3, buf.countChainElements());
EXPECT_EQ(6, buf.computeChainDataLength());
auto expected = vector<uint8_t>(32);
auto combined = ByteRange(StringPiece("foobar"));
HMAC(
EVP_sha256(),
key.data(), key.size(),
combined.data(), combined.size(),
expected.data(), nullptr);
auto out = vector<uint8_t>(32);
OpenSSLHash::hmac_sha256(range(out), key, buf);
EXPECT_EQ(expected, out);
}
......@@ -266,4 +266,9 @@ function_test_SOURCES = FunctionTest.cpp
function_test_LDADD = libfollytestmain.la
TESTS += function_test
ssl_test_SOURCES = \
../ssl/OpenSSLHashTest.cpp
ssl_test_LDADD = libfollytestmain.la
TESTS += ssl_test
check_PROGRAMS += $(TESTS)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment