1 /*
2  * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 /*
11  * AES low level APIs are deprecated for public use, but still ok for internal
12  * use where we're using them to implement the higher level EVP interface, as is
13  * the case here.
14  */
15 #include "internal/deprecated.h"
16 
17 #include <openssl/evp.h>
18 #include <internal/endian.h>
19 #include <prov/implementations.h>
20 #include "cipher_aes_gcm_siv.h"
21 
mulx_ghash(uint64_t * a)22 static ossl_inline void mulx_ghash(uint64_t *a)
23 {
24     uint64_t t[2], mask;
25     DECLARE_IS_ENDIAN;
26 
27     if (IS_LITTLE_ENDIAN) {
28         t[0] = GSWAP8(a[0]);
29         t[1] = GSWAP8(a[1]);
30     } else {
31         t[0] = a[0];
32         t[1] = a[1];
33     }
34     mask = -(int64_t)(t[1] & 1) & 0xe1;
35     mask <<= 56;
36 
37     if (IS_LITTLE_ENDIAN) {
38         a[1] = GSWAP8((t[1] >> 1) ^ (t[0] << 63));
39         a[0] = GSWAP8((t[0] >> 1) ^ mask);
40     } else {
41         a[1] = (t[1] >> 1) ^ (t[0] << 63);
42         a[0] = (t[0] >> 1) ^ mask;
43     }
44 }
45 
46 #define aligned64(p) (((uintptr_t)p & 0x07) == 0)
byte_reverse16(uint8_t * out,const uint8_t * in)47 static ossl_inline void byte_reverse16(uint8_t *out, const uint8_t *in)
48 {
49     if (aligned64(out) && aligned64(in)) {
50         ((uint64_t *)out)[0] = GSWAP8(((uint64_t *)in)[1]);
51         ((uint64_t *)out)[1] = GSWAP8(((uint64_t *)in)[0]);
52     } else {
53         int i;
54 
55         for (i = 0; i < 16; i++)
56             out[i] = in[15 - i];
57     }
58 }
59 
60 /* Initialization of POLYVAL via existing GHASH implementation */
ossl_polyval_ghash_init(u128 Htable[16],const uint64_t H[2])61 void ossl_polyval_ghash_init(u128 Htable[16], const uint64_t H[2])
62 {
63     uint64_t tmp[2];
64     DECLARE_IS_ENDIAN;
65 
66     byte_reverse16((uint8_t *)tmp, (const uint8_t *)H);
67     mulx_ghash(tmp);
68     if (IS_LITTLE_ENDIAN) {
69         /* "H is stored in host byte order" */
70         tmp[0] = GSWAP8(tmp[0]);
71         tmp[1] = GSWAP8(tmp[1]);
72     }
73 
74     ossl_gcm_init_4bit(Htable, (u64*)tmp);
75 }
76 
77 /* Implementation of POLYVAL via existing GHASH implementation */
ossl_polyval_ghash_hash(const u128 Htable[16],uint8_t * tag,const uint8_t * inp,size_t len)78 void ossl_polyval_ghash_hash(const u128 Htable[16], uint8_t *tag, const uint8_t *inp, size_t len)
79 {
80     uint64_t out[2];
81     uint64_t tmp[2];
82     size_t i;
83 
84     byte_reverse16((uint8_t *)out, (uint8_t *)tag);
85 
86     /*
87      * This implementation doesn't deal with partials, callers do,
88      * so, len is a multiple of 16
89      */
90     for (i = 0; i < len; i += 16) {
91         byte_reverse16((uint8_t *)tmp, &inp[i]);
92         ossl_gcm_ghash_4bit((u64*)out, Htable, (uint8_t *)tmp, 16);
93     }
94     byte_reverse16(tag, (uint8_t *)out);
95 }
96