1 /* 2 * Copyright (c) 2003, 2012, 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 while (len >= blockSize) { 126 implCompress(b, ofs); 127 len -= blockSize; 128 ofs += blockSize; 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 // reset this object. See JCA doc. 138 protected final void engineReset() { 139 if (bytesProcessed == 0) { 140 // already reset, ignore 141 return; 142 } 143 implReset(); 144 bufOfs = 0; 145 bytesProcessed = 0; 146 } 147 148 // return the digest. See JCA doc. 149 protected final byte[] engineDigest() { 150 byte[] b = new byte[digestLength]; 151 try { 152 engineDigest(b, 0, b.length); 153 } catch (DigestException e) { 154 throw (ProviderException) 155 new ProviderException("Internal error").initCause(e); 156 } 157 return b; 158 } 159 160 // return the digest in the specified array. See JCA doc. 161 protected final int engineDigest(byte[] out, int ofs, int len) 162 throws DigestException { 163 if (len < digestLength) { 164 throw new DigestException("Length must be at least " 165 + digestLength + " for " + algorithm + "digests"); 166 } 167 if ((ofs < 0) || (len < 0) || (ofs > out.length - len)) { 168 throw new DigestException("Buffer too short to store digest"); 169 } 170 if (bytesProcessed < 0) { 171 engineReset(); 172 } 173 implDigest(out, ofs); 174 bytesProcessed = -1; 175 return digestLength; 176 } 177 178 /** 179 * Core compression function. Processes blockSize bytes at a time 180 * and updates the state of this object. 181 */ 182 abstract void implCompress(byte[] b, int ofs); 183 184 /** 185 * Return the digest. Subclasses do not need to reset() themselves, 186 * DigestBase calls implReset() when necessary. 187 */ 188 abstract void implDigest(byte[] out, int ofs); 189 190 /** 191 * Reset subclass specific state to their initial values. DigestBase 192 * calls this method when necessary. 193 */ 194 abstract void implReset(); 195 196 public Object clone() throws CloneNotSupportedException { 197 DigestBase copy = (DigestBase) super.clone(); 198 copy.buffer = copy.buffer.clone(); 199 return copy; 200 } 201 202 // padding used for the MD5, and SHA-* message digests 203 static final byte[] padding; 204 205 static { 206 // we need 128 byte padding for SHA-384/512 207 // and an additional 8 bytes for the high 8 bytes of the 16 208 // byte bit counter in SHA-384/512 209 padding = new byte[136]; 210 padding[0] = (byte)0x80; 211 } 212 }