1 /* 2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 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 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.provider; 27 28 import java.security.MessageDigestSpi; 29 import java.security.DigestException; 30 import java.security.ProviderException; 31 32 /** 33 * Common base message digest implementation for the Sun provider. 34 * It implements all the JCA methods as suitable for a Java message digest 35 * implementation of an algorithm based on a compression function (as all 36 * commonly used algorithms are). The individual digest subclasses only need to 37 * implement the following methods: 38 * 39 * . abstract void implCompress(byte[] b, int ofs); 40 * . abstract void implDigest(byte[] out, int ofs); 41 * . abstract void implReset(); 42 * 43 * See the inline documentation for details. 44 * 45 * @since 1.5 46 * @author Andreas Sterbenz 47 */ 48 abstract class DigestBase extends MessageDigestSpi implements Cloneable { 49 50 // one element byte array, temporary storage for update(byte) 51 private byte[] oneByte; 52 53 // algorithm name to use in the exception message 54 private final String algorithm; 55 // length of the message digest in bytes 56 private final int digestLength; 57 58 // size of the input to the compression function in bytes 59 private final int blockSize; 60 // buffer to store partial blocks, blockSize bytes large 61 // Subclasses should not access this array directly except possibly in their 62 // implDigest() method. See MD5.java as an example. 63 byte[] buffer; 64 // offset into buffer 65 private int bufOfs; 66 67 // number of bytes processed so far. subclasses should not modify 68 // this value. 69 // also used as a flag to indicate reset status 70 // -1: need to call engineReset() before next call to update() 71 // 0: is already reset 72 long bytesProcessed; 73 74 /** 75 * Main constructor. 76 */ 77 DigestBase(String algorithm, int digestLength, int blockSize) { 78 super(); 79 this.algorithm = algorithm; 80 this.digestLength = digestLength; 81 this.blockSize = blockSize; 82 buffer = new byte[blockSize]; 83 } 84 85 // return digest length. See JCA doc. 86 protected final int engineGetDigestLength() { 87 return digestLength; 88 } 89 90 // single byte update. See JCA doc. 91 protected final void engineUpdate(byte b) { 92 if (oneByte == null) { 93 oneByte = new byte[1]; 94 } 95 oneByte[0] = b; 96 engineUpdate(oneByte, 0, 1); 97 } 98 99 // array update. See JCA doc. 100 protected final void engineUpdate(byte[] b, int ofs, int len) { 101 if (len == 0) { 102 return; 103 } 104 if ((ofs < 0) || (len < 0) || (ofs > b.length - len)) { 105 throw new ArrayIndexOutOfBoundsException(); 106 } 107 if (bytesProcessed < 0) { 108 engineReset(); 109 } 110 bytesProcessed += len; 111 // if buffer is not empty, we need to fill it before proceeding 112 if (bufOfs != 0) { 113 int n = Math.min(len, blockSize - bufOfs); 114 System.arraycopy(b, ofs, buffer, bufOfs, n); 115 bufOfs += n; 116 ofs += n; 117 len -= n; 118 if (bufOfs >= blockSize) { 119 // compress completed block now 120 implCompress(buffer, 0); 121 bufOfs = 0; 122 } 123 } 124 // compress complete blocks 125 if (len >= blockSize) { 126 int limit = ofs + len; 127 ofs = implCompressMultiBlock(b, ofs, limit - blockSize); 128 len = limit - ofs; 129 } 130 // copy remainder to buffer 131 if (len > 0) { 132 System.arraycopy(b, ofs, buffer, 0, len); 133 bufOfs = len; 134 } 135 } 136 137 // compress complete blocks 138 private int implCompressMultiBlock(byte[] b, int ofs, int limit) { 139 for (; ofs <= limit; ofs += blockSize) { 140 implCompress(b, ofs); 141 } 142 return ofs; 143 } 144 145 // reset this object. See JCA doc. 146 protected final void engineReset() { 147 if (bytesProcessed == 0) { 148 // already reset, ignore 149 return; 150 } 151 implReset(); 152 bufOfs = 0; 153 bytesProcessed = 0; 154 } 155 156 // return the digest. See JCA doc. 157 protected final byte[] engineDigest() { 158 byte[] b = new byte[digestLength]; 159 try { 160 engineDigest(b, 0, b.length); 161 } catch (DigestException e) { 162 throw (ProviderException) 163 new ProviderException("Internal error").initCause(e); 164 } 165 return b; 166 } 167 168 // return the digest in the specified array. See JCA doc. 169 protected final int engineDigest(byte[] out, int ofs, int len) 170 throws DigestException { 171 if (len < digestLength) { 172 throw new DigestException("Length must be at least " 173 + digestLength + " for " + algorithm + "digests"); 174 } 175 if ((ofs < 0) || (len < 0) || (ofs > out.length - len)) { 176 throw new DigestException("Buffer too short to store digest"); 177 } 178 if (bytesProcessed < 0) { 179 engineReset(); 180 } 181 implDigest(out, ofs); 182 bytesProcessed = -1; 183 return digestLength; 184 } 185 186 /** 187 * Core compression function. Processes blockSize bytes at a time 188 * and updates the state of this object. 189 */ 190 abstract void implCompress(byte[] b, int ofs); 191 192 /** 193 * Return the digest. Subclasses do not need to reset() themselves, 194 * DigestBase calls implReset() when necessary. 195 */ 196 abstract void implDigest(byte[] out, int ofs); 197 198 /** 199 * Reset subclass specific state to their initial values. DigestBase 200 * calls this method when necessary. 201 */ 202 abstract void implReset(); 203 204 public Object clone() throws CloneNotSupportedException { 205 DigestBase copy = (DigestBase) super.clone(); 206 copy.buffer = copy.buffer.clone(); 207 return copy; 208 } 209 210 // padding used for the MD5, and SHA-* message digests 211 static final byte[] padding; 212 213 static { 214 // we need 128 byte padding for SHA-384/512 215 // and an additional 8 bytes for the high 8 bytes of the 16 216 // byte bit counter in SHA-384/512 217 padding = new byte[136]; 218 padding[0] = (byte)0x80; 219 } 220 }