2080 return fragmentSize + headerSize + tagSize; |
2106 return fragmentSize + headerSize + tagSize; |
2081 } |
2107 } |
2082 } |
2108 } |
2083 } |
2109 } |
2084 |
2110 |
|
2111 private static final class T12CC20P1305ReadCipherGenerator |
|
2112 implements ReadCipherGenerator { |
|
2113 |
|
2114 @Override |
|
2115 public SSLReadCipher createCipher(SSLCipher sslCipher, |
|
2116 Authenticator authenticator, ProtocolVersion protocolVersion, |
|
2117 String algorithm, Key key, AlgorithmParameterSpec params, |
|
2118 SecureRandom random) throws GeneralSecurityException { |
|
2119 return new CC20P1305ReadCipher(authenticator, protocolVersion, |
|
2120 sslCipher, algorithm, key, params, random); |
|
2121 } |
|
2122 |
|
2123 static final class CC20P1305ReadCipher extends SSLReadCipher { |
|
2124 private final Cipher cipher; |
|
2125 private final int tagSize; |
|
2126 private final Key key; |
|
2127 private final byte[] iv; |
|
2128 private final SecureRandom random; |
|
2129 |
|
2130 CC20P1305ReadCipher(Authenticator authenticator, |
|
2131 ProtocolVersion protocolVersion, |
|
2132 SSLCipher sslCipher, String algorithm, |
|
2133 Key key, AlgorithmParameterSpec params, |
|
2134 SecureRandom random) throws GeneralSecurityException { |
|
2135 super(authenticator, protocolVersion); |
|
2136 this.cipher = JsseJce.getCipher(algorithm); |
|
2137 this.tagSize = sslCipher.tagSize; |
|
2138 this.key = key; |
|
2139 this.iv = ((IvParameterSpec)params).getIV(); |
|
2140 this.random = random; |
|
2141 |
|
2142 // DON'T initialize the cipher for AEAD! |
|
2143 } |
|
2144 |
|
2145 @Override |
|
2146 public Plaintext decrypt(byte contentType, ByteBuffer bb, |
|
2147 byte[] sequence) throws GeneralSecurityException { |
|
2148 if (bb.remaining() <= tagSize) { |
|
2149 throw new BadPaddingException( |
|
2150 "Insufficient buffer remaining for AEAD cipher " + |
|
2151 "fragment (" + bb.remaining() + "). Needs to be " + |
|
2152 "more than tag size (" + tagSize + ")"); |
|
2153 } |
|
2154 |
|
2155 byte[] sn = sequence; |
|
2156 if (sn == null) { |
|
2157 sn = authenticator.sequenceNumber(); |
|
2158 } |
|
2159 byte[] nonce = new byte[iv.length]; |
|
2160 System.arraycopy(sn, 0, nonce, nonce.length - sn.length, |
|
2161 sn.length); |
|
2162 for (int i = 0; i < nonce.length; i++) { |
|
2163 nonce[i] ^= iv[i]; |
|
2164 } |
|
2165 |
|
2166 // initialize the AEAD cipher with the unique IV |
|
2167 AlgorithmParameterSpec spec = new IvParameterSpec(nonce); |
|
2168 try { |
|
2169 cipher.init(Cipher.DECRYPT_MODE, key, spec, random); |
|
2170 } catch (InvalidKeyException | |
|
2171 InvalidAlgorithmParameterException ikae) { |
|
2172 // unlikely to happen |
|
2173 throw new RuntimeException( |
|
2174 "invalid key or spec in AEAD mode", ikae); |
|
2175 } |
|
2176 |
|
2177 // update the additional authentication data |
|
2178 byte[] aad = authenticator.acquireAuthenticationBytes( |
|
2179 contentType, bb.remaining() - tagSize, sequence); |
|
2180 cipher.updateAAD(aad); |
|
2181 |
|
2182 // DON'T decrypt the nonce_explicit for AEAD mode. The buffer |
|
2183 // position has moved out of the nonce_explicit range. |
|
2184 int len = bb.remaining(); |
|
2185 int pos = bb.position(); |
|
2186 ByteBuffer dup = bb.duplicate(); |
|
2187 try { |
|
2188 len = cipher.doFinal(dup, bb); |
|
2189 } catch (IllegalBlockSizeException ibse) { |
|
2190 // unlikely to happen |
|
2191 throw new RuntimeException( |
|
2192 "Cipher error in AEAD mode \"" + ibse.getMessage() + |
|
2193 " \"in JCE provider " + cipher.getProvider().getName()); |
|
2194 } catch (ShortBufferException sbe) { |
|
2195 // catch BouncyCastle buffering error |
|
2196 throw new RuntimeException("Cipher buffering error in " + |
|
2197 "JCE provider " + cipher.getProvider().getName(), sbe); |
|
2198 } |
|
2199 // reset the limit to the end of the decrypted data |
|
2200 bb.position(pos); |
|
2201 bb.limit(pos + len); |
|
2202 |
|
2203 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { |
|
2204 SSLLogger.fine( |
|
2205 "Plaintext after DECRYPTION", bb.duplicate()); |
|
2206 } |
|
2207 |
|
2208 return new Plaintext(contentType, |
|
2209 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, |
|
2210 -1, -1L, bb.slice()); |
|
2211 } |
|
2212 |
|
2213 @Override |
|
2214 void dispose() { |
|
2215 if (cipher != null) { |
|
2216 try { |
|
2217 cipher.doFinal(); |
|
2218 } catch (Exception e) { |
|
2219 // swallow all types of exceptions. |
|
2220 } |
|
2221 } |
|
2222 } |
|
2223 |
|
2224 @Override |
|
2225 int estimateFragmentSize(int packetSize, int headerSize) { |
|
2226 return packetSize - headerSize - tagSize; |
|
2227 } |
|
2228 } |
|
2229 } |
|
2230 |
|
2231 private static final class T12CC20P1305WriteCipherGenerator |
|
2232 implements WriteCipherGenerator { |
|
2233 @Override |
|
2234 public SSLWriteCipher createCipher(SSLCipher sslCipher, |
|
2235 Authenticator authenticator, ProtocolVersion protocolVersion, |
|
2236 String algorithm, Key key, AlgorithmParameterSpec params, |
|
2237 SecureRandom random) throws GeneralSecurityException { |
|
2238 return new CC20P1305WriteCipher(authenticator, protocolVersion, |
|
2239 sslCipher, algorithm, key, params, random); |
|
2240 } |
|
2241 |
|
2242 private static final class CC20P1305WriteCipher extends SSLWriteCipher { |
|
2243 private final Cipher cipher; |
|
2244 private final int tagSize; |
|
2245 private final Key key; |
|
2246 private final byte[] iv; |
|
2247 private final SecureRandom random; |
|
2248 |
|
2249 CC20P1305WriteCipher(Authenticator authenticator, |
|
2250 ProtocolVersion protocolVersion, |
|
2251 SSLCipher sslCipher, String algorithm, |
|
2252 Key key, AlgorithmParameterSpec params, |
|
2253 SecureRandom random) throws GeneralSecurityException { |
|
2254 super(authenticator, protocolVersion); |
|
2255 this.cipher = JsseJce.getCipher(algorithm); |
|
2256 this.tagSize = sslCipher.tagSize; |
|
2257 this.key = key; |
|
2258 this.iv = ((IvParameterSpec)params).getIV(); |
|
2259 this.random = random; |
|
2260 |
|
2261 keyLimitCountdown = cipherLimits.getOrDefault( |
|
2262 algorithm.toUpperCase() + ":" + tag[0], 0L); |
|
2263 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { |
|
2264 SSLLogger.fine("algorithm = " + algorithm.toUpperCase() + |
|
2265 ":" + tag[0] + "\ncountdown value = " + |
|
2266 keyLimitCountdown); |
|
2267 } |
|
2268 if (keyLimitCountdown > 0) { |
|
2269 keyLimitEnabled = true; |
|
2270 } |
|
2271 |
|
2272 // DON'T initialize the cipher for AEAD! |
|
2273 } |
|
2274 |
|
2275 @Override |
|
2276 public int encrypt(byte contentType, |
|
2277 ByteBuffer bb) { |
|
2278 byte[] sn = authenticator.sequenceNumber(); |
|
2279 byte[] nonce = new byte[iv.length]; |
|
2280 System.arraycopy(sn, 0, nonce, nonce.length - sn.length, |
|
2281 sn.length); |
|
2282 for (int i = 0; i < nonce.length; i++) { |
|
2283 nonce[i] ^= iv[i]; |
|
2284 } |
|
2285 |
|
2286 // initialize the AEAD cipher for the unique IV |
|
2287 AlgorithmParameterSpec spec = new IvParameterSpec(nonce); |
|
2288 try { |
|
2289 cipher.init(Cipher.ENCRYPT_MODE, key, spec, random); |
|
2290 } catch (InvalidKeyException | |
|
2291 InvalidAlgorithmParameterException ikae) { |
|
2292 // unlikely to happen |
|
2293 throw new RuntimeException( |
|
2294 "invalid key or spec in AEAD mode", ikae); |
|
2295 } |
|
2296 |
|
2297 // Update the additional authentication data, using the |
|
2298 // implicit sequence number of the authenticator. |
|
2299 byte[] aad = authenticator.acquireAuthenticationBytes( |
|
2300 contentType, bb.remaining(), null); |
|
2301 cipher.updateAAD(aad); |
|
2302 |
|
2303 // DON'T encrypt the nonce for AEAD mode. |
|
2304 int len = bb.remaining(); |
|
2305 int pos = bb.position(); |
|
2306 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { |
|
2307 SSLLogger.fine( |
|
2308 "Plaintext before ENCRYPTION", |
|
2309 bb.duplicate()); |
|
2310 } |
|
2311 |
|
2312 ByteBuffer dup = bb.duplicate(); |
|
2313 int outputSize = cipher.getOutputSize(dup.remaining()); |
|
2314 if (outputSize > bb.remaining()) { |
|
2315 // Need to expand the limit of the output buffer for |
|
2316 // the authentication tag. |
|
2317 // |
|
2318 // DON'T worry about the buffer's capacity, we have |
|
2319 // reserved space for the authentication tag. |
|
2320 bb.limit(pos + outputSize); |
|
2321 } |
|
2322 |
|
2323 try { |
|
2324 len = cipher.doFinal(dup, bb); |
|
2325 } catch (IllegalBlockSizeException | |
|
2326 BadPaddingException | ShortBufferException ibse) { |
|
2327 // unlikely to happen |
|
2328 throw new RuntimeException( |
|
2329 "Cipher error in AEAD mode in JCE provider " + |
|
2330 cipher.getProvider().getName(), ibse); |
|
2331 } |
|
2332 |
|
2333 if (len != outputSize) { |
|
2334 throw new RuntimeException( |
|
2335 "Cipher buffering error in JCE provider " + |
|
2336 cipher.getProvider().getName()); |
|
2337 } |
|
2338 |
|
2339 return len; |
|
2340 } |
|
2341 |
|
2342 @Override |
|
2343 void dispose() { |
|
2344 if (cipher != null) { |
|
2345 try { |
|
2346 cipher.doFinal(); |
|
2347 } catch (Exception e) { |
|
2348 // swallow all types of exceptions. |
|
2349 } |
|
2350 } |
|
2351 } |
|
2352 |
|
2353 @Override |
|
2354 int getExplicitNonceSize() { |
|
2355 return 0; |
|
2356 } |
|
2357 |
|
2358 @Override |
|
2359 int calculateFragmentSize(int packetLimit, int headerSize) { |
|
2360 return packetLimit - headerSize - tagSize; |
|
2361 } |
|
2362 |
|
2363 @Override |
|
2364 int calculatePacketSize(int fragmentSize, int headerSize) { |
|
2365 return fragmentSize + headerSize + tagSize; |
|
2366 } |
|
2367 } |
|
2368 } |
|
2369 |
|
2370 private static final class T13CC20P1305ReadCipherGenerator |
|
2371 implements ReadCipherGenerator { |
|
2372 |
|
2373 @Override |
|
2374 public SSLReadCipher createCipher(SSLCipher sslCipher, |
|
2375 Authenticator authenticator, ProtocolVersion protocolVersion, |
|
2376 String algorithm, Key key, AlgorithmParameterSpec params, |
|
2377 SecureRandom random) throws GeneralSecurityException { |
|
2378 return new CC20P1305ReadCipher(authenticator, protocolVersion, |
|
2379 sslCipher, algorithm, key, params, random); |
|
2380 } |
|
2381 |
|
2382 static final class CC20P1305ReadCipher extends SSLReadCipher { |
|
2383 private final Cipher cipher; |
|
2384 private final int tagSize; |
|
2385 private final Key key; |
|
2386 private final byte[] iv; |
|
2387 private final SecureRandom random; |
|
2388 |
|
2389 CC20P1305ReadCipher(Authenticator authenticator, |
|
2390 ProtocolVersion protocolVersion, |
|
2391 SSLCipher sslCipher, String algorithm, |
|
2392 Key key, AlgorithmParameterSpec params, |
|
2393 SecureRandom random) throws GeneralSecurityException { |
|
2394 super(authenticator, protocolVersion); |
|
2395 this.cipher = JsseJce.getCipher(algorithm); |
|
2396 this.tagSize = sslCipher.tagSize; |
|
2397 this.key = key; |
|
2398 this.iv = ((IvParameterSpec)params).getIV(); |
|
2399 this.random = random; |
|
2400 |
|
2401 // DON'T initialize the cipher for AEAD! |
|
2402 } |
|
2403 |
|
2404 @Override |
|
2405 public Plaintext decrypt(byte contentType, ByteBuffer bb, |
|
2406 byte[] sequence) throws GeneralSecurityException { |
|
2407 // An implementation may receive an unencrypted record of type |
|
2408 // change_cipher_spec consisting of the single byte value 0x01 |
|
2409 // at any time after the first ClientHello message has been |
|
2410 // sent or received and before the peer's Finished message has |
|
2411 // been received and MUST simply drop it without further |
|
2412 // processing. |
|
2413 if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) { |
|
2414 return new Plaintext(contentType, |
|
2415 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, |
|
2416 -1, -1L, bb.slice()); |
|
2417 } |
|
2418 |
|
2419 if (bb.remaining() <= tagSize) { |
|
2420 throw new BadPaddingException( |
|
2421 "Insufficient buffer remaining for AEAD cipher " + |
|
2422 "fragment (" + bb.remaining() + "). Needs to be " + |
|
2423 "more than tag size (" + tagSize + ")"); |
|
2424 } |
|
2425 |
|
2426 byte[] sn = sequence; |
|
2427 if (sn == null) { |
|
2428 sn = authenticator.sequenceNumber(); |
|
2429 } |
|
2430 byte[] nonce = new byte[iv.length]; |
|
2431 System.arraycopy(sn, 0, nonce, nonce.length - sn.length, |
|
2432 sn.length); |
|
2433 for (int i = 0; i < nonce.length; i++) { |
|
2434 nonce[i] ^= iv[i]; |
|
2435 } |
|
2436 |
|
2437 // initialize the AEAD cipher with the unique IV |
|
2438 AlgorithmParameterSpec spec = new IvParameterSpec(nonce); |
|
2439 try { |
|
2440 cipher.init(Cipher.DECRYPT_MODE, key, spec, random); |
|
2441 } catch (InvalidKeyException | |
|
2442 InvalidAlgorithmParameterException ikae) { |
|
2443 // unlikely to happen |
|
2444 throw new RuntimeException( |
|
2445 "invalid key or spec in AEAD mode", ikae); |
|
2446 } |
|
2447 |
|
2448 // Update the additional authentication data, using the |
|
2449 // implicit sequence number of the authenticator. |
|
2450 byte[] aad = authenticator.acquireAuthenticationBytes( |
|
2451 contentType, bb.remaining(), sn); |
|
2452 cipher.updateAAD(aad); |
|
2453 |
|
2454 int len = bb.remaining(); |
|
2455 int pos = bb.position(); |
|
2456 ByteBuffer dup = bb.duplicate(); |
|
2457 try { |
|
2458 len = cipher.doFinal(dup, bb); |
|
2459 } catch (IllegalBlockSizeException ibse) { |
|
2460 // unlikely to happen |
|
2461 throw new RuntimeException( |
|
2462 "Cipher error in AEAD mode \"" + ibse.getMessage() + |
|
2463 " \"in JCE provider " + cipher.getProvider().getName()); |
|
2464 } catch (ShortBufferException sbe) { |
|
2465 // catch BouncyCastle buffering error |
|
2466 throw new RuntimeException("Cipher buffering error in " + |
|
2467 "JCE provider " + cipher.getProvider().getName(), sbe); |
|
2468 } |
|
2469 // reset the limit to the end of the decrypted data |
|
2470 bb.position(pos); |
|
2471 bb.limit(pos + len); |
|
2472 |
|
2473 // remove inner plaintext padding |
|
2474 int i = bb.limit() - 1; |
|
2475 for (; i > 0 && bb.get(i) == 0; i--) { |
|
2476 // blank |
|
2477 } |
|
2478 if (i < (pos + 1)) { |
|
2479 throw new BadPaddingException( |
|
2480 "Incorrect inner plaintext: no content type"); |
|
2481 } |
|
2482 contentType = bb.get(i); |
|
2483 bb.limit(i); |
|
2484 |
|
2485 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { |
|
2486 SSLLogger.fine( |
|
2487 "Plaintext after DECRYPTION", bb.duplicate()); |
|
2488 } |
|
2489 |
|
2490 return new Plaintext(contentType, |
|
2491 ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor, |
|
2492 -1, -1L, bb.slice()); |
|
2493 } |
|
2494 |
|
2495 @Override |
|
2496 void dispose() { |
|
2497 if (cipher != null) { |
|
2498 try { |
|
2499 cipher.doFinal(); |
|
2500 } catch (Exception e) { |
|
2501 // swallow all types of exceptions. |
|
2502 } |
|
2503 } |
|
2504 } |
|
2505 |
|
2506 @Override |
|
2507 int estimateFragmentSize(int packetSize, int headerSize) { |
|
2508 return packetSize - headerSize - tagSize; |
|
2509 } |
|
2510 } |
|
2511 } |
|
2512 |
|
2513 private static final class T13CC20P1305WriteCipherGenerator |
|
2514 implements WriteCipherGenerator { |
|
2515 @Override |
|
2516 public SSLWriteCipher createCipher(SSLCipher sslCipher, |
|
2517 Authenticator authenticator, ProtocolVersion protocolVersion, |
|
2518 String algorithm, Key key, AlgorithmParameterSpec params, |
|
2519 SecureRandom random) throws GeneralSecurityException { |
|
2520 return new CC20P1305WriteCipher(authenticator, protocolVersion, |
|
2521 sslCipher, algorithm, key, params, random); |
|
2522 } |
|
2523 |
|
2524 private static final class CC20P1305WriteCipher extends SSLWriteCipher { |
|
2525 private final Cipher cipher; |
|
2526 private final int tagSize; |
|
2527 private final Key key; |
|
2528 private final byte[] iv; |
|
2529 private final SecureRandom random; |
|
2530 |
|
2531 CC20P1305WriteCipher(Authenticator authenticator, |
|
2532 ProtocolVersion protocolVersion, |
|
2533 SSLCipher sslCipher, String algorithm, |
|
2534 Key key, AlgorithmParameterSpec params, |
|
2535 SecureRandom random) throws GeneralSecurityException { |
|
2536 super(authenticator, protocolVersion); |
|
2537 this.cipher = JsseJce.getCipher(algorithm); |
|
2538 this.tagSize = sslCipher.tagSize; |
|
2539 this.key = key; |
|
2540 this.iv = ((IvParameterSpec)params).getIV(); |
|
2541 this.random = random; |
|
2542 |
|
2543 keyLimitCountdown = cipherLimits.getOrDefault( |
|
2544 algorithm.toUpperCase() + ":" + tag[0], 0L); |
|
2545 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { |
|
2546 SSLLogger.fine("algorithm = " + algorithm.toUpperCase() + |
|
2547 ":" + tag[0] + "\ncountdown value = " + |
|
2548 keyLimitCountdown); |
|
2549 } |
|
2550 if (keyLimitCountdown > 0) { |
|
2551 keyLimitEnabled = true; |
|
2552 } |
|
2553 |
|
2554 // DON'T initialize the cipher for AEAD! |
|
2555 } |
|
2556 |
|
2557 @Override |
|
2558 public int encrypt(byte contentType, |
|
2559 ByteBuffer bb) { |
|
2560 byte[] sn = authenticator.sequenceNumber(); |
|
2561 byte[] nonce = new byte[iv.length]; |
|
2562 System.arraycopy(sn, 0, nonce, nonce.length - sn.length, |
|
2563 sn.length); |
|
2564 for (int i = 0; i < nonce.length; i++) { |
|
2565 nonce[i] ^= iv[i]; |
|
2566 } |
|
2567 |
|
2568 // initialize the AEAD cipher for the unique IV |
|
2569 AlgorithmParameterSpec spec = new IvParameterSpec(nonce); |
|
2570 try { |
|
2571 cipher.init(Cipher.ENCRYPT_MODE, key, spec, random); |
|
2572 } catch (InvalidKeyException | |
|
2573 InvalidAlgorithmParameterException ikae) { |
|
2574 // unlikely to happen |
|
2575 throw new RuntimeException( |
|
2576 "invalid key or spec in AEAD mode", ikae); |
|
2577 } |
|
2578 |
|
2579 // Update the additional authentication data, using the |
|
2580 // implicit sequence number of the authenticator. |
|
2581 int outputSize = cipher.getOutputSize(bb.remaining()); |
|
2582 byte[] aad = authenticator.acquireAuthenticationBytes( |
|
2583 contentType, outputSize, sn); |
|
2584 cipher.updateAAD(aad); |
|
2585 |
|
2586 int len = bb.remaining(); |
|
2587 int pos = bb.position(); |
|
2588 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { |
|
2589 SSLLogger.fine( |
|
2590 "Plaintext before ENCRYPTION", |
|
2591 bb.duplicate()); |
|
2592 } |
|
2593 |
|
2594 ByteBuffer dup = bb.duplicate(); |
|
2595 if (outputSize > bb.remaining()) { |
|
2596 // Need to expand the limit of the output buffer for |
|
2597 // the authentication tag. |
|
2598 // |
|
2599 // DON'T worry about the buffer's capacity, we have |
|
2600 // reserved space for the authentication tag. |
|
2601 bb.limit(pos + outputSize); |
|
2602 } |
|
2603 |
|
2604 try { |
|
2605 len = cipher.doFinal(dup, bb); |
|
2606 } catch (IllegalBlockSizeException | |
|
2607 BadPaddingException | ShortBufferException ibse) { |
|
2608 // unlikely to happen |
|
2609 throw new RuntimeException( |
|
2610 "Cipher error in AEAD mode in JCE provider " + |
|
2611 cipher.getProvider().getName(), ibse); |
|
2612 } |
|
2613 |
|
2614 if (len != outputSize) { |
|
2615 throw new RuntimeException( |
|
2616 "Cipher buffering error in JCE provider " + |
|
2617 cipher.getProvider().getName()); |
|
2618 } |
|
2619 |
|
2620 if (keyLimitEnabled) { |
|
2621 keyLimitCountdown -= len; |
|
2622 } |
|
2623 return len; |
|
2624 } |
|
2625 |
|
2626 @Override |
|
2627 void dispose() { |
|
2628 if (cipher != null) { |
|
2629 try { |
|
2630 cipher.doFinal(); |
|
2631 } catch (Exception e) { |
|
2632 // swallow all types of exceptions. |
|
2633 } |
|
2634 } |
|
2635 } |
|
2636 |
|
2637 @Override |
|
2638 int getExplicitNonceSize() { |
|
2639 return 0; |
|
2640 } |
|
2641 |
|
2642 @Override |
|
2643 int calculateFragmentSize(int packetLimit, int headerSize) { |
|
2644 return packetLimit - headerSize - tagSize; |
|
2645 } |
|
2646 |
|
2647 @Override |
|
2648 int calculatePacketSize(int fragmentSize, int headerSize) { |
|
2649 return fragmentSize + headerSize + tagSize; |
|
2650 } |
|
2651 } |
|
2652 } |
|
2653 |
2085 private static void addMac(MAC signer, |
2654 private static void addMac(MAC signer, |
2086 ByteBuffer destination, byte contentType) { |
2655 ByteBuffer destination, byte contentType) { |
2087 if (signer.macAlg().size != 0) { |
2656 if (signer.macAlg().size != 0) { |
2088 int dstContent = destination.position(); |
2657 int dstContent = destination.position(); |
2089 byte[] hash = signer.compute(contentType, destination, false); |
2658 byte[] hash = signer.compute(contentType, destination, false); |