Coverage Report

Created: 2025-08-28 07:12

/src/ffmpeg/libavutil/des.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * DES encryption/decryption
3
 * Copyright (c) 2007 Reimar Doeffinger
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#include "config.h"
23
24
#include <stdint.h>
25
26
#include "attributes.h"
27
#include "error.h"
28
#include "intreadwrite.h"
29
#include "mem.h"
30
#include "des.h"
31
32
#define T(a, b, c, d, e, f, g, h) 64 - a, 64 - b, 64 - c, 64 - d, 64 - e, 64 - f, 64 - g, 64 - h
33
static const uint8_t IP_shuffle[] = {
34
    T(58, 50, 42, 34, 26, 18, 10, 2),
35
    T(60, 52, 44, 36, 28, 20, 12, 4),
36
    T(62, 54, 46, 38, 30, 22, 14, 6),
37
    T(64, 56, 48, 40, 32, 24, 16, 8),
38
    T(57, 49, 41, 33, 25, 17,  9, 1),
39
    T(59, 51, 43, 35, 27, 19, 11, 3),
40
    T(61, 53, 45, 37, 29, 21, 13, 5),
41
    T(63, 55, 47, 39, 31, 23, 15, 7)
42
};
43
#undef T
44
45
#if CONFIG_SMALL || defined(GENTABLES)
46
#define T(a, b, c, d) 32 - a, 32 - b, 32 - c, 32 - d
47
static const uint8_t P_shuffle[] = {
48
    T(16,  7, 20, 21),
49
    T(29, 12, 28, 17),
50
    T( 1, 15, 23, 26),
51
    T( 5, 18, 31, 10),
52
    T( 2,  8, 24, 14),
53
    T(32, 27,  3,  9),
54
    T(19, 13, 30,  6),
55
    T(22, 11,  4, 25)
56
};
57
#undef T
58
#endif
59
60
#define T(a, b, c, d, e, f, g) 64 - a, 64 - b, 64 - c, 64 - d, 64 - e, 64 - f, 64 - g
61
static const uint8_t PC1_shuffle[] = {
62
    T(57, 49, 41, 33, 25, 17,  9),
63
    T( 1, 58, 50, 42, 34, 26, 18),
64
    T(10,  2, 59, 51, 43, 35, 27),
65
    T(19, 11,  3, 60, 52, 44, 36),
66
    T(63, 55, 47, 39, 31, 23, 15),
67
    T( 7, 62, 54, 46, 38, 30, 22),
68
    T(14,  6, 61, 53, 45, 37, 29),
69
    T(21, 13,  5, 28, 20, 12,  4)
70
};
71
#undef T
72
73
#define T(a, b, c, d, e, f) 56 - a, 56 - b, 56 - c, 56 - d, 56 - e, 56 - f
74
static const uint8_t PC2_shuffle[] = {
75
    T(14, 17, 11, 24,  1,  5),
76
    T( 3, 28, 15,  6, 21, 10),
77
    T(23, 19, 12,  4, 26,  8),
78
    T(16,  7, 27, 20, 13,  2),
79
    T(41, 52, 31, 37, 47, 55),
80
    T(30, 40, 51, 45, 33, 48),
81
    T(44, 49, 39, 56, 34, 53),
82
    T(46, 42, 50, 36, 29, 32)
83
};
84
#undef T
85
86
#if CONFIG_SMALL
87
static const uint8_t S_boxes[8][32] = {
88
    { 0x0e, 0xf4, 0x7d, 0x41, 0xe2, 0x2f, 0xdb, 0x18, 0xa3, 0x6a, 0xc6, 0xbc, 0x95, 0x59, 0x30, 0x87,
89
      0xf4, 0xc1, 0x8e, 0x28, 0x4d, 0x96, 0x12, 0x7b, 0x5f, 0xbc, 0x39, 0xe7, 0xa3, 0x0a, 0x65, 0xd0, },
90
    { 0x3f, 0xd1, 0x48, 0x7e, 0xf6, 0x2b, 0x83, 0xe4, 0xc9, 0x07, 0x12, 0xad, 0x6c, 0x90, 0xb5, 0x5a,
91
      0xd0, 0x8e, 0xa7, 0x1b, 0x3a, 0xf4, 0x4d, 0x21, 0xb5, 0x68, 0x7c, 0xc6, 0x09, 0x53, 0xe2, 0x9f, },
92
    { 0xda, 0x70, 0x09, 0x9e, 0x36, 0x43, 0x6f, 0xa5, 0x21, 0x8d, 0x5c, 0xe7, 0xcb, 0xb4, 0xf2, 0x18,
93
      0x1d, 0xa6, 0xd4, 0x09, 0x68, 0x9f, 0x83, 0x70, 0x4b, 0xf1, 0xe2, 0x3c, 0xb5, 0x5a, 0x2e, 0xc7, },
94
    { 0xd7, 0x8d, 0xbe, 0x53, 0x60, 0xf6, 0x09, 0x3a, 0x41, 0x72, 0x28, 0xc5, 0x1b, 0xac, 0xe4, 0x9f,
95
      0x3a, 0xf6, 0x09, 0x60, 0xac, 0x1b, 0xd7, 0x8d, 0x9f, 0x41, 0x53, 0xbe, 0xc5, 0x72, 0x28, 0xe4, },
96
    { 0xe2, 0xbc, 0x24, 0xc1, 0x47, 0x7a, 0xdb, 0x16, 0x58, 0x05, 0xf3, 0xaf, 0x3d, 0x90, 0x8e, 0x69,
97
      0xb4, 0x82, 0xc1, 0x7b, 0x1a, 0xed, 0x27, 0xd8, 0x6f, 0xf9, 0x0c, 0x95, 0xa6, 0x43, 0x50, 0x3e, },
98
    { 0xac, 0xf1, 0x4a, 0x2f, 0x79, 0xc2, 0x96, 0x58, 0x60, 0x1d, 0xd3, 0xe4, 0x0e, 0xb7, 0x35, 0x8b,
99
      0x49, 0x3e, 0x2f, 0xc5, 0x92, 0x58, 0xfc, 0xa3, 0xb7, 0xe0, 0x14, 0x7a, 0x61, 0x0d, 0x8b, 0xd6, },
100
    { 0xd4, 0x0b, 0xb2, 0x7e, 0x4f, 0x90, 0x18, 0xad, 0xe3, 0x3c, 0x59, 0xc7, 0x25, 0xfa, 0x86, 0x61,
101
      0x61, 0xb4, 0xdb, 0x8d, 0x1c, 0x43, 0xa7, 0x7e, 0x9a, 0x5f, 0x06, 0xf8, 0xe0, 0x25, 0x39, 0xc2, },
102
    { 0x1d, 0xf2, 0xd8, 0x84, 0xa6, 0x3f, 0x7b, 0x41, 0xca, 0x59, 0x63, 0xbe, 0x05, 0xe0, 0x9c, 0x27,
103
      0x27, 0x1b, 0xe4, 0x71, 0x49, 0xac, 0x8e, 0xd2, 0xf0, 0xc6, 0x9a, 0x0d, 0x3f, 0x53, 0x65, 0xb8,
104
    }
105
};
106
#else
107
/**
108
 * This table contains the results of applying both the S-box and P-shuffle.
109
 * It can be regenerated by compiling tests/des.c with "-DCONFIG_SMALL -DGENTABLES".
110
 */
