176 |
176 |
177 return len; |
177 return len; |
178 } |
178 } |
179 |
179 |
180 /* |
180 /* |
181 * Verifies and removes the MAC value. Returns true if |
181 * Pass the data down if it's internally cached, otherwise |
182 * the MAC checks out OK. |
182 * do it here. |
183 * |
183 * |
184 * On entry: |
184 * If internal data, data is decrypted internally. |
185 * position = beginning of app/MAC data |
185 * |
186 * limit = end of MAC data. |
186 * If external data(app), return a new ByteBuffer with data to |
187 * |
187 * process. |
188 * On return: |
188 */ |
189 * position = beginning of app data |
189 ByteBuffer decrypt(Authenticator authenticator, |
190 * limit = end of app data |
190 CipherBox box, ByteBuffer bb) throws BadPaddingException { |
191 */ |
191 |
192 boolean checkMAC(MAC signer, ByteBuffer bb) { |
|
193 if (internalData) { |
192 if (internalData) { |
194 return checkMAC(signer); |
193 decrypt(authenticator, box); // MAC is checked during decryption |
195 } |
194 return tmpBB; |
196 |
195 } |
197 int len = signer.MAClen(); |
196 |
198 if (len == 0) { // no mac |
197 BadPaddingException bpe = null; |
199 return true; |
198 if (!box.isNullCipher()) { |
200 } |
199 try { |
201 |
200 // apply explicit nonce for AEAD/CBC cipher suites if needed |
202 /* |
201 int nonceSize = |
203 * Grab the original limit |
202 box.applyExplicitNonce(authenticator, contentType(), bb); |
204 */ |
203 |
205 int lim = bb.limit(); |
204 // decrypt the content |
206 |
205 if (box.isAEADMode()) { |
207 /* |
206 // DON'T encrypt the nonce_explicit for AEAD mode |
208 * Delineate the area to apply a MAC on. |
207 bb.position(bb.position() + nonceSize); |
209 */ |
208 } // The explicit IV for CBC mode can be decrypted. |
210 int macData = lim - len; |
209 |
211 bb.limit(macData); |
210 box.decrypt(bb); |
212 |
211 bb.position(nonceSize); // We don't actually remove the nonce. |
213 byte[] mac = signer.compute(contentType(), bb); |
212 } catch (BadPaddingException e) { |
214 |
213 // RFC 2246 states that decryption_failed should be used |
215 if (len != mac.length) { |
214 // for this purpose. However, that allows certain attacks, |
216 throw new RuntimeException("Internal MAC error"); |
215 // so we just send bad record MAC. We also need to make |
217 } |
216 // sure to always check the MAC to avoid a timing attack |
218 |
217 // for the same issue. See paper by Vaudenay et al and the |
219 /* |
218 // update in RFC 4346/5246. |
220 * Delineate the MAC values, position was already set |
219 // |
221 * by doing the compute above. |
220 // Failover to message authentication code checking. |
222 * |
221 bpe = new BadPaddingException("invalid padding"); |
223 * We could zero the MAC area, but not much useful information |
222 } |
224 * there anyway. |
223 } |
225 */ |
224 |
226 bb.position(macData); |
225 // Requires message authentication code for null, stream and block |
227 bb.limit(lim); |
226 // cipher suites. |
228 |
227 if (authenticator instanceof MAC) { |
229 try { |
228 MAC signer = (MAC)authenticator; |
230 for (int i = 0; i < len; i++) { |
229 int macLen = signer.MAClen(); |
231 if (bb.get() != mac[i]) { // No BB.equals(byte []); ! |
230 if (macLen != 0) { |
232 return false; |
231 if (bb.remaining() < macLen) { |
|
232 // negative data length, something is wrong |
|
233 throw new BadPaddingException("bad record"); |
|
234 } |
|
235 |
|
236 int position = bb.position(); |
|
237 int limit = bb.limit(); |
|
238 int macOffset = limit - macLen; |
|
239 |
|
240 bb.limit(macOffset); |
|
241 byte[] hash = signer.compute(contentType(), bb); |
|
242 if (hash == null || macLen != hash.length) { |
|
243 // something is wrong with MAC implementation |
|
244 throw new RuntimeException("Internal MAC error"); |
|
245 } |
|
246 |
|
247 bb.position(macOffset); |
|
248 bb.limit(limit); |
|
249 |
|
250 try { |
|
251 for (byte b : hash) { // No BB.equals(byte []); ! |
|
252 if (bb.get() != b) { |
|
253 throw new BadPaddingException("bad record MAC"); |
|
254 } |
|
255 } |
|
256 } finally { |
|
257 // reset to the data |
|
258 bb.position(position); |
|
259 bb.limit(macOffset); |
233 } |
260 } |
234 } |
261 } |
235 return true; |
262 } |
236 } finally { |
263 |
237 /* |
264 // Is it a failover? |
238 * Position to the data. |
265 if (bpe != null) { |
239 */ |
266 throw bpe; |
240 bb.rewind(); |
267 } |
241 bb.limit(macData); |
|
242 } |
|
243 } |
|
244 |
|
245 /* |
|
246 * Pass the data down if it's internally cached, otherwise |
|
247 * do it here. |
|
248 * |
|
249 * If internal data, data is decrypted internally. |
|
250 * |
|
251 * If external data(app), return a new ByteBuffer with data to |
|
252 * process. |
|
253 */ |
|
254 ByteBuffer decrypt(CipherBox box, ByteBuffer bb) |
|
255 throws BadPaddingException { |
|
256 |
|
257 if (internalData) { |
|
258 decrypt(box); |
|
259 return tmpBB; |
|
260 } |
|
261 |
|
262 box.decrypt(bb); |
|
263 bb.rewind(); |
|
264 |
268 |
265 return bb.slice(); |
269 return bb.slice(); |
266 } |
270 } |
267 |
271 |
268 /* |
272 /* |