Coverage Report

Created: 2026-05-30 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/chacha/chacha_enc.c
Line
Count
Source
1
/*
2
 * Copyright 2015-2020 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
/* Adapted from the public domain code by D. Bernstein from SUPERCOP. */
11
12
#include <stdint.h>
13
#include <string.h>
14
15
#include "internal/endian.h"
16
#include "crypto/chacha.h"
17
#include "crypto/ctype.h"
18
19
typedef union {
20
    uint32_t u[16];
21
    uint8_t c[64];
22
} chacha_buf;
23
24
0
#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
25
26
#ifndef PEDANTIC
27
#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
28
#if defined(__riscv_zbb) || defined(__riscv_zbkb)
29
#if __riscv_xlen == 64
30
#undef ROTATE
31
#define ROTATE(x, n) ({ uint32_t ret;                   \
32
                        asm ("roriw %0, %1, %2"        \
33
                        : "=r"(ret)                    \
34
                        : "r"(x), "i"(32 - (n))); ret; })
35
#endif
36
#if __riscv_xlen == 32
37
#undef ROTATE
38
#define ROTATE(x, n) ({ uint32_t ret;                   \
39
                        asm ("rori %0, %1, %2"         \
40
                        : "=r"(ret)                    \
41
                        : "r"(x), "i"(32 - (n))); ret; })
42
#endif
43
#endif
44
#endif
45
#endif
46
47
#define U32TO8_LITTLE(p, v)          \
48
0
    do {                             \
49
0
        (p)[0] = (uint8_t)(v >> 0);  \
50
0
        (p)[1] = (uint8_t)(v >> 8);  \
51
0
        (p)[2] = (uint8_t)(v >> 16); \
52
0
        (p)[3] = (uint8_t)(v >> 24); \
53
0
    } while (0)
54
55
/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
56
0
#define QUARTERROUND(a, b, c, d) (                  \
57
0
    x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]), 16), \
58
0
    x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]), 12), \
59
0
    x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]), 8),  \
60
0
    x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]), 7))
61
62
/* chacha_core performs 20 rounds of ChaCha on the input words in
63
 * |input| and writes the 64 output bytes to |output|. */
64
static void chacha20_core(chacha_buf *output, const uint32_t input[16])
65
0
{
66
0
    uint32_t x[16];
67
0
    int i;
68
0
    DECLARE_IS_ENDIAN;
69
70
0
    memcpy(x, input, sizeof(x));
71
72
0
    for (i = 20; i > 0; i -= 2) {
73
0
        QUARTERROUND(0, 4, 8, 12);
74
0
        QUARTERROUND(1, 5, 9, 13);
75
0
        QUARTERROUND(2, 6, 10, 14);
76
0
        QUARTERROUND(3, 7, 11, 15);
77
0
        QUARTERROUND(0, 5, 10, 15);
78
0
        QUARTERROUND(1, 6, 11, 12);
79
0
        QUARTERROUND(2, 7, 8, 13);
80
0
        QUARTERROUND(3, 4, 9, 14);
81
0
    }
82
83
0
    if (IS_LITTLE_ENDIAN) {
84
0
        for (i = 0; i < 16; ++i)
85
0
            output->u[i] = x[i] + input[i];
86
0
    } else {
87
0
        for (i = 0; i < 16; ++i)
88
0
            U32TO8_LITTLE(output->c + 4 * i, (x[i] + input[i]));
89
0
    }
90
0
}
91
92
#ifdef INCLUDE_C_CHACHA20
93
void ChaCha20_ctr32_c(unsigned char *out, const unsigned char *inp, size_t len,
94
    const unsigned int key[8], const unsigned int counter[4])
95
#else
96
void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp, size_t len,
97
    const unsigned int key[8], const unsigned int counter[4])
98
#endif
99
0
{
100
0
    uint32_t input[16];
101
0
    chacha_buf buf;
102
0
    size_t todo, i;
103
104
    /* sigma constant "expand 32-byte k" in little-endian encoding */
105
0
    input[0] = ((uint32_t)ossl_toascii('e')) | ((uint32_t)ossl_toascii('x') << 8)
106
0
        | ((uint32_t)ossl_toascii('p') << 16)
107
0
        | ((uint32_t)ossl_toascii('a') << 24);
108
0
    input[1] = ((uint32_t)ossl_toascii('n')) | ((uint32_t)ossl_toascii('d') << 8)
109
0
        | ((uint32_t)ossl_toascii(' ') << 16)
110
0
        | ((uint32_t)ossl_toascii('3') << 24);
111
0
    input[2] = ((uint32_t)ossl_toascii('2')) | ((uint32_t)ossl_toascii('-') << 8)
112
0
        | ((uint32_t)ossl_toascii('b') << 16)
113
0
        | ((uint32_t)ossl_toascii('y') << 24);
114
0
    input[3] = ((uint32_t)ossl_toascii('t')) | ((uint32_t)ossl_toascii('e') << 8)
115
0
        | ((uint32_t)ossl_toascii(' ') << 16)
116
0
        | ((uint32_t)ossl_toascii('k') << 24);
117
118
0
    input[4] = key[0];
119
0
    input[5] = key[1];
120
0
    input[6] = key[2];
121
0
    input[7] = key[3];
122
0
    input[8] = key[4];
123
0
    input[9] = key[5];
124
0
    input[10] = key[6];
125
0
    input[11] = key[7];
126
127
0
    input[12] = counter[0];
128
0
    input[13] = counter[1];
129
0
    input[14] = counter[2];
130
0
    input[15] = counter[3];
131
132
0
    while (len > 0) {
133
0
        todo = sizeof(buf);
134
0
        if (len < todo)
135
0
            todo = len;
136
137
0
        chacha20_core(&buf, input);
138
139
0
        for (i = 0; i < todo; i++)
140
0
            out[i] = inp[i] ^ buf.c[i];
141
0
        out += todo;
142
0
        inp += todo;
143
0
        len -= todo;
144
145
        /*
146
         * Advance 32-bit counter. Note that as subroutine is so to
147
         * say nonce-agnostic, this limited counter width doesn't
148
         * prevent caller from implementing wider counter. It would
149
         * simply take two calls split on counter overflow...
150
         */
151
0
        input[12]++;
152
0
    }
153
0
}