1 /* 2 * Copyright (c) 2005, 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.mscapi; 27 28 import java.nio.ByteBuffer; 29 import java.security.PublicKey; 30 import java.security.PrivateKey; 31 import java.security.InvalidKeyException; 32 import java.security.InvalidParameterException; 33 import java.security.KeyStoreException; 34 import java.security.NoSuchAlgorithmException; 35 import java.security.ProviderException; 36 import java.security.MessageDigest; 37 import java.security.SignatureException; 38 import java.math.BigInteger; 39 40 import sun.security.rsa.RSAKeyFactory; 41 42 /** 43 * RSA signature implementation. Supports RSA signing using PKCS#1 v1.5 padding. 44 * 45 * Objects should be instantiated by calling Signature.getInstance() using the 46 * following algorithm names: 47 * 48 * . "NONEwithRSA" 49 * . "SHA1withRSA" 50 * . "SHA256withRSA" 51 * . "SHA384withRSA" 52 * . "SHA512withRSA" 53 * . "MD5withRSA" 54 * . "MD2withRSA" 55 * 56 * NOTE: RSA keys must be at least 512 bits long. 57 * 58 * NOTE: NONEwithRSA must be supplied with a pre-computed message digest. 59 * Only the following digest algorithms are supported: MD5, SHA-1, 60 * SHA-256, SHA-384, SHA-512 and a special-purpose digest 61 * algorithm which is a concatenation of SHA-1 and MD5 digests. 62 * 63 * @since 1.6 64 * @author Stanley Man-Kit Ho 65 */ 66 abstract class RSASignature extends java.security.SignatureSpi 67 { 68 // message digest implementation we use 69 private final MessageDigest messageDigest; 70 71 // message digest name 72 private String messageDigestAlgorithm; 73 74 // flag indicating whether the digest has been reset 75 private boolean needsReset; 76 77 // the signing key 78 private Key privateKey = null; 79 80 // the verification key 81 private Key publicKey = null; 82 83 /** 84 * Constructs a new RSASignature. Used by Raw subclass. 85 */ 86 RSASignature() { 87 messageDigest = null; 88 messageDigestAlgorithm = null; 89 } 90 91 /** 92 * Constructs a new RSASignature. Used by subclasses. 93 */ 94 RSASignature(String digestName) { 95 96 try { 97 messageDigest = MessageDigest.getInstance(digestName); 98 // Get the digest's canonical name 99 messageDigestAlgorithm = messageDigest.getAlgorithm(); 100 101 } catch (NoSuchAlgorithmException e) { 102 throw new ProviderException(e); 103 } 104 105 needsReset = false; 106 } 107 108 // Nested class for NONEwithRSA signatures 109 public static final class Raw extends RSASignature { 110 111 // the longest supported digest is 512 bits (SHA-512) 112 private static final int RAW_RSA_MAX = 64; 113 114 private final byte[] precomputedDigest; 115 private int offset = 0; 116 117 public Raw() { 118 precomputedDigest = new byte[RAW_RSA_MAX]; 119 } 120 121 // Stores the precomputed message digest value. 122 @Override 123 protected void engineUpdate(byte b) throws SignatureException { 124 if (offset >= precomputedDigest.length) { 125 offset = RAW_RSA_MAX + 1; 126 return; 127 } 128 precomputedDigest[offset++] = b; 129 } 130 131 // Stores the precomputed message digest value. 132 @Override 133 protected void engineUpdate(byte[] b, int off, int len) 134 throws SignatureException { 135 if (offset + len > precomputedDigest.length) { 136 offset = RAW_RSA_MAX + 1; 137 return; 138 } 139 System.arraycopy(b, off, precomputedDigest, offset, len); 140 offset += len; 141 } 142 143 // Stores the precomputed message digest value. 144 @Override 145 protected void engineUpdate(ByteBuffer byteBuffer) { 146 int len = byteBuffer.remaining(); 147 if (len <= 0) { 148 return; 149 } 150 if (offset + len > precomputedDigest.length) { 151 offset = RAW_RSA_MAX + 1; 152 return; 153 } 154 byteBuffer.get(precomputedDigest, offset, len); 155 offset += len; 156 } 157 158 @Override 159 protected void resetDigest(){ 160 offset = 0; 161 } 162 163 // Returns the precomputed message digest value. 164 @Override 165 protected byte[] getDigestValue() throws SignatureException { 166 if (offset > RAW_RSA_MAX) { 167 throw new SignatureException("Message digest is too long"); 168 } 169 170 // Determine the digest algorithm from the digest length 171 if (offset == 20) { 172 setDigestName("SHA1"); 173 } else if (offset == 36) { 174 setDigestName("SHA1+MD5"); 175 } else if (offset == 32) { 176 setDigestName("SHA-256"); 177 } else if (offset == 48) { 178 setDigestName("SHA-384"); 179 } else if (offset == 64) { 180 setDigestName("SHA-512"); 181 } else if (offset == 16) { 182 setDigestName("MD5"); 183 } else { 184 throw new SignatureException( 185 "Message digest length is not supported"); 186 } 187 188 byte[] result = new byte[offset]; 189 System.arraycopy(precomputedDigest, 0, result, 0, offset); 190 offset = 0; 191 192 return result; 193 } 194 } 195 196 public static final class SHA1 extends RSASignature { 197 public SHA1() { 198 super("SHA1"); 199 } 200 } 201 202 public static final class SHA256 extends RSASignature { 203 public SHA256() { 204 super("SHA-256"); 205 } 206 } 207 208 public static final class SHA384 extends RSASignature { 209 public SHA384() { 210 super("SHA-384"); 211 } 212 } 213 214 public static final class SHA512 extends RSASignature { 215 public SHA512() { 216 super("SHA-512"); 217 } 218 } 219 220 public static final class MD5 extends RSASignature { 221 public MD5() { 222 super("MD5"); 223 } 224 } 225 226 public static final class MD2 extends RSASignature { 227 public MD2() { 228 super("MD2"); 229 } 230 } 231 232 // initialize for signing. See JCA doc 233 protected void engineInitVerify(PublicKey key) 234 throws InvalidKeyException 235 { 236 // This signature accepts only RSAPublicKey 237 if ((key instanceof java.security.interfaces.RSAPublicKey) == false) { 238 throw new InvalidKeyException("Key type not supported"); 239 } 240 241 java.security.interfaces.RSAPublicKey rsaKey = 242 (java.security.interfaces.RSAPublicKey) key; 243 244 if ((key instanceof sun.security.mscapi.RSAPublicKey) == false) { 245 246 // convert key to MSCAPI format 247 248 BigInteger modulus = rsaKey.getModulus(); 249 BigInteger exponent = rsaKey.getPublicExponent(); 250 251 // Check against the local and global values to make sure 252 // the sizes are ok. Round up to the nearest byte. 253 RSAKeyFactory.checkKeyLengths(((modulus.bitLength() + 7) & ~7), 254 exponent, -1, RSAKeyPairGenerator.KEY_SIZE_MAX); 255 256 byte[] modulusBytes = modulus.toByteArray(); 257 byte[] exponentBytes = exponent.toByteArray(); 258 259 // Adjust key length due to sign bit 260 int keyBitLength = (modulusBytes[0] == 0) 261 ? (modulusBytes.length - 1) * 8 262 : modulusBytes.length * 8; 263 264 byte[] keyBlob = generatePublicKeyBlob( 265 keyBitLength, modulusBytes, exponentBytes); 266 267 try { 268 publicKey = importPublicKey(keyBlob, keyBitLength); 269 270 } catch (KeyStoreException e) { 271 throw new InvalidKeyException(e); 272 } 273 274 } else { 275 publicKey = (sun.security.mscapi.RSAPublicKey) key; 276 } 277 278 this.privateKey = null; 279 resetDigest(); 280 } 281 282 // initialize for signing. See JCA doc 283 protected void engineInitSign(PrivateKey key) throws InvalidKeyException 284 { 285 // This signature accepts only RSAPrivateKey 286 if ((key instanceof sun.security.mscapi.RSAPrivateKey) == false) { 287 throw new InvalidKeyException("Key type not supported"); 288 } 289 privateKey = (sun.security.mscapi.RSAPrivateKey) key; 290 291 // Check against the local and global values to make sure 292 // the sizes are ok. Round up to nearest byte. 293 RSAKeyFactory.checkKeyLengths(((privateKey.length() + 7) & ~7), 294 null, RSAKeyPairGenerator.KEY_SIZE_MIN, 295 RSAKeyPairGenerator.KEY_SIZE_MAX); 296 297 this.publicKey = null; 298 resetDigest(); 299 } 300 301 /** 302 * Resets the message digest if needed. 303 */ 304 protected void resetDigest() { 305 if (needsReset) { 306 messageDigest.reset(); 307 needsReset = false; 308 } 309 } 310 311 protected byte[] getDigestValue() throws SignatureException { 312 needsReset = false; 313 return messageDigest.digest(); 314 } 315 316 protected void setDigestName(String name) { 317 messageDigestAlgorithm = name; 318 } 319 320 /** 321 * Updates the data to be signed or verified 322 * using the specified byte. 323 * 324 * @param b the byte to use for the update. 325 * 326 * @exception SignatureException if the engine is not initialized 327 * properly. 328 */ 329 protected void engineUpdate(byte b) throws SignatureException 330 { 331 messageDigest.update(b); 332 needsReset = true; 333 } 334 335 /** 336 * Updates the data to be signed or verified, using the 337 * specified array of bytes, starting at the specified offset. 338 * 339 * @param b the array of bytes 340 * @param off the offset to start from in the array of bytes 341 * @param len the number of bytes to use, starting at offset 342 * 343 * @exception SignatureException if the engine is not initialized 344 * properly 345 */ 346 protected void engineUpdate(byte[] b, int off, int len) 347 throws SignatureException 348 { 349 messageDigest.update(b, off, len); 350 needsReset = true; 351 } 352 353 /** 354 * Updates the data to be signed or verified, using the 355 * specified ByteBuffer. 356 * 357 * @param input the ByteBuffer 358 */ 359 protected void engineUpdate(ByteBuffer input) 360 { 361 messageDigest.update(input); 362 needsReset = true; 363 } 364 365 /** 366 * Returns the signature bytes of all the data 367 * updated so far. 368 * The format of the signature depends on the underlying 369 * signature scheme. 370 * 371 * @return the signature bytes of the signing operation's result. 372 * 373 * @exception SignatureException if the engine is not 374 * initialized properly or if this signature algorithm is unable to 375 * process the input data provided. 376 */ 377 protected byte[] engineSign() throws SignatureException { 378 379 byte[] hash = getDigestValue(); 380 381 // Omit the hash OID when generating a Raw signature 382 boolean noHashOID = this instanceof Raw; 383 384 // Sign hash using MS Crypto APIs 385 386 byte[] result = signHash(noHashOID, hash, hash.length, 387 messageDigestAlgorithm, privateKey.getHCryptProvider(), 388 privateKey.getHCryptKey()); 389 390 // Convert signature array from little endian to big endian 391 return convertEndianArray(result); 392 } 393 394 /** 395 * Convert array from big endian to little endian, or vice versa. 396 */ 397 private byte[] convertEndianArray(byte[] byteArray) 398 { 399 if (byteArray == null || byteArray.length == 0) 400 return byteArray; 401 402 byte [] retval = new byte[byteArray.length]; 403 404 // make it big endian 405 for (int i=0;i < byteArray.length;i++) 406 retval[i] = byteArray[byteArray.length - i - 1]; 407 408 return retval; 409 } 410 411 /** 412 * Sign hash using Microsoft Crypto API with HCRYPTKEY. 413 * The returned data is in little-endian. 414 */ 415 private native static byte[] signHash(boolean noHashOID, byte[] hash, 416 int hashSize, String hashAlgorithm, long hCryptProv, long hCryptKey) 417 throws SignatureException; 418 419 /** 420 * Verify a signed hash using Microsoft Crypto API with HCRYPTKEY. 421 */ 422 private native static boolean verifySignedHash(byte[] hash, int hashSize, 423 String hashAlgorithm, byte[] signature, int signatureSize, 424 long hCryptProv, long hCryptKey) throws SignatureException; 425 426 /** 427 * Verifies the passed-in signature. 428 * 429 * @param sigBytes the signature bytes to be verified. 430 * 431 * @return true if the signature was verified, false if not. 432 * 433 * @exception SignatureException if the engine is not 434 * initialized properly, the passed-in signature is improperly 435 * encoded or of the wrong type, if this signature algorithm is unable to 436 * process the input data provided, etc. 437 */ 438 protected boolean engineVerify(byte[] sigBytes) 439 throws SignatureException 440 { 441 byte[] hash = getDigestValue(); 442 443 return verifySignedHash(hash, hash.length, 444 messageDigestAlgorithm, convertEndianArray(sigBytes), 445 sigBytes.length, publicKey.getHCryptProvider(), 446 publicKey.getHCryptKey()); 447 } 448 449 /** 450 * Sets the specified algorithm parameter to the specified 451 * value. This method supplies a general-purpose mechanism through 452 * which it is possible to set the various parameters of this object. 453 * A parameter may be any settable parameter for the algorithm, such as 454 * a parameter size, or a source of random bits for signature generation 455 * (if appropriate), or an indication of whether or not to perform 456 * a specific but optional computation. A uniform algorithm-specific 457 * naming scheme for each parameter is desirable but left unspecified 458 * at this time. 459 * 460 * @param param the string identifier of the parameter. 461 * 462 * @param value the parameter value. 463 * 464 * @exception InvalidParameterException if <code>param</code> is an 465 * invalid parameter for this signature algorithm engine, 466 * the parameter is already set 467 * and cannot be set again, a security exception occurs, and so on. 468 * 469 * @deprecated Replaced by {@link 470 * #engineSetParameter(java.security.spec.AlgorithmParameterSpec) 471 * engineSetParameter}. 472 */ 473 @Deprecated 474 protected void engineSetParameter(String param, Object value) 475 throws InvalidParameterException 476 { 477 throw new InvalidParameterException("Parameter not supported"); 478 } 479 480 481 /** 482 * Gets the value of the specified algorithm parameter. 483 * This method supplies a general-purpose mechanism through which it 484 * is possible to get the various parameters of this object. A parameter 485 * may be any settable parameter for the algorithm, such as a parameter 486 * size, or a source of random bits for signature generation (if 487 * appropriate), or an indication of whether or not to perform a 488 * specific but optional computation. A uniform algorithm-specific 489 * naming scheme for each parameter is desirable but left unspecified 490 * at this time. 491 * 492 * @param param the string name of the parameter. 493 * 494 * @return the object that represents the parameter value, or null if 495 * there is none. 496 * 497 * @exception InvalidParameterException if <code>param</code> is an 498 * invalid parameter for this engine, or another exception occurs while 499 * trying to get this parameter. 500 * 501 * @deprecated 502 */ 503 @Deprecated 504 protected Object engineGetParameter(String param) 505 throws InvalidParameterException 506 { 507 throw new InvalidParameterException("Parameter not supported"); 508 } 509 510 /** 511 * Generates a public-key BLOB from a key's components. 512 */ 513 // used by RSACipher 514 static native byte[] generatePublicKeyBlob( 515 int keyBitLength, byte[] modulus, byte[] publicExponent) 516 throws InvalidKeyException; 517 518 /** 519 * Imports a public-key BLOB. 520 */ 521 // used by RSACipher 522 static native RSAPublicKey importPublicKey(byte[] keyBlob, int keySize) 523 throws KeyStoreException; 524 }