Skip to content

Commit

Permalink
Add module circl
Browse files Browse the repository at this point in the history
  • Loading branch information
guidovranken committed Jan 24, 2022
1 parent a01e030 commit 680f199
Show file tree
Hide file tree
Showing 7 changed files with 384 additions and 0 deletions.
8 changes: 8 additions & 0 deletions entry.cpp
Expand Up @@ -317,6 +317,10 @@
#include <modules/v8/module.h>
#endif

#if defined(CRYPTOFUZZ_CIRCL)
#include <modules/circl/module.h>
#endif

std::shared_ptr<cryptofuzz::Driver> driver = nullptr;

const cryptofuzz::Options* cryptofuzz_options = nullptr;
Expand Down Expand Up @@ -641,6 +645,10 @@ extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
driver->LoadModule( std::make_shared<cryptofuzz::module::V8>() );
#endif

#if defined(CRYPTOFUZZ_CIRCL)
driver->LoadModule( std::make_shared<cryptofuzz::module::circl>() );
#endif

/* TODO check if options.forceModule (if set) refers to a module that is
* actually loaded, warn otherwise.
*/
Expand Down
1 change: 1 addition & 0 deletions gen_repository.py
Expand Up @@ -306,6 +306,7 @@ def getTableEntryList(self, index):
modules.Add( Module("bn.js") )
modules.Add( Module("chia_bls") )
modules.Add( Module("cifra") )
modules.Add( Module("circl") )
modules.Add( Module("cloudflare-bn256") )
modules.Add( Module("crypto-js") )
modules.Add( Module("elliptic") )
Expand Down
20 changes: 20 additions & 0 deletions modules/circl/Makefile
@@ -0,0 +1,20 @@
all: module.a cryptofuzz.a

CXXFLAGS += -Wall -Wextra -std=c++17 -I ../../include -I ../../fuzzing-headers/include -DFUZZING_HEADERS_NO_IMPL

module.a: module.o
rm -rf tmp/
mkdir tmp/
cd tmp/ && ar x ../cryptofuzz.a && ar rcs ../module.a *.o ../module.o
ranlib module.a
rm -rf tmp/
generate_ids : generate_ids.cpp
$(CXX) $(CXXFLAGS) generate_ids.cpp -o generate_ids
ids.go : generate_ids
./generate_ids
cryptofuzz.a: cryptofuzz.go ids.go
go build -o cryptofuzz.a -buildmode=c-archive cryptofuzz.go ids.go
module.o: cryptofuzz.a module.cpp module.h
$(CXX) $(CXXFLAGS) -fPIC -c module.cpp -o module.o
clean:
rm -rf *.o module.a cryptofuzz.a cryptofuzz.h generate_ids ids.go
217 changes: 217 additions & 0 deletions modules/circl/cryptofuzz.go
@@ -0,0 +1,217 @@
package main

import (
"bytes"
"strconv"
"encoding/hex"
"encoding/json"
"math/big"
"github.com/cloudflare/circl/ecc/p384"
)

import "C"

type ByteSlice []byte
type Type uint64

type SliceOpt struct {
slice ByteSlice
opt byte
}

func (t *Type) UnmarshalJSON(in []byte) error {
res, err := strconv.ParseUint(string(in[1:len(in)-1]), 10, 64)
*t = Type(res)
return err
}

func (b *ByteSlice) MarshalJSON() ([]byte, error) {
var buffer bytes.Buffer
buffer.WriteString("\"")
buffer.WriteString(hex.EncodeToString(*b))
buffer.WriteString("\"")
return buffer.Bytes(), nil
}

func (b *ByteSlice) UnmarshalJSON(in []byte) error {
res, err := hex.DecodeString(string(in[1:len(in)-1]))
*b = res
return err
}

func decodeBignum(s string) *big.Int {
if s == "" {
s = "0"
}

bn, ok := new(big.Int).SetString(s, 10)
if ok == false {
panic("Cannot decode bignum")
}
return bn
}

