summaryrefslogtreecommitdiffstats
path: root/providers/implementations/ciphers/cipher_aes_siv_hw.c
blob: 1e6b3d56e4bde167b2523a7d8d28cde253be9129 (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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * 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
 */

/*
 * This file uses the low level AES functions (which are deprecated for
 * non-internal use) in order to implement provider AES ciphers.
 */
#include "internal/deprecated.h"

#include "cipher_aes_siv.h"

static void aes_siv_cleanup(void *vctx);

static int aes_siv_initkey(void *vctx, const unsigned char *key, size_t keylen)
{
    PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
    SIV128_CONTEXT *sctx = &ctx->siv;
    size_t klen  = keylen / 2;
    OSSL_LIB_CTX *libctx = ctx->libctx;
    const char *propq = NULL;

    EVP_CIPHER_free(ctx->cbc);
    EVP_CIPHER_free(ctx->ctr);
    ctx->cbc = NULL;
    ctx->ctr = NULL;

    switch (klen) {
    case 16:
        ctx->cbc = EVP_CIPHER_fetch(libctx, "AES-128-CBC", propq);
        ctx->ctr = EVP_CIPHER_fetch(libctx, "AES-128-CTR", propq);
        break;
    case 24:
        ctx->cbc = EVP_CIPHER_fetch(libctx, "AES-192-CBC", propq);
        ctx->ctr = EVP_CIPHER_fetch(libctx, "AES-192-CTR", propq);
        break;
    case 32:
        ctx->cbc = EVP_CIPHER_fetch(libctx, "AES-256-CBC", propq);
        ctx->ctr = EVP_CIPHER_fetch(libctx, "AES-256-CTR", propq);
        break;
    default:
        break;
    }
    if (ctx->cbc == NULL || ctx->ctr == NULL)
        return 0;
    /*
     * klen is the length of the underlying cipher, not the input key,
     * which should be twice as long
     */
    return ossl_siv128_init(sctx, key, klen, ctx->cbc, ctx->ctr, libctx,
                              propq);
}

static int aes_siv_dupctx(void *in_vctx, void *out_vctx)
{
    PROV_AES_SIV_CTX *in = (PROV_AES_SIV_CTX *)in_vctx;
    PROV_AES_SIV_CTX *out = (PROV_AES_SIV_CTX *)out_vctx;

    *out = *in;
    out->siv.cipher_ctx = NULL;
    out->siv.mac_ctx_init = NULL;
    out->siv.mac = NULL;
    if (!ossl_siv128_copy_ctx(&out->siv, &in->siv))
        return 0;
    if (out->cbc != NULL)
        EVP_CIPHER_up_ref(out->cbc);
    if (out->ctr != NULL)
        EVP_CIPHER_up_ref(out->ctr);
    return 1;
}

static int aes_siv_settag(void *vctx, const unsigned char *tag, size_t tagl)
{
    PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
    SIV128_CONTEXT *sctx = &ctx->siv;

    return ossl_siv128_set_tag(sctx, tag, tagl);
}

static void aes_siv_setspeed(void *vctx, int speed)
{
    PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
    SIV128_CONTEXT *sctx = &ctx->siv;

    ossl_siv128_speed(sctx, (int)speed);
}

static void aes_siv_cleanup(void *vctx)
{
    PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
    SIV128_CONTEXT *sctx = &ctx->siv;

    ossl_siv128_cleanup(sctx);
    EVP_CIPHER_free(ctx->cbc);
    EVP_CIPHER_free(ctx->ctr);
}

static int aes_siv_cipher(void *vctx, unsigned char *out,
                          const unsigned char *in, size_t len)
{
    PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
    SIV128_CONTEXT *sctx = &ctx->siv;

    /* EncryptFinal or DecryptFinal */
    if (in == NULL)
        return ossl_siv128_finish(sctx) == 0;

    /* Deal with associated data */
    if (out == NULL)
        return (ossl_siv128_aad(sctx, in, len) == 1);

    if (ctx->enc)
        return ossl_siv128_encrypt(sctx, in, out, len) > 0;

    return ossl_siv128_decrypt(sctx, in, out, len) > 0;
}

static const PROV_CIPHER_HW_AES_SIV aes_siv_hw =
{
    aes_siv_initkey,
    aes_siv_cipher,
    aes_siv_setspeed,
    aes_siv_settag,
    aes_siv_cleanup,
    aes_siv_dupctx,
};

const PROV_CIPHER_HW_AES_SIV *ossl_prov_cipher_hw_aes_siv(size_t keybits)
{
    return &aes_siv_hw;
}