* ====================================================================
*/
+#include <openssl/crypto.h>
#include "modes_lcl.h"
#include <string.h>
/*
* Extra 256+16 bytes per-key plus 512 bytes shared tables
* [should] give ~50% improvement... One could have PACK()-ed
- * the rem_8bit even here, but priority is to minimize memory
- * usage...
+ * the rem_8bit even here, but the priority is to minimize
+ * cache footprint...
*/
u128 Hshr4[16]; /* Htable shifted right by 4 bits */
u8 Hshl4[16]; /* Htable shifted left by 4 bits */
0xA7D0, 0xA612, 0xA454, 0xA596, 0xA0D8, 0xA11A, 0xA35C, 0xA29E,
0xB5E0, 0xB422, 0xB664, 0xB7A6, 0xB2E8, 0xB32A, 0xB16C, 0xB0AE,
0xBBF0, 0xBA32, 0xB874, 0xB9B6, 0xBCF8, 0xBD3A, 0xBF7C, 0xBEBE };
-
/*
* This pre-processing phase slows down procedure by approximately
* same time as it makes each loop spin faster. In other words
}
do {
- nlo = ((const u8 *)Xi)[15];
- nlo ^= inp[15];
- nhi = nlo>>4;
- nlo &= 0xf;
-
- Z.hi = Htable[nlo].hi;
- Z.lo = Htable[nlo].lo;
-
- rem = (size_t)Z.lo&0xff;
-
- Z.lo = (Z.hi<<56)|(Z.lo>>8);
- Z.hi = (Z.hi>>8);
-
- Z.hi ^= Hshr4[nhi].hi;
- Z.lo ^= Hshr4[nhi].lo;
- Z.hi ^= (u64)rem_8bit[rem^Hshl4[nhi]]<<48;
-
- for (cnt=14; cnt>0; --cnt) {
+ for (Z.lo=0, Z.hi=0, cnt=15; cnt; --cnt) {
nlo = ((const u8 *)Xi)[cnt];
nlo ^= inp[cnt];
nhi = nlo>>4;
#if TABLE_BITS==8
gcm_init_8bit(ctx->Htable,ctx->H.u);
#elif TABLE_BITS==4
-# if defined(GHASH_ASM_IAX)
+# if defined(GHASH_ASM_IAX) /* both x86 and x86_64 */
if (OPENSSL_ia32cap_P[1]&(1<<1)) {
gcm_init_clmul(ctx->Htable,ctx->H.u);
ctx->gmult = gcm_gmult_clmul;
return;
}
gcm_init_4bit(ctx->Htable,ctx->H.u);
-# if defined(GHASH_ASM_X86)
+# if defined(GHASH_ASM_X86) /* x86 only */
if (OPENSSL_ia32cap_P[0]&(1<<23)) {
ctx->gmult = gcm_gmult_4bit_mmx;
ctx->ghash = gcm_ghash_4bit_mmx;
ctx->res = n;
}
-void CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx)
+void CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx,
+ const unsigned char *in, unsigned char *out,
+ size_t len, ctr128_f stream)
+{
+ const union { long one; char little; } is_endian = {1};
+ unsigned int n, ctr;
+ size_t i;
+
+ ctx->len.u[1] += len;
+ n = ctx->res;
+ if (is_endian.little)
+ ctr = GETU32(ctx->Yi.c+12);
+ else
+ ctr = ctx->Yi.d[3];
+
+ if (n) {
+ while (n && len) {
+ ctx->Xi.c[n] ^= *(out++) = *(in++)^ctx->EKi.c[n];
+ --len;
+ n = (n+1)%16;
+ }
+ if (n==0) GCM_MUL(ctx,Xi);
+ else {
+ ctx->res = n;
+ return;
+ }
+ }
+#if defined(GHASH) && !defined(OPENSSL_SMALL_FOOTPRINT)
+ while (len>=GHASH_CHUNK) {
+ (*stream)(in,out,GHASH_CHUNK/16,ctx->key,ctx->Yi.c);
+ ctr += GHASH_CHUNK/16;
+ if (is_endian.little)
+ PUTU32(ctx->Yi.c+12,ctr);
+ else
+ ctx->Yi.d[3] = ctr;
+ GHASH(ctx,out,GHASH_CHUNK);
+ out += GHASH_CHUNK;
+ in += GHASH_CHUNK;
+ len -= GHASH_CHUNK;
+ }
+#endif
+ if ((i = (len&(size_t)-16))) {
+ size_t j=i/16;
+
+ (*stream)(in,out,j,ctx->key,ctx->Yi.c);
+ ctr += j;
+ if (is_endian.little)
+ PUTU32(ctx->Yi.c+12,ctr);
+ else
+ ctx->Yi.d[3] = ctr;
+ in += i;
+ len -= i;
+#if defined(GHASH)
+ GHASH(ctx,out,i);
+ out += i;
+#else
+ while (j--) {
+ for (i=0;i<16;++i) ctx->Xi.c[i] ^= out[i];
+ GCM_MUL(ctx,Xi);
+ out += 16;
+ }
+#endif
+ }
+ if (len) {
+ (*ctx->block)(ctx->Yi.c,ctx->EKi.c,ctx->key);
+ ++ctr;
+ if (is_endian.little)
+ PUTU32(ctx->Yi.c+12,ctr);
+ else
+ ctx->Yi.d[3] = ctr;
+ while (len--) {
+ ctx->Xi.c[n] ^= out[n] = in[n]^ctx->EKi.c[n];
+ ++n;
+ }
+ }
+
+ ctx->res = n;
+}
+
+void CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx,
+ const unsigned char *in, unsigned char *out,
+ size_t len,ctr128_f stream)
+{
+ const union { long one; char little; } is_endian = {1};
+ unsigned int n, ctr;
+ size_t i;
+
+ ctx->len.u[1] += len;
+ n = ctx->res;
+ if (is_endian.little)
+ ctr = GETU32(ctx->Yi.c+12);
+ else
+ ctr = ctx->Yi.d[3];
+
+ if (n) {
+ while (n && len) {
+ u8 c = *(in++);
+ *(out++) = c^ctx->EKi.c[n];
+ ctx->Xi.c[n] ^= c;
+ --len;
+ n = (n+1)%16;
+ }
+ if (n==0) GCM_MUL (ctx,Xi);
+ else {
+ ctx->res = n;
+ return;
+ }
+ }
+#if defined(GHASH) && !defined(OPENSSL_SMALL_FOOTPRINT)
+ while (len>=GHASH_CHUNK) {
+ GHASH(ctx,in,GHASH_CHUNK);
+ (*stream)(in,out,GHASH_CHUNK/16,ctx->key,ctx->Yi.c);
+ ctr += GHASH_CHUNK/16;
+ if (is_endian.little)
+ PUTU32(ctx->Yi.c+12,ctr);
+ else
+ ctx->Yi.d[3] = ctr;
+ out += GHASH_CHUNK;
+ in += GHASH_CHUNK;
+ len -= GHASH_CHUNK;
+ }
+#endif
+ if ((i = (len&(size_t)-16))) {
+ size_t j=i/16;
+
+#if defined(GHASH)
+ GHASH(ctx,in,i);
+#else
+ while (j--) {
+ size_t k;
+ for (k=0;k<16;++k) ctx->Xi.c[k] ^= in[k];
+ GCM_MUL(ctx,Xi);
+ in += 16;
+ }
+ j = i/16;
+ in -= i;
+#endif
+ (*stream)(in,out,j,ctx->key,ctx->Yi.c);
+ ctr += j;
+ if (is_endian.little)
+ PUTU32(ctx->Yi.c+12,ctr);
+ else
+ ctx->Yi.d[3] = ctr;
+ out += i;
+ in += i;
+ len -= i;
+ }
+ if (len) {
+ (*ctx->block)(ctx->Yi.c,ctx->EKi.c,ctx->key);
+ ++ctr;
+ if (is_endian.little)
+ PUTU32(ctx->Yi.c+12,ctr);
+ else
+ ctx->Yi.d[3] = ctr;
+ while (len--) {
+ u8 c = in[n];
+ ctx->Xi.c[n] ^= c;
+ out[n] = c^ctx->EKi.c[n];
+ ++n;
+ }
+ }
+
+ ctx->res = n;
+}
+
+int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx,const unsigned char *tag,
+ size_t len)
{
const union { long one; char little; } is_endian = {1};
u64 alen = ctx->len.u[0]<<3;
ctx->Xi.u[0] ^= ctx->EK0.u[0];
ctx->Xi.u[1] ^= ctx->EK0.u[1];
+
+ if (tag && len<=sizeof(ctx->Xi))
+ return memcmp(ctx->Xi.c,tag,len);
+ else
+ return -1;
+}
+
+GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block)
+{
+ GCM128_CONTEXT *ret;
+
+ if ((ret = (GCM128_CONTEXT *)OPENSSL_malloc(sizeof(GCM128_CONTEXT))))
+ CRYPTO_gcm128_init(ret,key,block);
+
+ return ret;
+}
+
+void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx)
+{
+ if (ctx) {
+ OPENSSL_cleanse(ctx,sizeof(*ctx));
+ OPENSSL_free(ctx);
+ }
}
#if defined(SELFTEST)
CRYPTO_gcm128_setiv(&ctx,IV##n,sizeof(IV##n)); \
if (A##n) CRYPTO_gcm128_aad(&ctx,A##n,sizeof(A##n)); \
if (P##n) CRYPTO_gcm128_encrypt(&ctx,P##n,out,sizeof(out)); \
- CRYPTO_gcm128_finish(&ctx); \
- if (memcmp(ctx.Xi.c,T##n,16) || (C##n && memcmp(out,C##n,sizeof(out)))) \
+ if (CRYPTO_gcm128_finish(&ctx,T##n,16) || \
+ (C##n && memcmp(out,C##n,sizeof(out)))) \
ret++, printf ("encrypt test#%d failed.\n",n);\
CRYPTO_gcm128_setiv(&ctx,IV##n,sizeof(IV##n)); \
if (A##n) CRYPTO_gcm128_aad(&ctx,A##n,sizeof(A##n)); \
if (C##n) CRYPTO_gcm128_decrypt(&ctx,C##n,out,sizeof(out)); \
- CRYPTO_gcm128_finish(&ctx); \
- if (memcmp(ctx.Xi.c,T##n,16) || (P##n && memcmp(out,P##n,sizeof(out)))) \
- ret++, printf ("decrypt test#%d failed.\n",n);\
+ if (CRYPTO_gcm128_finish(&ctx,T##n,16) || \
+ (P##n && memcmp(out,P##n,sizeof(out)))) \
+ ret++, printf ("decrypt test#%d failed.\n",n); \
} while(0)
int main()