Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/aesgcm-sw.c')
-rw-r--r--crypto/aesgcm-sw.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/crypto/aesgcm-sw.c b/crypto/aesgcm-sw.c
new file mode 100644
index 00000000..f322ae30
--- /dev/null
+++ b/crypto/aesgcm-sw.c
@@ -0,0 +1,145 @@
+/*
+ * Implementation of the GCM polynomial hash in pure software.
+ *
+ * I don't know of a faster way to do this in a side-channel safe
+ * manner than by precomputing a giant table and iterating over the
+ * whole thing.
+ *
+ * The original GCM reference suggests that you precompute the effects
+ * of multiplying a 128-bit value by the fixed key, in the form of a
+ * table indexed by some number of bits of the input value, so that
+ * you end up computing something of the form
+ *
+ * table1[x & 0xFF] ^ table2[(x>>8) & 0xFF] ^ ... ^ table15[(x>>120) & 0xFF]
+ *
+ * But that was obviously written before cache and timing leaks were
+ * known about. What's a time-safe approach?
+ *
+ * Well, the above technique isn't fixed to 8 bits of input per table.
+ * You could trade off the number of tables against the size of each
+ * table. At one extreme of this tradeoff, you have 128 tables each
+ * indexed by a single input bit - which is to say, you have 128
+ * values, each 128 bits wide, and you XOR together the subset of
+ * those values corresponding to the input bits, which you can do by
+ * making a bitmask out of each input bit using standard constant-
+ * time-coding bit twiddling techniques.
+ *
+ * That's pretty unpleasant when GCM is supposed to be a fast
+ * algorithm, but I don't know of a better approach that meets current
+ * security standards! Suggestions welcome, if they can get through
+ * testsc.
+ */
+
+#include "ssh.h"
+#include "aesgcm.h"
+
+/*
+ * Store a 128-bit value in the most convenient form standard C will
+ * let us, namely two uint64_t giving its most and least significant
+ * halves.
+ */
+typedef struct {
+ uint64_t hi, lo;
+} value128_t;
+
+typedef struct aesgcm_sw {
+ AESGCM_COMMON_FIELDS;
+
+ /* Accumulator for the current evaluation, and mask that will be
+ * XORed in at the end. High */
+ value128_t acc, mask;
+
+ /*
+ * Table of values to XOR in for each bit, representing the effect
+ * of multiplying by the fixed key. The key itself doesn't need to
+ * be stored separately, because it's never used. (However, it is
+ * also the first entry in the table, so if you _do_ need it,
+ * there it is.)
+ *
+ * Table is indexed from the low bit of the input upwards.
+ */
+ value128_t table[128];
+} aesgcm_sw;
+
+static bool aesgcm_sw_available(void)
+{
+ return true; /* pure software implementation, always available */
+}
+
+static void aesgcm_sw_setkey_impl(aesgcm_sw *gcm, const unsigned char *var)
+{
+ value128_t v;
+ v.hi = GET_64BIT_MSB_FIRST(var);
+ v.lo = GET_64BIT_MSB_FIRST(var + 8);
+
+ /*
+ * Prepare the table. This has to be done in reverse order, so
+ * that the original value of the variable corresponds to
+ * table[127], because AES-GCM works in the bit-reversal of its
+ * logical specification so that's where the logical constant term
+ * lives. (See more detailed comment in aesgcm-ref-poly.c.)
+ */
+ for (size_t i = 0; i < 128; i++) {
+ gcm->table[127 - i] = v;
+
+ /* Multiply v by x, which means shifting right (bit reversal
+ * again) and then adding 0xE1 at the top if we shifted a 1 out. */
+ uint64_t lobit = v.lo & 1;
+ v.lo = (v.lo >> 1) ^ (v.hi << 63);
+ v.hi = (v.hi >> 1) ^ (0xE100000000000000ULL & -lobit);
+ }
+}
+
+static inline void aesgcm_sw_setup(aesgcm_sw *gcm, const unsigned char *mask)
+{
+ gcm->mask.hi = GET_64BIT_MSB_FIRST(mask);
+ gcm->mask.lo = GET_64BIT_MSB_FIRST(mask + 8);
+ gcm->acc.hi = gcm->acc.lo = 0;
+}
+
+static inline void aesgcm_sw_coeff(aesgcm_sw *gcm, const unsigned char *coeff)
+{
+ /* XOR in the new coefficient */
+ gcm->acc.hi ^= GET_64BIT_MSB_FIRST(coeff);
+ gcm->acc.lo ^= GET_64BIT_MSB_FIRST(coeff + 8);
+
+ /* And now just loop over the bits of acc, making up a new value
+ * by XORing together the entries of 'table' corresponding to set
+ * bits. */
+
+ value128_t out;
+ out.lo = out.hi = 0;
+
+ const value128_t *tableptr = gcm->table;
+
+ for (size_t i = 0; i < 64; i++) {
+ uint64_t bit = 1 & gcm->acc.lo;
+ gcm->acc.lo >>= 1;
+ uint64_t mask = -bit;
+ out.hi ^= mask & tableptr->hi;
+ out.lo ^= mask & tableptr->lo;
+ tableptr++;
+ }
+ for (size_t i = 0; i < 64; i++) {
+ uint64_t bit = 1 & gcm->acc.hi;
+ gcm->acc.hi >>= 1;
+ uint64_t mask = -bit;
+ out.hi ^= mask & tableptr->hi;
+ out.lo ^= mask & tableptr->lo;
+ tableptr++;
+ }
+
+ gcm->acc = out;
+}
+
+static inline void aesgcm_sw_output(aesgcm_sw *gcm, unsigned char *output)
+{
+ PUT_64BIT_MSB_FIRST(output, gcm->acc.hi ^ gcm->mask.hi);
+ PUT_64BIT_MSB_FIRST(output + 8, gcm->acc.lo ^ gcm->mask.lo);
+ smemclr(&gcm->acc, 16);
+ smemclr(&gcm->mask, 16);
+}
+
+#define AESGCM_FLAVOUR sw
+#define AESGCM_NAME "unaccelerated"
+#include "aesgcm-footer.h"