From 7d62132c407dccec2ea944f2d35cc7d90e62232d Mon Sep 17 00:00:00 2001 From: Alexander Wagner Date: Tue, 7 Mar 2023 18:20:46 +0100 Subject: [PATCH] cryptolib/botan: Add Kyber scripts --- cryptolib/botan/algo_kyber/.gitignore | 2 + cryptolib/botan/algo_kyber/Makefile | 8 ++ cryptolib/botan/algo_kyber/data_run.sh | 28 +++++ cryptolib/botan/algo_kyber/framework.sh | 133 ++++++++++++++++++++++ cryptolib/botan/algo_kyber/kyber.cpp | 140 ++++++++++++++++++++++++ 5 files changed, 311 insertions(+) create mode 100644 cryptolib/botan/algo_kyber/.gitignore create mode 100644 cryptolib/botan/algo_kyber/Makefile create mode 100755 cryptolib/botan/algo_kyber/data_run.sh create mode 100755 cryptolib/botan/algo_kyber/framework.sh create mode 100644 cryptolib/botan/algo_kyber/kyber.cpp diff --git a/cryptolib/botan/algo_kyber/.gitignore b/cryptolib/botan/algo_kyber/.gitignore new file mode 100644 index 0000000..1294176 --- /dev/null +++ b/cryptolib/botan/algo_kyber/.gitignore @@ -0,0 +1,2 @@ +bin/ +results/ diff --git a/cryptolib/botan/algo_kyber/Makefile b/cryptolib/botan/algo_kyber/Makefile new file mode 100644 index 0000000..58bb9ee --- /dev/null +++ b/cryptolib/botan/algo_kyber/Makefile @@ -0,0 +1,8 @@ +all: kyber + +kyber: kyber.cpp + mkdir -p bin + g++-11 -std=c++20 -g -O3 -Wall -I ../botan/build/include -Wl,-rpath=../botan/ $^ -o bin/$@ -L ../botan/ -l:libbotan-3.a + +clean: + rm -rf bin/ diff --git a/cryptolib/botan/algo_kyber/data_run.sh b/cryptolib/botan/algo_kyber/data_run.sh new file mode 100755 index 0000000..00b5324 --- /dev/null +++ b/cryptolib/botan/algo_kyber/data_run.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -e + +PINFLAGS="--phase1 --phase2 --export --parallel" +export RESULTDIR=results + + +pushd ${BASH_SOURCE%/*} + +if [[ $1 == "clean" || $2 == "clean" ]]; then + rm -rf results +fi + +./framework.sh ${PINFLAGS} 512 + +if [[ $1 == "test" || $2 == "test" ]]; then + popd + exit 0 +fi + +./framework.sh ${PINFLAGS} 512-90s +./framework.sh ${PINFLAGS} 768 +./framework.sh ${PINFLAGS} 768-90s +./framework.sh ${PINFLAGS} 1024 +./framework.sh ${PINFLAGS} 1024-90s + +popd diff --git a/cryptolib/botan/algo_kyber/framework.sh b/cryptolib/botan/algo_kyber/framework.sh new file mode 100755 index 0000000..24dfc9a --- /dev/null +++ b/cryptolib/botan/algo_kyber/framework.sh @@ -0,0 +1,133 @@ +#!/bin/bash + +######################################################################### +# DO NOT CHANGE: Preparing DATA +#------------------------------------------------------------------------ +source "${DATA_COMMON}/DATA_init.sh" || { echo "source data.sh first!" && exit 1; } +######################################################################### + +#------------------------------------------------------------------------ +# Specify your framework settings used by DATA +#------------------------------------------------------------------------ + +# The name of the framework. Do not use spaces or special characters. +export FRAMEWORK=botan + +# The file containing all supported algorithms +export TARGETFILE=targets.txt + +# The number of measurements for difference detection (phase1) +export PHASE1_TRACES=3 + +# The number of constant keys for generic tests (phase2) +# Make sure that PHASE2_FIXEDKEYS <= PHASE1_TRACES +export PHASE2_FIXEDKEYS=3 + +# The number of measurements per constant key for generic tests (phase2) +export PHASE2_TRACES=100 + +# The number of measurements for specific tests (phase3) +export PHASE3_TRACES=200 + +# (Optional) Additional flags for the pintool. Supported flags are: +# -main
Start recording at function
. Note that the
+# symbol must exist, otherwise this will yield empty traces! +# -heap Trace heap allocations and replace heap addresses with +# relative offset +export PINTOOL_ARGS="-heap" + +#------------------------------------------------------------------------ +# Implement your framework-specific callbacks +#------------------------------------------------------------------------ +# +# Globally available environment variables: +# $FRAMEWORK The framework name +# $BASEDIR The absolute directory path of this script +# $DATA_COMMON The absolute directory for common DATA scripts +# $DATA_LEAKAGE_MODELS The absolute directory for DATA leakage models +# +# Available for cb_genkey, cb_pre_run, cb_run_command, cb_post_run +# $ALGO The currently tested algo +# +# Available for cb_pre_run, cb_run_command, cb_post_run +# $ENVFILE + +export BINARY=${PWD}/bin/kyber + +# The leakage model of phase 3. +# See ${DATA_LEAKAGE_MODELS} for all options. +export SPECIFIC_LEAKAGE_CALLBACK=${DATA_LEAKAGE_MODELS}/rsa_privkey_hw.py + +# DATA callback for setting up the framework to analyze. This callback +# is invoked once inside the current directory before analysis starts. +# Implement framework-specific tasks here like framework compilation. +function cb_prepare_framework { + : +} + +# DATA callback for generating keys. This callback is invoked every +# time a new key is needed. Implement key generation according to +# your algorithm and store the generated key inside a file named $2. +# +# $1 ... key file name +function cb_genkey { + ${BINARY} ${ALGO} keygen $1 + RES=$((RES + $?)) +} + +# DATA callback for custom commands that are executed immediately before +# the algorithm is profiled. It is executed in a temporary directory +# which contains the keyfile $1 and ${ENVFILE}. +# +# If 'cb_run_command' needs any other files, copy them to ${PWD}. +# +# $1 ... key file name +function cb_pre_run { + log_verbose "running with key $1" +} + +# DATA callback for the main invocation of the tested algorithm. +# It shall return the bash command to execute as string. It is +# executed inside a temporary directory with a clean environment. +# If you need special files or environment variables set, specify +# them in cb_pre_run. +# +# $1 ... key file name +function cb_run_command { + echo "${BINARY} ${ALGO} kem $1" +} + +# DATA callback for custom commands that are executed immediately after +# the algorithm is profiled. It is executed in a temporary directory. +# You can cleanup any custom files generated by your algorithm. +# +# $1 ... key file name +function cb_post_run { + : +} + +# DATA callback for preparing an individual algorithm. It shall: +# 1. Parse the next algorithm from the commandline string of all algorithms +# and set up anything necessary for analyzing this algorithm. +# If the algorithm needs additional parameters (like key sizes), +# increase $SHIFT accordingly. +# 2. Configure $WORKDIR, which will create a subdirectory holding all +# intermediate files generated by the algorithm and the results. +# Do not use an absolute path! +# +# $* ... algorithm string from the commandline +function cb_prepare_algo { + ALGO=$1 + # key bits + SHIFT=$((SHIFT)) + + WORKDIR="kyber-$ALGO" +} + +######################################################################### +# DO NOT CHANGE: Running DATA's commandline parser +#------------------------------------------------------------------------ +DATA_parse "$@" +#------------------------------------------------------------------------ +# DO NOT ADD CODE AFTER THIS LINE +######################################################################### diff --git a/cryptolib/botan/algo_kyber/kyber.cpp b/cryptolib/botan/algo_kyber/kyber.cpp new file mode 100644 index 0000000..bb30566 --- /dev/null +++ b/cryptolib/botan/algo_kyber/kyber.cpp @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +#include +#include +#include +#include + +vector modes = { + "512", + "512-90s", + "768", + "768-90s", + "1024", + "1024-90s" +}; + +vector operations = { + "keygen", + "kem" +}; + +const size_t shared_secret_length = 32; + +Botan::KyberMode name_to_mode(const std::string& algo_name) { + if(algo_name == "Kyber-512") + { return Botan::KyberMode::Kyber512; } + if(algo_name == "Kyber-512-90s") + { return Botan::KyberMode::Kyber512_90s; } + if(algo_name == "Kyber-768") + { return Botan::KyberMode::Kyber768; } + if(algo_name == "Kyber-768-90s") + { return Botan::KyberMode::Kyber768_90s; } + if(algo_name == "Kyber-1024") + { return Botan::KyberMode::Kyber1024; } + if(algo_name == "Kyber-1024-90s") + { return Botan::KyberMode::Kyber1024_90s; } + + assert(false); +} + +void kyber_kem_encrypt( + Botan::Kyber_PublicKey pub_key, + Botan::secure_vector &cipher_text, + Botan::secure_vector &sym_key + ) { + Botan::AutoSeeded_RNG rng; + auto encryptor = Botan::PK_KEM_Encryptor(pub_key, rng, "HKDF(SHA-256)", ""); + encryptor.encrypt(cipher_text, sym_key, shared_secret_length, rng); +} + +void kyber_kem_decrypt( + Botan::Kyber_PrivateKey priv_key, + Botan::secure_vector &cipher_text, + Botan::secure_vector &sym_key + ) { + Botan::AutoSeeded_RNG rng; + auto decryptor = Botan::PK_KEM_Decryptor(priv_key, rng, "HKDF(SHA-256)", ""); + sym_key = decryptor.decrypt(cipher_text.data(), cipher_text.size(), shared_secret_length); +} + +int main(int argc, char* argv[]) { + Botan::AutoSeeded_RNG rng; + + if (argc != 4) { + cout << "Usage:\n\n" + << " kyber \n\n" + << " ..... asymmetric cipher mode\n" + << " ..... operation to execute, e.g. keygen or kem\n" + << " ... kyber key file, read as text\n" + // << " ..... symmetric key file, read as text\n" + << endl; + cout << "List of available modes:" << endl; + for(vector::size_type i = 0; i != modes.size(); i++) { + cout << " " << modes[i] << endl; + } + cout << endl; + cout << "List of available operations:" << endl; + for(vector::size_type i = 0; i != operations.size(); i++) { + cout << " " << operations[i] << endl; + } + cout << endl; + return (1); + } + + string str_mode (argv[1]); + string str_operation (argv[2]); + string str_kyberkeyfile (argv[3]); + + std::string mode_buffer("Kyber-"); + mode_buffer.append(str_mode); + Botan::KyberMode mode = name_to_mode(mode_buffer); + + std::string kyberkeyfile_buffer_sk(str_kyberkeyfile); + + if (str_operation == "keygen") { + // Alice KeyGen + const Botan::Kyber_PrivateKey priv_key(rng, mode); + const auto priv_key_bits = priv_key.private_key_bits(); + + // Store key pair + ofstream kyberkeyfile_sk; + kyberkeyfile_sk.open(kyberkeyfile_buffer_sk); + kyberkeyfile_sk << Botan::hex_encode(priv_key_bits); + kyberkeyfile_sk.close(); + } else if (str_operation == "kem") { + Botan::secure_vector cipher_text, key_bob, key_alice; + + // Load key pair + string line_sk; + ifstream kyberkeyfile_sk; + kyberkeyfile_sk.open(kyberkeyfile_buffer_sk); + getline(kyberkeyfile_sk, line_sk); + kyberkeyfile_sk.close(); + Botan::secure_vector priv_key_bits = Botan::hex_decode_locked(line_sk); + + Botan::Kyber_PrivateKey priv_key(priv_key_bits, mode, Botan::KyberKeyEncoding::Full); + const auto pk = priv_key.public_key(); + const auto pk_bits = pk->public_key_bits(); + Botan::Kyber_PublicKey pub_key(pk_bits, mode, Botan::KyberKeyEncoding::Full); + + kyber_kem_encrypt(pub_key, cipher_text, key_bob); + kyber_kem_decrypt(priv_key, cipher_text, key_alice); + + assert(key_bob == key_alice); + } else { + cout << str_operation << " is no valid operation!" << endl; + assert(false); + } + + return (0); +} +