jdk/src/windows/classes/sun/security/mscapi/RSASignature.java
changeset 9533 13cc5e8eb9f1
parent 9524 8417d0e74ac5
child 10336 0bb1999251f8
--- a/jdk/src/windows/classes/sun/security/mscapi/RSASignature.java	Thu Apr 28 10:14:12 2011 -0700
+++ b/jdk/src/windows/classes/sun/security/mscapi/RSASignature.java	Fri Apr 29 00:21:54 2011 +0100
@@ -49,6 +49,7 @@
  * Objects should be instantiated by calling Signature.getInstance() using the
  * following algorithm names:
  *
+ *  . "NONEwithRSA"
  *  . "SHA1withRSA"
  *  . "SHA256withRSA"
  *  . "SHA384withRSA"
@@ -56,7 +57,12 @@
  *  . "MD5withRSA"
  *  . "MD2withRSA"
  *
- * Note: RSA keys must be at least 512 bits long
+ * NOTE: RSA keys must be at least 512 bits long.
+ *
+ * NOTE: NONEwithRSA must be supplied with a pre-computed message digest.
+ *       Only the following digest algorithms are supported: MD5, SHA-1,
+ *       SHA-256, SHA-384, SHA-512 and a special-purpose digest algorithm
+ *       which is a concatenation of SHA-1 and MD5 digests.
  *
  * @since   1.6
  * @author  Stanley Man-Kit Ho
@@ -67,7 +73,7 @@
     private final MessageDigest messageDigest;
 
     // message digest name
-    private final String messageDigestAlgorithm;
+    private String messageDigestAlgorithm;
 
     // flag indicating whether the digest has been reset
     private boolean needsReset;
@@ -78,6 +84,13 @@
     // the verification key
     private Key publicKey = null;
 
+    /**
+     * Constructs a new RSASignature. Used by Raw subclass.
+     */
+    RSASignature() {
+        messageDigest = null;
+        messageDigestAlgorithm = null;
+    }
 
     /**
      * Constructs a new RSASignature. Used by subclasses.
@@ -96,6 +109,94 @@
         needsReset = false;
     }
 
+    // Nested class for NONEwithRSA signatures
+    public static final class Raw extends RSASignature {
+
+        // the longest supported digest is 512 bits (SHA-512)
+        private static final int RAW_RSA_MAX = 64;
+
+        private final byte[] precomputedDigest;
+        private int offset = 0;
+
+        public Raw() {
+            precomputedDigest = new byte[RAW_RSA_MAX];
+        }
+
+        // Stores the precomputed message digest value.
+        @Override
+        protected void engineUpdate(byte b) throws SignatureException {
+            if (offset >= precomputedDigest.length) {
+                offset = RAW_RSA_MAX + 1;
+                return;
+            }
+            precomputedDigest[offset++] = b;
+        }
+
+        // Stores the precomputed message digest value.
+        @Override
+        protected void engineUpdate(byte[] b, int off, int len)
+                throws SignatureException {
+            if (offset + len > precomputedDigest.length) {
+                offset = RAW_RSA_MAX + 1;
+                return;
+            }
+            System.arraycopy(b, off, precomputedDigest, offset, len);
+            offset += len;
+        }
+
+        // Stores the precomputed message digest value.
+        @Override
+        protected void engineUpdate(ByteBuffer byteBuffer) {
+            int len = byteBuffer.remaining();
+            if (len <= 0) {
+                return;
+            }
+            if (offset + len > precomputedDigest.length) {
+                offset = RAW_RSA_MAX + 1;
+                return;
+            }
+            byteBuffer.get(precomputedDigest, offset, len);
+            offset += len;
+        }
+
+        @Override
+        protected void resetDigest(){
+            offset = 0;
+        }
+
+        // Returns the precomputed message digest value.
+        @Override
+        protected byte[] getDigestValue() throws SignatureException {
+            if (offset > RAW_RSA_MAX) {
+                throw new SignatureException("Message digest is too long");
+            }
+
+            // Determine the digest algorithm from the digest length
+            if (offset == 20) {
+                setDigestName("SHA1");
+            } else if (offset == 36) {
+                setDigestName("SHA1+MD5");
+            } else if (offset == 32) {
+                setDigestName("SHA-256");
+            } else if (offset == 48) {
+                setDigestName("SHA-384");
+            } else if (offset == 64) {
+                setDigestName("SHA-512");
+            } else if (offset == 16) {
+                setDigestName("MD5");
+            } else {
+                throw new SignatureException(
+                    "Message digest length is not supported");
+            }
+
+            byte[] result = new byte[offset];
+            System.arraycopy(precomputedDigest, 0, result, 0, offset);
+            offset = 0;
+
+            return result;
+        }
+    }
+
     public static final class SHA1 extends RSASignature {
         public SHA1() {
             super("SHA1");
@@ -204,18 +305,22 @@
     /**
      * Resets the message digest if needed.
      */
-    private void resetDigest() {
+    protected void resetDigest() {
         if (needsReset) {
             messageDigest.reset();
             needsReset = false;
         }
     }
 
-    private byte[] getDigestValue() {
+    protected byte[] getDigestValue() throws SignatureException {
         needsReset = false;
         return messageDigest.digest();
     }
 
+    protected void setDigestName(String name) {
+        messageDigestAlgorithm = name;
+    }
+
     /**
      * Updates the data to be signed or verified
      * using the specified byte.
@@ -277,9 +382,12 @@
 
         byte[] hash = getDigestValue();
 
+        // Omit the hash OID when generating a Raw signature
+        boolean noHashOID = this instanceof Raw;
+
         // Sign hash using MS Crypto APIs
 
-        byte[] result = signHash(hash, hash.length,
+        byte[] result = signHash(noHashOID, hash, hash.length,
             messageDigestAlgorithm, privateKey.getHCryptProvider(),
             privateKey.getHCryptKey());
 
@@ -308,8 +416,8 @@
      * Sign hash using Microsoft Crypto API with HCRYPTKEY.
      * The returned data is in little-endian.
      */
-    private native static byte[] signHash(byte[] hash, int hashSize,
-        String hashAlgorithm, long hCryptProv, long hCryptKey)
+    private native static byte[] signHash(boolean noHashOID, byte[] hash,
+        int hashSize, String hashAlgorithm, long hCryptProv, long hCryptKey)
             throws SignatureException;
 
     /**