All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.joyent.http.signature.Signer Maven / Gradle / Ivy

/*
 * Copyright (c) 2013-2017, Joyent, Inc. All rights reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package com.joyent.http.signature;

import com.joyent.http.signature.crypto.NativeRSAProvider;
import org.bouncycastle.util.encoders.Base64;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Signature;
import java.security.SignatureException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;

/**
 *  HTTP authorization signer. This adheres to the specs of the node-http-signature spec.
 *
 * @see Signing HTTP Messages
 * @see Original Version
 * @author Yunong Xiao
 * @author Elijah Zupancic
 * @since 1.0.0
 */
public class Signer {
    /**
     * The format for the http date header.
     *
     * @deprecated In java8 and later a RFC appropriate format is
     * defined in the standard library using modern classes.
     */
    @Deprecated
    @SuppressWarnings("DateFormatConstant")
    public static final DateFormat DATE_FORMAT = new SimpleDateFormat(
            "EEE MMM d HH:mm:ss yyyy zzz", Locale.ENGLISH);

    /**
     * The template for the Authorization header.
     */
    private static final String AUTHZ_HEADER =
            "Signature keyId=\"/%s/keys/%s\",algorithm=\"%s\",signature=\"%s\"";

    /**
     * The template for the authorization signing signing string.
     */
    private static final String AUTHZ_SIGNING_STRING = "date: %s";

    /**
     * The prefix for the signature component of the authorization header.
     */
    private static final String AUTHZ_PATTERN = "signature=\"";

    /**
     * Cryptographic signature used for signing requests.
     */
    private final Signature signature;

    /**
     *  Private field with the computed http header algorithm.
     */
    private final String httpHeaderAlgorithm;

    /**
     * Creates a new instance of the class and enables native code acceleration of
     * cryptographic signing by default.
     *
     * @deprecated Prefer use of {@link Signer.Builder}
     */
    @Deprecated
    public Signer() {
        this(true);
    }

    /**
     * Creates a new instance of the class.
     *
     * @param useNativeCodeToSign true to enable native code acceleration of cryptographic singing
     *
     * @deprecated Prefer use of {@link Signer.Builder}
     */
    @Deprecated
    @SuppressWarnings("checkstyle:avoidinlineconditionals")
    public Signer(final boolean useNativeCodeToSign) {
        this(new Builder("RSA").providerCode(useNativeCodeToSign ? "native.jnagmp" : "stdlib"));
    }

    /**
     * {@link Signer.Builder} This is public (a difference from the
     * normal Builder pattern) for use by {@link ThreadLocalSigner}.
     *
     * @param builder {@link Signer.Builder}
     */
    public Signer(final Builder builder) {
        Provider provider = builder.algHelper.makeProvider(builder.providerCode);
        httpHeaderAlgorithm = builder.httpHeaderAlgorithm();
        if (provider == null) {
            try {
                signature = Signature.getInstance(builder.javaStandardName(null));
            } catch (NoSuchAlgorithmException nsae) {
                throw new CryptoException(nsae);
            }
        } else {
            try {
                signature = Signature.getInstance(builder.javaStandardName(provider), provider);
            } catch (NoSuchAlgorithmException nsae) {
                throw new CryptoException(nsae);
            }
        }
    }

    /**
     * @see KeyPairLoader#getKeyPair
     *
     * @param keyPath The path to the key
     * @return public-private keypair object
     * @throws IOException If unable to read the private key from the file
     *
     * @deprecated Since a {@code KeyPair} is needed to instantiate,
     * is is now backwards for this to be an instance method.
     */
    @Deprecated
    public KeyPair getKeyPair(final Path keyPath) throws IOException {
        return KeyPairLoader.getKeyPair(keyPath);
    }

    /**
     * @see KeyPairLoader#getKeyPair
     *
     * @param privateKeyContent private key content as a string
     * @param password password associated with key
     * @return public-private keypair object
     * @throws IOException If unable to read the private key from the string
     *
     * @deprecated Since a {@code KeyPair} is needed to instantiate,
     * is is now backwards for this to be an instance method.
     */
    @Deprecated
    public KeyPair getKeyPair(final String privateKeyContent, final char[] password) throws IOException {
        return KeyPairLoader.getKeyPair(privateKeyContent, password);
    }

