001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2015-2016 ForgeRock AS.
015 */
016
017package org.forgerock.util;
018
019import java.security.InvalidKeyException;
020import java.security.NoSuchAlgorithmException;
021import java.security.PrivateKey;
022import java.security.PublicKey;
023import java.security.Signature;
024import java.security.SignatureException;
025import java.security.cert.X509Certificate;
026import java.text.MessageFormat;
027
028/**
029 * Utility class for signing and verifying signatures.
030 */
031public final class SignatureUtil {
032
033    /**
034     * Singleton approach by using a static inner class.
035     */
036    private static final class SingletonHolder {
037        private static final SignatureUtil INSTANCE = new SignatureUtil();
038    }
039
040    /**
041     * Private constructor to ensure SignatureUtil remains a Singleton.
042     */
043    private SignatureUtil() {
044    }
045
046    /**
047     * Gets the SignatureUtil instance.
048     *
049     * @return The SignatureUtil singleton instance.
050     */
051    public static SignatureUtil getInstance() {
052        return SingletonHolder.INSTANCE;
053    }
054
055    /**
056     * Signs a String using the given private key. Uses the algorithm from the
057     * private key to perform the signature.
058     *
059     * @param privateKey
060     *            The private key to use to sign the String.
061     * @param algorithm
062     *            The algorithm to use in the signing.
063     * @param message
064     *            The String to sign.
065     * @return The byte array of the signature.
066     * @throws java.security.SignatureException
067     *             If there is a problem when performing the signature.
068     */
069    public byte[] sign(PrivateKey privateKey, String algorithm, String message)
070            throws SignatureException {
071        try {
072            Signature signature = Signature.getInstance(algorithm);
073            signature.initSign(privateKey);
074            signature.update(message.getBytes());
075            return signature.sign();
076        } catch (NoSuchAlgorithmException e) {
077            throw new SignatureException(MessageFormat.format(
078                    "Could not get Signature instance with the algorithm: {0}", algorithm), e);
079        } catch (InvalidKeyException e) {
080            throw new SignatureException("Invalid key", e);
081        }
082    }
083
084    /**
085     * Verifies a signature of a String using the certificate. Uses the
086     * algorithm from the certificate to perform the verification of the
087     * signature.
088     *
089     * @param certificate
090     *            The X509Certificate to use to verify the signature.
091     * @param algorithm
092     *            The algorithm to use in the signing.
093     * @param message
094     *            The String that was signed.
095     * @param signatureData
096     *            The byte array of the signature.
097     * @return Whether or not the signature is valid for the String that was
098     *         signed.
099     * @throws java.security.SignatureException
100     *             If there is a problem when verifying the signature.
101     */
102    public boolean verify(X509Certificate certificate, String algorithm, String message,
103            byte[] signatureData) throws SignatureException {
104        return verify(certificate.getPublicKey(), algorithm, message, signatureData);
105    }
106
107    /**
108     * Verifies a signature of a String using the public key. Uses the algorithm
109     * from the public key to perform the verification of the signature.
110     *
111     * @param publicKey
112     *            The public key to use to verify the signature.
113     * @param algorithm
114     *            The algorithm to use in the signing.
115     * @param message
116     *            The String that was signed.
117     * @param signatureData
118     *            The byte array of the signature.
119     * @return Whether or not the signature is valid for the String that was
120     *         signed.
121     * @throws java.security.SignatureException
122     *             If there is a problem when verifying the signature.
123     */
124    public boolean verify(PublicKey publicKey, String algorithm, String message,
125            byte[] signatureData) throws SignatureException {
126        try {
127            Signature signature = Signature.getInstance(algorithm);
128            signature.initVerify(publicKey);
129            signature.update(message.getBytes());
130            return signature.verify(signatureData);
131        } catch (NoSuchAlgorithmException e) {
132            throw new SignatureException(MessageFormat.format(
133                    "Could not get Signature instance with the algorithm: {0}", algorithm), e);
134        } catch (InvalidKeyException e) {
135            throw new SignatureException("Invalid key", e);
136        }
137    }
138}