提交 61d02916 编写于 作者: V vinnie

6753664: Support SHA256 (and higher) in SunMSCAPI

Reviewed-by: mullan
上级 cbcf28a8
......@@ -50,6 +50,9 @@ import sun.security.rsa.RSAKeyFactory;
* following algorithm names:
*
* . "SHA1withRSA"
* . "SHA256withRSA"
* . "SHA384withRSA"
* . "SHA512withRSA"
* . "MD5withRSA"
* . "MD2withRSA"
*
......@@ -63,7 +66,10 @@ abstract class RSASignature extends java.security.SignatureSpi
// message digest implementation we use
private final MessageDigest messageDigest;
// flag indicating whether the digest is reset
// message digest name
private final String messageDigestAlgorithm;
// flag indicating whether the digest has been reset
private boolean needsReset;
// the signing key
......@@ -73,10 +79,15 @@ abstract class RSASignature extends java.security.SignatureSpi
private Key publicKey = null;
/**
* Constructs a new RSASignature. Used by subclasses.
*/
RSASignature(String digestName) {
try {
messageDigest = MessageDigest.getInstance(digestName);
// Get the digest's canonical name
messageDigestAlgorithm = messageDigest.getAlgorithm();
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(e);
......@@ -91,6 +102,24 @@ abstract class RSASignature extends java.security.SignatureSpi
}
}
public static final class SHA256 extends RSASignature {
public SHA256() {
super("SHA-256");
}
}
public static final class SHA384 extends RSASignature {
public SHA384() {
super("SHA-384");
}
}
public static final class SHA512 extends RSASignature {
public SHA512() {
super("SHA-512");
}
}
public static final class MD5 extends RSASignature {
public MD5() {
super("MD5");
......@@ -103,16 +132,7 @@ abstract class RSASignature extends java.security.SignatureSpi
}
}
/**
* Initializes this signature object with the specified
* public key for verification operations.
*
* @param publicKey the public key of the identity whose signature is
* going to be verified.
*
* @exception InvalidKeyException if the key is improperly
* encoded, parameters are missing, and so on.
*/
// initialize for signing. See JCA doc
protected void engineInitVerify(PublicKey key)
throws InvalidKeyException
{
......@@ -158,24 +178,12 @@ abstract class RSASignature extends java.security.SignatureSpi
publicKey = (sun.security.mscapi.RSAPublicKey) key;
}
if (needsReset) {
messageDigest.reset();
needsReset = false;
}
this.privateKey = null;
resetDigest();
}
/**
* Initializes this signature object with the specified
* private key for signing operations.
*
* @param privateKey the private key of the identity whose signature
* will be generated.
*
* @exception InvalidKeyException if the key is improperly
* encoded, parameters are missing, and so on.
*/
protected void engineInitSign(PrivateKey key)
throws InvalidKeyException
// initialize for signing. See JCA doc
protected void engineInitSign(PrivateKey key) throws InvalidKeyException
{
// This signature accepts only RSAPrivateKey
if ((key instanceof sun.security.mscapi.RSAPrivateKey) == false) {
......@@ -189,12 +197,25 @@ abstract class RSASignature extends java.security.SignatureSpi
null, RSAKeyPairGenerator.KEY_SIZE_MIN,
RSAKeyPairGenerator.KEY_SIZE_MAX);
this.publicKey = null;
resetDigest();
}
/**
* Resets the message digest if needed.
*/
private void resetDigest() {
if (needsReset) {
messageDigest.reset();
needsReset = false;
}
}
private byte[] getDigestValue() {
needsReset = false;
return messageDigest.digest();
}
/**
* Updates the data to be signed or verified
* using the specified byte.
......@@ -254,13 +275,12 @@ abstract class RSASignature extends java.security.SignatureSpi
*/
protected byte[] engineSign() throws SignatureException {
byte[] hash = messageDigest.digest();
needsReset = false;
byte[] hash = getDigestValue();
// Sign hash using MS Crypto APIs
byte[] result = signHash(hash, hash.length,
messageDigest.getAlgorithm(), privateKey.getHCryptProvider(),
messageDigestAlgorithm, privateKey.getHCryptProvider(),
privateKey.getHCryptKey());
// Convert signature array from little endian to big endian
......@@ -314,11 +334,10 @@ abstract class RSASignature extends java.security.SignatureSpi
protected boolean engineVerify(byte[] sigBytes)
throws SignatureException
{
byte[] hash = messageDigest.digest();
needsReset = false;
byte[] hash = getDigestValue();
return verifySignedHash(hash, hash.length,
messageDigest.getAlgorithm(), convertEndianArray(sigBytes),
messageDigestAlgorithm, convertEndianArray(sigBytes),
sigBytes.length, publicKey.getHCryptProvider(),
publicKey.getHCryptKey());
}
......
/*
* Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -81,6 +81,12 @@ public final class SunMSCAPI extends Provider {
*/
map.put("Signature.SHA1withRSA",
"sun.security.mscapi.RSASignature$SHA1");
map.put("Signature.SHA256withRSA",
"sun.security.mscapi.RSASignature$SHA256");
map.put("Signature.SHA384withRSA",
"sun.security.mscapi.RSASignature$SHA384");
map.put("Signature.SHA512withRSA",
"sun.security.mscapi.RSASignature$SHA512");
map.put("Signature.MD5withRSA",
"sun.security.mscapi.RSASignature$MD5");
map.put("Signature.MD2withRSA",
......@@ -89,12 +95,16 @@ public final class SunMSCAPI extends Provider {
// supported key classes
map.put("Signature.SHA1withRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
map.put("Signature.SHA256withRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
map.put("Signature.SHA384withRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
map.put("Signature.SHA512withRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
map.put("Signature.MD5withRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
map.put("Signature.MD2withRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
map.put("Signature.NONEwithRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
/*
* Key Pair Generator engines
......
......@@ -483,6 +483,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_signHash
jbyte* pHashBuffer = NULL;
jbyte* pSignedHashBuffer = NULL;
jbyteArray jSignedHash = NULL;
HCRYPTPROV hCryptProvAlt = NULL;
__try
{
......@@ -492,8 +493,32 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_signHash
// Acquire a hash object handle.
if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash) == FALSE)
{
ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
__leave;
// Failover to using the PROV_RSA_AES CSP
DWORD cbData = 256;
BYTE pbData[256];
pbData[0] = '\0';
// Get name of the key container
::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER,
(BYTE *)pbData, &cbData, 0);
// Acquire an alternative CSP handle
if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL,
PROV_RSA_AES, 0) == FALSE)
{
ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
__leave;
}
// Acquire a hash object handle.
if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0,
&hHash) == FALSE)
{
ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
__leave;
}
}
// Copy hash from Java to native buffer
......@@ -546,6 +571,9 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_signHash
}
__finally
{
if (hCryptProvAlt)
::CryptReleaseContext(hCryptProvAlt, 0);
if (pSignedHashBuffer)
delete [] pSignedHashBuffer;
......@@ -574,6 +602,7 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_RSASignature_verifySignedHas
jbyte* pSignedHashBuffer = NULL;
DWORD dwSignedHashBufferLen = jSignedHashSize;
jboolean result = JNI_FALSE;
HCRYPTPROV hCryptProvAlt = NULL;
__try
{
......@@ -584,8 +613,32 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_RSASignature_verifySignedHas
if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash)
== FALSE)
{
ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
__leave;
// Failover to using the PROV_RSA_AES CSP
DWORD cbData = 256;
BYTE pbData[256];
pbData[0] = '\0';
// Get name of the key container
::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER,
(BYTE *)pbData, &cbData, 0);
// Acquire an alternative CSP handle
if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL,
PROV_RSA_AES, 0) == FALSE)
{
ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
__leave;
}
// Acquire a hash object handle.
if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0,
&hHash) == FALSE)
{
ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
__leave;
}
}
// Copy hash and signedHash from Java to native buffer
......@@ -616,6 +669,9 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_RSASignature_verifySignedHas
__finally
{
if (hCryptProvAlt)
::CryptReleaseContext(hCryptProvAlt, 0);
if (pSignedHashBuffer)
delete [] pSignedHashBuffer;
......@@ -648,15 +704,27 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSAKeyPairGenerator_generateR
pszKeyContainerName = env->GetStringUTFChars(keyContainerName, NULL);
// Acquire a CSP context (create a new key container).
// Prefer a PROV_RSA_AES CSP, when available, due to its support
// for SHA-2-based signatures.
if (::CryptAcquireContext(
&hCryptProv,
pszKeyContainerName,
NULL,
PROV_RSA_FULL,
PROV_RSA_AES,
CRYPT_NEWKEYSET) == FALSE)
{
ThrowException(env, KEY_EXCEPTION, GetLastError());
__leave;
// Failover to using the default CSP (PROV_RSA_FULL)
if (::CryptAcquireContext(
&hCryptProv,
pszKeyContainerName,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET) == FALSE)
{
ThrowException(env, KEY_EXCEPTION, GetLastError());
__leave;
}
}
// Generate an RSA keypair
......@@ -1849,15 +1917,27 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSASignature_importPublicKey
pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0);
// Acquire a CSP context (create a new key container).
// Prefer a PROV_RSA_AES CSP, when available, due to its support
// for SHA-2-based signatures.
if (::CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
PROV_RSA_AES,
CRYPT_VERIFYCONTEXT) == FALSE)
{
ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
__leave;
// Failover to using the default CSP (PROV_RSA_FULL)
if (::CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT) == FALSE)
{
ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
__leave;
}
}
// Import the public key
......
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @see SignUsingSHA2withRSA.sh
*/
import java.security.*;
import java.util.*;
public class SignUsingSHA2withRSA {
private static final byte[] toBeSigned = new byte[] {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10
};
private static List<byte[]> generatedSignatures = new ArrayList<>();
public static void main(String[] args) throws Exception {
Provider[] providers = Security.getProviders("Signature.SHA256withRSA");
if (providers == null) {
System.out.println("No JCE providers support the " +
"'Signature.SHA256withRSA' algorithm");
System.out.println("Skipping this test...");
return;
} else {
System.out.println("The following JCE providers support the " +
"'Signature.SHA256withRSA' algorithm: ");
for (Provider provider : providers) {
System.out.println(" " + provider.getName());
}
}
System.out.println("-------------------------------------------------");
KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
ks.load(null, null);
System.out.println("Loaded keystore: Windows-MY");
Enumeration e = ks.aliases();
PrivateKey privateKey = null;
PublicKey publicKey = null;
while (e.hasMoreElements()) {
String alias = (String) e.nextElement();
if (alias.equals("6753664")) {
System.out.println("Loaded entry: " + alias);
privateKey = (PrivateKey) ks.getKey(alias, null);
publicKey = (PublicKey) ks.getCertificate(alias).getPublicKey();
}
}
if (privateKey == null || publicKey == null) {
throw new Exception("Cannot load the keys need to run this test");
}
System.out.println("-------------------------------------------------");
generatedSignatures.add(signUsing("SHA256withRSA", privateKey));
generatedSignatures.add(signUsing("SHA384withRSA", privateKey));
generatedSignatures.add(signUsing("SHA512withRSA", privateKey));
System.out.println("-------------------------------------------------");
verifyUsing("SHA256withRSA", publicKey, generatedSignatures.get(0));
verifyUsing("SHA384withRSA", publicKey, generatedSignatures.get(1));
verifyUsing("SHA512withRSA", publicKey, generatedSignatures.get(2));
System.out.println("-------------------------------------------------");
}
private static byte[] signUsing(String signAlgorithm,
PrivateKey privateKey) throws Exception {
// Must explicitly specify the SunMSCAPI JCE provider
// (otherwise SunJCE is chosen because it appears earlier in the list)
Signature sig1 = Signature.getInstance(signAlgorithm, "SunMSCAPI");
if (sig1 == null) {
throw new Exception("'" + signAlgorithm + "' is not supported");
}
System.out.println("Using " + signAlgorithm + " signer from the " +
sig1.getProvider().getName() + " JCE provider");
System.out.println("Using key: " + privateKey);
sig1.initSign(privateKey);
sig1.update(toBeSigned);
byte [] sigBytes = null;
try {
sigBytes = sig1.sign();
System.out.println("Generated RSA signature over a " +
toBeSigned.length + "-byte data (signature length: " +
sigBytes.length * 8 + " bits)");
System.out.println(String.format("0x%0" +
(sigBytes.length * 2) + "x",
new java.math.BigInteger(1, sigBytes)));
} catch (SignatureException se) {
System.out.println("Error generating RSA signature: " + se);
}
return sigBytes;
}
private static void verifyUsing(String signAlgorithm, PublicKey publicKey,
byte[] signature) throws Exception {
// Must explicitly specify the SunMSCAPI JCE provider
// (otherwise SunJCE is chosen because it appears earlier in the list)
Signature sig1 = Signature.getInstance(signAlgorithm, "SunMSCAPI");
if (sig1 == null) {
throw new Exception("'" + signAlgorithm + "' is not supported");
}
System.out.println("Using " + signAlgorithm + " verifier from the "
+ sig1.getProvider().getName() + " JCE provider");
System.out.println("Using key: " + publicKey);
System.out.println("\nVerifying RSA Signature over a " +
toBeSigned.length + "-byte data (signature length: " +
signature.length * 8 + " bits)");
System.out.println(String.format("0x%0" + (signature.length * 2) +
"x", new java.math.BigInteger(1, signature)));
sig1.initVerify(publicKey);
sig1.update(toBeSigned);
if (sig1.verify(signature)) {
System.out.println("Verify PASSED\n");
} else {
throw new Exception("Verify FAILED");
}
}
}
#!/bin/sh
#
# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# @test
# @bug 6753664
# @run shell SignUsingSHA2withRSA.sh
# @summary Support SHA256 (and higher) in SunMSCAPI
# set a few environment variables so that the shell-script can run stand-alone
# in the source directory
if [ "${TESTSRC}" = "" ] ; then
TESTSRC="."
fi
if [ "${TESTCLASSES}" = "" ] ; then
TESTCLASSES="."
fi
if [ "${TESTJAVA}" = "" ] ; then
echo "TESTJAVA not set. Test cannot execute."
echo "FAILED!!!"
exit 1
fi
OS=`uname -s`
case "$OS" in
Windows* | CYGWIN* )
echo "Creating a temporary RSA keypair in the Windows-My store..."
${TESTJAVA}/bin/keytool \
-genkeypair \
-storetype Windows-My \
-keyalg RSA \
-alias 6753664 \
-dname "cn=6753664,c=US" \
-noprompt
echo
echo "Running the test..."
${TESTJAVA}/bin/javac -d . ${TESTSRC}\\SignUsingSHA2withRSA.java
${TESTJAVA}/bin/java SignUsingSHA2withRSA
rc=$?
echo
echo "Removing the temporary RSA keypair from the Windows-My store..."
${TESTJAVA}/bin/keytool \
-delete \
-storetype Windows-My \
-alias 6753664
echo done.
exit $rc
;;
* )
echo "This test is not intended for '$OS' - passing test"
exit 0
;;
esac
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册