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