111
static const uint32_t S_boxes_P_shuffle[8][64] = {
112
    { 0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000,
113
      0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002,
114
      0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202,
115
      0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000,
116
      0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200,
117
      0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202,
118
      0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200,
119
      0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002, },
120
    { 0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010,
121
      0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010,
122
      0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000,
123
      0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010,
124
      0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000,
125
      0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000,
126
      0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010,
127
      0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000, },
128
    { 0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100,
129
      0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104,
130
      0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104,
131
      0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000,
132
      0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000,
133
      0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004,
134
      0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004,
135
      0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100, },
136
    { 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000,
137
      0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000,
138
      0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040,
139
      0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040,
140
      0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000,
141
      0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040,
142
      0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040,
143
      0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040, },
144
    { 0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000,
145
      0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000,
146
      0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080,
147
      0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080,
148
      0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080,
149
      0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000,
150
      0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000,
151
      0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080, },
152
    { 0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000,
153
      0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008,
154
      0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008,
155
      0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000,
156
      0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008,
157
      0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000,
158
      0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008,
159
      0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008, },
160
    { 0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400,
161
      0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401,
162
      0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001,
163
      0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400,
164
      0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001,
165
      0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400,
166
      0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401,
167
      0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001, },
168
    { 0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000,
169
      0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020,
170
      0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800,
171
      0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000,
172
      0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820,
173
      0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820,
174
      0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000,
175
      0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800, },
176
};
177
#endif
178
179
static uint64_t shuffle(uint64_t in, const uint8_t *shuffle, int shuffle_len)
180
269k
{
181
269k
    int i;
182
269k
    uint64_t res = 0;
183
14.1M
    for (i = 0; i < shuffle_len; i++)
184
13.9M
        res += res + ((in >> *shuffle++) & 1);
185
269k
    return res;
186
269k
}
187
188
static uint64_t shuffle_inv(uint64_t in, const uint8_t *shuffle, int shuffle_len)
189
55.1k
{
190
55.1k
    int i;
191
55.1k
    uint64_t res = 0;
192
55.1k
    shuffle += shuffle_len - 1;
193
3.58M
    for (i = 0; i < shuffle_len; i++) {
194
3.53M
        res |= (in & 1) << *shuffle--;
195
3.53M
        in >>= 1;
196
3.53M
    }
197
55.1k
    return res;
198
55.1k
}
199
200
static uint32_t f_func(uint32_t r, uint64_t k)
201
882k
{
202
882k
    int i;
203
882k
    uint32_t out = 0;
204
    // rotate to get first part of E-shuffle in the lowest 6 bits
205
882k
    r = (r << 1) | (r >> 31);
206
    // apply S-boxes, those compress the data again from 8 * 6 to 8 * 4 bits
207
7.94M
    for (i = 7; i >= 0; i--) {
208
7.06M
        uint8_t tmp = (r ^ k) & 0x3f;
209
#if CONFIG_SMALL
210
        uint8_t v = S_boxes[i][tmp >> 1];
211
        if (tmp & 1)
212
            v >>= 4;
213
        out = (out >> 4) | (v << 28);
214
#else
215
7.06M
        out |= S_boxes_P_shuffle[i][tmp];
216
7.06M
#endif
217
        // get next 6 bits of E-shuffle and round key k into the lowest bits
218
7.06M
        r   = (r >> 4) | (r << 28);
219
7.06M
        k >>= 6;
220
7.06M
    }
221
#if CONFIG_SMALL
222
    out = shuffle(out, P_shuffle, sizeof(P_shuffle));
223
#endif
224
882k
    return out;
225
882k
}
226
227
/**
228
 * @brief rotate the two halves of the expanded 56 bit key each 1 bit left
229
 *
230
 * Note: the specification calls this "shift", so I kept it although
231
 * it is confusing.
232
 */
