/*
* Part of the CCNx Java Library.
*
* Copyright (C) 2008, 2009, 2012 Palo Alto Research Center, Inc.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. You should have received
* a copy of the GNU Lesser General Public License along with this library;
* if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.ccnx.ccn.impl.security.crypto;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import org.ccnx.ccn.impl.encoding.XMLEncodable;
import org.ccnx.ccn.impl.security.crypto.util.SignatureHelper;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.io.content.ContentEncodingException;
/**
* Helper class for generating signatures, supporting CCN-specific operations.
*/
public class CCNSignatureHelper extends SignatureHelper {
/**
* Helper method that encodes and then signs an XMLEncodable object.
* @param digestAlgorithm the digest algorithm to use for the signature
* @param toBeSigned the object to encode and sign
* @param signingKey the private key to sign with
* @return the signature
* @throws SignatureException if the content is null, or there is an error generating the signature
* @throws NoSuchAlgorithmException if the digestAlgorithm is not recognized
* @throws InvalidKeyException if the signingKey is not valid
* @throws ContentEncodingException if the object cannot be encoded
*/
public static byte [] sign(String digestAlgorithm,
XMLEncodable toBeSigned,
PrivateKey signingKey)
throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, ContentEncodingException {
if (null == toBeSigned) {
Log.info("Value to be signed must not be null.");
throw new SignatureException("Cannot sign null content!");
}
return sign(digestAlgorithm,
toBeSigned.encode(),
signingKey);
}
/**
* Helper method that encodes, concatenates and then signs a set of
* XMLEncodable objects and auxiliary data
* @param digestAlgorithm the digest algorithm to use for the signature
* @param toBeSigneds the objects to encode, concatenate and sign
* @param additionalToBeSigneds additional data to be concatenated with the
* encoded toBeSigneds prior to signing
* @param signingKey the private key to sign with
* @return the signature
* @throws SignatureException if the content is null, or there is an error generating the signature
* @throws NoSuchAlgorithmException if the digestAlgorithm is not recognized
* @throws InvalidKeyException if the signingKey is not valid
* @throws ContentEncodingException if the object cannot be encoded
*/
public static byte [] sign(String digestAlgorithm,
XMLEncodable [] toBeSigneds,
byte additionalToBeSigneds[][],
PrivateKey signingKey)
throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, ContentEncodingException {
if (null == toBeSigneds) {
Log.info("Value to be signed must not be null.");
throw new SignatureException("Cannot sign null content!");
}
byte [][] encodedData = new byte [toBeSigneds.length + ((null != additionalToBeSigneds) ? additionalToBeSigneds.length : 0)][];
for (int i=0; i < toBeSigneds.length; ++i) {
encodedData[i] = toBeSigneds[i].encode();
}
if (null != additionalToBeSigneds) {
for (int i=0,j=toBeSigneds.length; j < encodedData.length; ++i,++j) {
encodedData[j] = additionalToBeSigneds[i];
}
}
return sign(digestAlgorithm,
encodedData,
signingKey);
}
/**
* Helper method that encodes and then verifies a signature on an XMLEncodable object.
* @param xmlData the object to encode and verify
* @param signature the signature
* @param digestAlgorithm the digest algorithm used for the signature
* @param verificationKey the public key to verify with
* @return true if valid, false otherwise
* @throws SignatureException if the content is null, or there is an error generating the signature
* @throws NoSuchAlgorithmException if the digestAlgorithm is not recognized
* @throws InvalidKeyException if the signingKey is not valid
* @throws ContentEncodingException if the object cannot be encoded
*/
public static boolean verify(
XMLEncodable xmlData,
byte [] signature,
String digestAlgorithm,
Key verificationKey)
throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, ContentEncodingException {
if ((null == xmlData) || (null == signature)) {
Log.info("Value to be verified and signature must not be null.");
throw new SignatureException("verify: Value to be verified and signature must not be null.");
}
return verify(
xmlData.encode(),
signature,
digestAlgorithm,
verificationKey);
}
/**
* Helper method that encodes, concatenates and then verifies a signature on a
* set of XMLEncodable objects and auxiliary data.
* @param xmlData the objects to encode and verify
* @param auxiliaryData
* @param signature the signature
* @param digestAlgorithm the digest algorithm used for the signature
* @param verificationKey the public key to verify with
* @return true if valid, false otherwise
* @throws SignatureException if the content is null, or there is an error generating the signature
* @throws NoSuchAlgorithmException if the digestAlgorithm is not recognized
* @throws InvalidKeyException if the signingKey is not valid
* @throws ContentEncodingException if the object cannot be encoded
*/
public static boolean verify(XMLEncodable [] xmlData,
byte auxiliaryData[][],
byte [] signature,
String digestAlgorithm,
Key verificationKey)
throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, ContentEncodingException {
if ((null == xmlData) || (null == signature)) {
Log.info("Value to be verified and signature must not be null.");
throw new SignatureException("verify: Value to be verified and signature must not be null.");
}
byte [][] encodedData = new byte [xmlData.length + ((null != auxiliaryData) ? auxiliaryData.length : 0)][];
for (int i=0; i < xmlData.length; ++i) {
encodedData[i] = xmlData[i].encode();
} // DKS TODO -- switch to ostreams to handle binary end/begin tags
if (null != auxiliaryData) {
for (int i=0,j=xmlData.length; j < encodedData.length; ++i,++j) {
encodedData[j] = auxiliaryData[i];
}
}
return verify(
encodedData,
signature,
digestAlgorithm,
verificationKey);
}
/**
* Signs an array of bytes with a private signing key and specified digest algorithm.
* Overrides SignatureHelper to get correct default digest.
* @param digestAlgorithm the digest algorithm. if null uses DEFAULT_DIGEST_ALGORITHM
* @param toBeSigned the array of bytes to be signed.
* @param signingKey the signing key.
* @return the signature.
* @throws SignatureException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static byte [] sign(String digestAlgorithm,
byte [] toBeSigned,
Key signingKey) throws SignatureException,
NoSuchAlgorithmException, InvalidKeyException {
return SignatureHelper.sign(((null == digestAlgorithm) || (digestAlgorithm.length() == 0)) ?
CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM : digestAlgorithm, toBeSigned, signingKey);
}
/**
* Sign concatenation of the toBeSigneds.
* Overrides SignatureHelper to get correct default digest.
* @param digestAlgorithm the digest algorithm. if null uses DEFAULT_DIGEST_ALGORITHM
* @param toBeSigneds the content to be signed.
* @param signingKey the signing key.
* @return the signature.
* @throws SignatureException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static byte [] sign(String digestAlgorithm,
byte toBeSigneds[][],
PrivateKey signingKey) throws SignatureException,
NoSuchAlgorithmException, InvalidKeyException {
return SignatureHelper.sign(((null == digestAlgorithm) || (digestAlgorithm.length() == 0)) ?
CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM : digestAlgorithm, toBeSigneds, signingKey);
}
/**
* Verifies the signature on the concatenation of a set of individual
* data items, given the verification key and digest algorithm.
* Overrides SignatureHelper to get correct default digest.
* @param data the data; which are expected to have been concatenated before
* signing. Any null arrays are skipped.
* @param signature the signature.
* @param digestAlgorithm the digest algorithm. if null uses DEFAULT_DIGEST_ALGORITHM
* @param verificationKey the public verification key.
* @return the correctness of the signature as a boolean.
* @throws SignatureException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static boolean verify(
byte data[][],
byte [] signature,
String digestAlgorithm,
Key verificationKey) throws SignatureException,
NoSuchAlgorithmException, InvalidKeyException {
return SignatureHelper.verify(data, signature,
((null == digestAlgorithm) || (digestAlgorithm.length() == 0)) ?
CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM : digestAlgorithm, verificationKey);
}
/**
* Verify a standalone signature.
* Overrides SignatureHelper to get correct default digest.
* @param data the data whose signature we want to verify
* @param signature the signature itself
* @param digestAlgorithm the digest algorithm used to generate the signature.
* if null uses DEFAULT_DIGEST_ALGORITHM
* @param verificationKey the key to verify the signature with
* @return true if signature valid, false otherwise
* @throws InvalidKeyException
* @throws SignatureException
* @throws NoSuchAlgorithmException
*/
public static boolean verify(byte [] data, byte [] signature, String digestAlgorithm,
Key verificationKey)
throws InvalidKeyException, SignatureException, NoSuchAlgorithmException {
return verify(new byte[][]{data}, signature, digestAlgorithm, verificationKey);
}
}