1、下载最新的bc包,bcmail-jdk15on-149.jar、bcprov-jdk15on149.jar、bcpkix-jdk15on-149.jar,并导入工程。

2、编写SignedMail类。新建SignedMail类。

package com.suresec.simplemail;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.security.auth.x500.X500Principal;
import javax.security.auth.x500.X500PrivateCredential;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.pkcs.Attribute;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute;
import org.bouncycastle.asn1.smime.SMIMECapability;
import org.bouncycastle.asn1.smime.SMIMECapabilityVector;
import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.mail.smime.SMIMEEnvelopedGenerator;
import org.bouncycastle.mail.smime.SMIMEException;
import org.bouncycastle.mail.smime.SMIMESignedGenerator;
import org.bouncycastle.mail.smime.SMIMEUtil;
import org.bouncycastle.x509.X509V1CertificateGenerator;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
public class SignedMail {
public static String ROOT_ALIAS = "root";
public static String INTERMEDIATE_ALIAS = "intermediate";
public static String END_ENTITY_ALIAS = "end";
private static final int VALIDITY_PERIOD = 365 * 24 * 60 * 60 * 1000; // one year
public static char[] KEY_PASSWD = "suresec".toCharArray();
public static KeyStore        credentials;
public static PrivateKey key;
public static Certificate[]   chain;
public static X509Certificate cert;
public static CertStore       certsAndCRLs;
public boolean init() throws Exception
{
Security.addProvider(new BouncyCastleProvider());
credentials = createCredentials();
key = (PrivateKey)credentials.getKey(END_ENTITY_ALIAS, KEY_PASSWD);
chain = credentials.getCertificateChain(END_ENTITY_ALIAS);
certsAndCRLs = CertStore.getInstance("Collection",
new CollectionCertStoreParameters(Arrays.asList(chain)), "BC");
cert = (X509Certificate)chain[0];
return true;
}
/**
* Create a KeyStore containing the a private credential with
* certificate chain and a trust anchor.
*/
public static KeyStore createCredentials()
throws Exception
{
KeyStore store = KeyStore.getInstance("JKS");
store.load(null, null);
X500PrivateCredential    rootCredential = createRootCredential();
X500PrivateCredential    interCredential = createIntermediateCredential(rootCredential.getPrivateKey(), rootCredential.getCertificate());
X500PrivateCredential    endCredential = createEndEntityCredential(interCredential.getPrivateKey(), interCredential.getCertificate());
store.setCertificateEntry(rootCredential.getAlias(), rootCredential.getCertificate());
store.setKeyEntry(endCredential.getAlias(), endCredential.getPrivateKey(), KEY_PASSWD,
new Certificate[] { endCredential.getCertificate(), interCredential.getCertificate(), rootCredential.getCertificate() });
return store;
}
/**
* Generate a X500PrivateCredential for the end entity.
*/
public static X500PrivateCredential createEndEntityCredential(
PrivateKey      caKey,
X509Certificate caCert)
throws Exception
{
KeyPair         endPair = generateRSAKeyPair();
X509Certificate endCert = generateEndEntityCert(endPair.getPublic(), caKey, caCert);
return new X500PrivateCredential(endCert, endPair.getPrivate(), END_ENTITY_ALIAS);
}
/**
* Generate a sample V3 certificate to use as an end entity certificate
*/
public static X509Certificate generateEndEntityCert(PublicKey entityKey, PrivateKey caKey, X509Certificate caCert)
throws Exception
{
X509V3CertificateGenerator  certGen = new X509V3CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(1));
certGen.setIssuerDN(caCert.getSubjectX500Principal());
certGen.setNotBefore(new Date(System.currentTimeMillis()));
certGen.setNotAfter(new Date(System.currentTimeMillis() + VALIDITY_PERIOD));
certGen.setSubjectDN(new X500Principal("CN=Test End Certificate"));
certGen.setPublicKey(entityKey);
certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert));
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(entityKey));
certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
//certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
return certGen.generateX509Certificate(caKey, "BC");
}
/**
* Generate a X500PrivateCredential for the intermediate entity.
*/
public static X500PrivateCredential createIntermediateCredential(
PrivateKey      caKey,
X509Certificate caCert)
throws Exception
{
KeyPair         interPair = generateRSAKeyPair();
X509Certificate interCert = generateIntermediateCert(interPair, caKey, caCert);
return new X500PrivateCredential(interCert, interPair.getPrivate(), INTERMEDIATE_ALIAS);
}
/**
* Generate a sample V3 certificate to use as an intermediate CA certificate
*/
public static X509Certificate generateIntermediateCert(KeyPair pair, PrivateKey caKey, X509Certificate caCert)
throws Exception
{
PKCS10CertificationRequest  request = generateRequest(pair);
// validate the certification request
if (!request.verify("BC"))
{
System.out.println("request failed to verify!");
System.exit(1);
}
// create the certificate using the information in the request
X509V3CertificateGenerator  certGen = new X509V3CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setIssuerDN(caCert.getSubjectX500Principal());
certGen.setNotBefore(new Date(System.currentTimeMillis()));
certGen.setNotAfter(new Date(System.currentTimeMillis() + VALIDITY_PERIOD));
certGen.setSubjectDN(new X500Principal(request.getCertificationRequestInfo().getSubject().getEncoded()));
certGen.setPublicKey(request.getPublicKey("BC"));
certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert));
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(request.getPublicKey("BC")));
certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true));
//certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign));
//certGen.addExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth));
// extract the extension request attribute
ASN1Set attributes = request.getCertificationRequestInfo().getAttributes();
for (int i = 0; i != attributes.size(); i++)
{
Attribute    attr = Attribute.getInstance(attributes.getObjectAt(i));
// process extension request
if (attr.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest))
{
X509Extensions extensions = X509Extensions.getInstance(attr.getAttrValues().getObjectAt(0));
Enumeration e = extensions.oids();
while (e.hasMoreElements())
{
DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
X509Extension       ext = extensions.getExtension(oid);
certGen.addExtension(oid, ext.isCritical(), ext.getValue().getOctets());
}
}
}
X509Certificate  issuedCert = certGen.generateX509Certificate(caKey, "BC");
return issuedCert;
}
public static PKCS10CertificationRequest generateRequest(
KeyPair pair)
throws Exception
{
// create a SubjectAlternativeName extension value
GeneralNames  subjectAltNames = new GeneralNames(
new GeneralName(GeneralName.rfc822Name, "test@test.test"));
// create the extensions object and add it as an attribute
Vector  oids = new Vector();
Vector  values = new Vector();
oids.add(X509Extensions.SubjectAlternativeName);
values.add(new X509Extension(false, new DEROctetString(subjectAltNames)));
X509Extensions  extensions = new X509Extensions(oids, values);
Attribute  attribute = new Attribute(
PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,
new DERSet(extensions));
return new PKCS10CertificationRequest(
"SHA1withRSA",
new X500Principal("CN=Test Certificate"),
pair.getPublic(),
new DERSet(attribute),
pair.getPrivate());
}
/**
* Generate a X500PrivateCredential for the root entity.
*/
public static X500PrivateCredential createRootCredential()
throws Exception
{
KeyPair         rootPair = generateRSAKeyPair();
X509Certificate rootCert = generateRootCert(rootPair);
return new X500PrivateCredential(rootCert, rootPair.getPrivate(), ROOT_ALIAS);
}
/**
* Create a random 1024 bit RSA key pair
*/
public static KeyPair generateRSAKeyPair()
throws Exception
{
KeyPairGenerator  kpGen = KeyPairGenerator.getInstance("RSA", "BC");
kpGen.initialize(1024, new SecureRandom());
return kpGen.generateKeyPair();
}
/**
* Generate a sample V1 certificate to use as a CA root certificate
*/
public static X509Certificate generateRootCert(KeyPair pair)
throws Exception
{
X509V1CertificateGenerator  certGen = new X509V1CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(1));
certGen.setIssuerDN(new X500Principal("CN=Test CA Certificate"));
certGen.setNotBefore(new Date(System.currentTimeMillis()));
certGen.setNotAfter(new Date(System.currentTimeMillis() + VALIDITY_PERIOD));
certGen.setSubjectDN(new X500Principal("CN=Test CA Certificate"));
certGen.setPublicKey(pair.getPublic());
certGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
return certGen.generateX509Certificate(pair.getPrivate(), "BC");
}
public MimeMultipart createMultipartWithSignature(
PrivateKey      key,
X509Certificate cert,
CertStore       certsAndCRLs,
MimeBodyPart    dataPart)
throws Exception
{
// create some smime capabilities in case someone wants to respond
ASN1EncodableVector         signedAttrs = new ASN1EncodableVector();
SMIMECapabilityVector       caps = new SMIMECapabilityVector();
caps.addCapability(SMIMECapability.aES256_CBC);
caps.addCapability(SMIMECapability.dES_EDE3_CBC);
caps.addCapability(SMIMECapability.rC2_CBC, 128);
signedAttrs.add(new SMIMECapabilitiesAttribute(caps));
signedAttrs.add(new SMIMEEncryptionKeyPreferenceAttribute(SMIMEUtil.createIssuerAndSerialNumberFor(cert)));
// set up the generator
SMIMESignedGenerator gen = new SMIMESignedGenerator();
gen.addSigner(key, cert, SMIMESignedGenerator.DIGEST_SHA256, new AttributeTable(signedAttrs), null);
gen.addCertificatesAndCRLs(certsAndCRLs);
// create the signed message
return gen.generate(dataPart, "BC");
}
public MimeMultipart signMail(MimeBodyPart    dataPart)
{
try {
return createMultipartWithSignature(this.key, this.cert, this.certsAndCRLs, dataPart);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 邮件加密
* @param dataPart
* @return
*/
public MimeBodyPart encryptMail(MimeBodyPart dataPart)
{
SMIMEEnvelopedGenerator gen = new SMIMEEnvelopedGenerator();
MimeBodyPart envPart;
try {
envPart = gen.generate(dataPart, SMIMEEnvelopedGenerator.DES_EDE3_CBC, "BC");
return envPart;
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SMIMEException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
//   public static MimeMessage createMimeMessage(
//              Object content,
//              String contentType,
//              MimeMessage message)
//              throws MessagingException
//          {
//              message.setContent(content, contentType);
//              message.saveChanges();
//
//              return message;
//          }
}

3、对SimpleMailSender类稍作修改,接上篇博文。

MimeBodyPart    dataPart = new MimeBodyPart();
dataPart.setText("Hello world!");
//MimeMultipart multiPart = signMail.signMail(dataPart);
//mailMessage = signMail.createMimeMessage(multiPart, multiPart.getContentType(), mailMessage);
//mailMessage.setText(mailContent);
// 发送邮件
MimeBodyPart envPart = signMail.encryptMail(dataPart);
mailMessage.setContent(envPart.getContent(), envPart.getContentType());
Transport.send(mailMessage);

4、运行程序,可以看到数字签名文件。如下图所示:

171311844.png