233
static uint64_t key_shift_left(uint64_t CDn)
234
352k
{
235
352k
    uint64_t carries = (CDn >> 27) & 0x10000001;
236
352k
    CDn <<= 1;
237
352k
    CDn  &= ~0x10000001;
238
352k
    CDn  |= carries;
239
352k
    return CDn;
240
352k
}
241
242
static void gen_roundkeys(uint64_t K[16], uint64_t key)
243
12.5k
{
244
12.5k
    int i;
245
    // discard parity bits from key and shuffle it into C and D parts
246
12.5k
    uint64_t CDn = shuffle(key, PC1_shuffle, sizeof(PC1_shuffle));
247
    // generate round keys
248
214k
    for (i = 0; i < 16; i++) {
249
201k
        CDn = key_shift_left(CDn);
250
201k
        if (i > 1 && i != 8 && i != 15)
251
151k
            CDn = key_shift_left(CDn);
252
201k
        K[i] = shuffle(CDn, PC2_shuffle, sizeof(PC2_shuffle));
253
201k
    }
254
12.5k
}
255
256
static uint64_t des_encdec(uint64_t in, uint64_t K[16], int decrypt)
257
55.1k
{
258
55.1k
    int i;
259
    // used to apply round keys in reverse order for decryption
260
55.1k
    decrypt = decrypt ? 15 : 0;
261
    // shuffle irrelevant to security but to ease hardware implementations
262
55.1k
    in = shuffle(in, IP_shuffle, sizeof(IP_shuffle));
263
937k
    for (i = 0; i < 16; i++) {
264
882k
        uint32_t f_res;
265
882k
        f_res = f_func(in, K[decrypt ^ i]);
266
882k
        in    = (in << 32) | (in >> 32);
267
882k
        in   ^= f_res;
268
882k
    }
269
55.1k
    in = (in << 32) | (in >> 32);
270
    // reverse shuffle used to ease hardware implementations
271
55.1k
    in = shuffle_inv(in, IP_shuffle, sizeof(IP_shuffle));
272
55.1k
    return in;
273
55.1k
}
274
275
AVDES *av_des_alloc(void)
276
2.71k
{
277
2.71k
    return av_mallocz(sizeof(struct AVDES));
278
2.71k
}
279
280
7.41k
int av_des_init(AVDES *d, const uint8_t *key, int key_bits, av_unused int decrypt) {
281
7.41k
    if (key_bits != 64 && key_bits != 192)
282
0
        return AVERROR(EINVAL);
283
7.41k
    d->triple_des = key_bits > 64;
284
7.41k
    gen_roundkeys(d->round_keys[0], AV_RB64(key));
285
7.41k
    if (d->triple_des) {
286
2.59k
        gen_roundkeys(d->round_keys[1], AV_RB64(key +  8));
287
2.59k
        gen_roundkeys(d->round_keys[2], AV_RB64(key + 16));
288
2.59k
    }
289
7.41k
    return 0;
290
7.41k
}
291
292
static void av_des_crypt_mac(AVDES *d, uint8_t *dst, const uint8_t *src,
293
                             int count, uint8_t *iv, int decrypt, int mac)
