summaryrefslogtreecommitdiff
path: root/cipher
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2019-03-28 23:25:52 +0200
committerJussi Kivilinna <jussi.kivilinna@iki.fi>2019-03-28 23:59:47 +0200
commitefd700e31dc8e1e386d367d1b682000977e0c810 (patch)
tree79620940c21aa3d9eca4baacf991cf9119c063cb /cipher
parenteacbd59b1333b95858886999c8049e04bf72ad74 (diff)
downloadlibgcrypt-efd700e31dc8e1e386d367d1b682000977e0c810.tar.gz
Optimize OCB set_key and set_nonce
* cipher/cipher-ocb.c (double_block): Change to input/output host-endian block instead of big-endian buffer. (double_block_cpy): Remove. (bit_copy): Use fixed length copy and 'u64' for calculations. (ocb_get_L_big): Handle block endian conversions for double_block. (_gcry_cipher_ocb_setkey): Handle block endian conversions for double_block. (_gcry_cipher_ocb_set_nonce): Set full length of 'ktop' to zero; Drop length parameter for bit_copy. -- Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Diffstat (limited to 'cipher')
-rw-r--r--cipher/cipher-ocb.c91
1 files changed, 42 insertions, 49 deletions
diff --git a/cipher/cipher-ocb.c b/cipher/cipher-ocb.c
index f1c94db0..b146d058 100644
--- a/cipher/cipher-ocb.c
+++ b/cipher/cipher-ocb.c
@@ -48,64 +48,40 @@
/* Double the OCB_BLOCK_LEN sized block B in-place. */
static inline void
-double_block (unsigned char *b)
+double_block (u64 b[2])
{
-#if OCB_BLOCK_LEN != 16
- unsigned char b_0 = b[0];
- int i;
-
- for (i=0; i < OCB_BLOCK_LEN - 1; i++)
- b[i] = (b[i] << 1) | (b[i+1] >> 7);
-
- b[OCB_BLOCK_LEN-1] = (b[OCB_BLOCK_LEN-1] << 1) ^ ((b_0 >> 7) * 135);
-#else
- /* This is the generic code for 16 byte blocks. However it is not
- faster than the straight byte by byte implementation. */
u64 l_0, l, r;
- l = buf_get_be64 (b);
- r = buf_get_be64 (b + 8);
+ l = b[1];
+ r = b[0];
l_0 = -(l >> 63);
l = (l + l) ^ (r >> 63);
r = (r + r) ^ (l_0 & 135);
- buf_put_be64 (b, l);
- buf_put_be64 (b+8, r);
-#endif
-}
-
-
-/* Double the OCB_BLOCK_LEN sized block S and store it at D. S and D
- may point to the same memory location but they may not overlap. */
-static void
-double_block_cpy (unsigned char *d, const unsigned char *s)
-{
- if (d != s)
- cipher_block_cpy (d, s, OCB_BLOCK_LEN);
- double_block (d);
+ b[1] = l;
+ b[0] = r;
}
-/* Copy NBYTES from buffer S starting at bit offset BITOFF to buffer D. */
+/* Copy OCB_BLOCK_LEN from buffer S starting at bit offset BITOFF to
+ * buffer D. */
static void
-bit_copy (unsigned char *d, const unsigned char *s,
- unsigned int bitoff, unsigned int nbytes)
+bit_copy (unsigned char *d, const unsigned char *s, unsigned int bitoff)
{
+ u64 s0l, s1l, s1r, s2r;
unsigned int shift;
s += bitoff / 8;
shift = bitoff % 8;
- if (shift)
- {
- for (; nbytes; nbytes--, d++, s++)
- *d = (s[0] << shift) | (s[1] >> (8 - shift));
- }
- else
- {
- for (; nbytes; nbytes--, d++, s++)
- *d = *s;
- }
+
+ s0l = buf_get_be64 (s + 0);
+ s1l = buf_get_be64 (s + 8);
+ s1r = shift ? s1l : 0;
+ s2r = shift ? buf_get_be64 (s + 16) : 0;
+
+ buf_put_be64 (d + 0, (s0l << shift) | (s1r >> ((64 - shift) & 63)));
+ buf_put_be64 (d + 8, (s1l << shift) | (s2r >> ((64 - shift) & 63)));
}
@@ -114,12 +90,18 @@ static void
ocb_get_L_big (gcry_cipher_hd_t c, u64 n, unsigned char *l_buf)
{
int ntz = _gcry_ctz64 (n);
+ u64 L[2];
gcry_assert(ntz >= OCB_L_TABLE_SIZE);
- double_block_cpy (l_buf, c->u_mode.ocb.L[OCB_L_TABLE_SIZE - 1]);
- for (ntz -= OCB_L_TABLE_SIZE; ntz; ntz--)
- double_block (l_buf);
+ L[1] = buf_get_be64 (c->u_mode.ocb.L[OCB_L_TABLE_SIZE - 1]);
+ L[0] = buf_get_be64 (c->u_mode.ocb.L[OCB_L_TABLE_SIZE - 1] + 8);
+
+ for (ntz -= OCB_L_TABLE_SIZE - 1; ntz; ntz--)
+ double_block (L);
+
+ buf_put_be64 (l_buf + 0, L[1]);
+ buf_put_be64 (l_buf + 8, L[0]);
}
@@ -129,6 +111,7 @@ void _gcry_cipher_ocb_setkey (gcry_cipher_hd_t c)
unsigned char ktop[OCB_BLOCK_LEN];
unsigned int burn = 0;
unsigned int nburn;
+ u64 L[2];
int i;
/* L_star = E(zero_128) */
@@ -136,11 +119,21 @@ void _gcry_cipher_ocb_setkey (gcry_cipher_hd_t c)
nburn = c->spec->encrypt (&c->context.c, c->u_mode.ocb.L_star, ktop);
burn = nburn > burn ? nburn : burn;
/* L_dollar = double(L_star) */
- double_block_cpy (c->u_mode.ocb.L_dollar, c->u_mode.ocb.L_star);
+ L[1] = buf_get_be64 (c->u_mode.ocb.L_star);
+ L[0] = buf_get_be64 (c->u_mode.ocb.L_star + 8);
+ double_block (L);
+ buf_put_be64 (c->u_mode.ocb.L_dollar + 0, L[1]);
+ buf_put_be64 (c->u_mode.ocb.L_dollar + 8, L[0]);
/* L_0 = double(L_dollar), ... */
- double_block_cpy (c->u_mode.ocb.L[0], c->u_mode.ocb.L_dollar);
+ double_block (L);
+ buf_put_be64 (c->u_mode.ocb.L[0] + 0, L[1]);
+ buf_put_be64 (c->u_mode.ocb.L[0] + 8, L[0]);
for (i = 1; i < OCB_L_TABLE_SIZE; i++)
- double_block_cpy (c->u_mode.ocb.L[i], c->u_mode.ocb.L[i-1]);
+ {
+ double_block (L);
+ buf_put_be64 (c->u_mode.ocb.L[i] + 0, L[1]);
+ buf_put_be64 (c->u_mode.ocb.L[i] + 8, L[0]);
+ }
/* Precalculated offset L0+L1 */
cipher_block_xor (c->u_mode.ocb.L0L1,
c->u_mode.ocb.L[0], c->u_mode.ocb.L[1], OCB_BLOCK_LEN);
@@ -188,7 +181,7 @@ _gcry_cipher_ocb_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce,
return GPG_ERR_INV_LENGTH;
/* Prepare the nonce. */
- memset (ktop, 0, (OCB_BLOCK_LEN - noncelen));
+ memset (ktop, 0, OCB_BLOCK_LEN);
buf_cpy (ktop + (OCB_BLOCK_LEN - noncelen), nonce, noncelen);
ktop[0] = ((c->u_mode.ocb.taglen * 8) % 128) << 1;
ktop[OCB_BLOCK_LEN - noncelen - 1] |= 1;
@@ -201,7 +194,7 @@ _gcry_cipher_ocb_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce,
cipher_block_xor (stretch + OCB_BLOCK_LEN, ktop, ktop + 1, 8);
/* Offset_0 = Stretch[1+bottom..128+bottom]
(We use the IV field to store the offset) */
- bit_copy (c->u_iv.iv, stretch, bottom, OCB_BLOCK_LEN);
+ bit_copy (c->u_iv.iv, stretch, bottom);
c->marks.iv = 1;
/* Checksum_0 = zeros(128)