1545N/A/*
2362N/A * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
1545N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1545N/A *
1545N/A * This code is free software; you can redistribute it and/or modify it
1545N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
1545N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
1545N/A *
1545N/A * This code is distributed in the hope that it will be useful, but WITHOUT
1545N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1545N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1545N/A * version 2 for more details (a copy is included in the LICENSE file that
1545N/A * accompanied this code).
1545N/A *
1545N/A * You should have received a copy of the GNU General Public License version
1545N/A * 2 along with this work; if not, write to the Free Software Foundation,
1545N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1545N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
1545N/A */
1545N/A
1545N/Apackage sun.security.ec;
1545N/A
1545N/Aimport java.io.IOException;
1545N/Aimport java.nio.ByteBuffer;
1545N/Aimport java.math.BigInteger;
1545N/Aimport java.util.Arrays;
1545N/A
1545N/Aimport java.security.*;
1545N/Aimport java.security.interfaces.*;
1545N/Aimport java.security.spec.*;
1545N/A
1545N/Aimport sun.security.jca.JCAUtil;
1545N/Aimport sun.security.util.*;
1545N/Aimport sun.security.x509.AlgorithmId;
1545N/A
1545N/A/**
1545N/A * ECDSA signature implementation. This class currently supports the
1545N/A * following algorithm names:
1545N/A *
1545N/A * . "NONEwithECDSA"
1545N/A * . "SHA1withECDSA"
1545N/A * . "SHA256withECDSA"
1545N/A * . "SHA384withECDSA"
1545N/A * . "SHA512withECDSA"
1545N/A *
1545N/A * @since 1.7
1545N/A */
1545N/Aabstract class ECDSASignature extends SignatureSpi {
1545N/A
1545N/A // message digest implementation we use
1545N/A private final MessageDigest messageDigest;
1545N/A
1545N/A // supplied entropy
1545N/A private SecureRandom random;
1545N/A
1545N/A // flag indicating whether the digest has been reset
1545N/A private boolean needsReset;
1545N/A
1545N/A // private key, if initialized for signing
1545N/A private ECPrivateKey privateKey;
1545N/A
1545N/A // public key, if initialized for verifying
1545N/A private ECPublicKey publicKey;
1545N/A
1545N/A /**
1545N/A * Constructs a new ECDSASignature. Used by Raw subclass.
1545N/A *
1545N/A * @exception ProviderException if the native ECC library is unavailable.
1545N/A */
1545N/A ECDSASignature() {
1545N/A messageDigest = null;
1545N/A }
1545N/A
1545N/A /**
1545N/A * Constructs a new ECDSASignature. Used by subclasses.
1545N/A */
1545N/A ECDSASignature(String digestName) {
1545N/A try {
1545N/A messageDigest = MessageDigest.getInstance(digestName);
1545N/A } catch (NoSuchAlgorithmException e) {
1545N/A throw new ProviderException(e);
1545N/A }
1545N/A needsReset = false;
1545N/A }
1545N/A
1545N/A // Nested class for NONEwithECDSA signatures
1545N/A public static final class Raw extends ECDSASignature {
1545N/A
1545N/A // the longest supported digest is 512 bits (SHA-512)
1545N/A private static final int RAW_ECDSA_MAX = 64;
1545N/A
1545N/A private final byte[] precomputedDigest;
1545N/A private int offset = 0;
1545N/A
1545N/A public Raw() {
1545N/A precomputedDigest = new byte[RAW_ECDSA_MAX];
1545N/A }
1545N/A
1545N/A // Stores the precomputed message digest value.
1545N/A @Override
1545N/A protected void engineUpdate(byte b) throws SignatureException {
1545N/A if (offset >= precomputedDigest.length) {
1545N/A offset = RAW_ECDSA_MAX + 1;
1545N/A return;
1545N/A }
1545N/A precomputedDigest[offset++] = b;
1545N/A }
1545N/A
1545N/A // Stores the precomputed message digest value.
1545N/A @Override
1545N/A protected void engineUpdate(byte[] b, int off, int len)
1545N/A throws SignatureException {
1545N/A if (offset >= precomputedDigest.length) {
1545N/A offset = RAW_ECDSA_MAX + 1;
1545N/A return;
1545N/A }
1545N/A System.arraycopy(b, off, precomputedDigest, offset, len);
1545N/A offset += len;
1545N/A }
1545N/A
1545N/A // Stores the precomputed message digest value.
1545N/A @Override
1545N/A protected void engineUpdate(ByteBuffer byteBuffer) {
1545N/A int len = byteBuffer.remaining();
1545N/A if (len <= 0) {
1545N/A return;
1545N/A }
1545N/A if (offset + len >= precomputedDigest.length) {
1545N/A offset = RAW_ECDSA_MAX + 1;
1545N/A return;
1545N/A }
1545N/A byteBuffer.get(precomputedDigest, offset, len);
1545N/A offset += len;
1545N/A }
1545N/A
1545N/A @Override
1545N/A protected void resetDigest(){
1545N/A offset = 0;
1545N/A }
1545N/A
1545N/A // Returns the precomputed message digest value.
1545N/A @Override
1545N/A protected byte[] getDigestValue() throws SignatureException {
1545N/A if (offset > RAW_ECDSA_MAX) {
1545N/A throw new SignatureException("Message digest is too long");
1545N/A
1545N/A }
1545N/A byte[] result = new byte[offset];
1545N/A System.arraycopy(precomputedDigest, 0, result, 0, offset);
1545N/A offset = 0;
1545N/A
1545N/A return result;
1545N/A }
1545N/A }
1545N/A
1545N/A // Nested class for SHA1withECDSA signatures
1545N/A public static final class SHA1 extends ECDSASignature {
1545N/A public SHA1() {
1545N/A super("SHA1");
1545N/A }
1545N/A }
1545N/A
1545N/A // Nested class for SHA256withECDSA signatures
1545N/A public static final class SHA256 extends ECDSASignature {
1545N/A public SHA256() {
1545N/A super("SHA-256");
1545N/A }
1545N/A }
1545N/A
1545N/A // Nested class for SHA384withECDSA signatures
1545N/A public static final class SHA384 extends ECDSASignature {
1545N/A public SHA384() {
1545N/A super("SHA-384");
1545N/A }
1545N/A }
1545N/A
1545N/A // Nested class for SHA512withECDSA signatures
1545N/A public static final class SHA512 extends ECDSASignature {
1545N/A public SHA512() {
1545N/A super("SHA-512");
1545N/A }
1545N/A }
1545N/A
1545N/A // initialize for verification. See JCA doc
1545N/A @Override
1545N/A protected void engineInitVerify(PublicKey publicKey)
1545N/A throws InvalidKeyException {
1545N/A this.publicKey = (ECPublicKey) ECKeyFactory.toECKey(publicKey);
1545N/A
1545N/A // Should check that the supplied key is appropriate for signature
1545N/A // algorithm (e.g. P-256 for SHA256withECDSA)
1545N/A this.privateKey = null;
1545N/A resetDigest();
1545N/A }
1545N/A
1545N/A // initialize for signing. See JCA doc
1545N/A @Override
1545N/A protected void engineInitSign(PrivateKey privateKey)
1545N/A throws InvalidKeyException {
1545N/A engineInitSign(privateKey, null);
1545N/A }
1545N/A
1545N/A // initialize for signing. See JCA doc
1545N/A @Override
1545N/A protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
1545N/A throws InvalidKeyException {
1545N/A this.privateKey = (ECPrivateKey) ECKeyFactory.toECKey(privateKey);
1545N/A
1545N/A // Should check that the supplied key is appropriate for signature
1545N/A // algorithm (e.g. P-256 for SHA256withECDSA)
1545N/A this.publicKey = null;
1545N/A this.random = random;
1545N/A resetDigest();
1545N/A }
1545N/A
1545N/A /**
1545N/A * Resets the message digest if needed.
1545N/A */
1545N/A protected void resetDigest() {
1545N/A if (needsReset) {
1545N/A if (messageDigest != null) {
1545N/A messageDigest.reset();
1545N/A }
1545N/A needsReset = false;
1545N/A }
1545N/A }
1545N/A
1545N/A /**
1545N/A * Returns the message digest value.
1545N/A */
1545N/A protected byte[] getDigestValue() throws SignatureException {
1545N/A needsReset = false;
1545N/A return messageDigest.digest();
1545N/A }
1545N/A
1545N/A // update the signature with the plaintext data. See JCA doc
1545N/A @Override
1545N/A protected void engineUpdate(byte b) throws SignatureException {
1545N/A messageDigest.update(b);
1545N/A needsReset = true;
1545N/A }
1545N/A
1545N/A // update the signature with the plaintext data. See JCA doc
1545N/A @Override
1545N/A protected void engineUpdate(byte[] b, int off, int len)
1545N/A throws SignatureException {
1545N/A messageDigest.update(b, off, len);
1545N/A needsReset = true;
1545N/A }
1545N/A
1545N/A // update the signature with the plaintext data. See JCA doc
1545N/A @Override
1545N/A protected void engineUpdate(ByteBuffer byteBuffer) {
1545N/A int len = byteBuffer.remaining();
1545N/A if (len <= 0) {
1545N/A return;
1545N/A }
1545N/A
1545N/A messageDigest.update(byteBuffer);
1545N/A needsReset = true;
1545N/A }
1545N/A
1545N/A // sign the data and return the signature. See JCA doc
1545N/A @Override
1545N/A protected byte[] engineSign() throws SignatureException {
1545N/A byte[] s = privateKey.getS().toByteArray();
1545N/A ECParameterSpec params = privateKey.getParams();
1545N/A byte[] encodedParams = ECParameters.encodeParameters(params); // DER OID
1545N/A int keySize = params.getCurve().getField().getFieldSize();
1545N/A
1674N/A // seed is twice the key size (in bytes) plus 1
1674N/A byte[] seed = new byte[(((keySize + 7) >> 3) + 1) * 2];
1545N/A if (random == null) {
1545N/A random = JCAUtil.getSecureRandom();
1545N/A }
1545N/A random.nextBytes(seed);
1545N/A
1545N/A try {
1545N/A
1545N/A return encodeSignature(
1545N/A signDigest(getDigestValue(), s, encodedParams, seed));
1545N/A
1545N/A } catch (GeneralSecurityException e) {
1545N/A throw new SignatureException("Could not sign data", e);
1545N/A }
1545N/A }
1545N/A
1545N/A // verify the data and return the result. See JCA doc
1545N/A @Override
1545N/A protected boolean engineVerify(byte[] signature) throws SignatureException {
1545N/A
1545N/A byte[] w;
1545N/A ECParameterSpec params = publicKey.getParams();
1545N/A byte[] encodedParams = ECParameters.encodeParameters(params); // DER OID
1545N/A
1545N/A if (publicKey instanceof ECPublicKeyImpl) {
1545N/A w = ((ECPublicKeyImpl)publicKey).getEncodedPublicValue();
1545N/A } else { // instanceof ECPublicKey
1545N/A w = ECParameters.encodePoint(publicKey.getW(), params.getCurve());
1545N/A }
1545N/A
1545N/A try {
1545N/A
1545N/A return verifySignedDigest(
1545N/A decodeSignature(signature), getDigestValue(), w, encodedParams);
1545N/A
1545N/A } catch (GeneralSecurityException e) {
1545N/A throw new SignatureException("Could not verify signature", e);
1545N/A }
1545N/A }
1545N/A
1545N/A // set parameter, not supported. See JCA doc
1545N/A @Override
1545N/A protected void engineSetParameter(String param, Object value)
1545N/A throws InvalidParameterException {
1545N/A throw new UnsupportedOperationException("setParameter() not supported");
1545N/A }
1545N/A
1545N/A // get parameter, not supported. See JCA doc
1545N/A @Override
1545N/A protected Object engineGetParameter(String param)
1545N/A throws InvalidParameterException {
1545N/A throw new UnsupportedOperationException("getParameter() not supported");
1545N/A }
1545N/A
1545N/A // Convert the concatenation of R and S into their DER encoding
1545N/A private byte[] encodeSignature(byte[] signature) throws SignatureException {
1674N/A
1545N/A try {
1545N/A
1545N/A int n = signature.length >> 1;
1545N/A byte[] bytes = new byte[n];
1545N/A System.arraycopy(signature, 0, bytes, 0, n);
1545N/A BigInteger r = new BigInteger(1, bytes);
1545N/A System.arraycopy(signature, n, bytes, 0, n);
1545N/A BigInteger s = new BigInteger(1, bytes);
1545N/A
1545N/A DerOutputStream out = new DerOutputStream(signature.length + 10);
1545N/A out.putInteger(r);
1545N/A out.putInteger(s);
1545N/A DerValue result =
1545N/A new DerValue(DerValue.tag_Sequence, out.toByteArray());
1545N/A
1545N/A return result.toByteArray();
1545N/A
1545N/A } catch (Exception e) {
1545N/A throw new SignatureException("Could not encode signature", e);
1545N/A }
1545N/A }
1545N/A
1545N/A // Convert the DER encoding of R and S into a concatenation of R and S
1545N/A private byte[] decodeSignature(byte[] signature) throws SignatureException {
1545N/A
1545N/A try {
1545N/A DerInputStream in = new DerInputStream(signature);
1545N/A DerValue[] values = in.getSequence(2);
1545N/A BigInteger r = values[0].getPositiveBigInteger();
1545N/A BigInteger s = values[1].getPositiveBigInteger();
1545N/A // trim leading zeroes
1545N/A byte[] rBytes = trimZeroes(r.toByteArray());
1545N/A byte[] sBytes = trimZeroes(s.toByteArray());
1545N/A int k = Math.max(rBytes.length, sBytes.length);
1545N/A // r and s each occupy half the array
1545N/A byte[] result = new byte[k << 1];
1545N/A System.arraycopy(rBytes, 0, result, k - rBytes.length,
1545N/A rBytes.length);
1545N/A System.arraycopy(sBytes, 0, result, result.length - sBytes.length,
1545N/A sBytes.length);
1545N/A return result;
1545N/A
1545N/A } catch (Exception e) {
1545N/A throw new SignatureException("Could not decode signature", e);
1545N/A }
1545N/A }
1545N/A
1545N/A // trim leading (most significant) zeroes from the result
1545N/A private static byte[] trimZeroes(byte[] b) {
1545N/A int i = 0;
1545N/A while ((i < b.length - 1) && (b[i] == 0)) {
1545N/A i++;
1545N/A }
1545N/A if (i == 0) {
1545N/A return b;
1545N/A }
1545N/A byte[] t = new byte[b.length - i];
1545N/A System.arraycopy(b, i, t, 0, t.length);
1545N/A return t;
1545N/A }
1545N/A
1545N/A /**
1545N/A * Signs the digest using the private key.
1545N/A *
1545N/A * @param digest the digest to be signed.
1545N/A * @param s the private key's S value.
1545N/A * @param encodedParams the curve's DER encoded object identifier.
1545N/A * @param seed the random seed.
1545N/A *
1545N/A * @return byte[] the signature.
1545N/A */
1545N/A private static native byte[] signDigest(byte[] digest, byte[] s,
1545N/A byte[] encodedParams, byte[] seed) throws GeneralSecurityException;
1545N/A
1545N/A /**
1545N/A * Verifies the signed digest using the public key.
1545N/A *
1545N/A * @param signedDigest the signature to be verified. It is encoded
1545N/A * as a concatenation of the key's R and S values.
1545N/A * @param digest the digest to be used.
1545N/A * @param w the public key's W point (in uncompressed form).
1545N/A * @param encodedParams the curve's DER encoded object identifier.
1545N/A *
1545N/A * @return boolean true if the signature is successfully verified.
1545N/A */
1545N/A private static native boolean verifySignedDigest(byte[] signature,
1545N/A byte[] digest, byte[] w, byte[] encodedParams)
1545N/A throws GeneralSecurityException;
1545N/A}