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