Files
ternfs-XTXMarkets/cpp/core/Crypto.cpp
Francesco Mazzoli 85889266b1 Various housekeeping while I get ready to deploy...
...most notably we now produce fully static binaries in an alpine
image.

A few assorted thoughts:

* I really like static binaries, ideally I'd like to run EggsFS
    deployments with just systemd scripts and a few binaries.

* Go already does this, which is great.

* C++ does not, which is less great.

* Linking statically against `glibc` works, but is unsupported.
    Not only stuff like NSS (which `gethostbyname` requires)
    straight up does not work, unless you build `glibc` with
    unsupported and currently apparently broken flags
    (`--enable-static-nss`), but also other stuff is subtly
    broken (I couldn't remember exactly what was broken,
    but see comments such as
    <https://github.com/haskell/haskell-language-server/issues/2431#issuecomment-985880838>).

* So we're left with alternative libcs -- the most popular being
    musl.

* The simplest way to build a C++ application using musl is to just
    build on a system where musl is already the default libc -- such
    as alpine linux.

The backtrace support is in a bit of a bad state. Exception stacktraces
work on musl, but DWARF seems to be broken on the normal release build.

Moreover, libunwind doesn't play well with musl's signal handler:
<https://maskray.me/blog/2022-04-10-unwinding-through-signal-handler>.

Keeping it working seems to be a bit of a chore, and I'm going to revisit
it later.

In the meantime, gdb stack traces do work fine.
2023-01-29 21:41:40 +00:00

113 lines
3.8 KiB
C++

// Code from
// <https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf>.
#include <emmintrin.h>
#include <wmmintrin.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/random.h>
#include "Crypto.hpp"
#include "Exception.hpp"
void generateSecretKey(std::array<uint8_t, 16>& key) {
ssize_t read = getrandom(key.data(), key.size(), 0);
if (read < 0) {
throw SYSCALL_EXCEPTION("getrandom");
}
if (read != key.size()) {
// getrandom(2) states that once initialized you can always get up to 256 bytes.
throw EGGS_EXCEPTION("could not read %s random bytes, read %s instead!", key.size(), read);
}
}
inline __m128i AES_128_ASSIST(__m128i temp1, __m128i temp2) {
__m128i temp3;
temp2 = _mm_shuffle_epi32(temp2 ,0xff);
temp3 = _mm_slli_si128(temp1, 0x4);
temp1 = _mm_xor_si128(temp1, temp3);
temp3 = _mm_slli_si128(temp3, 0x4);
temp1 = _mm_xor_si128(temp1, temp3);
temp3 = _mm_slli_si128(temp3, 0x4);
temp1 = _mm_xor_si128(temp1, temp3);
temp1 = _mm_xor_si128(temp1, temp2);
return temp1;
}
void expandKey(const std::array<uint8_t, 16>& userkey, AES128Key& key) {
__m128i temp1, temp2;
__m128i *Key_Schedule = (__m128i*)&key;
temp1 = _mm_loadu_si128((__m128i*)userkey.data());
Key_Schedule[0] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x1);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[1] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x2);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[2] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x4);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[3] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x8);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[4] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x10);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[5] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x20);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[6] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x40);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[7] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x80);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[8] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x1b);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[9] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x36);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[10] = temp1;
}
std::array<uint8_t, 8> cbcmac(const AES128Key& key, const uint8_t* data, size_t len) {
// load key
__m128i xmmKey[11];
for (int i = 0; i < 11; i++) {
xmmKey[i] = _mm_load_si128((__m128i*)(&key) + i);
}
// CBC MAC step
__m128i block = _mm_setzero_si128();
__m128i dataBlock;
auto step = [&xmmKey, &block, &dataBlock]() {
// CBC xor
block = _mm_xor_si128(block, dataBlock);
// encrypt
block = _mm_xor_si128(block, xmmKey[0]); // Whitening step (Round 0)
for (int i = 1; i < 10; i++) {
block = _mm_aesenc_si128(block, xmmKey[i]); // Round i
}
block = _mm_aesenclast_si128(block, xmmKey[10]); // Round 10
};
// unpadded load
size_t i = 0;
for (; len-i >= 16; i += 16) {
dataBlock = _mm_loadu_si128((__m128i*)(data+i));
step();
}
// zero-padded load
ALIGNED(16) uint8_t scratch[16];
if (len-i > 0) {
memset(scratch, 0, 16);
memcpy(scratch, data+i, len-i);
dataBlock = _mm_load_si128((__m128i*)scratch);
step();
}
// extract MAC
_mm_store_si128((__m128i*)scratch, block);
std::array<uint8_t, 8> mac;
memcpy(mac.data(), scratch, 8);
return mac;
}