src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSASignature.java
branchJDK-8200758-branch
changeset 57076 687505381ca4
parent 57072 29604aafa0fc
parent 53039 3bc260237317
child 57077 8f9cf6ad59f0
equal deleted inserted replaced
57072:29604aafa0fc 57076:687505381ca4
     1 /*
       
     2  * Copyright (c) 2005, 2018, 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.*;
       
    30 import java.security.spec.AlgorithmParameterSpec;
       
    31 import java.math.BigInteger;
       
    32 import java.security.spec.MGF1ParameterSpec;
       
    33 import java.security.spec.PSSParameterSpec;
       
    34 import java.util.Locale;
       
    35 
       
    36 import sun.security.rsa.RSAKeyFactory;
       
    37 
       
    38 /**
       
    39  * RSA signature implementation. Supports RSA signing using PKCS#1 v1.5 padding.
       
    40  *
       
    41  * Objects should be instantiated by calling Signature.getInstance() using the
       
    42  * following algorithm names:
       
    43  *
       
    44  *  . "NONEwithRSA"
       
    45  *  . "SHA1withRSA"
       
    46  *  . "SHA256withRSA"
       
    47  *  . "SHA384withRSA"
       
    48  *  . "SHA512withRSA"
       
    49  *  . "MD5withRSA"
       
    50  *  . "MD2withRSA"
       
    51  *  . "RSASSA-PSS"
       
    52  *
       
    53  * NOTE: RSA keys must be at least 512 bits long.
       
    54  *
       
    55  * NOTE: NONEwithRSA must be supplied with a pre-computed message digest.
       
    56  *       Only the following digest algorithms are supported: MD5, SHA-1,
       
    57  *       SHA-256, SHA-384, SHA-512 and a special-purpose digest
       
    58  *       algorithm which is a concatenation of SHA-1 and MD5 digests.
       
    59  *
       
    60  * @since   1.6
       
    61  * @author  Stanley Man-Kit Ho
       
    62  */
       
    63 abstract class RSASignature extends java.security.SignatureSpi
       
    64 {
       
    65     // message digest implementation we use
       
    66     protected MessageDigest messageDigest;
       
    67 
       
    68     // message digest name
       
    69     private String messageDigestAlgorithm;
       
    70 
       
    71     // flag indicating whether the digest has been reset
       
    72     protected boolean needsReset;
       
    73 
       
    74     // the signing key
       
    75     protected Key privateKey = null;
       
    76 
       
    77     // the verification key
       
    78     protected Key publicKey = null;
       
    79 
       
    80     /**
       
    81      * Constructs a new RSASignature. Used by Raw subclass.
       
    82      */
       
    83     RSASignature() {
       
    84         messageDigest = null;
       
    85         messageDigestAlgorithm = null;
       
    86     }
       
    87 
       
    88     /**
       
    89      * Constructs a new RSASignature. Used by subclasses.
       
    90      */
       
    91     RSASignature(String digestName) {
       
    92 
       
    93         try {
       
    94             messageDigest = MessageDigest.getInstance(digestName);
       
    95             // Get the digest's canonical name
       
    96             messageDigestAlgorithm = messageDigest.getAlgorithm();
       
    97 
       
    98         } catch (NoSuchAlgorithmException e) {
       
    99            throw new ProviderException(e);
       
   100         }
       
   101 
       
   102         needsReset = false;
       
   103     }
       
   104 
       
   105     // Nested class for NONEwithRSA signatures
       
   106     public static final class Raw extends RSASignature {
       
   107 
       
   108         // the longest supported digest is 512 bits (SHA-512)
       
   109         private static final int RAW_RSA_MAX = 64;
       
   110 
       
   111         private final byte[] precomputedDigest;
       
   112         private int offset = 0;
       
   113 
       
   114         public Raw() {
       
   115             precomputedDigest = new byte[RAW_RSA_MAX];
       
   116         }
       
   117 
       
   118         // Stores the precomputed message digest value.
       
   119         @Override
       
   120         protected void engineUpdate(byte b) throws SignatureException {
       
   121             if (offset >= precomputedDigest.length) {
       
   122                 offset = RAW_RSA_MAX + 1;
       
   123                 return;
       
   124             }
       
   125             precomputedDigest[offset++] = b;
       
   126         }
       
   127 
       
   128         // Stores the precomputed message digest value.
       
   129         @Override
       
   130         protected void engineUpdate(byte[] b, int off, int len)
       
   131                 throws SignatureException {
       
   132             if (len > (precomputedDigest.length - offset)) {
       
   133                 offset = RAW_RSA_MAX + 1;
       
   134                 return;
       
   135             }
       
   136             System.arraycopy(b, off, precomputedDigest, offset, len);
       
   137             offset += len;
       
   138         }
       
   139 
       
   140         // Stores the precomputed message digest value.
       
   141         @Override
       
   142         protected void engineUpdate(ByteBuffer byteBuffer) {
       
   143             int len = byteBuffer.remaining();
       
   144             if (len <= 0) {
       
   145                 return;
       
   146             }
       
   147             if (len > (precomputedDigest.length - offset)) {
       
   148                 offset = RAW_RSA_MAX + 1;
       
   149                 return;
       
   150             }
       
   151             byteBuffer.get(precomputedDigest, offset, len);
       
   152             offset += len;
       
   153         }
       
   154 
       
   155         @Override
       
   156         protected void resetDigest(){
       
   157             offset = 0;
       
   158         }
       
   159 
       
   160         // Returns the precomputed message digest value.
       
   161         @Override
       
   162         protected byte[] getDigestValue() throws SignatureException {
       
   163             if (offset > RAW_RSA_MAX) {
       
   164                 throw new SignatureException("Message digest is too long");
       
   165             }
       
   166 
       
   167             // Determine the digest algorithm from the digest length
       
   168             if (offset == 20) {
       
   169                 setDigestName("SHA1");
       
   170             } else if (offset == 36) {
       
   171                 setDigestName("SHA1+MD5");
       
   172             } else if (offset == 32) {
       
   173                 setDigestName("SHA-256");
       
   174             } else if (offset == 48) {
       
   175                 setDigestName("SHA-384");
       
   176             } else if (offset == 64) {
       
   177                 setDigestName("SHA-512");
       
   178             } else if (offset == 16) {
       
   179                 setDigestName("MD5");
       
   180             } else {
       
   181                 throw new SignatureException(
       
   182                     "Message digest length is not supported");
       
   183             }
       
   184 
       
   185             byte[] result = new byte[offset];
       
   186             System.arraycopy(precomputedDigest, 0, result, 0, offset);
       
   187             offset = 0;
       
   188 
       
   189             return result;
       
   190         }
       
   191     }
       
   192 
       
   193     public static final class SHA1 extends RSASignature {
       
   194         public SHA1() {
       
   195             super("SHA1");
       
   196         }
       
   197     }
       
   198 
       
   199     public static final class SHA256 extends RSASignature {
       
   200         public SHA256() {
       
   201             super("SHA-256");
       
   202         }
       
   203     }
       
   204 
       
   205     public static final class SHA384 extends RSASignature {
       
   206         public SHA384() {
       
   207             super("SHA-384");
       
   208         }
       
   209     }
       
   210 
       
   211     public static final class SHA512 extends RSASignature {
       
   212         public SHA512() {
       
   213             super("SHA-512");
       
   214         }
       
   215     }
       
   216 
       
   217     public static final class MD5 extends RSASignature {
       
   218         public MD5() {
       
   219             super("MD5");
       
   220         }
       
   221     }
       
   222 
       
   223     public static final class MD2 extends RSASignature {
       
   224         public MD2() {
       
   225             super("MD2");
       
   226         }
       
   227     }
       
   228 
       
   229     public static final class PSS extends RSASignature {
       
   230 
       
   231         private PSSParameterSpec pssParams = null;
       
   232 
       
   233         // Workaround: Cannot import raw public key to CNG. This signature
       
   234         // will be used for verification if key is not from MSCAPI.
       
   235         private Signature fallbackSignature;
       
   236 
       
   237         @Override
       
   238         protected void engineInitSign(PrivateKey key) throws InvalidKeyException {
       
   239             super.engineInitSign(key);
       
   240             fallbackSignature = null;
       
   241         }
       
   242 
       
   243         @Override
       
   244         protected void engineInitVerify(PublicKey key) throws InvalidKeyException {
       
   245             // This signature accepts only RSAPublicKey
       
   246             if ((key instanceof java.security.interfaces.RSAPublicKey) == false) {
       
   247                 throw new InvalidKeyException("Key type not supported");
       
   248             }
       
   249 
       
   250             this.privateKey = null;
       
   251 
       
   252             if (key instanceof sun.security.mscapi.RSAPublicKey) {
       
   253                 fallbackSignature = null;
       
   254                 publicKey = (sun.security.mscapi.RSAPublicKey) key;
       
   255             } else {
       
   256                 if (fallbackSignature == null) {
       
   257                     try {
       
   258                         fallbackSignature = Signature.getInstance(
       
   259                                 "RSASSA-PSS", "SunRsaSign");
       
   260                     } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
       
   261                         throw new InvalidKeyException("Invalid key", e);
       
   262                     }
       
   263                 }
       
   264                 fallbackSignature.initVerify(key);
       
   265                 if (pssParams != null) {
       
   266                     try {
       
   267                         fallbackSignature.setParameter(pssParams);
       
   268                     } catch (InvalidAlgorithmParameterException e) {
       
   269                         throw new InvalidKeyException("Invalid params", e);
       
   270                     }
       
   271                 }
       
   272                 publicKey = null;
       
   273             }
       
   274             resetDigest();
       
   275         }
       
   276 
       
   277         @Override
       
   278         protected void engineUpdate(byte b) throws SignatureException {
       
   279             ensureInit();
       
   280             if (fallbackSignature != null) {
       
   281                 fallbackSignature.update(b);
       
   282             } else {
       
   283                 messageDigest.update(b);
       
   284             }
       
   285             needsReset = true;
       
   286         }
       
   287 
       
   288         @Override
       
   289         protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
       
   290             ensureInit();
       
   291             if (fallbackSignature != null) {
       
   292                 fallbackSignature.update(b, off, len);
       
   293             } else {
       
   294                 messageDigest.update(b, off, len);
       
   295             }
       
   296             needsReset = true;
       
   297         }
       
   298 
       
   299         @Override
       
   300         protected void engineUpdate(ByteBuffer input) {
       
   301             try {
       
   302                 ensureInit();
       
   303             } catch (SignatureException se) {
       
   304                 // hack for working around API bug
       
   305                 throw new RuntimeException(se.getMessage());
       
   306             }
       
   307             if (fallbackSignature != null) {
       
   308                 try {
       
   309                     fallbackSignature.update(input);
       
   310                 } catch (SignatureException se) {
       
   311                     // hack for working around API bug
       
   312                     throw new RuntimeException(se.getMessage());
       
   313                 }
       
   314             } else {
       
   315                 messageDigest.update(input);
       
   316             }
       
   317             needsReset = true;
       
   318         }
       
   319 
       
   320         @Override
       
   321         protected byte[] engineSign() throws SignatureException {
       
   322             ensureInit();
       
   323             byte[] hash = getDigestValue();
       
   324             return signPssHash(hash, hash.length,
       
   325                     pssParams.getSaltLength(),
       
   326                     ((MGF1ParameterSpec)
       
   327                             pssParams.getMGFParameters()).getDigestAlgorithm(),
       
   328                     privateKey.getHCryptProvider(), privateKey.getHCryptKey());
       
   329         }
       
   330 
       
   331         @Override
       
   332         protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
       
   333             ensureInit();
       
   334             if (fallbackSignature != null) {
       
   335                 needsReset = false;
       
   336                 return fallbackSignature.verify(sigBytes);
       
   337             } else {
       
   338                 byte[] hash = getDigestValue();
       
   339                 return verifyPssSignedHash(
       
   340                         hash, hash.length,
       
   341                         sigBytes, sigBytes.length,
       
   342                         pssParams.getSaltLength(),
       
   343                         ((MGF1ParameterSpec)
       
   344                                 pssParams.getMGFParameters()).getDigestAlgorithm(),
       
   345                         publicKey.getHCryptProvider(),
       
   346                         publicKey.getHCryptKey()
       
   347                 );
       
   348             }
       
   349         }
       
   350 
       
   351         @Override
       
   352         protected void engineSetParameter(AlgorithmParameterSpec params)
       
   353                 throws InvalidAlgorithmParameterException {
       
   354             if (needsReset) {
       
   355                 throw new ProviderException
       
   356                         ("Cannot set parameters during operations");
       
   357             }
       
   358             this.pssParams = validateSigParams(params);
       
   359             if (fallbackSignature != null) {
       
   360                 fallbackSignature.setParameter(params);
       
   361             }
       
   362         }
       
   363 
       
   364         @Override
       
   365         protected AlgorithmParameters engineGetParameters() {
       
   366             AlgorithmParameters ap = null;
       
   367             if (this.pssParams != null) {
       
   368                 try {
       
   369                     ap = AlgorithmParameters.getInstance("RSASSA-PSS");
       
   370                     ap.init(this.pssParams);
       
   371                 } catch (GeneralSecurityException gse) {
       
   372                     throw new ProviderException(gse.getMessage());
       
   373                 }
       
   374             }
       
   375             return ap;
       
   376         }
       
   377 
       
   378         private void ensureInit() throws SignatureException {
       
   379             if (this.privateKey == null && this.publicKey == null
       
   380                     && fallbackSignature == null) {
       
   381                 throw new SignatureException("Missing key");
       
   382             }
       
   383             if (this.pssParams == null) {
       
   384                 // Parameters are required for signature verification
       
   385                 throw new SignatureException
       
   386                         ("Parameters required for RSASSA-PSS signatures");
       
   387             }
       
   388             if (fallbackSignature == null && messageDigest == null) {
       
   389                 // This could happen if initVerify(softKey), setParameter(),
       
   390                 // and initSign() were called. No messageDigest. Create it.
       
   391                 try {
       
   392                     messageDigest = MessageDigest
       
   393                             .getInstance(pssParams.getDigestAlgorithm());
       
   394                 } catch (NoSuchAlgorithmException e) {
       
   395                     throw new SignatureException(e);
       
   396                 }
       
   397             }
       
   398         }
       
   399 
       
   400         /**
       
   401          * Validate the specified Signature PSS parameters.
       
   402          */
       
   403         private PSSParameterSpec validateSigParams(AlgorithmParameterSpec p)
       
   404                 throws InvalidAlgorithmParameterException {
       
   405 
       
   406             if (p == null) {
       
   407                 throw new InvalidAlgorithmParameterException
       
   408                         ("Parameters cannot be null");
       
   409             }
       
   410 
       
   411             if (!(p instanceof PSSParameterSpec)) {
       
   412                 throw new InvalidAlgorithmParameterException
       
   413                         ("parameters must be type PSSParameterSpec");
       
   414             }
       
   415 
       
   416             // no need to validate again if same as current signature parameters
       
   417             PSSParameterSpec params = (PSSParameterSpec) p;
       
   418             if (params == this.pssParams) return params;
       
   419 
       
   420             // now sanity check the parameter values
       
   421             if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) {
       
   422                 throw new InvalidAlgorithmParameterException("Only supports MGF1");
       
   423 
       
   424             }
       
   425 
       
   426             if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
       
   427                 throw new InvalidAlgorithmParameterException
       
   428                         ("Only supports TrailerFieldBC(1)");
       
   429             }
       
   430 
       
   431             AlgorithmParameterSpec algSpec = params.getMGFParameters();
       
   432             if (!(algSpec instanceof MGF1ParameterSpec)) {
       
   433                 throw new InvalidAlgorithmParameterException
       
   434                         ("Only support MGF1ParameterSpec");
       
   435             }
       
   436 
       
   437             MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)algSpec;
       
   438 
       
   439             String msgHashAlg = params.getDigestAlgorithm()
       
   440                     .toLowerCase(Locale.ROOT).replaceAll("-", "");
       
   441             if (msgHashAlg.equals("sha")) {
       
   442                 msgHashAlg = "sha1";
       
   443             }
       
   444             String mgf1HashAlg = mgfSpec.getDigestAlgorithm()
       
   445                     .toLowerCase(Locale.ROOT).replaceAll("-", "");
       
   446             if (mgf1HashAlg.equals("sha")) {
       
   447                 mgf1HashAlg = "sha1";
       
   448             }
       
   449 
       
   450             if (!mgf1HashAlg.equals(msgHashAlg)) {
       
   451                 throw new InvalidAlgorithmParameterException
       
   452                         ("MGF1 hash must be the same as message hash");
       
   453             }
       
   454 
       
   455             return params;
       
   456         }
       
   457 
       
   458         /**
       
   459          * Sign hash using CNG API with HCRYPTKEY. Used by RSASSA-PSS.
       
   460          */
       
   461         private native static byte[] signPssHash(byte[] hash,
       
   462                 int hashSize, int saltLength, String hashAlgorithm,
       
   463                 long hCryptProv, long nCryptKey)
       
   464                 throws SignatureException;
       
   465 
       
   466         /**
       
   467          * Verify a signed hash using CNG API with HCRYPTKEY. Used by RSASSA-PSS.
       
   468          * This method is not used now. See {@link #fallbackSignature}.
       
   469          */
       
   470         private native static boolean verifyPssSignedHash(byte[] hash, int hashSize,
       
   471                 byte[] signature, int signatureSize,
       
   472                 int saltLength, String hashAlgorithm,
       
   473                 long hCryptProv, long hKey) throws SignatureException;
       
   474     }
       
   475 
       
   476     // initialize for signing. See JCA doc
       
   477     @Override
       
   478     protected void engineInitVerify(PublicKey key)
       
   479         throws InvalidKeyException
       
   480     {
       
   481         // This signature accepts only RSAPublicKey
       
   482         if ((key instanceof java.security.interfaces.RSAPublicKey) == false) {
       
   483             throw new InvalidKeyException("Key type not supported");
       
   484         }
       
   485 
       
   486         java.security.interfaces.RSAPublicKey rsaKey =
       
   487             (java.security.interfaces.RSAPublicKey) key;
       
   488 
       
   489         if ((key instanceof sun.security.mscapi.RSAPublicKey) == false) {
       
   490 
       
   491             // convert key to MSCAPI format
       
   492 
       
   493             BigInteger modulus = rsaKey.getModulus();
       
   494             BigInteger exponent =  rsaKey.getPublicExponent();
       
   495 
       
   496             // Check against the local and global values to make sure
       
   497             // the sizes are ok.  Round up to the nearest byte.
       
   498             RSAKeyFactory.checkKeyLengths(((modulus.bitLength() + 7) & ~7),
       
   499                 exponent, -1, RSAKeyPairGenerator.KEY_SIZE_MAX);
       
   500 
       
   501             byte[] modulusBytes = modulus.toByteArray();
       
   502             byte[] exponentBytes = exponent.toByteArray();
       
   503 
       
   504             // Adjust key length due to sign bit
       
   505             int keyBitLength = (modulusBytes[0] == 0)
       
   506                 ? (modulusBytes.length - 1) * 8
       
   507                 : modulusBytes.length * 8;
       
   508 
       
   509             byte[] keyBlob = generatePublicKeyBlob(
       
   510                 keyBitLength, modulusBytes, exponentBytes);
       
   511 
       
   512             try {
       
   513                 publicKey = importPublicKey(keyBlob, keyBitLength);
       
   514 
       
   515             } catch (KeyStoreException e) {
       
   516                 throw new InvalidKeyException(e);
       
   517             }
       
   518 
       
   519         } else {
       
   520             publicKey = (sun.security.mscapi.RSAPublicKey) key;
       
   521         }
       
   522 
       
   523         this.privateKey = null;
       
   524         resetDigest();
       
   525     }
       
   526 
       
   527     // initialize for signing. See JCA doc
       
   528     @Override
       
   529     protected void engineInitSign(PrivateKey key) throws InvalidKeyException
       
   530     {
       
   531         // This signature accepts only RSAPrivateKey
       
   532         if ((key instanceof sun.security.mscapi.RSAPrivateKey) == false) {
       
   533             throw new InvalidKeyException("Key type not supported");
       
   534         }
       
   535         privateKey = (sun.security.mscapi.RSAPrivateKey) key;
       
   536 
       
   537         // Check against the local and global values to make sure
       
   538         // the sizes are ok.  Round up to nearest byte.
       
   539         RSAKeyFactory.checkKeyLengths(((privateKey.length() + 7) & ~7),
       
   540             null, RSAKeyPairGenerator.KEY_SIZE_MIN,
       
   541             RSAKeyPairGenerator.KEY_SIZE_MAX);
       
   542 
       
   543         this.publicKey = null;
       
   544         resetDigest();
       
   545     }
       
   546 
       
   547     /**
       
   548      * Resets the message digest if needed.
       
   549      */
       
   550     protected void resetDigest() {
       
   551         if (needsReset) {
       
   552             if (messageDigest != null) {
       
   553                 messageDigest.reset();
       
   554             }
       
   555             needsReset = false;
       
   556         }
       
   557     }
       
   558 
       
   559     protected byte[] getDigestValue() throws SignatureException {
       
   560         needsReset = false;
       
   561         return messageDigest.digest();
       
   562     }
       
   563 
       
   564     protected void setDigestName(String name) {
       
   565         messageDigestAlgorithm = name;
       
   566     }
       
   567 
       
   568     /**
       
   569      * Updates the data to be signed or verified
       
   570      * using the specified byte.
       
   571      *
       
   572      * @param b the byte to use for the update.
       
   573      *
       
   574      * @exception SignatureException if the engine is not initialized
       
   575      * properly.
       
   576      */
       
   577     @Override
       
   578     protected void engineUpdate(byte b) throws SignatureException
       
   579     {
       
   580         messageDigest.update(b);
       
   581         needsReset = true;
       
   582     }
       
   583 
       
   584     /**
       
   585      * Updates the data to be signed or verified, using the
       
   586      * specified array of bytes, starting at the specified offset.
       
   587      *
       
   588      * @param b the array of bytes
       
   589      * @param off the offset to start from in the array of bytes
       
   590      * @param len the number of bytes to use, starting at offset
       
   591      *
       
   592      * @exception SignatureException if the engine is not initialized
       
   593      * properly
       
   594      */
       
   595     @Override
       
   596     protected void engineUpdate(byte[] b, int off, int len)
       
   597         throws SignatureException
       
   598     {
       
   599         messageDigest.update(b, off, len);
       
   600         needsReset = true;
       
   601     }
       
   602 
       
   603     /**
       
   604      * Updates the data to be signed or verified, using the
       
   605      * specified ByteBuffer.
       
   606      *
       
   607      * @param input the ByteBuffer
       
   608      */
       
   609     @Override
       
   610     protected void engineUpdate(ByteBuffer input)
       
   611     {
       
   612         messageDigest.update(input);
       
   613         needsReset = true;
       
   614     }
       
   615 
       
   616     /**
       
   617      * Returns the signature bytes of all the data
       
   618      * updated so far.
       
   619      * The format of the signature depends on the underlying
       
   620      * signature scheme.
       
   621      *
       
   622      * @return the signature bytes of the signing operation's result.
       
   623      *
       
   624      * @exception SignatureException if the engine is not
       
   625      * initialized properly or if this signature algorithm is unable to
       
   626      * process the input data provided.
       
   627      */
       
   628     @Override
       
   629     protected byte[] engineSign() throws SignatureException {
       
   630 
       
   631         byte[] hash = getDigestValue();
       
   632 
       
   633         // Omit the hash OID when generating a Raw signature
       
   634         boolean noHashOID = this instanceof Raw;
       
   635 
       
   636         // Sign hash using MS Crypto APIs
       
   637 
       
   638         byte[] result = signHash(noHashOID, hash, hash.length,
       
   639             messageDigestAlgorithm, privateKey.getHCryptProvider(),
       
   640             privateKey.getHCryptKey());
       
   641 
       
   642         // Convert signature array from little endian to big endian
       
   643         return convertEndianArray(result);
       
   644     }
       
   645 
       
   646     /**
       
   647      * Convert array from big endian to little endian, or vice versa.
       
   648      */
       
   649     private byte[] convertEndianArray(byte[] byteArray)
       
   650     {
       
   651         if (byteArray == null || byteArray.length == 0)
       
   652             return byteArray;
       
   653 
       
   654         byte [] retval = new byte[byteArray.length];
       
   655 
       
   656         // make it big endian
       
   657         for (int i=0;i < byteArray.length;i++)
       
   658             retval[i] = byteArray[byteArray.length - i - 1];
       
   659 
       
   660         return retval;
       
   661     }
       
   662 
       
   663     /**
       
   664      * Sign hash using Microsoft Crypto API with HCRYPTKEY.
       
   665      * The returned data is in little-endian.
       
   666      */
       
   667     private native static byte[] signHash(boolean noHashOID, byte[] hash,
       
   668         int hashSize, String hashAlgorithm, long hCryptProv, long hCryptKey)
       
   669             throws SignatureException;
       
   670 
       
   671     /**
       
   672      * Verify a signed hash using Microsoft Crypto API with HCRYPTKEY.
       
   673      */
       
   674     private native static boolean verifySignedHash(byte[] hash, int hashSize,
       
   675         String hashAlgorithm, byte[] signature, int signatureSize,
       
   676         long hCryptProv, long hCryptKey) throws SignatureException;
       
   677 
       
   678     /**
       
   679      * Verifies the passed-in signature.
       
   680      *
       
   681      * @param sigBytes the signature bytes to be verified.
       
   682      *
       
   683      * @return true if the signature was verified, false if not.
       
   684      *
       
   685      * @exception SignatureException if the engine is not
       
   686      * initialized properly, the passed-in signature is improperly
       
   687      * encoded or of the wrong type, if this signature algorithm is unable to
       
   688      * process the input data provided, etc.
       
   689      */
       
   690     @Override
       
   691     protected boolean engineVerify(byte[] sigBytes)
       
   692         throws SignatureException
       
   693     {
       
   694         byte[] hash = getDigestValue();
       
   695 
       
   696         return verifySignedHash(hash, hash.length,
       
   697             messageDigestAlgorithm, convertEndianArray(sigBytes),
       
   698             sigBytes.length, publicKey.getHCryptProvider(),
       
   699             publicKey.getHCryptKey());
       
   700     }
       
   701 
       
   702     /**
       
   703      * Sets the specified algorithm parameter to the specified
       
   704      * value. This method supplies a general-purpose mechanism through
       
   705      * which it is possible to set the various parameters of this object.
       
   706      * A parameter may be any settable parameter for the algorithm, such as
       
   707      * a parameter size, or a source of random bits for signature generation
       
   708      * (if appropriate), or an indication of whether or not to perform
       
   709      * a specific but optional computation. A uniform algorithm-specific
       
   710      * naming scheme for each parameter is desirable but left unspecified
       
   711      * at this time.
       
   712      *
       
   713      * @param param the string identifier of the parameter.
       
   714      *
       
   715      * @param value the parameter value.
       
   716      *
       
   717      * @exception InvalidParameterException if <code>param</code> is an
       
   718      * invalid parameter for this signature algorithm engine,
       
   719      * the parameter is already set
       
   720      * and cannot be set again, a security exception occurs, and so on.
       
   721      *
       
   722      * @deprecated Replaced by {@link
       
   723      * #engineSetParameter(java.security.spec.AlgorithmParameterSpec)
       
   724      * engineSetParameter}.
       
   725      */
       
   726     @Override
       
   727     @Deprecated
       
   728     protected void engineSetParameter(String param, Object value)
       
   729         throws InvalidParameterException
       
   730     {
       
   731         throw new InvalidParameterException("Parameter not supported");
       
   732     }
       
   733 
       
   734     /**
       
   735      * Sets this signature engine with the specified algorithm parameter.
       
   736      *
       
   737      * @param params the parameters
       
   738      *
       
   739      * @exception InvalidAlgorithmParameterException if the given
       
   740      * parameter is invalid
       
   741      */
       
   742     @Override
       
   743     protected void engineSetParameter(AlgorithmParameterSpec params)
       
   744         throws InvalidAlgorithmParameterException
       
   745     {
       
   746         if (params != null) {
       
   747             throw new InvalidAlgorithmParameterException("No parameter accepted");
       
   748         }
       
   749     }
       
   750 
       
   751     /**
       
   752      * Gets the value of the specified algorithm parameter.
       
   753      * This method supplies a general-purpose mechanism through which it
       
   754      * is possible to get the various parameters of this object. A parameter
       
   755      * may be any settable parameter for the algorithm, such as a parameter
       
   756      * size, or  a source of random bits for signature generation (if
       
   757      * appropriate), or an indication of whether or not to perform a
       
   758      * specific but optional computation. A uniform algorithm-specific
       
   759      * naming scheme for each parameter is desirable but left unspecified
       
   760      * at this time.
       
   761      *
       
   762      * @param param the string name of the parameter.
       
   763      *
       
   764      * @return the object that represents the parameter value, or null if
       
   765      * there is none.
       
   766      *
       
   767      * @exception InvalidParameterException if <code>param</code> is an
       
   768      * invalid parameter for this engine, or another exception occurs while
       
   769      * trying to get this parameter.
       
   770      *
       
   771      * @deprecated
       
   772      */
       
   773     @Override
       
   774     @Deprecated
       
   775     protected Object engineGetParameter(String param)
       
   776         throws InvalidParameterException
       
   777     {
       
   778         throw new InvalidParameterException("Parameter not supported");
       
   779     }
       
   780 
       
   781     /**
       
   782      * Gets the algorithm parameter from this signature engine.
       
   783      *
       
   784      * @return the parameter, or null if no parameter is used.
       
   785      */
       
   786     @Override
       
   787     protected AlgorithmParameters engineGetParameters() {
       
   788         return null;
       
   789     }
       
   790 
       
   791     /**
       
   792      * Generates a public-key BLOB from a key's components.
       
   793      */
       
   794     // used by RSACipher
       
   795     static native byte[] generatePublicKeyBlob(
       
   796         int keyBitLength, byte[] modulus, byte[] publicExponent)
       
   797             throws InvalidKeyException;
       
   798 
       
   799     /**
       
   800      * Imports a public-key BLOB.
       
   801      */
       
   802     // used by RSACipher
       
   803     static native RSAPublicKey importPublicKey(byte[] keyBlob, int keySize)
       
   804         throws KeyStoreException;
       
   805 }