294
20.8k
{
295
20.8k
    uint64_t iv_val = iv ? AV_RB64(iv) : 0;
296
64.2k
    while (count-- > 0) {
297
43.4k
        uint64_t dst_val;
298
43.4k
        uint64_t src_val = src ? AV_RB64(src) : 0;
299
43.4k
        if (decrypt) {
300
18.5k
            uint64_t tmp = src_val;
301
18.5k
            if (d->triple_des) {
302
5.85k
                src_val = des_encdec(src_val, d->round_keys[2], 1);
303
5.85k
                src_val = des_encdec(src_val, d->round_keys[1], 0);
304
5.85k
            }
305
18.5k
            dst_val = des_encdec(src_val, d->round_keys[0], 1) ^ iv_val;
306
18.5k
            iv_val  = iv ? tmp : 0;
307
24.9k
        } else {
308
24.9k
            dst_val = des_encdec(src_val ^ iv_val, d->round_keys[0], 0);
309
24.9k
            if (d->triple_des) {
310
0
                dst_val = des_encdec(dst_val, d->round_keys[1], 1);
311
0
                dst_val = des_encdec(dst_val, d->round_keys[2], 0);
312
0
            }
313
24.9k
            iv_val = iv ? dst_val : 0;
314
24.9k
        }
315
43.4k
        AV_WB64(dst, dst_val);
316
43.4k
        src += 8;
317
43.4k
        if (!mac)
318
20.9k
            dst += 8;
319
43.4k
    }
320
20.8k
    if (iv)
321
20.8k
        AV_WB64(iv, iv_val);
322
20.8k
}
323
324
void av_des_crypt(AVDES *d, uint8_t *dst, const uint8_t *src,
325
                  int count, uint8_t *iv, int decrypt)
326
18.5k
{
327
18.5k
    av_des_crypt_mac(d, dst, src, count, iv, decrypt, 0);
328
18.5k
}
329
330
void av_des_mac(AVDES *d, uint8_t *dst, const uint8_t *src, int count)
331
2.29k
{
332
2.29k
    av_des_crypt_mac(d, dst, src, count, (uint8_t[8]) { 0 }, 0, 1);
333
2.29k
}