    /**
     * @see KeyPairLoader#getKeyPair
     *
     * @param pKeyBytes private key content as a byte array
     * @param password password associated with key
     * @return public-private keypair object
     * @throws IOException If unable to read the private key from the string
     *
     * @deprecated Since a {@code KeyPair} is needed to instantiate,
     * is is now backwards for this to be an instance method.
     */
    @Deprecated
    public KeyPair getKeyPair(final byte[] pKeyBytes, final char[] password) throws IOException {
        return KeyPairLoader.getKeyPair(pKeyBytes, password);
    }

    /**
     * @see KeyPairLoader#getKeyPair
     *
     * @param is private key content as a stream
     * @param password password associated with key
     * @return public/private keypair object
     * @throws IOException If unable to read the private key from the string
     *
     * @deprecated Since a {@code KeyPair} is needed to instantiate,
     * is is now backwards for this to be an instance method.
     */
    @Deprecated
    public KeyPair getKeyPair(final InputStream is,
                              final char[] password) throws IOException {
        return KeyPairLoader.getKeyPair(is, password);
    }

    /**
     * Generate a signature for an authorization HTTP header using the
     * current time as a timestamp.
     *
     * @param login Account/login name
     * @param fingerprint key fingerprint (ignored)
     * @param keyPair public/private keypair
     * @return value to Authorization header
     *
     * @deprecated The fingerprint is now calculated from the given key.
     */
    @Deprecated
    public String createAuthorizationHeader(final String login,
                                            final String fingerprint,
                                            final KeyPair keyPair) {
        return createAuthorizationHeader(login, keyPair, defaultSignDateAsString());
    }

    /**
     * Generate a signature for an authorization HTTP header using the
     * current time as a timestamp.
     *
     * @param login Account/login name
     * @param keyPair public/private keypair
     * @return value to Authorization header
     */
    @SuppressWarnings("unused")
    public String createAuthorizationHeader(final String login,
                                            final KeyPair keyPair) {
        return createAuthorizationHeader(login, keyPair, defaultSignDateAsString());
    }

    /**
     * Generate a signature for an authorization HTTP header.
     *
     * @param login Account/login name
     * @param fingerprint key fingerprint (ignored)
     * @param keyPair public/private keypair
     * @param date Date to be converted to a RFC 822 compliant string
     * @return value to Authorization header
     *
     * @deprecated The fingerprint is now calculated from the given key.
     */
    @Deprecated
    public String createAuthorizationHeader(final String login,
                                            final String fingerprint,
                                            final KeyPair keyPair,
                                            final Date date) {
        return createAuthorizationHeader(login, keyPair, date);
    }

    /**
     * Generate a signature for an authorization HTTP header.
     *
     * @param login Account/login name
     * @param keyPair public/private keypair
     * @param date DateTime to be converted to a RFC 822 compliant string
     * @return value to Authorization header
     *
     * @deprecated Prefer ZonedDateTime to java.util.Date
     */
    @Deprecated
    public String createAuthorizationHeader(final String login,
                                            final KeyPair keyPair,
                                            final Date date) {
        final ZonedDateTime zdt;
        if (date == null) {
            zdt = null;
        } else {
            zdt = ZonedDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);
        }