type OpECC_Point_Add struct {
Modifier ByteSlice
CurveType Type
A_x string
A_y string
B_x string
B_y string
}

type OpECC_Point_Mul struct {
Modifier ByteSlice
CurveType Type
A_x string
A_y string
B string
}

type OpECC_Point_Dbl struct {
Modifier ByteSlice
CurveType Type
A_x string
A_y string
}

var result []byte

func resetResult() {
result = []byte{}
}

func setResult(r ByteSlice) {
r2, err := json.Marshal(&r)
if err != nil {
panic("Cannot marshal to JSON")
}
result = r2
}

func unmarshal(in []byte, op interface{}) {
err := json.Unmarshal(in, &op)
if err != nil {
panic("Cannot unmarshal JSON, which is expected to be well-formed")
}
}

//export circl_Cryptofuzz_GetResult
func circl_Cryptofuzz_GetResult() *C.char {
return C.CString(string(result))
}

//export circl_Cryptofuzz_OpECC_Point_Add
func circl_Cryptofuzz_OpECC_Point_Add(in []byte) {
resetResult()

var op OpECC_Point_Add
unmarshal(in, &op)

if !issecp384r1(op.CurveType) {
return
}

curve := p384.P384()

a_x := decodeBignum(op.A_x)
a_y := decodeBignum(op.A_y)

b_x := decodeBignum(op.B_x)
b_y := decodeBignum(op.B_y)

res_x, res_y := curve.Add(a_x, a_y, b_x, b_y)

if curve.IsOnCurve(a_x, a_y) == false {
return
}

if curve.IsOnCurve(b_x, b_y) == false {
return
}

res := make([]string, 2)
res[0], res[1] = res_x.String(), res_y.String()

r2, err := json.Marshal(&res)
if err != nil {
panic("Cannot marshal to JSON")
}

result = r2
}

//export circl_Cryptofuzz_OpECC_Point_Mul
func circl_Cryptofuzz_OpECC_Point_Mul(in []byte) {
resetResult()

var op OpECC_Point_Mul
unmarshal(in, &op)

if !issecp384r1(op.CurveType) {
return
}

curve := p384.P384()

a_x := decodeBignum(op.A_x)
a_y := decodeBignum(op.A_y)

b := decodeBignum(op.B)
/* https://github.com/cloudflare/circl/issues/312 */
order := decodeBignum("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643")
if ( b.Cmp(order) >= 0 ) {
return
}

res_x, res_y := curve.ScalarMult(a_x, a_y, b.Bytes())

if curve.IsOnCurve(a_x, a_y) == false {
return
}

res := make([]string, 2)
res[0], res[1] = res_x.String(), res_y.String()

r2, err := json.Marshal(&res)
if err != nil {
panic("Cannot marshal to JSON")
}

result = r2
}

//export circl_Cryptofuzz_OpECC_Point_Dbl
func circl_Cryptofuzz_OpECC_Point_Dbl(in []byte) {
resetResult()

var op OpECC_Point_Dbl
unmarshal(in, &op)

if !issecp384r1(op.CurveType) {
return
}

curve := p384.P384()

a_x := decodeBignum(op.A_x)
a_y := decodeBignum(op.A_y)

res_x, res_y := curve.Double(a_x, a_y)

if curve.IsOnCurve(a_x, a_y) == false {
return
}

res := make([]string, 2)
res[0], res[1] = res_x.String(), res_y.String()

r2, err := json.Marshal(&res)
if err != nil {
panic("Cannot marshal to JSON")
}

result = r2
}

func main() { }
37 changes: 37 additions & 0 deletions modules/circl/generate_ids.cpp
@@ -0,0 +1,37 @@
#include <cstdint>
#include <cstddef>
#include <stdio.h>
#include <regex>
#include <fuzzing/datasource/id.hpp>
#include "../../repository_map.h"

int main(void)
{
FILE* fp = fopen("ids.go", "wb");
fprintf(fp, "package main\n");
for (const auto& digest : DigestLUTMap ) {
auto digestStr = std::string(digest.second.name);
digestStr = std::regex_replace(digestStr, std::regex("[.-]"), "_");
fprintf(fp, "func is%s(id Type) bool { return id == %s }\n", digestStr.c_str(), std::to_string(digest.first).c_str());
}
for (const auto& cipher : CipherLUTMap ) {
auto cipherStr = std::string(cipher.second.name);
cipherStr = std::regex_replace(cipherStr, std::regex("[.-]"), "_");
if ( cipherStr == "GOST_28147_89" ) {
/* XXX */
continue;
}
fprintf(fp, "func is%s(id Type) bool { return id == %s }\n", cipherStr.c_str(), std::to_string(cipher.first).c_str());
}
for (const auto& curve : ECC_CurveLUTMap ) {
auto curveStr = std::string(curve.second.name);
curveStr = std::regex_replace(curveStr, std::regex("[.-]"), "_");
fprintf(fp, "func is%s(id Type) bool { return id == %s }\n", curveStr.c_str(), std::to_string(curve.first).c_str());
}
for (const auto& bnOp : CalcOpLUTMap ) {
auto bnOpStr = std::string(bnOp.second.name);
bnOpStr = std::regex_replace(bnOpStr, std::regex("\\(.*"), "");
fprintf(fp, "func is%s(id Type) bool { return id == %s }\n", bnOpStr.c_str(), std::to_string(bnOp.first).c_str());
}
fclose(fp);
}
76 changes: 76 additions & 0 deletions modules/circl/module.cpp
@@ -0,0 +1,76 @@
#include "module.h"
#include <cryptofuzz/util.h>
#include <cryptofuzz/repository.h>
#include <fuzzing/datasource/id.hpp>
#include <boost/lexical_cast.hpp>

extern "C" {
#include "cryptofuzz.h"
}

namespace cryptofuzz {
namespace module {

circl::circl(void) :
Module("circl") {
}

std::string circl::getResult(void) const {
auto res = circl_Cryptofuzz_GetResult();
std::string ret(res);
free(res);
return ret;
}

std::optional<nlohmann::json> circl::getJsonResult(void) const {
const auto res = getResult();
if ( res.empty() ) {
return std::nullopt;
}

try {
return nlohmann::json::parse(getResult());
} catch ( std::exception e ) {
/* Must always parse correctly non-empty strings */
abort();
}
}

template <class T> std::optional<T> circl::getResultAs(void) const {
std::optional<T> ret = std::nullopt;

auto j = getJsonResult();
if ( j != std::nullopt ) {
ret = T(*j);
}

return ret;
}

static GoSlice toGoSlice(std::string& in) {
return {in.data(), static_cast<GoInt>(in.size()), static_cast<GoInt>(in.size())};
}

std::optional<component::ECC_Point> circl::OpECC_Point_Add(operation::ECC_Point_Add& op) {
auto jsonStr = op.ToJSON().dump();
circl_Cryptofuzz_OpECC_Point_Add(toGoSlice(jsonStr));

return getResultAs<component::ECC_Point>();
}

std::optional<component::ECC_Point> circl::OpECC_Point_Mul(operation::ECC_Point_Mul& op) {
auto jsonStr = op.ToJSON().dump();
circl_Cryptofuzz_OpECC_Point_Mul(toGoSlice(jsonStr));

return getResultAs<component::ECC_Point>();
}

std::optional<component::ECC_Point> circl::OpECC_Point_Dbl(operation::ECC_Point_Dbl& op) {
auto jsonStr = op.ToJSON().dump();
circl_Cryptofuzz_OpECC_Point_Dbl(toGoSlice(jsonStr));

return getResultAs<component::ECC_Point>();
}

} /* namespace module */
} /* namespace cryptofuzz */

0 comments on commit 680f199

Please sign in to comment.