Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental code from HACL* for AES128-GCM #18

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
12 changes: 11 additions & 1 deletion fizz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.1)

project("fizz" VERSION 1.0.0 LANGUAGES CXX C)

add_compile_options(-std=c++14)
add_compile_options(-std=c++14 -maes -mpclmul -mavx)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
Expand Down Expand Up @@ -64,6 +64,9 @@ set(FIZZ_HEADER_DIRS
server
util
tool

# hacl
crypto/experimental/hacl
)

set(FIZZ_TEST_HEADER_DIRS
Expand Down Expand Up @@ -134,6 +137,10 @@ set(FIZZ_SOURCES
client/SynchronizedLruPskCache.cpp
client/EarlyDataRejectionPolicy.cpp
util/FizzUtil.cpp

# hacl
crypto/experimental/hacl/Hacl_AesGCM_NI.cpp
crypto/experimental/hacl/Hacl.cpp
)

add_library(fizz
Expand Down Expand Up @@ -344,6 +351,9 @@ if(BUILD_TESTS)
add_gtest(util/test/FizzUtilTest.cpp FizzUtilTest)
add_gtest(test/AsyncFizzBaseTest.cpp AsyncFizzBaseTest)
add_gtest(test/HandshakeTest.cpp HandshakeTest)

# Hacl
add_gtest(crypto/experimental/hacl/test/HaclCipherTest HaclCipherTest)
endif()

option(BUILD_EXAMPLES "BUILD_EXAMPLES" ON)
Expand Down
105 changes: 105 additions & 0 deletions fizz/crypto/experimental/hacl/Hacl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "Hacl.h"

#include "Hacl_AesGCM_NI.h"
#include <fizz/crypto/aead/IOBufUtil.h>
#include <folly/Range.h>
#include <folly/lang/Bits.h>

namespace fizz {
namespace hacl {

std::array<uint8_t, 12> Hacl::createIV(uint64_t seqNum) const {
std::array<uint8_t, 12> iv;
uint64_t bigEndianSeqNum = folly::Endian::big(seqNum);
const size_t prefixLength = 12 - sizeof(uint64_t);
memset(iv.data(), 0, prefixLength);
memcpy(iv.data() + prefixLength, &bigEndianSeqNum, 8);
XOR(key_.iv->coalesce(), folly::range(iv));
return iv;
}

void Hacl::setKey(TrafficKey tk) {
tk.key->coalesce();
tk.iv->coalesce();
key_ = std::move(tk);
}

std::unique_ptr<folly::IOBuf> Hacl::encrypt(
std::unique_ptr<folly::IOBuf>&& plaintext,
const folly::IOBuf* associatedData,
uint64_t seqNum) const {
Lib_Vec128_vec128 ctx[22] = {0};
// get iv and init hacl
auto iv = createIV(seqNum);
uint8_t* keyData = const_cast<uint8_t*>(key_.key->data());
Hacl_AesGCM_NI_aes128_gcm_init(ctx, keyData, iv.data());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you need to modify the key here? or is it just a limitation of the hacl interface?

iobuf has a writableData() as well which will give you a non const ptr to the data

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const cast is fine if you dont have to change the key but its just takes a non const ptr


// plaintext needs to be coalesced
plaintext->coalesce();
auto inputLen = plaintext->computeChainDataLength();
// output needs to be one contiguous buffer w/ room for the tag
auto out = folly::IOBuf::create(headroom_ + inputLen + getCipherOverhead());
out->advance(headroom_);
out->append(inputLen + getCipherOverhead());
auto inData = const_cast<uint8_t*>(plaintext->data());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

writableData() here will do what you want.


// set up aad
uint8_t* aad = nullptr;
size_t aadLen = 0;
if (associatedData) {
auto adbuf = const_cast<folly::IOBuf*>(associatedData);
adbuf->coalesce();
aad = const_cast<uint8_t*>(adbuf->data());
aadLen = adbuf->computeChainDataLength();
}

// hacl encrypt!
Hacl_AesGCM_NI_aes128_gcm_encrypt(
ctx, inputLen, out->writableData(), inData, aadLen, aad);

// assume it worked?
return out;
}

folly::Optional<std::unique_ptr<folly::IOBuf>> Hacl::tryDecrypt(
std::unique_ptr<folly::IOBuf>&& ciphertext,
const folly::IOBuf* associatedData,
uint64_t seqNum) const {
Lib_Vec128_vec128 ctx[22] = {0};
// set up
// get iv and init hacl
auto iv = createIV(seqNum);
uint8_t* keyData = const_cast<uint8_t*>(key_.key->data());
Hacl_AesGCM_NI_aes128_gcm_init(ctx, keyData, iv.data());

// set up aad
uint8_t* aad = nullptr;
size_t aadLen = 0;
if (associatedData) {
auto adbuf = const_cast<folly::IOBuf*>(associatedData);
adbuf->coalesce();
aad = const_cast<uint8_t*>(adbuf->data());
aadLen = adbuf->computeChainDataLength();
}

ciphertext->coalesce();
auto inputLen = ciphertext->computeChainDataLength();
if (inputLen <= getCipherOverhead()) {
return folly::none;
}
auto out = folly::IOBuf::create(inputLen - getCipherOverhead());
out->append(inputLen - getCipherOverhead());

auto cipherData = const_cast<uint8_t*>(ciphertext->data());

auto res = Hacl_AesGCM_NI_aes128_gcm_decrypt(
ctx, inputLen-16, out->writableData(), cipherData, aadLen, aad);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: spacing here inputLen - 16


if (!res) {
return folly::none;
}
return out;
}

} // namespace hacl
} // namespace fizz
53 changes: 53 additions & 0 deletions fizz/crypto/experimental/hacl/Hacl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once

#include <fizz/crypto/aead/Aead.h>

namespace fizz {
namespace hacl {

class Hacl : public Aead {
public:
size_t keyLength() const override {
return 16;
}

size_t ivLength() const override {
return 12;
}

void setEncryptedBufferHeadroom(size_t headroom) override {
headroom_ = headroom;
}

void setKey(TrafficKey trafficKey) override;

std::unique_ptr<folly::IOBuf> encrypt(
std::unique_ptr<folly::IOBuf>&& plaintext,
const folly::IOBuf* associatedData,
uint64_t seqNum) const override;

folly::Optional<std::unique_ptr<folly::IOBuf>> tryDecrypt(
std::unique_ptr<folly::IOBuf>&& ciphertext,
const folly::IOBuf* associatedData,
uint64_t seqNum) const override;

size_t getCipherOverhead() const override {
return 16;
}

std::array<uint8_t, 12> createIV(uint64_t seqNum) const;

private:
size_t headroom_{5};
TrafficKey key_;
};

} // namespace hacl
} // namespace fizz
Loading