|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.rsa; |
|
|
|
import java.io.IOException; |
|
import java.nio.ByteBuffer; |
|
|
|
import java.security.*; |
|
import java.security.interfaces.*; |
|
import java.security.spec.AlgorithmParameterSpec; |
|
|
|
import sun.security.rsa.RSAUtil.KeyType; |
|
import sun.security.util.*; |
|
import sun.security.x509.AlgorithmId; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract class RSASignature extends SignatureSpi { |
|
|
|
// we sign an ASN.1 SEQUENCE of AlgorithmId and digest |
|
// it has the form 30:xx:30:xx:[digestOID]:05:00:04:xx:[digest] |
|
|
|
private static final int baseLength = 8; |
|
|
|
|
|
private final ObjectIdentifier digestOID; |
|
|
|
|
|
private final int encodedLength; |
|
|
|
|
|
private final MessageDigest md; |
|
|
|
private boolean digestReset; |
|
|
|
|
|
private RSAPrivateKey privateKey; |
|
|
|
private RSAPublicKey publicKey; |
|
|
|
|
|
private RSAPadding padding; |
|
|
|
|
|
|
|
*/ |
|
RSASignature(String algorithm, ObjectIdentifier digestOID, int oidLength) { |
|
this.digestOID = digestOID; |
|
try { |
|
md = MessageDigest.getInstance(algorithm); |
|
} catch (NoSuchAlgorithmException e) { |
|
throw new ProviderException(e); |
|
} |
|
digestReset = true; |
|
encodedLength = baseLength + oidLength + md.getDigestLength(); |
|
} |
|
|
|
|
|
@Override |
|
protected void engineInitVerify(PublicKey publicKey) |
|
throws InvalidKeyException { |
|
RSAPublicKey rsaKey = (RSAPublicKey)RSAKeyFactory.toRSAKey(publicKey); |
|
this.privateKey = null; |
|
this.publicKey = rsaKey; |
|
initCommon(rsaKey, null); |
|
} |
|
|
|
|
|
@Override |
|
protected void engineInitSign(PrivateKey privateKey) |
|
throws InvalidKeyException { |
|
engineInitSign(privateKey, null); |
|
} |
|
|
|
|
|
@Override |
|
protected void engineInitSign(PrivateKey privateKey, SecureRandom random) |
|
throws InvalidKeyException { |
|
RSAPrivateKey rsaKey = |
|
(RSAPrivateKey)RSAKeyFactory.toRSAKey(privateKey); |
|
this.privateKey = rsaKey; |
|
this.publicKey = null; |
|
initCommon(rsaKey, random); |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void initCommon(RSAKey rsaKey, SecureRandom random) |
|
throws InvalidKeyException { |
|
try { |
|
RSAUtil.checkParamsAgainstType(KeyType.RSA, rsaKey.getParams()); |
|
} catch (ProviderException e) { |
|
throw new InvalidKeyException("Invalid key for RSA signatures", e); |
|
} |
|
resetDigest(); |
|
int keySize = RSACore.getByteLength(rsaKey); |
|
try { |
|
padding = RSAPadding.getInstance |
|
(RSAPadding.PAD_BLOCKTYPE_1, keySize, random); |
|
} catch (InvalidAlgorithmParameterException iape) { |
|
throw new InvalidKeyException(iape.getMessage()); |
|
} |
|
int maxDataSize = padding.getMaxDataSize(); |
|
if (encodedLength > maxDataSize) { |
|
throw new InvalidKeyException |
|
("Key is too short for this signature algorithm"); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void resetDigest() { |
|
if (digestReset == false) { |
|
md.reset(); |
|
digestReset = true; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private byte[] getDigestValue() { |
|
digestReset = true; |
|
return md.digest(); |
|
} |
|
|
|
|
|
@Override |
|
protected void engineUpdate(byte b) throws SignatureException { |
|
md.update(b); |
|
digestReset = false; |
|
} |
|
|
|
|
|
@Override |
|
protected void engineUpdate(byte[] b, int off, int len) |
|
throws SignatureException { |
|
md.update(b, off, len); |
|
digestReset = false; |
|
} |
|
|
|
|
|
@Override |
|
protected void engineUpdate(ByteBuffer b) { |
|
md.update(b); |
|
digestReset = false; |
|
} |
|
|
|
|
|
@Override |
|
protected byte[] engineSign() throws SignatureException { |
|
if (privateKey == null) { |
|
throw new SignatureException("Missing private key"); |
|
} |
|
byte[] digest = getDigestValue(); |
|
try { |
|
byte[] encoded = encodeSignature(digestOID, digest); |
|
byte[] padded = padding.pad(encoded); |
|
byte[] encrypted = RSACore.rsa(padded, privateKey, true); |
|
return encrypted; |
|
} catch (GeneralSecurityException e) { |
|
throw new SignatureException("Could not sign data", e); |
|
} catch (IOException e) { |
|
throw new SignatureException("Could not encode data", e); |
|
} |
|
} |
|
|
|
|
|
@Override |
|
protected boolean engineVerify(byte[] sigBytes) throws SignatureException { |
|
if (publicKey == null) { |
|
throw new SignatureException("Missing public key"); |
|
} |
|
|
|
if (sigBytes.length != RSACore.getByteLength(publicKey)) { |
|
throw new SignatureException("Signature length not correct: got " + |
|
sigBytes.length + " but was expecting " + |
|
RSACore.getByteLength(publicKey)); |
|
} |
|
byte[] digest = getDigestValue(); |
|
try { |
|
byte[] decrypted = RSACore.rsa(sigBytes, publicKey); |
|
byte[] unpadded = padding.unpad(decrypted); |
|
byte[] decodedDigest = decodeSignature(digestOID, unpadded); |
|
return MessageDigest.isEqual(digest, decodedDigest); |
|
} catch (javax.crypto.BadPaddingException e) { |
|
// occurs if the app has used the wrong RSA public key |
|
// or if sigBytes is invalid |
|
// return false rather than propagating the exception for |
|
|
|
return false; |
|
} catch (IOException e) { |
|
throw new SignatureException("Signature encoding error", e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest) |
|
throws IOException { |
|
DerOutputStream out = new DerOutputStream(); |
|
new AlgorithmId(oid).encode(out); |
|
out.putOctetString(digest); |
|
DerValue result = |
|
new DerValue(DerValue.tag_Sequence, out.toByteArray()); |
|
return result.toByteArray(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public static byte[] decodeSignature(ObjectIdentifier oid, byte[] sig) |
|
throws IOException { |
|
|
|
DerInputStream in = new DerInputStream(sig, 0, sig.length, false); |
|
DerValue[] values = in.getSequence(2); |
|
if ((values.length != 2) || (in.available() != 0)) { |
|
throw new IOException("SEQUENCE length error"); |
|
} |
|
AlgorithmId algId = AlgorithmId.parse(values[0]); |
|
if (algId.getOID().equals((Object)oid) == false) { |
|
throw new IOException("ObjectIdentifier mismatch: " |
|
+ algId.getOID()); |
|
} |
|
if (algId.getEncodedParams() != null) { |
|
throw new IOException("Unexpected AlgorithmId parameters"); |
|
} |
|
byte[] digest = values[1].getOctetString(); |
|
return digest; |
|
} |
|
|
|
|
|
@Deprecated |
|
@Override |
|
protected void engineSetParameter(String param, Object value) |
|
throws InvalidParameterException { |
|
throw new UnsupportedOperationException("setParameter() not supported"); |
|
} |
|
|
|
|
|
@Override |
|
protected void engineSetParameter(AlgorithmParameterSpec params) |
|
throws InvalidAlgorithmParameterException { |
|
if (params != null) { |
|
throw new InvalidAlgorithmParameterException("No parameters accepted"); |
|
} |
|
} |
|
|
|
|
|
@Deprecated |
|
@Override |
|
protected Object engineGetParameter(String param) |
|
throws InvalidParameterException { |
|
throw new UnsupportedOperationException("getParameter() not supported"); |
|
} |
|
|
|
|
|
@Override |
|
protected AlgorithmParameters engineGetParameters() { |
|
return null; |
|
} |
|
|
|
|
|
public static final class MD2withRSA extends RSASignature { |
|
public MD2withRSA() { |
|
super("MD2", AlgorithmId.MD2_oid, 10); |
|
} |
|
} |
|
|
|
|
|
public static final class MD5withRSA extends RSASignature { |
|
public MD5withRSA() { |
|
super("MD5", AlgorithmId.MD5_oid, 10); |
|
} |
|
} |
|
|
|
|
|
public static final class SHA1withRSA extends RSASignature { |
|
public SHA1withRSA() { |
|
super("SHA-1", AlgorithmId.SHA_oid, 7); |
|
} |
|
} |
|
|
|
|
|
public static final class SHA224withRSA extends RSASignature { |
|
public SHA224withRSA() { |
|
super("SHA-224", AlgorithmId.SHA224_oid, 11); |
|
} |
|
} |
|
|
|
|
|
public static final class SHA256withRSA extends RSASignature { |
|
public SHA256withRSA() { |
|
super("SHA-256", AlgorithmId.SHA256_oid, 11); |
|
} |
|
} |
|
|
|
|
|
public static final class SHA384withRSA extends RSASignature { |
|
public SHA384withRSA() { |
|
super("SHA-384", AlgorithmId.SHA384_oid, 11); |
|
} |
|
} |
|
|
|
|
|
public static final class SHA512withRSA extends RSASignature { |
|
public SHA512withRSA() { |
|
super("SHA-512", AlgorithmId.SHA512_oid, 11); |
|
} |
|
} |
|
|
|
|
|
public static final class SHA512_224withRSA extends RSASignature { |
|
public SHA512_224withRSA() { |
|
super("SHA-512/224", AlgorithmId.SHA512_224_oid, 11); |
|
} |
|
} |
|
|
|
|
|
public static final class SHA512_256withRSA extends RSASignature { |
|
public SHA512_256withRSA() { |
|
super("SHA-512/256", AlgorithmId.SHA512_256_oid, 11); |
|
} |
|
} |
|
} |