/src/ghostpdl/base/saes.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | |
18 | | /* AES filter implementation */ |
19 | | |
20 | | #include "memory_.h" |
21 | | #include "gserrors.h" |
22 | | #include "strimpl.h" |
23 | | #include "saes.h" |
24 | | |
25 | | /* stream implementation */ |
26 | | |
27 | | private_st_aes_state(); /* creates a gc object for our state, |
28 | | defined in saes.h */ |
29 | | |
30 | | /* Store a key in our crypt context */ |
31 | | int |
32 | | s_aes_set_key(stream_aes_state * state, const unsigned char *key, |
33 | | int keylength) |
34 | 39.1k | { |
35 | 39.1k | int code = 0; |
36 | | |
37 | 39.1k | if ( (keylength < 1) || (keylength > SAES_MAX_KEYLENGTH) ) |
38 | 0 | return_error(gs_error_rangecheck); |
39 | 39.1k | if (key == NULL) |
40 | 0 | return_error(gs_error_invalidaccess); |
41 | | |
42 | | /* we can't set the key here because the interpreter's |
43 | | filter implementation wants to duplicate our state |
44 | | after the zfaes.c binding calls us. So stash it now |
45 | | and handle it in our process method. */ |
46 | 39.1k | memcpy(state->key, key, keylength); |
47 | 39.1k | state->keylength = keylength; |
48 | | |
49 | 39.1k | if (code) { |
50 | 0 | return gs_throw(gs_error_rangecheck, "could not set AES key"); |
51 | 0 | } |
52 | | |
53 | | /* return successfully */ |
54 | 39.1k | return 0; |
55 | 39.1k | } |
56 | | |
57 | | /* Specify whether the plaintext stream uses RFC 1423-style padding |
58 | | * (allowing it to be an arbitrary length), or is unpadded (and must |
59 | | * therefore be a multiple of 16 bytes long). */ |
60 | | void |
61 | | s_aes_set_padding(stream_aes_state *state, int use_padding) |
62 | 39.1k | { |
63 | 39.1k | state->use_padding = use_padding; |
64 | 39.1k | } |
65 | | |
66 | | /* initialize our state object. */ |
67 | | static int |
68 | | s_aes_init(stream_state *ss) |
69 | 39.1k | { |
70 | 39.1k | stream_aes_state *const state = (stream_aes_state *) ss; |
71 | | |
72 | | /* clear the flags so we know we're at the start of a stream */ |
73 | 39.1k | state->initialized = 0; |
74 | 39.1k | state->ctx = NULL; |
75 | | |
76 | 39.1k | return 0; |
77 | 39.1k | } |
78 | | |
79 | | /* release our private storage */ |
80 | | static void |
81 | | s_aes_release(stream_state *ss) |
82 | 39.1k | { |
83 | 39.1k | stream_aes_state *const state = (stream_aes_state *) ss; |
84 | | |
85 | 39.1k | if (state->ctx != NULL) |
86 | 38.4k | gs_free_object(state->memory, state->ctx, "aes context structure"); |
87 | 39.1k | } |
88 | | |
89 | | /* (de)crypt a section of text--the procedure is the same |
90 | | * in each direction. see strimpl.h for return codes. |
91 | | */ |
92 | | static int |
93 | | s_aes_process(stream_state * ss, stream_cursor_read * pr, |
94 | | stream_cursor_write * pw, bool last) |
95 | 115k | { |
96 | 115k | stream_aes_state *const state = (stream_aes_state *) ss; |
97 | 115k | const unsigned char *limit; |
98 | 115k | const long in_size = pr->limit - pr->ptr; |
99 | 115k | const long out_size = pw->limit - pw->ptr; |
100 | 115k | unsigned char temp[16]; |
101 | 115k | int status = 0; |
102 | | |
103 | | /* figure out if we're going to run out of space */ |
104 | 115k | if (in_size > out_size) { |
105 | 30.0k | limit = pr->ptr + out_size; |
106 | 30.0k | status = 1; /* need more output space */ |
107 | 85.0k | } else { |
108 | 85.0k | limit = pr->limit; |
109 | 85.0k | status = last ? EOFC : 0; /* need more input */ |
110 | 85.0k | } |
111 | | |
112 | | /* set up state and context */ |
113 | 115k | if (state->ctx == NULL) { |
114 | | /* allocate the aes context. this is a public struct but it |
115 | | contains internal pointers, so we need to store it separately |
116 | | in immovable memory like any opaque structure. */ |
117 | 38.4k | state->ctx = (aes_context *)gs_alloc_bytes_immovable(state->memory, |
118 | 38.4k | sizeof(aes_context), "aes context structure"); |
119 | 38.4k | if (state->ctx == NULL) { |
120 | 0 | gs_throw(gs_error_VMerror, "could not allocate aes context"); |
121 | 0 | return ERRC; |
122 | 0 | } |
123 | 38.4k | memset(state->ctx, 0x00, sizeof(aes_context)); |
124 | 38.4k | if (state->keylength < 1 || state->keylength > SAES_MAX_KEYLENGTH) { |
125 | 0 | gs_throw1(gs_error_rangecheck, "invalid aes key length (%d bytes)", |
126 | 0 | state->keylength); |
127 | 0 | return ERRC; |
128 | 0 | } |
129 | 38.4k | aes_setkey_dec(state->ctx, state->key, state->keylength * 8); |
130 | 38.4k | } |
131 | 115k | if (!state->initialized) { |
132 | | /* read the initialization vector from the first 16 bytes */ |
133 | 64.7k | if (in_size < 16) return 0; /* get more data */ |
134 | 37.6k | memcpy(state->iv, pr->ptr + 1, 16); |
135 | 37.6k | state->initialized = 1; |
136 | 37.6k | pr->ptr += 16; |
137 | 37.6k | } |
138 | | |
139 | | /* decrypt available blocks */ |
140 | 4.51M | while (pr->ptr + 16 <= limit) { |
141 | 4.44M | aes_crypt_cbc(state->ctx, AES_DECRYPT, 16, state->iv, |
142 | 4.44M | pr->ptr + 1, temp); |
143 | 4.44M | pr->ptr += 16; |
144 | 4.44M | if (last && pr->ptr == pr->limit) { |
145 | | /* we're on the last block; unpad if necessary */ |
146 | 24.5k | int pad; |
147 | | |
148 | 24.5k | if (state->use_padding) { |
149 | | /* we are using RFC 1423-style padding, so the last byte of the |
150 | | plaintext gives the number of bytes to discard */ |
151 | 24.5k | pad = temp[15]; |
152 | 24.5k | if (pad < 1 || pad > 16) { |
153 | | /* Bug 692343 - don't error here, just warn. Take padding to be |
154 | | * zero. This may give us a stream that's too long - preferable |
155 | | * to the alternatives. */ |
156 | 1.26k | gs_warn1("invalid aes padding byte (0x%02x)", |
157 | 1.26k | (unsigned char)pad); |
158 | 1.26k | pad = 0; |
159 | 1.26k | } |
160 | 24.5k | } else { |
161 | | /* not using padding */ |
162 | 0 | pad = 0; |
163 | 0 | } |
164 | | |
165 | 24.5k | memcpy(pw->ptr + 1, temp, 16 - pad); |
166 | 24.5k | pw->ptr += 16 - pad; |
167 | 24.5k | return EOFC; |
168 | 24.5k | } |
169 | 4.42M | memcpy(pw->ptr + 1, temp, 16); |
170 | 4.42M | pw->ptr += 16; |
171 | 4.42M | } |
172 | | |
173 | | /* if we got to the end of the file without triggering the padding |
174 | | check, the input must not have been a multiple of 16 bytes long. |
175 | | complain. */ |
176 | 63.4k | if (status == EOFC) { |
177 | 3.36k | gs_throw(gs_error_rangecheck, "aes stream isn't a multiple of 16 bytes"); |
178 | 3.36k | return 0; |
179 | 3.36k | } |
180 | | |
181 | 60.1k | return status; |
182 | 63.4k | } |
183 | | |
184 | | /* stream template */ |
185 | | const stream_template s_aes_template = { |
186 | | &st_aes_state, s_aes_init, |
187 | | s_aes_process, 16, 16, |
188 | | s_aes_release |
189 | | }; |