summaryrefslogtreecommitdiffstats
path: root/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c
blob: 66f6ed457ec133234d65bfbf539bce024d4cf051 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/*
 * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

/*
 * AES low level APIs are deprecated for public use, but still ok for internal
 * use where we're using them to implement the higher level EVP interface, as is
 * the case here.
 */
#include "internal/deprecated.h"

#include <openssl/evp.h>
#include <internal/endian.h>
#include <prov/implementations.h>
#include "cipher_aes_gcm_siv.h"

static ossl_inline void mulx_ghash(uint64_t *a)
{
    uint64_t t[2], mask;

    t[0] = BSWAP8(a[0]);
    t[1] = BSWAP8(a[1]);
    mask = -(int64_t)(t[1] & 1) & 0xe1;
    mask <<= 56;

    a[1] = BSWAP8((t[1] >> 1) ^ (t[0] << 63));
    a[0] = BSWAP8((t[0] >> 1) ^ mask);
}

#define aligned64(p) (((uintptr_t)p & 0x07) == 0)
static ossl_inline void byte_reverse16(uint8_t *out, const uint8_t *in)
{
    if (aligned64(out) && aligned64(in)) {
        ((uint64_t *)out)[0] = BSWAP8(((uint64_t *)in)[1]);
        ((uint64_t *)out)[1] = BSWAP8(((uint64_t *)in)[0]);
    } else {
        int i;

        for (i = 0; i < 16; i++)
            out[i] = in[15 - i];
    }
}

/* Initialization of POLYVAL via existing GHASH implementation */
void ossl_polyval_ghash_init(u128 Htable[16], const uint64_t H[2])
{
    uint64_t tmp[2];
    DECLARE_IS_ENDIAN;

    byte_reverse16((uint8_t *)tmp, (const uint8_t *)H);
    mulx_ghash(tmp);
    if (IS_LITTLE_ENDIAN) {
        /* "H is stored in host byte order" */
        tmp[0] = BSWAP8(tmp[0]);
        tmp[1] = BSWAP8(tmp[1]);
    }

    ossl_gcm_init_4bit(Htable, (u64*)tmp);
}

/* Implmentation of POLYVAL via existing GHASH implementation */
void ossl_polyval_ghash_hash(const u128 Htable[16], uint8_t *tag, const uint8_t *inp, size_t len)
{
    uint64_t out[2];
    uint64_t tmp[2];
    size_t i;

    byte_reverse16((uint8_t *)out, (uint8_t *)tag);

    /*
     * This implementation doesn't deal with partials, callers do,
     * so, len is a multiple of 16
     */
    for (i = 0; i < len; i += 16) {
        byte_reverse16((uint8_t *)tmp, &inp[i]);
        ossl_gcm_ghash_4bit((u64*)out, Htable, (uint8_t *)tmp, 16);
    }
    byte_reverse16(tag, (uint8_t *)out);
}