src/java.base/share/classes/sun/security/ssl/InputRecord.java
changeset 50768 68fa3d4026ea
parent 47216 71c04702a3d5
child 54443 dfba4e321ab3
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
     1 /*
     1 /*
     2  * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package sun.security.ssl;
    26 package sun.security.ssl;
    27 
    27 
    28 import java.io.*;
    28 import java.io.Closeable;
    29 import java.nio.*;
    29 import java.io.IOException;
    30 import java.util.*;
    30 import java.io.InputStream;
    31 
    31 import java.io.OutputStream;
       
    32 import java.nio.BufferUnderflowException;
       
    33 import java.nio.ByteBuffer;
    32 import javax.crypto.BadPaddingException;
    34 import javax.crypto.BadPaddingException;
    33 
    35 import sun.security.ssl.SSLCipher.SSLReadCipher;
    34 import javax.net.ssl.*;
       
    35 
       
    36 import sun.security.util.HexDumpEncoder;
       
    37 
       
    38 
    36 
    39 /**
    37 /**
    40  * {@code InputRecord} takes care of the management of SSL/TLS/DTLS input
    38  * {@code InputRecord} takes care of the management of SSL/TLS/DTLS input
    41  * records, including buffering, decryption, handshake messages marshal, etc.
    39  * records, including buffering, decryption, handshake messages marshal, etc.
    42  *
    40  *
    43  * @author David Brownell
    41  * @author David Brownell
    44  */
    42  */
    45 class InputRecord implements Record, Closeable {
    43 abstract class InputRecord implements Record, Closeable {
    46 
    44     SSLReadCipher       readCipher;
    47     /* Class and subclass dynamic debugging support */
    45     // Needed for KeyUpdate, used after Handshake.Finished
    48     static final Debug debug = Debug.getInstance("ssl");
    46     TransportContext            tc;
    49 
    47 
    50     Authenticator       readAuthenticator;
    48     final HandshakeHash handshakeHash;
    51     CipherBox           readCipher;
       
    52 
       
    53     HandshakeHash       handshakeHash;
       
    54     boolean             isClosed;
    49     boolean             isClosed;
    55 
    50 
    56     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
    51     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
    57     // and the first message we read is a ClientHello in V2 format, we convert
    52     // and the first message we read is a ClientHello in V2 format, we convert
    58     // it to V3. Otherwise we throw an exception when encountering a V2 hello.
    53     // it to V3. Otherwise we throw an exception when encountering a V2 hello.
    59     ProtocolVersion     helloVersion;
    54     ProtocolVersion     helloVersion;
    60 
    55 
    61     // fragment size
    56     // fragment size
    62     int                 fragmentSize;
    57     int                 fragmentSize;
    63 
    58 
    64     InputRecord() {
    59     InputRecord(HandshakeHash handshakeHash, SSLReadCipher readCipher) {
    65         this.readCipher = CipherBox.NULL;
    60         this.readCipher = readCipher;
    66         this.readAuthenticator = null;      // Please override this assignment.
    61         this.helloVersion = ProtocolVersion.TLS10;
    67         this.helloVersion = ProtocolVersion.DEFAULT_HELLO;
    62         this.handshakeHash = handshakeHash;
       
    63         this.isClosed = false;
    68         this.fragmentSize = Record.maxDataSize;
    64         this.fragmentSize = Record.maxDataSize;
    69     }
    65     }
    70 
    66 
    71     void setHelloVersion(ProtocolVersion helloVersion) {
    67     void setHelloVersion(ProtocolVersion helloVersion) {
    72         this.helloVersion = helloVersion;
    68         this.helloVersion = helloVersion;
    73     }
    69     }
    74 
    70 
    75     ProtocolVersion getHelloVersion() {
       
    76         return helloVersion;
       
    77     }
       
    78 
       
    79     /*
       
    80      * Set instance for the computation of handshake hashes.
       
    81      *
       
    82      * For handshaking, we need to be able to hash every byte above the
       
    83      * record marking layer.  This is where we're guaranteed to see those
       
    84      * bytes, so this is where we can hash them ... especially in the
       
    85      * case of hashing the initial V2 message!
       
    86      */
       
    87     void setHandshakeHash(HandshakeHash handshakeHash) {
       
    88         if (handshakeHash != null) {
       
    89             byte[] reserved = null;
       
    90             if (this.handshakeHash != null) {
       
    91                 reserved = this.handshakeHash.getAllHandshakeMessages();
       
    92             }
       
    93             if ((reserved != null) && (reserved.length != 0)) {
       
    94                 handshakeHash.update(reserved, 0, reserved.length);
       
    95 
       
    96                if (debug != null && Debug.isOn("data")) {
       
    97                     Debug.printHex(
       
    98                         "[reserved] handshake hash: len = " + reserved.length,
       
    99                         reserved);
       
   100                }
       
   101             }
       
   102         }
       
   103 
       
   104         this.handshakeHash = handshakeHash;
       
   105     }
       
   106 
       
   107     boolean seqNumIsHuge() {
    71     boolean seqNumIsHuge() {
   108         return (readAuthenticator != null) &&
    72         return (readCipher.authenticator != null) &&
   109                         readAuthenticator.seqNumIsHuge();
    73                         readCipher.authenticator.seqNumIsHuge();
   110     }
    74     }
   111 
    75 
   112     boolean isEmpty() {
    76     boolean isEmpty() {
   113         return false;
    77         return false;
   114     }
    78     }
   115 
    79 
   116     // apply to DTLS SSLEngine
    80     // apply to DTLS SSLEngine
   117     void expectingFinishFlight() {
    81     void expectingFinishFlight() {
       
    82         // blank
       
    83     }
       
    84 
       
    85     // apply to DTLS SSLEngine
       
    86     void finishHandshake() {
   118         // blank
    87         // blank
   119     }
    88     }
   120 
    89 
   121     /**
    90     /**
   122      * Prevent any more data from being read into this record,
    91      * Prevent any more data from being read into this record,
   128             isClosed = true;
    97             isClosed = true;
   129             readCipher.dispose();
    98             readCipher.dispose();
   130         }
    99         }
   131     }
   100     }
   132 
   101 
       
   102     synchronized boolean isClosed() {
       
   103         return isClosed;
       
   104     }
       
   105 
   133     // apply to SSLSocket and SSLEngine
   106     // apply to SSLSocket and SSLEngine
   134     void changeReadCiphers(
   107     void changeReadCiphers(SSLReadCipher readCipher) {
   135             Authenticator readAuthenticator, CipherBox readCipher) {
       
   136 
   108 
   137         /*
   109         /*
   138          * Dispose of any intermediate state in the underlying cipher.
   110          * Dispose of any intermediate state in the underlying cipher.
   139          * For PKCS11 ciphers, this will release any attached sessions,
   111          * For PKCS11 ciphers, this will release any attached sessions,
   140          * and thus make finalization faster.
   112          * and thus make finalization faster.
   142          * Since MAC's doFinal() is called for every SSL/TLS packet, it's
   114          * Since MAC's doFinal() is called for every SSL/TLS packet, it's
   143          * not necessary to do the same with MAC's.
   115          * not necessary to do the same with MAC's.
   144          */
   116          */
   145         readCipher.dispose();
   117         readCipher.dispose();
   146 
   118 
   147         this.readAuthenticator = readAuthenticator;
       
   148         this.readCipher = readCipher;
   119         this.readCipher = readCipher;
   149     }
   120     }
   150 
   121 
   151     // change fragment size
   122     // change fragment size
   152     void changeFragmentSize(int fragmentSize) {
   123     void changeFragmentSize(int fragmentSize) {
   158      * a inbound packet.
   129      * a inbound packet.
   159      *
   130      *
   160      * @return -1 if there are not enough bytes to tell (small header),
   131      * @return -1 if there are not enough bytes to tell (small header),
   161      */
   132      */
   162     // apply to SSLEngine only
   133     // apply to SSLEngine only
   163     int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
   134     int bytesInCompletePacket(
   164         throw new UnsupportedOperationException();
   135         ByteBuffer[] srcs, int srcsOffset, int srcsLength) throws IOException {
       
   136 
       
   137         throw new UnsupportedOperationException("Not supported yet.");
   165     }
   138     }
   166 
   139 
   167     // apply to SSLSocket only
   140     // apply to SSLSocket only
   168     int bytesInCompletePacket(InputStream is) throws IOException {
   141     int bytesInCompletePacket() throws IOException {
   169         throw new UnsupportedOperationException();
   142         throw new UnsupportedOperationException();
   170     }
   143     }
   171 
   144 
   172     /**
   145     // apply to SSLSocket only
   173      * Return true if the specified record protocol version is out of the
   146     void setReceiverStream(InputStream inputStream) {
   174      * range of the possible supported versions.
   147         throw new UnsupportedOperationException();
   175      */
       
   176     void checkRecordVersion(ProtocolVersion version,
       
   177             boolean allowSSL20Hello) throws SSLException {
       
   178         // blank
       
   179     }
   148     }
   180 
   149 
   181     // apply to DTLS SSLEngine only
   150     // apply to DTLS SSLEngine only
   182     Plaintext acquirePlaintext()
   151     Plaintext acquirePlaintext()
   183             throws IOException, BadPaddingException {
   152             throws IOException, BadPaddingException {
   184         throw new UnsupportedOperationException();
   153         throw new UnsupportedOperationException();
   185     }
   154     }
   186 
   155 
   187     // read, decrypt and decompress the network record.
   156     // read, decrypt and decompress the network record.
   188     //
   157     //
   189     // apply to SSLEngine only
   158     abstract Plaintext[] decode(ByteBuffer[] srcs, int srcsOffset,
   190     Plaintext decode(ByteBuffer netData)
   159             int srcsLength) throws IOException, BadPaddingException;
   191             throws IOException, BadPaddingException {
       
   192         throw new UnsupportedOperationException();
       
   193     }
       
   194 
       
   195     // apply to SSLSocket only
       
   196     Plaintext decode(InputStream is, ByteBuffer destination)
       
   197             throws IOException, BadPaddingException {
       
   198         throw new UnsupportedOperationException();
       
   199     }
       
   200 
   160 
   201     // apply to SSLSocket only
   161     // apply to SSLSocket only
   202     void setDeliverStream(OutputStream outputStream) {
   162     void setDeliverStream(OutputStream outputStream) {
   203         throw new UnsupportedOperationException();
   163         throw new UnsupportedOperationException();
   204     }
   164     }
   214     // shared helpers
   174     // shared helpers
   215     //
   175     //
   216 
   176 
   217     // Not apply to DTLS
   177     // Not apply to DTLS
   218     static ByteBuffer convertToClientHello(ByteBuffer packet) {
   178     static ByteBuffer convertToClientHello(ByteBuffer packet) {
   219 
       
   220         int srcPos = packet.position();
   179         int srcPos = packet.position();
   221         int srcLim = packet.limit();
       
   222 
   180 
   223         byte firstByte = packet.get();
   181         byte firstByte = packet.get();
   224         byte secondByte = packet.get();
   182         byte secondByte = packet.get();
   225         int recordLen = (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2;
   183         int recordLen = (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2;
   226 
   184 
   242         //  2: ClientHello.client_version
   200         //  2: ClientHello.client_version
   243         // 32: ClientHello.random
   201         // 32: ClientHello.random
   244         //  1: length byte of ClientHello.session_id
   202         //  1: length byte of ClientHello.session_id
   245         //  2: length bytes of ClientHello.cipher_suites
   203         //  2: length bytes of ClientHello.cipher_suites
   246         //  2: empty ClientHello.compression_methods
   204         //  2: empty ClientHello.compression_methods
   247         int requiredSize = 48 + sessionIdLen + ((cipherSpecLen * 2 ) / 3 );
   205         int requiredSize = 48 + sessionIdLen + ((cipherSpecLen * 2 ) / 3);
   248         byte[] converted = new byte[requiredSize];
   206         byte[] converted = new byte[requiredSize];
   249 
   207 
   250         /*
   208         /*
   251          * Build the first part of the V3 record header from the V2 one
   209          * Build the first part of the V3 record header from the V2 one
   252          * that's now buffered up.  (Lengths are fixed up later).
   210          * that's now buffered up.  (Lengths are fixed up later).
   253          */
   211          */
   254         // Note: need not to set the header actually.
   212         // Note: need not to set the header actually.
   255         converted[0] = ct_handshake;
   213         converted[0] = ContentType.HANDSHAKE.id;
   256         converted[1] = majorVersion;
   214         converted[1] = majorVersion;
   257         converted[2] = minorVersion;
   215         converted[2] = minorVersion;
   258         // header [3..4] for handshake message length
   216         // header [3..4] for handshake message length
   259         // required size is 5;
   217         // required size is 5;
   260 
   218 
   323         packet.position(offset);
   281         packet.position(offset);
   324 
   282 
   325         j = pointer + 2;
   283         j = pointer + 2;
   326         for (int i = 0; i < cipherSpecLen; i += 3) {
   284         for (int i = 0; i < cipherSpecLen; i += 3) {
   327             if (packet.get() != 0) {
   285             if (packet.get() != 0) {
   328                 // Ignore version 2.0 specifix cipher suite.  Clients
   286                 // Ignore version 2.0 specific cipher suite.  Clients
   329                 // should also include the version 3.0 equivalent in
   287                 // should also include the version 3.0 equivalent in
   330                 // the V2ClientHello message.
   288                 // the V2ClientHello message.
   331                 packet.get();           // ignore the 2nd byte
   289                 packet.get();           // ignore the 2nd byte
   332                 packet.get();           // ignore the 3rd byte
   290                 packet.get();           // ignore the 3rd byte
   333                 continue;
   291                 continue;
   370 
   328 
   371         // Need no header bytes.
   329         // Need no header bytes.
   372         return ByteBuffer.wrap(converted, 5, pointer - 5);  // 5: header size
   330         return ByteBuffer.wrap(converted, 5, pointer - 5);  // 5: header size
   373     }
   331     }
   374 
   332 
   375     static ByteBuffer decrypt(Authenticator authenticator, CipherBox box,
   333     // Extract an SSL/(D)TLS record from the specified source buffers.
   376             byte contentType, ByteBuffer bb) throws BadPaddingException {
   334     static ByteBuffer extract(
   377 
   335             ByteBuffer[] buffers, int offset, int length, int headerSize) {
   378         return decrypt(authenticator, box, contentType, bb, null);
   336 
   379     }
   337         boolean hasFullHeader = false;
   380 
   338         int contentLen = -1;
   381     static ByteBuffer decrypt(Authenticator authenticator,
   339         for (int i = offset, j = 0;
   382             CipherBox box, byte contentType, ByteBuffer bb,
   340                 i < (offset + length) && j < headerSize; i++) {
   383             byte[] sequence) throws BadPaddingException {
   341             int remains = buffers[i].remaining();
   384 
   342             int pos = buffers[i].position();
   385         BadPaddingException reservedBPE = null;
   343             for (int k = 0; k < remains && j < headerSize; j++, k++) {
   386         int tagLen =
   344                 byte b = buffers[i].get(pos + k);
   387             (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
   345                 if (j == (headerSize - 2)) {
   388         int cipheredLength = bb.remaining();
   346                     contentLen = ((b & 0xFF) << 8);
   389         int srcPos = bb.position();
   347                 } else if (j == (headerSize -1)) {
   390         if (!box.isNullCipher()) {
   348                     contentLen |= (b & 0xFF);
   391             try {
   349                     hasFullHeader = true;
   392                 // apply explicit nonce for AEAD/CBC cipher suites if needed
   350                     break;
   393                 int nonceSize = box.applyExplicitNonce(
       
   394                         authenticator, contentType, bb, sequence);
       
   395 
       
   396                 // decrypt the content
       
   397                 if (box.isAEADMode()) {
       
   398                     // DON'T decrypt the nonce_explicit for AEAD mode
       
   399                     bb.position(srcPos + nonceSize);
       
   400                 }   // The explicit IV for CBC mode can be decrypted.
       
   401 
       
   402                 // Note that the CipherBox.decrypt() does not change
       
   403                 // the capacity of the buffer.
       
   404                 box.decrypt(bb, tagLen);
       
   405                 // We don't actually remove the nonce.
       
   406                 bb.position(srcPos + nonceSize);
       
   407             } catch (BadPaddingException bpe) {
       
   408                 // RFC 2246 states that decryption_failed should be used
       
   409                 // for this purpose. However, that allows certain attacks,
       
   410                 // so we just send bad record MAC. We also need to make
       
   411                 // sure to always check the MAC to avoid a timing attack
       
   412                 // for the same issue. See paper by Vaudenay et al and the
       
   413                 // update in RFC 4346/5246.
       
   414                 //
       
   415                 // Failover to message authentication code checking.
       
   416                 reservedBPE = bpe;
       
   417             }
       
   418         }
       
   419 
       
   420         // Requires message authentication code for null, stream and block
       
   421         // cipher suites.
       
   422         if ((authenticator instanceof MAC) && (tagLen != 0)) {
       
   423             MAC signer = (MAC)authenticator;
       
   424             int contentLen = bb.remaining() - tagLen;
       
   425 
       
   426             // Note that although it is not necessary, we run the same MAC
       
   427             // computation and comparison on the payload for both stream
       
   428             // cipher and CBC block cipher.
       
   429             if (contentLen < 0) {
       
   430                 // negative data length, something is wrong
       
   431                 if (reservedBPE == null) {
       
   432                     reservedBPE = new BadPaddingException("bad record");
       
   433                 }
   351                 }
   434 
   352             }
   435                 // set offset of the dummy MAC
   353         }
   436                 contentLen = cipheredLength - tagLen;
   354 
   437                 bb.limit(srcPos + cipheredLength);
   355         if (!hasFullHeader) {
   438             }
   356             throw new BufferUnderflowException();
   439 
   357         }
   440             // Run MAC computation and comparison on the payload.
   358 
   441             //
   359         int packetLen = headerSize + contentLen;
   442             // MAC data would be stripped off during the check.
   360         int remains = 0;
   443             if (checkMacTags(contentType, bb, signer, sequence, false)) {
   361         for (int i = offset; i < offset + length; i++) {
   444                 if (reservedBPE == null) {
   362             remains += buffers[i].remaining();
   445                     reservedBPE = new BadPaddingException("bad record MAC");
   363             if (remains >= packetLen) {
   446                 }
   364                 break;
   447             }
   365             }
   448 
   366         }
   449             // Run MAC computation and comparison on the remainder.
   367 
   450             //
   368         if (remains < packetLen) {
   451             // It is only necessary for CBC block cipher.  It is used to get a
   369             throw new BufferUnderflowException();
   452             // constant time of MAC computation and comparison on each record.
   370         }
   453             if (box.isCBCMode()) {
   371 
   454                 int remainingLen = calculateRemainingLen(
   372         byte[] packet = new byte[packetLen];
   455                                         signer, cipheredLength, contentLen);
   373         int packetOffset = 0;
   456 
   374         int packetSpaces = packetLen;
   457                 // NOTE: remainingLen may be bigger (less than 1 block of the
   375         for (int i = offset; i < offset + length; i++) {
   458                 // hash algorithm of the MAC) than the cipheredLength.
   376             if (buffers[i].hasRemaining()) {
   459                 //
   377                 int len = Math.min(packetSpaces, buffers[i].remaining());
   460                 // Is it possible to use a static buffer, rather than allocate
   378                 buffers[i].get(packet, packetOffset, len);
   461                 // it dynamically?
   379                 packetOffset += len;
   462                 remainingLen += signer.MAClen();
   380                 packetSpaces -= len;
   463                 ByteBuffer temporary = ByteBuffer.allocate(remainingLen);
   381             }
   464 
   382 
   465                 // Won't need to worry about the result on the remainder. And
   383             if (packetSpaces <= 0) {
   466                 // then we won't need to worry about what's actual data to
   384                 break;
   467                 // check MAC tag on.  We start the check from the header of the
   385             }
   468                 // buffer so that we don't need to construct a new byte buffer.
   386         }
   469                 checkMacTags(contentType, temporary, signer, sequence, true);
   387 
   470             }
   388         return ByteBuffer.wrap(packet);
   471         }
       
   472 
       
   473         // Is it a failover?
       
   474         if (reservedBPE != null) {
       
   475             throw reservedBPE;
       
   476         }
       
   477 
       
   478         return bb.slice();
       
   479     }
       
   480 
       
   481     /*
       
   482      * Run MAC computation and comparison
       
   483      *
       
   484      */
       
   485     private static boolean checkMacTags(byte contentType, ByteBuffer bb,
       
   486             MAC signer, byte[] sequence, boolean isSimulated) {
       
   487 
       
   488         int tagLen = signer.MAClen();
       
   489         int position = bb.position();
       
   490         int lim = bb.limit();
       
   491         int macOffset = lim - tagLen;
       
   492 
       
   493         bb.limit(macOffset);
       
   494         byte[] hash = signer.compute(contentType, bb, sequence, isSimulated);
       
   495         if (hash == null || tagLen != hash.length) {
       
   496             // Something is wrong with MAC implementation.
       
   497             throw new RuntimeException("Internal MAC error");
       
   498         }
       
   499 
       
   500         bb.position(macOffset);
       
   501         bb.limit(lim);
       
   502         try {
       
   503             int[] results = compareMacTags(bb, hash);
       
   504             return (results[0] != 0);
       
   505         } finally {
       
   506             // reset to the data
       
   507             bb.position(position);
       
   508             bb.limit(macOffset);
       
   509         }
       
   510     }
       
   511 
       
   512     /*
       
   513      * A constant-time comparison of the MAC tags.
       
   514      *
       
   515      * Please DON'T change the content of the ByteBuffer parameter!
       
   516      */
       
   517     private static int[] compareMacTags(ByteBuffer bb, byte[] tag) {
       
   518 
       
   519         // An array of hits is used to prevent Hotspot optimization for
       
   520         // the purpose of a constant-time check.
       
   521         int[] results = {0, 0};     // {missed #, matched #}
       
   522 
       
   523         // The caller ensures there are enough bytes available in the buffer.
       
   524         // So we won't need to check the remaining of the buffer.
       
   525         for (int i = 0; i < tag.length; i++) {
       
   526             if (bb.get() != tag[i]) {
       
   527                 results[0]++;       // mismatched bytes
       
   528             } else {
       
   529                 results[1]++;       // matched bytes
       
   530             }
       
   531         }
       
   532 
       
   533         return results;
       
   534     }
       
   535 
       
   536     /*
       
   537      * Run MAC computation and comparison
       
   538      *
       
   539      * Please DON'T change the content of the byte buffer parameter!
       
   540      */
       
   541     private static boolean checkMacTags(byte contentType, byte[] buffer,
       
   542             int offset, int contentLen, MAC signer, boolean isSimulated) {
       
   543 
       
   544         int tagLen = signer.MAClen();
       
   545         byte[] hash = signer.compute(
       
   546                 contentType, buffer, offset, contentLen, isSimulated);
       
   547         if (hash == null || tagLen != hash.length) {
       
   548             // Something is wrong with MAC implementation.
       
   549             throw new RuntimeException("Internal MAC error");
       
   550         }
       
   551 
       
   552         int[] results = compareMacTags(buffer, offset + contentLen, hash);
       
   553         return (results[0] != 0);
       
   554     }
       
   555 
       
   556     /*
       
   557      * A constant-time comparison of the MAC tags.
       
   558      *
       
   559      * Please DON'T change the content of the byte buffer parameter!
       
   560      */
       
   561     private static int[] compareMacTags(
       
   562             byte[] buffer, int offset, byte[] tag) {
       
   563 
       
   564         // An array of hits is used to prevent Hotspot optimization for
       
   565         // the purpose of a constant-time check.
       
   566         int[] results = {0, 0};    // {missed #, matched #}
       
   567 
       
   568         // The caller ensures there are enough bytes available in the buffer.
       
   569         // So we won't need to check the length of the buffer.
       
   570         for (int i = 0; i < tag.length; i++) {
       
   571             if (buffer[offset + i] != tag[i]) {
       
   572                 results[0]++;       // mismatched bytes
       
   573             } else {
       
   574                 results[1]++;       // matched bytes
       
   575             }
       
   576         }
       
   577 
       
   578         return results;
       
   579     }
       
   580 
       
   581     /*
       
   582      * Calculate the length of a dummy buffer to run MAC computation
       
   583      * and comparison on the remainder.
       
   584      *
       
   585      * The caller MUST ensure that the fullLen is not less than usedLen.
       
   586      */
       
   587     private static int calculateRemainingLen(
       
   588             MAC signer, int fullLen, int usedLen) {
       
   589 
       
   590         int blockLen = signer.hashBlockLen();
       
   591         int minimalPaddingLen = signer.minimalPaddingLen();
       
   592 
       
   593         // (blockLen - minimalPaddingLen) is the maximum message size of
       
   594         // the last block of hash function operation. See FIPS 180-4, or
       
   595         // MD5 specification.
       
   596         fullLen += 13 - (blockLen - minimalPaddingLen);
       
   597         usedLen += 13 - (blockLen - minimalPaddingLen);
       
   598 
       
   599         // Note: fullLen is always not less than usedLen, and blockLen
       
   600         // is always bigger than minimalPaddingLen, so we don't worry
       
   601         // about negative values. 0x01 is added to the result to ensure
       
   602         // that the return value is positive.  The extra one byte does
       
   603         // not impact the overall MAC compression function evaluations.
       
   604         return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
       
   605                 Math.ceil(usedLen/(1.0d * blockLen))) * blockLen;
       
   606     }
   389     }
   607 }
   390 }
   608