        return createAuthorizationHeader(login, keyPair, zdt);
    }

    /**
     * Generate a signature for an authorization HTTP header.
     *
     * @param login Account/login name
     * @param keyPair public/private keypair
     * @param dateTime DateTime to be converted to a RFC 822 compliant string
     * @return value to Authorization header
     */
    public String createAuthorizationHeader(final String login,
                                            final KeyPair keyPair,
                                            final ZonedDateTime dateTime) {
        final String stringDate;

        if (dateTime == null) {
            stringDate = defaultSignDateAsString();
        } else {
            stringDate = DateTimeFormatter.RFC_1123_DATE_TIME.format(dateTime);
        }

        return createAuthorizationHeader(login, keyPair, stringDate);
    }

    /**
     * Generate a signature for an authorization HTTP header.
     *
     * @param login Account/login name
     * @param fingerprint key fingerprint (ignored)
     * @param keyPair public/private keypair
     * @param date Date as RFC 822 compliant string
     * @return value to Authorization header
     *
     * @deprecated The fingerprint is now calculated from the given key.
     */
    @Deprecated
    public String createAuthorizationHeader(final String login,
                                            final String fingerprint,
                                            final KeyPair keyPair,
                                            final String date) {
        Objects.requireNonNull(login, "Login must be present");
        Objects.requireNonNull(keyPair, "Keypair must be present");
        return createAuthorizationHeader(login, keyPair, date);
    }


    /**
     * Generate a signature for an authorization HTTP header.
     *
     * @param login Account/login name
     * @param keyPair public/private keypair
     * @param date Date as RFC 822 compliant string
     * @return value to Authorization header
     */
    public String createAuthorizationHeader(final String login,
                                            final KeyPair keyPair,
                                            final String date) {
        Objects.requireNonNull(login, "Login must be present");
        Objects.requireNonNull(keyPair, "Keypair must be present");

        try {
            signature.initSign(keyPair.getPrivate());
            final String signingString = String.format(AUTHZ_SIGNING_STRING, date);
            signature.update(signingString.getBytes(StandardCharsets.UTF_8));
            final byte[] signedDate = signature.sign();
            final byte[] encodedSignedDate = Base64.encode(signedDate);
            final String fingerprint = KeyFingerprinter.md5Fingerprint(keyPair);

            return String.format(AUTHZ_HEADER, login, fingerprint, httpHeaderAlgorithm,
                    new String(encodedSignedDate, StandardCharsets.US_ASCII));
        } catch (final InvalidKeyException e) {
            throw new CryptoException("invalid key", e);
        } catch (final SignatureException e) {
            throw new CryptoException("invalid signature", e);
        }
    }

    /**
     * Cryptographically signs an any data input.
     *
     * @param login Account/login name
     * @param fingerprint key fingerprint (ignored)
     * @param keyPair public/private keypair
     * @param data data to be signed
     * @return signed value of data
     *
     * @deprecated The fingerprint is now calculated from the given key.
     */
    @Deprecated
    public byte[] sign(final String login,
                       final String fingerprint,
                       final KeyPair keyPair,
                       final byte[] data) {
        return sign(login, keyPair, data);
    }

    /**
     * Cryptographically signs an any data input.
     *
     * @param login Account/login name
     * @param keyPair public/private keypair
     * @param data data to be signed
     * @return signed value of data
     */
    public byte[] sign(final String login,
                       final KeyPair keyPair,
                       final byte[] data) {
        Objects.requireNonNull(login, "Login must be present");
        Objects.requireNonNull(keyPair, "Keypair must be present");
        Objects.requireNonNull(data, "Data must be present");

        try {
            signature.initSign(keyPair.getPrivate());
            signature.update(data);
            return signature.sign();
        } catch (final InvalidKeyException e) {
            throw new CryptoException("invalid key", e);
        } catch (final SignatureException e) {
            throw new CryptoException("invalid signature", e);
        }
    }

    /**
     * Cryptographically signs an any data input.
     *
     * @param login Account/login name
     * @param fingerprint key fingerprint (ignored)
     * @param keyPair public/private keypair
     * @param data data that was signed
     * @param signedData data to verify against signature
     * @return signed value of data
     *
     * @deprecated The fingerprint is now calculated from the given key.
     */
    @Deprecated
    public boolean verify(final String login,
                                 final String fingerprint,
                                 final KeyPair keyPair,
                                 final byte[] data,
                                 final byte[] signedData) {
        return verify(login, keyPair, data, signedData);
    }

    /**
     * Cryptographically signs an any data input.
     *
     * @param login Account/login name
     * @param keyPair public/private keypair
     * @param data data that was signed
     * @param signedData data to verify against signature
     * @return signed value of data
     */
    public boolean verify(final String login,
                          final KeyPair keyPair,
                          final byte[] data,
                          final byte[] signedData) {
        Objects.requireNonNull(login, "Login must be present");
        Objects.requireNonNull(keyPair, "Keypair must be present");
        Objects.requireNonNull(signedData, "Data must be present");

        try {
            signature.initVerify(keyPair.getPublic());
            signature.update(data);
            return signature.verify(signedData);
        } catch (final InvalidKeyException e) {
            throw new CryptoException("invalid key", e);
        } catch (final SignatureException e) {
            throw new CryptoException("invalid signature", e);
        }
    }

    /**
     * The current timestamp in UTC as a RFC 822 compliant string.
     * @return Date as RFC 822 compliant string
     */
    public String defaultSignDateAsString() {
        return DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(ZoneOffset.UTC));
    }

    /**
     * Verify a signed HTTP Authorization header.
     *
     * @param keyPair public/private keypair
     * @param authzHeader authorization header value
     * @param date Date as RFC 822 compliant string
     * @return True if the request is valid, false if not.
     * @throws CryptoException If unable to verify the request.
     */
    public boolean verifyAuthorizationHeader(final KeyPair keyPair,
                                             final String authzHeader,
                                             final String date) {
        Objects.requireNonNull(keyPair, "Keypair must be present");
        Objects.requireNonNull(authzHeader, "AuthzHeader must be present");
        Objects.requireNonNull(date, "Date must be present");

        String myDate = String.format(AUTHZ_SIGNING_STRING, date);

        try {
            signature.initVerify(keyPair.getPublic());

            final int startIndex = authzHeader.indexOf(AUTHZ_PATTERN);
            if (startIndex == -1) {
                throw new CryptoException(
                        String.format("invalid authorization header %s", authzHeader));
            }

            final String encodedSignedDate = authzHeader.substring(startIndex + AUTHZ_PATTERN.length(),
                    authzHeader.length() - 1);
            final byte[] signedDate = Base64.decode(encodedSignedDate.getBytes(StandardCharsets.UTF_8));

            signature.update(myDate.getBytes(StandardCharsets.UTF_8));
            return signature.verify(signedDate);

        } catch (final InvalidKeyException e) {
            throw new CryptoException("invalid key", e);
        } catch (final SignatureException e) {
            throw new CryptoException("invalid signature", e);
        }
    }

    /**
     * Return a string representation of the full algorithm.  For
     * example: "rsa-sha256"
     *
     * @return Algorithm name.
     */
    public String getHttpHeaderAlgorithm() {
        return httpHeaderAlgorithm;
    }

    /**
     * This method is visible for tests or benchmarks.
     *
     * @return instance of the signature cipher implementation
     */
    Signature getSignature() {
        return signature;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Signer{");
        sb.append("signature=").append(signature);
        sb.append(",provider=").append(signature.getProvider().getName());
        sb.append(",httpHeaderAlgorithm=").append(httpHeaderAlgorithm);
        sb.append('}');
        return sb.toString();
    }

    /**
     * Builder class for {@link Signer}.
     *
     * The signing algorithm can be identified by a string (using the
     * same names as {@link java.security.PrivateKey#getAlgorithm}),
     * or by just passing in a {@link java.security.KeyPair}.  The
     * supported singing algorithms are RSA, DSA, and ECDSA.
     *
     * Signers can be further configured by specifying a string
     * representation of a hashing algorithms.  For example, {@code
     * SHA512} instead of {@code SHA256}.  The default is {@code
     * SHA256} in for all cases. The supported hash names are:
     *
     * 
    *
  • RSA: {@code SHA1}, {@code SHA256}, {@code SHA512}
  • *
  • DSA: {@code SHA1}, {@code SHA256}
  • *
  • ECDSA: {@code SHA256}, {@code SHA384}, {@code SHA512}
  • *
* * {@code providerCode} is designate and alternative provider to * the standard library. Currently the only algorithm that * supports a custom provider is {@code RSA} with {@code * native.jnagmp}. This is the default. See {@link * com.joyent.http.signature.crypto.NativeRSAWithSHA} for more * information. All singing algorithms support {@code stdlib} to * use the standard library. */ @SuppressWarnings("checkstyle:javadocvariable") public static class Builder { private final SigningAlgorithmHelper algHelper; private String hash; private String providerCode; /** * Instantiate a new Builder based on the algorithm of the * given keypair. * * @param keyPair The given KeyPair. */ public Builder(final KeyPair keyPair) { this.algHelper = SigningAlgorithmHelper.create(keyPair); hash = algHelper.defaultHash(); providerCode = algHelper.defaultProviderCode(); } /** * Instantiate a new Builder based on the explicitly given * algorithm. * * @param algorithm {@link java.security.PrivateKey#getAlgorithm} */ public Builder(final String algorithm) { this.algHelper = SigningAlgorithmHelper.create(algorithm); hash = algHelper.defaultHash(); providerCode = algHelper.defaultProviderCode(); } /** * Overrides the default hash type. * * @param hash New hash type * @return This {@code Builder} object */ @SuppressWarnings("checkstyle:hiddenfield") public Builder hash(final String hash) { algHelper.checkSupportedHash(hash); this.hash = hash; return this; } /** * Overrides the default provider code. * * @param providerCode New provider code * @return This {@code Builder} object */ @SuppressWarnings("checkstyle:hiddenfield") public Builder providerCode(final String providerCode) { algHelper.checkSupportedProviderCode(providerCode); this.providerCode = providerCode; return this; } /** * From the configured singing algorithm and hash, return a * string representation as used by the @see Java * Cryptography Architecture Standard Algorithm Name * Documentation. * * @param provider Provider used for signing. * @return The standard representation */ private String javaStandardName(final Provider provider) { return hash + "with" + algHelper.providerPrefix(provider) + algHelper.getAlgorithm(); } /** * From the configured signing algorithm and hash, return the * representation formatted for the HTTP Signature field. * * @return The header string */ private String httpHeaderAlgorithm() { return algHelper.getAlgorithm().toLowerCase() + "-" + hash.toLowerCase(); } /** * Returns a newly-created {@code Signer} based on the contents of the * {@code Builder}. * * @return The new {@code Builder} */ public Signer build() { return new Signer(this); } /** * Helper class with per algorithm configuration. */ private abstract static class SigningAlgorithmHelper { /** * Create a new {@code SigningAlgorithmHelper} based on * the given {@code KeyPair}. * * @param keyPair {@code} KeyPair to sign for * @return New {@code SigningAlgorithmHelper} instance. */ public static SigningAlgorithmHelper create(final KeyPair keyPair) { return create(keyPair.getPrivate().getAlgorithm()); } /** * Create a new {@code SigningAlgorithmHelper} based on * the given algorithm code. * @param algorithm {@see java.security.KeyPair#getAlgorithm} * @return New {@code SigningAlgorithmHelper} instance. */ public static SigningAlgorithmHelper create(final String algorithm) { switch (algorithm) { case "RSA": return new RsaHelper(); case "DSA": return new DsaHelper(); // See NssBridgeKeyConverter on the two names case "ECDSA": case "EC": return new EcdsaHelper(); default: throw new IllegalArgumentException("invalid signing algorithm: " + algorithm); } } /** * Return the string code for the instantiated algorithm helper. * * @return {@see java.security.KeyPair#getAlgorithm} */ public abstract String getAlgorithm(); /** * Get all of the hash algorithms supported by the * algorithm, in sorted order. * * @return The sorted hash algorihtm names. */ public abstract String[] getSupportedHashes(); /** * Get the default hash name for this signing algorithm. * * @return The default hash name. */ public abstract String defaultHash(); /** * Get all of the provider codes supported by the * algorithm, in sorted order. * * @return The sorted provider codes. */ public abstract String[] getSupportedProviderCodes(); /** * Get the default provider code for this signing algorithm. * * @return The default provider code */ public abstract String defaultProviderCode(); /** * Throws {@code IllegalArgumentException} if the given * {@code String} does not match a supported hash algorithm. * * @param hash Name to check. */ public void checkSupportedHash(final String hash) { if (Arrays.binarySearch(getSupportedHashes(), hash) == -1) { throw new IllegalArgumentException("invalid hash algorithm: " + hash); } } /** * Throws {@code IllegalArgumentException} if the given * {@code String} does not match a supported provider code. * * @param providerCode Name to check. */ public void checkSupportedProviderCode(final String providerCode) { if (Arrays.binarySearch(getSupportedProviderCodes(), providerCode) == -1) { throw new IllegalArgumentException("invalid providerCode algorithm: " + providerCode); } } /** * A {@code Provider} outside of the Java standard * library, might have a special "Algorithm Name". @see * Signer.Builder#javaStandardName and @see #makeProvider * * @param provider The {@code Provider} from @see #makeProvider. * @return The "Algorithm Name" modification, or the empty string. */ public String providerPrefix(final Provider provider) { return ""; } /** * If a special {@link java.security.Provider} is * requested, construct and return it, otherwise return * {@code null} to use the Java standard library. * * @param providerCode The configured {@code Provider} * code. * @return The new {@link java.security.Provider}, or * {@code null} if using the standard library. */ public Provider makeProvider(final String providerCode) { return null; } } /** * RSA implementation of {@code SigningAlgorithmHelper}. */ @SuppressWarnings({"checkstyle:javadocmethod", "checkstyle:javadoctype"}) private static class RsaHelper extends SigningAlgorithmHelper { private static final String[] SUPPORTED_HASHES = {"SHA1", "SHA256", "SHA512"}; private static final String[] SUPPORTED_PROVIDER_CODES = {"native.jnagmp", "stdlib"}; /** * OS names with native support in jnagmp. * Always keep values sorted because we binary search them. */ private static final String[] SUPPORTED_NATIVE_OS = new String[] {"linux", "mac os x", "sunos"}; /** * Architectures with native support in jnagmp. * Always keep values sorted because we binary search them. */ private static final String[] SUPPORTED_NATIVE_ARCH = new String[] {"amd64", "x86_64"}; /** * When true we are on a platform that supports native libgmp for modpow. */ private static final boolean JNAGMP_SUPPORTED; static { final String os = System.getProperty("os.name").toLowerCase(); final String arch = System.getProperty("os.arch").toLowerCase(); JNAGMP_SUPPORTED = Arrays.binarySearch(SUPPORTED_NATIVE_OS, os) >= 0 && Arrays.binarySearch(SUPPORTED_NATIVE_ARCH, arch) >= 0; System.setProperty("native.jnagmp", Objects.toString(JNAGMP_SUPPORTED)); } @Override public String getAlgorithm() { return "RSA"; } @Override public String[] getSupportedHashes() { return SUPPORTED_HASHES; } @Override public String defaultHash() { return "SHA256"; } @Override public String[] getSupportedProviderCodes() { return SUPPORTED_PROVIDER_CODES; } @Override public String defaultProviderCode() { return "native.jnagmp"; } @Override public String providerPrefix(final Provider provider) { if (provider != null) { return "Native"; } else { return ""; } } @Override public Provider makeProvider(final String providerCode) { if (providerCode.equals("native.jnagmp") && JNAGMP_SUPPORTED) { try { return new NativeRSAProvider(); // if ANYTHING goes wrong, we default to the JVM implementation of the signing algo } catch (Exception e) { e.printStackTrace(); return null; } } else { return null; } } } /** * DSA implementation {@code SigningAlgorithmHelper}. */ @SuppressWarnings({"checkstyle:javadocmethod", "checkstyle:javadoctype"}) private static class DsaHelper extends SigningAlgorithmHelper { private static final String[] SUPPORTED_HASHES = {"SHA1", "SHA256"}; private static final String[] SUPPORTED_PROVIDER_CODES = {"stdlib"}; @Override public String getAlgorithm() { return "DSA"; } @Override public String[] getSupportedHashes() { return SUPPORTED_HASHES; } @Override public String defaultHash() { return "SHA256"; } @Override public String[] getSupportedProviderCodes() { return SUPPORTED_PROVIDER_CODES; } @Override public String defaultProviderCode() { return "stdlib"; } } /** * ECDSA implementation {@code SigningAlgorithmHelper}. */ @SuppressWarnings({"checkstyle:javadocmethod", "checkstyle:javadoctype"}) private static class EcdsaHelper extends SigningAlgorithmHelper { private static final String[] SUPPORTED_HASHES = {"SHA256", "SHA384", "SHA512"}; private static final String[] SUPPORTED_PROVIDER_CODES = {"stdlib"}; @Override public String getAlgorithm() { return "ECDSA"; } @Override public String[] getSupportedHashes() { return SUPPORTED_HASHES; } @Override public String defaultHash() { return "SHA256"; } @Override public String[] getSupportedProviderCodes() { return SUPPORTED_PROVIDER_CODES; } @Override public String defaultProviderCode() { return "stdlib"; } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy