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.rsa; 27 28 import java.io.IOException; 29 import java.nio.ByteBuffer; 30 import java.math.BigInteger; 31 import java.util.Arrays; 32 33 import java.security.*; 34 import java.security.interfaces.*; 35 36 import sun.security.util.*; 37 import sun.security.x509.AlgorithmId; 38 39 /** 40 * PKCS#1 RSA signatures with the various message digest algorithms. 41 * This file contains an abstract base class with all the logic plus 42 * a nested static class for each of the message digest algorithms 43 * (see end of the file). We support MD2, MD5, SHA-1, SHA-224, SHA-256, 44 * SHA-384, and SHA-512. 45 * 46 * @since 1.5 47 * @author Andreas Sterbenz 48 */ 49 public abstract class RSASignature extends SignatureSpi { 50 51 // we sign an ASN.1 SEQUENCE of AlgorithmId and digest 52 // it has the form 30:xx:30:xx:[digestOID]:05:00:04:xx:[digest] 53 // this means the encoded length is (8 + digestOID.length + digest.length) 54 private static final int baseLength = 8; 55 56 // object identifier for the message digest algorithm used 57 private final ObjectIdentifier digestOID; 58 59 // length of the encoded signature blob 60 private final int encodedLength; 61 62 // message digest implementation we use 63 private final MessageDigest md; 64 // flag indicating whether the digest is reset 65 private boolean digestReset; 66 67 // private key, if initialized for signing 68 private RSAPrivateKey privateKey; 69 // public key, if initialized for verifying 70 private RSAPublicKey publicKey; 71 72 // padding to use, set when the initSign/initVerify is called 73 private RSAPadding padding; 74 75 /** 76 * Construct a new RSASignature. Used by subclasses. 77 */ 78 RSASignature(String algorithm, ObjectIdentifier digestOID, int oidLength) { 79 this.digestOID = digestOID; 80 try { 81 md = MessageDigest.getInstance(algorithm); 82 } catch (NoSuchAlgorithmException e) { 83 throw new ProviderException(e); 84 } 85 digestReset = true; 86 encodedLength = baseLength + oidLength + md.getDigestLength(); 87 } 88 89 // initialize for verification. See JCA doc 90 protected void engineInitVerify(PublicKey publicKey) 91 throws InvalidKeyException { 92 RSAPublicKey rsaKey = (RSAPublicKey)RSAKeyFactory.toRSAKey(publicKey); 93 this.privateKey = null; 94 this.publicKey = rsaKey; 95 initCommon(rsaKey, null); 96 } 97 98 // initialize for signing. See JCA doc 99 protected void engineInitSign(PrivateKey privateKey) 100 throws InvalidKeyException { 101 engineInitSign(privateKey, null); 102 } 103 104 // initialize for signing. See JCA doc 105 protected void engineInitSign(PrivateKey privateKey, SecureRandom random) 106 throws InvalidKeyException { 107 RSAPrivateKey rsaKey = 108 (RSAPrivateKey)RSAKeyFactory.toRSAKey(privateKey); 109 this.privateKey = rsaKey; 110 this.publicKey = null; 111 initCommon(rsaKey, random); 112 } 113 114 /** 115 * Init code common to sign and verify. 116 */ 117 private void initCommon(RSAKey rsaKey, SecureRandom random) 118 throws InvalidKeyException { 119 resetDigest(); 120 int keySize = RSACore.getByteLength(rsaKey); 121 try { 122 padding = RSAPadding.getInstance 123 (RSAPadding.PAD_BLOCKTYPE_1, keySize, random); 124 } catch (InvalidAlgorithmParameterException iape) { 125 throw new InvalidKeyException(iape.getMessage()); 126 } 127 int maxDataSize = padding.getMaxDataSize(); 128 if (encodedLength > maxDataSize) { 129 throw new InvalidKeyException 130 ("Key is too short for this signature algorithm"); 131 } 132 } 133 134 /** 135 * Reset the message digest if it is not already reset. 136 */ 137 private void resetDigest() { 138 if (digestReset == false) { 139 md.reset(); 140 digestReset = true; 141 } 142 } 143 144 /** 145 * Return the message digest value. 146 */ 147 private byte[] getDigestValue() { 148 digestReset = true; 149 return md.digest(); 150 } 151 152 // update the signature with the plaintext data. See JCA doc 153 protected void engineUpdate(byte b) throws SignatureException { 154 md.update(b); 155 digestReset = false; 156 } 157 158 // update the signature with the plaintext data. See JCA doc 159 protected void engineUpdate(byte[] b, int off, int len) 160 throws SignatureException { 161 md.update(b, off, len); 162 digestReset = false; 163 } 164 165 // update the signature with the plaintext data. See JCA doc 166 protected void engineUpdate(ByteBuffer b) { 167 md.update(b); 168 digestReset = false; 169 } 170 171 // sign the data and return the signature. See JCA doc 172 protected byte[] engineSign() throws SignatureException { 173 byte[] digest = getDigestValue(); 174 try { 175 byte[] encoded = encodeSignature(digestOID, digest); 176 byte[] padded = padding.pad(encoded); 177 byte[] encrypted = RSACore.rsa(padded, privateKey); 178 return encrypted; 179 } catch (GeneralSecurityException e) { 180 throw new SignatureException("Could not sign data", e); 181 } catch (IOException e) { 182 throw new SignatureException("Could not encode data", e); 183 } 184 } 185 186 // verify the data and return the result. See JCA doc 187 protected boolean engineVerify(byte[] sigBytes) throws SignatureException { 188 if (sigBytes.length != RSACore.getByteLength(publicKey)) { 189 throw new SignatureException("Signature length not correct: got " + 190 sigBytes.length + " but was expecting " + 191 RSACore.getByteLength(publicKey)); 192 } 193 byte[] digest = getDigestValue(); 194 try { 195 byte[] decrypted = RSACore.rsa(sigBytes, publicKey); 196 byte[] unpadded = padding.unpad(decrypted); 197 byte[] decodedDigest = decodeSignature(digestOID, unpadded); 198 return Arrays.equals(digest, decodedDigest); 199 } catch (javax.crypto.BadPaddingException e) { 200 // occurs if the app has used the wrong RSA public key 201 // or if sigBytes is invalid 202 // return false rather than propagating the exception for 203 // compatibility/ease of use 204 return false; 205 } catch (GeneralSecurityException e) { 206 throw new SignatureException("Signature verification failed", e); 207 } catch (IOException e) { 208 throw new SignatureException("Signature encoding error", e); 209 } 210 } 211 212 /** 213 * Encode the digest, return the to-be-signed data. 214 * Also used by the PKCS#11 provider. 215 */ 216 public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest) 217 throws IOException { 218 DerOutputStream out = new DerOutputStream(); 219 new AlgorithmId(oid).encode(out); 220 out.putOctetString(digest); 221 DerValue result = 222 new DerValue(DerValue.tag_Sequence, out.toByteArray()); 223 return result.toByteArray(); 224 } 225 226 /** 227 * Decode the signature data. Verify that the object identifier matches 228 * and return the message digest. 229 */ 230 public static byte[] decodeSignature(ObjectIdentifier oid, byte[] signature) 231 throws IOException { 232 DerInputStream in = new DerInputStream(signature); 233 DerValue[] values = in.getSequence(2); 234 if ((values.length != 2) || (in.available() != 0)) { 235 throw new IOException("SEQUENCE length error"); 236 } 237 AlgorithmId algId = AlgorithmId.parse(values[0]); 238 if (algId.getOID().equals(oid) == false) { 239 throw new IOException("ObjectIdentifier mismatch: " 240 + algId.getOID()); 241 } 242 if (algId.getEncodedParams() != null) { 243 throw new IOException("Unexpected AlgorithmId parameters"); 244 } 245 byte[] digest = values[1].getOctetString(); 246 return digest; 247 } 248 249 // set parameter, not supported. See JCA doc 250 protected void engineSetParameter(String param, Object value) 251 throws InvalidParameterException { 252 throw new UnsupportedOperationException("setParameter() not supported"); 253 } 254 255 // get parameter, not supported. See JCA doc 256 protected Object engineGetParameter(String param) 257 throws InvalidParameterException { 258 throw new UnsupportedOperationException("getParameter() not supported"); 259 } 260 261 // Nested class for MD2withRSA signatures 262 public static final class MD2withRSA extends RSASignature { 263 public MD2withRSA() { 264 super("MD2", AlgorithmId.MD2_oid, 10); 265 } 266 } 267 268 // Nested class for MD5withRSA signatures 269 public static final class MD5withRSA extends RSASignature { 270 public MD5withRSA() { 271 super("MD5", AlgorithmId.MD5_oid, 10); 272 } 273 } 274 275 // Nested class for SHA1withRSA signatures 276 public static final class SHA1withRSA extends RSASignature { 277 public SHA1withRSA() { 278 super("SHA-1", AlgorithmId.SHA_oid, 7); 279 } 280 } 281 282 // Nested class for SHA224withRSA signatures 283 public static final class SHA224withRSA extends RSASignature { 284 public SHA224withRSA() { 285 super("SHA-224", AlgorithmId.SHA224_oid, 11); 286 } 287 } 288 289 // Nested class for SHA256withRSA signatures 290 public static final class SHA256withRSA extends RSASignature { 291 public SHA256withRSA() { 292 super("SHA-256", AlgorithmId.SHA256_oid, 11); 293 } 294 } 295 296 // Nested class for SHA384withRSA signatures 297 public static final class SHA384withRSA extends RSASignature { 298 public SHA384withRSA() { 299 super("SHA-384", AlgorithmId.SHA384_oid, 11); 300 } 301 } 302 303 // Nested class for SHA512withRSA signatures 304 public static final class SHA512withRSA extends RSASignature { 305 public SHA512withRSA() { 306 super("SHA-512", AlgorithmId.SHA512_oid, 11); 307 } 308 } 309 310 }