Changeset View
Changeset View
Standalone View
Standalone View
sys/crypto/openssl/ossl_arm.h
Show All 15 Lines | |||||
ossl_cipher_encrypt_t bsaes_cbc_encrypt; | ossl_cipher_encrypt_t bsaes_cbc_encrypt; | ||||
void AES_encrypt(void *, void *, const void *); | void AES_encrypt(void *, void *, const void *); | ||||
static void | static void | ||||
AES_CBC_ENCRYPT(const unsigned char *in, unsigned char *out, | AES_CBC_ENCRYPT(const unsigned char *in, unsigned char *out, | ||||
size_t length, const void *key, unsigned char *iv, int encrypt) | size_t length, const void *key, unsigned char *iv, int encrypt) | ||||
{ | { | ||||
KASSERT(!(length % AES_BLOCK_LEN), "AES_CBC_ENCRYPT: size error"); | KASSERT(!(length % AES_BLOCK_LEN), ("AES_CBC_ENCRYPT: size error")); | ||||
if (encrypt) { | if (encrypt) { | ||||
size_t i; | size_t i; | ||||
for(i = 0; i < length / AES_BLOCK_LEN; i++){ | for(i = 0; i < length / AES_BLOCK_LEN; i++){ | ||||
uint32_t buf[4]; | uint32_t buf[4]; | ||||
int a; | int a; | ||||
/* XOR IV with plaintext */ | /* XOR IV with plaintext */ | ||||
for (a = 0; a < 4; a++) | for (a = 0; a < 4; a++) | ||||
buf[a] = ((const uint32_t *)in)[a] ^ | buf[a] = ((const uint32_t *)in)[a] ^ | ||||
((const uint32_t *)iv)[a]; | ((const uint32_t *)iv)[a]; | ||||
AES_encrypt(buf, out, (const void*)key); | AES_encrypt(buf, out, (const void*)key); | ||||
/* Ciphertext is our new IV */ | /* Ciphertext is our new IV */ | ||||
memcpy(iv, out, 16); | memcpy(iv, out, 16); | ||||
in += AES_BLOCK_LEN; | in += AES_BLOCK_LEN; | ||||
out += AES_BLOCK_LEN; | out += AES_BLOCK_LEN; | ||||
} | } | ||||
} else | } else | ||||
bsaes_cbc_encrypt(in, out, length, key, iv, encrypt); | bsaes_cbc_encrypt(in, out, length, key, iv, encrypt); | ||||
} | } | ||||
#endif | |||||
#define BIT(x) (1ULL << (x)) | |||||
#define IS_LITTLE_ENDIAN BYTE_ORDER == LITTLE_ENDIAN | |||||
#define GETU32(pt) (((uint32_t)(pt)[0] << 24) ^ \ | |||||
((uint32_t)(pt)[1] << 16) ^ \ | |||||
((uint32_t)(pt)[2] << 8) ^ \ | |||||
((uint32_t)(pt)[3])) | |||||
#define PUTU32(ct, st) { \ | |||||
(ct)[0] = (uint8_t)((st) >> 24); \ | |||||
(ct)[1] = (uint8_t)((st) >> 16); \ | |||||
(ct)[2] = (uint8_t)((st) >> 8); \ | |||||
(ct)[3] = (uint8_t)(st); \ | |||||
} | |||||
void gcm_init_neon(uint128_t *Htable, const uint64_t *Xi); | |||||
void gcm_ghash_neon(uint64_t *Xi, const uint128_t *Htable, const uint8_t *inp, size_t len); | |||||
void gcm_gmult_neon(uint64_t *Xi, const uint128_t *Htable); | |||||
void AES_encrypt(void *in, void *out, const void *key); | |||||
static void | |||||
gcm_init(struct ossl_gcm_context *ctx, void *key) | |||||
{ | |||||
memset(ctx, 0, sizeof(*ctx)); | |||||
ctx->key = key; | |||||
/* encrypt 0^128 => const value H */ | |||||
AES_encrypt(ctx->H.c, ctx->H.c, (const void*)key); | |||||
if (IS_LITTLE_ENDIAN) { | |||||
uint8_t *p = ctx->H.c; | |||||
uint64_t hi, lo; | |||||
hi = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); | |||||
lo = (uint64_t)GETU32(p+8) << 32 | GETU32(p + 12); | |||||
ctx->H.u[0] = hi; | |||||
ctx->H.u[1] = lo; | |||||
} | |||||
gcm_init_neon(ctx->Htable, ctx->H.u); | |||||
} | |||||
/* According to NIST recomendation - const IV len (96 bits) */ | |||||
static void | |||||
gcm_setiv(struct ossl_gcm_context *ctx, const unsigned char *iv) | |||||
{ | |||||
uint32_t ctr; | |||||
ctx->len.u[0] = 0; /* AAD length */ | |||||
ctx->len.u[1] = 0; /* Message length */ | |||||
ctx->ares = 0; | |||||
ctx->mres = 0; | |||||
ctx->Xi.u[0] = 0; | |||||
ctx->Xi.u[1] = 0; | |||||
memcpy(ctx->Yi.c, iv, 12); | |||||
memset(&ctx->Yi.c[12], 0, 4); | |||||
ctx->Yi.c[15] = 1; | |||||
ctr = 1; | |||||
/* Encrypt first counter value */ | |||||
AES_encrypt(ctx->Yi.c, ctx->EK0.c, ctx->key); | |||||
++ctr; | |||||
if (IS_LITTLE_ENDIAN) | |||||
PUTU32(ctx->Yi.c + 12, ctr) | |||||
else | |||||
ctx->Yi.d[3] = ctr; | |||||
} | |||||
static int | |||||
gcm_aad(struct ossl_gcm_context *ctx, const unsigned char *aad, size_t len) | |||||
{ | |||||
size_t i; | |||||
uint32_t n; | |||||
uint64_t alen = ctx->len.u[0]; | |||||
if (ctx->len.u[1]) | |||||
return -2; | |||||
alen += len; | |||||
if (alen > BIT(61) || (sizeof(len) == 8 && alen < len)) | |||||
return -1; | |||||
ctx->len.u[0] = alen; | |||||
/* AAD's reserve - buffered data */ | |||||
n = ctx->ares; | |||||
if (n) { | |||||
while (n && len) { | |||||
ctx->Xi.c[n] ^= *(aad++); | |||||
--len; | |||||
n = (n + 1) % 16; | |||||
} | |||||
if (n == 0) | |||||
gcm_gmult_neon(ctx->Xi.u, ctx->Htable); | |||||
else { | |||||
ctx->ares = n; | |||||
return 0; | |||||
} | |||||
} | |||||
if ((i = (len & (size_t) - 16))) { | |||||
gcm_ghash_neon(ctx->Xi.u, ctx->Htable, aad, i); | |||||
aad += i; | |||||
len -= i; | |||||
} | |||||
if (len) { | |||||
n = (uint32_t)len; | |||||
for (i = 0; i< len; ++i) | |||||
ctx->Xi.c[i] ^= aad[i]; | |||||
} | |||||
ctx->ares = n; | |||||
return 0; | |||||
} | |||||
static int | |||||
gcm_encrypt(struct ossl_gcm_context *ctx, const unsigned char *in, unsigned char *out, size_t len) | |||||
{ | |||||
uint32_t n, ctr, mres; | |||||
size_t i; | |||||
/* Message len */ | |||||
uint64_t mlen = ctx->len.u[1] + len; | |||||
if (mlen > (BIT(36) - 32) || (sizeof(len) == 8 && mlen < len)) | |||||
return -1; | |||||
ctx->len.u[1] = mlen; | |||||
mres = ctx->mres; | |||||
/* Encrypt AAD first - with padding */ | |||||
if (ctx->ares) { | |||||
gcm_gmult_neon(ctx->Xi.u, ctx->Htable); | |||||
ctx->ares = 0; | |||||
} | |||||
/* Get counter value */ | |||||
if (IS_LITTLE_ENDIAN) | |||||
ctr = GETU32(ctx->Yi.c + 12); | |||||
else | |||||
ctr = ctx->Yi.d[3]; | |||||
n = mres % 16; | |||||
/* Encrypt message */ | |||||
for (i = 0; i < len; ++i) { | |||||
if (n == 0) { | |||||
AES_encrypt(ctx->Yi.c, ctx->EKi.c, ctx->key); | |||||
++ctr; | |||||
if (IS_LITTLE_ENDIAN) | |||||
PUTU32(ctx->Yi.c + 12, ctr) | |||||
else | |||||
ctx->Yi.d[3] = ctr; | |||||
} | |||||
/* XOR - ghash */ | |||||
ctx->Xi.c[n] ^= out[i] = in[i] ^ ctx->EKi.c[n]; | |||||
mres = n = (n + 1) % 16; | |||||
/* Mult to complete ghash */ | |||||
if (n == 0) | |||||
gcm_gmult_neon(ctx->Xi.u, ctx->Htable); | |||||
} | |||||
ctx->mres = mres; | |||||
return 0; | |||||
} | |||||
static int | |||||
gcm_decrypt(struct ossl_gcm_context *ctx, const unsigned char *in, unsigned char *out, size_t len) | |||||
{ | |||||
uint32_t n, ctr, mres; | |||||
uint64_t mlen; | |||||
size_t i; | |||||
mlen = ctx->len.u[1] + len; | |||||
if (mlen > (BIT(36) - 32) || (sizeof(len) == 8 && mlen < len)) | |||||
return -1; | |||||
ctx->len.u[1] = mlen; | |||||
mres = ctx->mres; | |||||
if (ctx->ares) { | |||||
gcm_gmult_neon(ctx->Xi.u, ctx->Htable); | |||||
ctx->ares = 0; | |||||
} | |||||
/* Get counter value */ | |||||
if (IS_LITTLE_ENDIAN) | |||||
ctr = GETU32(ctx->Yi.c + 12); | |||||
else | |||||
ctr = ctx->Yi.d[3]; | |||||
n = mres % 16; | |||||
/* Encrypt message */ | |||||
for (i = 0; i < len; ++i) { | |||||
uint8_t c; | |||||
/* Get EKi value (encrypted counter) */ | |||||
if (n == 0) { | |||||
AES_encrypt(ctx->Yi.c, ctx->EKi.c, ctx->key); | |||||
++ctr; | |||||
if (IS_LITTLE_ENDIAN) | |||||
PUTU32(ctx->Yi.c + 12, ctr) | |||||
else | |||||
ctx->Yi.d[3] = ctr; | |||||
} | |||||
c = in[i]; | |||||
out[i] = c ^ ctx->EKi.c[n]; | |||||
ctx->Xi.c[n] ^= c; | |||||
mres = n = (n + 1) % 16; | |||||
/* Mult to complete ghash */ | |||||
if (n == 0) | |||||
gcm_gmult_neon(ctx->Xi.u, ctx->Htable); | |||||
} | |||||
ctx->mres = mres; | |||||
return 0; | |||||
} | |||||
static int | |||||
gcm_finish(struct ossl_gcm_context *ctx, const unsigned char *tag, size_t len) | |||||
{ | |||||
/* Get bit size (<< 3 == *8) */ | |||||
uint64_t alen = ctx->len.u[0] << 3; | |||||
uint64_t clen = ctx->len.u[1] << 3; | |||||
/* Process buffered data */ | |||||
if (ctx->mres || ctx->ares) | |||||
gcm_gmult_neon(ctx->Xi.u, ctx->Htable); | |||||
if (IS_LITTLE_ENDIAN) { | |||||
uint8_t *p = ctx->len.c; | |||||
ctx->len.u[0] = alen; | |||||
ctx->len.u[1] = clen; | |||||
alen = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); | |||||
clen = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12); | |||||
} | |||||
/* Ghash len data */ | |||||
ctx->Xi.u[0] ^= alen; | |||||
ctx->Xi.u[1] ^= clen; | |||||
gcm_gmult_neon(ctx->Xi.u, ctx->Htable); | |||||
/* GCTR(J0, S) - encode/decode using counter 0 */ | |||||
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; | |||||
} | |||||
static void | |||||
gcm_tag(struct ossl_gcm_context *ctx, unsigned char *tag, size_t len) | |||||
{ | |||||
gcm_finish(ctx, NULL, 0); | |||||
memcpy(tag, ctx->Xi.c, | |||||
len <= sizeof(ctx->Xi.c) ? len : sizeof(ctx->Xi.c)); | |||||
} | |||||
static int | |||||
AES_GCM_ENCRYPT(struct ossl_gcm_context *ctx, const unsigned char *in, unsigned char *out, | |||||
size_t len, int encrypt) | |||||
{ | |||||
if (encrypt) | |||||
return(gcm_encrypt(ctx, in, out, len)); | |||||
else | |||||
return(gcm_decrypt(ctx, in, out, len)); | |||||
} | |||||
#endif //__OSSL_GCM__ |