summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/galois.c95
1 files changed, 79 insertions, 16 deletions
diff --git a/src/galois.c b/src/galois.c
index 3c76c99..2660044 100644
--- a/src/galois.c
+++ b/src/galois.c
@@ -93,6 +93,42 @@ static const t_v_tables* make_v_tables(const uint8_t y[16])
}
/**
+ * Multiply to elements of GF(2**128) using the reducing polynomial
+ * (x^128 + x^7 + x^2 + x + 1).
+ */
+static void gcm_mult(uint8_t out[16], const uint8_t x[16], const uint8_t y[16])
+{
+ uint64_t z[2], v[2];
+ int i;
+
+ /** z, v = 0, y **/
+ z[0] = z[1] = 0;
+ v[0] = be_to_word(&y[0]);
+ v[1] = be_to_word(&y[8]);
+
+ for (i=0; i<16; i++) {
+ uint8_t j;
+
+ for (j=0x80; j>0; j>>=1) {
+ uint64_t c;
+
+ /** z ^= (x>>i&1)*v **/
+ if (x[i] & j) {
+
+ z[0] ^= v[0];
+ z[1] ^= v[1];
+ }
+ /** v = (v&1)*0xE1000000000000000000000000000000L ^ (v>>1) **/
+ c = v[1]&1 ? 0xE100000000000000 : 0;
+ v[1] = v[1]>>1 | (v[0] << 63);
+ v[0] = v[0]>>1 ^ c;
+ }
+ }
+ word_to_be(out, z[0]);
+ word_to_be(out+8, z[1]);
+}
+
+/**
* Multiply two elements of GF(2**128) using the reducing polynomial
* (x^128 + x^7 + x^2 + x + 1).
*
@@ -177,31 +213,58 @@ static int ghash_expand(t_key_tables *key_tables, const uint8_t h[16])
* Compute the GHASH of a piece of an arbitrary data given an
* arbitrary Y_0, as specified in NIST SP 800 38D.
*
- * \param y_out The resulting GHASH (16 bytes).
- * \param block_data Pointer to the data to hash.
- * \param len Length of the data to hash (multiple of 16).
- * \param y_in The initial Y (Y_0, 16 bytes).
- * \param key_tables The expanded hash key (16*256*16 bytes).
+ * \param y_out The resulting GHASH (16 bytes).
+ * \param block_data Pointer to the data to hash.
+ * \param len Length of the data to hash (multiple of 16).
+ * \param y_in The initial Y (Y_0, 16 bytes).
+ * \param key_tables The hash key, possibly expanded to 16*256*16 bytes.
+ * \param key_tables_len The length of the data pointed by key_table.
*/
static void ghash(
uint8_t y_out[16],
const uint8_t block_data[],
int len,
const uint8_t y_in[16],
- const t_key_tables *key_tables
+ const void *key_tables,
+ int key_tables_len
)
{
- int i;
+ int i, j;
+ uint8_t x[16];
+ const t_key_tables *key_tables_64 = NULL;
+ const uint8_t (*key)[16] = NULL;
+
+ switch (key_tables_len) {
+ case sizeof(t_key_tables):
+ {
+ key_tables_64 = (const t_key_tables*) key_tables;
+ break;
+ }
+ case 16:
+ {
+ key = (const uint8_t (*)[16]) key_tables;
+ break;
+ }
+ default:
+ return;
+ }
memcpy(y_out, y_in, 16);
- for (i=0; i<len; i+=16) {
- int j;
- uint8_t x[16];
- for (j=0; j<16; j++) {
- x[j] = y_out[j] ^ block_data[i+j];
+ if (key_tables_64) {
+ for (i=0; i<len; i+=16) {
+ for (j=0; j<16; j++) {
+ x[j] = y_out[j] ^ block_data[i+j];
+ }
+ gcm_mult2(y_out, key_tables_64, x);
+ }
+ } else {
+ for (i=0; i<len; i+=16) {
+ for (j=0; j<16; j++) {
+ x[j] = y_out[j] ^ block_data[i+j];
+ }
+ gcm_mult(y_out, *key, x);
}
- gcm_mult2(y_out, key_tables, x);
}
}
@@ -284,8 +347,8 @@ ghash_function(PyObject *self, PyObject *args)
goto out;
}
- if (len_exp_h!=sizeof(t_key_tables)) {
- PyErr_SetString(PyExc_ValueError, "Length of expanded h is incorrect.");
+ if (len_exp_h!=sizeof(t_key_tables) && len_exp_h!=16) {
+ PyErr_SetString(PyExc_ValueError, "Length of expanded key is incorrect.");
goto out;
}
@@ -301,7 +364,7 @@ ghash_function(PyObject *self, PyObject *args)
ghash( PyBytes_Buffer(retval), PyBytes_Buffer(data), len_data,
PyBytes_Buffer(y),
- (const t_key_tables*)PyBytes_AS_STRING(exp_h));
+ PyBytes_Buffer(exp_h), len_exp_h );
#undef PyBytes_Buffer