/src/nettle/pkcs1-sec-decrypt.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* pkcs1-sec-decrypt.c |
2 | | |
3 | | The RSA publickey algorithm. Side channel resistant PKCS#1 decryption. |
4 | | |
5 | | Copyright (C) 2001, 2012 Niels Möller |
6 | | Copyright (C) 2018 Red Hat, Inc. |
7 | | |
8 | | This file is part of GNU Nettle. |
9 | | |
10 | | GNU Nettle is free software: you can redistribute it and/or |
11 | | modify it under the terms of either: |
12 | | |
13 | | * the GNU Lesser General Public License as published by the Free |
14 | | Software Foundation; either version 3 of the License, or (at your |
15 | | option) any later version. |
16 | | |
17 | | or |
18 | | |
19 | | * the GNU General Public License as published by the Free |
20 | | Software Foundation; either version 2 of the License, or (at your |
21 | | option) any later version. |
22 | | |
23 | | or both in parallel, as here. |
24 | | |
25 | | GNU Nettle is distributed in the hope that it will be useful, |
26 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
27 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
28 | | General Public License for more details. |
29 | | |
30 | | You should have received copies of the GNU General Public License and |
31 | | the GNU Lesser General Public License along with this program. If |
32 | | not, see http://www.gnu.org/licenses/. |
33 | | */ |
34 | | |
35 | | #if HAVE_CONFIG_H |
36 | | # include "config.h" |
37 | | #endif |
38 | | |
39 | | #include <assert.h> |
40 | | |
41 | | #include <string.h> |
42 | | |
43 | | #include "memops.h" |
44 | | |
45 | | #include "gmp-glue.h" |
46 | | #include "pkcs1-internal.h" |
47 | | #include "nettle-internal.h" |
48 | | |
49 | | /* Inputs are always cast to uint32_t values. But all values used in this |
50 | | * function should never exceed the maximum value of a uint32_t anyway. |
51 | | * these macros returns 1 on success, 0 on failure */ |
52 | | #define NOT_EQUAL(a, b) \ |
53 | 0 | ((0U - ((uint32_t)(a) ^ (uint32_t)(b))) >> 31) |
54 | 0 | #define EQUAL(a, b) (IS_ZERO_SMALL ((a) ^ (b))) |
55 | | #define GREATER_OR_EQUAL(a, b) \ |
56 | 0 | (1U - (((uint32_t)(a) - (uint32_t)(b)) >> 31)) |
57 | | |
58 | | int |
59 | | _pkcs1_sec_decrypt (size_t length, uint8_t *message, |
60 | | size_t padded_message_length, |
61 | | const volatile uint8_t *padded_message) |
62 | 0 | { |
63 | 0 | volatile int ok; |
64 | 0 | size_t i, t; |
65 | | |
66 | | /* Message independent branch */ |
67 | 0 | if (length + 11 > padded_message_length) |
68 | 0 | return 0; |
69 | | |
70 | 0 | t = padded_message_length - length - 1; |
71 | | |
72 | | /* Check format, padding, message_size */ |
73 | 0 | ok = EQUAL(padded_message[0], 0); /* ok if padded_message[0] == 0 */ |
74 | 0 | ok &= EQUAL(padded_message[1], 2); /* ok if padded_message[1] == 2 */ |
75 | 0 | for (i = 2; i < t; i++) /* check padding has no zeros */ |
76 | 0 | { |
77 | 0 | ok &= NOT_EQUAL(padded_message[i], 0); |
78 | 0 | } |
79 | 0 | ok &= EQUAL(padded_message[t], 0); /* ok if terminator == 0 */ |
80 | | |
81 | | /* fill destination buffer regardless of outcome */ |
82 | 0 | cnd_memcpy(ok, message, padded_message + t + 1, length); |
83 | |
|
84 | 0 | return ok; |
85 | 0 | } |
86 | | |
87 | | int |
88 | | _pkcs1_sec_decrypt_variable(size_t *length, uint8_t *message, |
89 | | size_t padded_message_length, |
90 | | const volatile uint8_t *padded_message) |
91 | 0 | { |
92 | 0 | volatile int not_found = 1; |
93 | 0 | volatile int ok; |
94 | 0 | volatile size_t offset; |
95 | 0 | size_t buflen, msglen; |
96 | 0 | size_t shift, i; |
97 | | |
98 | | /* Check format, padding, message_size */ |
99 | 0 | ok = EQUAL(padded_message[0], 0); |
100 | 0 | ok &= EQUAL(padded_message[1], 2); |
101 | | |
102 | | /* length is discovered in a side-channel silent way. |
103 | | * not_found goes to 0 when the terminator is found. |
104 | | * offset starts at 3 as it includes the terminator and |
105 | | * the format bytes already */ |
106 | 0 | offset = 3; |
107 | 0 | for (i = 2; i < padded_message_length; i++) |
108 | 0 | { |
109 | 0 | not_found &= NOT_EQUAL(padded_message[i], 0); |
110 | 0 | offset += not_found; |
111 | 0 | } |
112 | | /* check if we ran out of buffer */ |
113 | 0 | ok &= NOT_EQUAL(not_found, 1); |
114 | | /* padding must be >= 11 (2 format bytes + 8 pad bytes min. + terminator) */ |
115 | 0 | ok &= GREATER_OR_EQUAL(offset, 11); |
116 | | |
117 | | /* offset can vary between 3 and padded_message_length, due to the loop |
118 | | * above, therefore msglen can't underflow */ |
119 | 0 | msglen = padded_message_length - offset; |
120 | | |
121 | | /* we always fill the whole buffer but only up to |
122 | | * padded_message_length length */ |
123 | 0 | buflen = *length; |
124 | 0 | if (buflen > padded_message_length) { /* input independent branch */ |
125 | 0 | buflen = padded_message_length; |
126 | 0 | } |
127 | | |
128 | | /* if the message length is larger than the buffer we must fail */ |
129 | 0 | ok &= GREATER_OR_EQUAL(buflen, msglen); |
130 | | |
131 | | /* fill destination buffer fully regardless of outcome. Copies the message |
132 | | * in a memory access independent way. The destination message buffer will |
133 | | * be clobbered past the message length. */ |
134 | 0 | shift = padded_message_length - buflen; |
135 | 0 | cnd_memcpy(ok, message, padded_message + shift, buflen); |
136 | 0 | offset -= shift; |
137 | | /* In this loop, the bits of the 'offset' variable are used as shifting |
138 | | * conditions, starting from the least significant bit. The end result is |
139 | | * that the buffer is shifted left exactly 'offset' bytes. */ |
140 | 0 | for (shift = 1; shift < buflen; shift <<= 1, offset >>= 1) |
141 | 0 | { |
142 | | /* 'ok' is both a least significant bit mask and a condition */ |
143 | 0 | cnd_memcpy(offset & ok, message, message + shift, buflen - shift); |
144 | 0 | } |
145 | | |
146 | | /* update length only if we succeeded, otherwise leave unchanged */ |
147 | 0 | *length = (msglen & (-(size_t) ok)) + (*length & ((size_t) ok - 1)); |
148 | |
|
149 | 0 | return ok; |
150 | 0 | } |