/*
* FileSigner.java
*
* Created on Jan 27, 2010, 1:08:52 AM
*
* Description: Provides digital signatures for files.
*
* Copyright (C) Jan 27, 2010 reed.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.texai.x509;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.X509Certificate;
import net.jcip.annotations.NotThreadSafe;
/** Provides digital signatures for files.
*
* @author reed
*/
@NotThreadSafe
public final class FileSigner {
/** Prevents this utility class from being instantiated. */
private FileSigner() {
}
/** Signs the given file and returns the digital signature bytes.
*
* @param pathName the file path name
* @param privateKey the sender's private key
* @return the digital signature bytes
*
* @throws NoSuchAlgorithmException when the signature algorithm is invalid
* @throws InvalidKeyException if there is an error with the private key
* @throws IOException if an input/output error occurs
* @throws SignatureException if there is a problem with the signature
*/
public static byte[] sign(
final String pathName,
final PrivateKey privateKey)
throws
NoSuchAlgorithmException,
InvalidKeyException,
IOException,
SignatureException {
//Preconditions
assert pathName != null : "pathName must not be null";
assert !pathName.isEmpty() : "pathName must not be empty";
assert privateKey != null : "privateKey must not be null";
final Signature signature = Signature.getInstance(X509Utils.DIGITAL_SIGNATURE_ALGORITHM);
signature.initSign(privateKey);
try (FileInputStream fileInputStream = new FileInputStream(pathName)) {
final byte[] dataBytes = new byte[1024];
int nbrBytesRead = fileInputStream.read(dataBytes);
while (nbrBytesRead > 0) {
signature.update(dataBytes, 0, nbrBytesRead);
nbrBytesRead = fileInputStream.read(dataBytes);
}
}
return signature.sign();
}
/** Returns whether the given signature bytes verify the given file.
*
* @param pathName the file path name
* @param x509Certificate the sender's X.509 certificate, that contains the public key
* @param signatureBytes the signature bytes
* @return whether the given signature bytes verify the given file
*
* @throws NoSuchAlgorithmException when the signature algorithm is invalid
* @throws InvalidKeyException if there is an error with the private key
* @throws IOException if an input/output error occurs
* @throws SignatureException if there is a problem with the signature
*/
public static boolean verify(
final String pathName,
final X509Certificate x509Certificate,
final byte[] signatureBytes)
throws
NoSuchAlgorithmException,
InvalidKeyException,
IOException,
SignatureException {
//Preconditions
assert pathName != null : "pathName must not be null";
assert !pathName.isEmpty() : "pathName must not be empty";
assert x509Certificate != null : "x509Certificate must not be null";
assert signatureBytes.length > 0 : "signatureBytes must not be empty";
final Signature signature = Signature.getInstance(X509Utils.DIGITAL_SIGNATURE_ALGORITHM);
signature.initVerify(x509Certificate.getPublicKey());
try (FileInputStream fileInputStream = new FileInputStream(pathName)) {
final byte[] dataBytes = new byte[1024];
int nbrBytesRead = fileInputStream.read(dataBytes);
while (nbrBytesRead > 0) {
signature.update(dataBytes, 0, nbrBytesRead);
nbrBytesRead = fileInputStream.read(dataBytes);
}
}
return signature.verify(signatureBytes);
}
}