Skip to content

Signing and Encryption

Yash edited this page Apr 14, 2021 · 2 revisions

Multipurpose Internet Mail Extensions (MIME) is an Internet standard that extends the format of email messages to support text in character sets other than ASCII, as well as attachments of audio, video, images, and application programs.

Message Content-Type

Content-Type               : text/plain
Content-Type               : text/html; charset="us-ascii"
Content-Type               : multipart/mixed; boundary=frontier

Content-Type               : application/pkcs7-signature; name=smime.p7s; smime-type=signed-data
Content-Transfer-Encoding  : base64
Content-Disposition        : attachment; filename="smime.p7s"
Content-Description        : S/MIME Cryptographic Signature

Content-Type               : application/pkcs7-mime; name="smime.p7m"; smime-type=enveloped-data
Content-Transfer-Encoding  : base64
Content-Disposition        : attachment; filename="smime.p7m"
Content-Description        : S/MIME Encrypted Message
Content-Type: multipart/mixed; boundary=frontier

This is a message with multiple parts in MIME format.
--frontier
Content-Type: text/plain

This is the body of the message.
--frontier
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64

PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==
--frontier--

Algorithms and key specifications for S/MIME

The following algorithms and keys must be used with the specified key lengths7:

SIGNATURE key length
Hash algorithm SHA-256 or SHA-512 (in accordance with IETF RFC 5754).
Signature algorithm RSA key length at least 2048 bit
RSASSA-PSS (in accordance with IETF RFC 4056)
ENCRYPTION key length
Content encryption AES-128 CBC or AES-192 CBC (in accordance with IETF RFC 3565) or AES-256 CBC
Key encryption RSA key length at least 2048 bit.
RSAES-OAEP (in accordance with IETF RFC 8017). Key encryption has hash functions as parameters.
private X509Certificate[] signerCertificatesChain;
protected HashMap<String, Object> buildCertificateAndGetPrivateKey(InputStream is, String password) throws Exception {
    HashMap<String, Object> certificateDataHashMap = new HashMap<String, Object>();
    // org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access:
    // this web application instance has been stopped already. YASH: https://stackoverflow.com/a/61952755/5081877
    KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");

    if (password == null) {
        keystore.load(is, null);
    } else {
        keystore.load(is, password.toCharArray());
    }

    Enumeration<String> keyStoreAliasEnum = keystore.aliases();
    PrivateKey privateKey = null;
    String alias = null;
    if (keyStoreAliasEnum.hasMoreElements()) {
        alias = keyStoreAliasEnum.nextElement();
        if (password != null) {
            privateKey = (PrivateKey) keystore.getKey(alias, password.toCharArray());
        }
    }

    CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
    Certificate certificate = keystore.getCertificate(alias);
    ByteArrayInputStream bais = new ByteArrayInputStream(certificate.getEncoded());
    X509Certificate x509Certificate = (X509Certificate) cf.generateCertificate(bais);

    Certificate[] chain = (Certificate[]) keystore.getCertificateChain(alias);

    if (chain != null) {
        signerCertificatesChain = new X509Certificate[chain.length];
        for (int i = 0; i < chain.length; i++) {
            signerCertificatesChain[i] = (X509Certificate) chain[i];
        }
    }
    certificateDataHashMap.put("certificate", x509Certificate);
    certificateDataHashMap.put("certificatePrivateKey", privateKey);
    return certificateDataHashMap;
}
public SMIMESignedGenerator createSignerUsingBouncyCastle() {
    SMIMECapabilityVector capabilities = new SMIMECapabilityVector();
    capabilities.addCapability(SMIMECapability.dES_EDE3_CBC);
    capabilities.addCapability(SMIMECapability.rC2_CBC, 128);
    capabilities.addCapability(SMIMECapability.dES_CBC);
    //capabilities.addCapability(SMIMECapability.aES256_CBC);

    ASN1EncodableVector attributes = new ASN1EncodableVector();
    attributes.add(new SMIMEEncryptionKeyPreferenceAttribute(SMIMEUtil.createIssuerAndSerialNumberFor(signerCertificate)));
    attributes.add(new SMIMECapabilitiesAttribute(capabilities));

    SMIMESignedGenerator signer = new SMIMESignedGenerator();
    signer.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC")
                    .setSignedAttributeGenerator(new AttributeTable(attributes))
                    .build(signerCertificate.getSigAlgName(), signerPrivateKey, signerCertificate));

    List<X509Certificate> certList = Arrays.asList(signerCertificatesChain);
    Store certs;
    /** Add the list of certs to the generator */
    certs = new JcaCertStore(certList);
    signer.addCertificates(certs);
    return signer;
}

RSAES_OAEP as Key encryption Example:

private MimeBodyPart getEncryptedPart(MimeMessage message) {
    JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
    OAEPParameterSpec oaepParameters = new javax.crypto.spec.OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
    AlgorithmIdentifier idRsaOaep = null;
    try {
        idRsaOaep = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, oaepParameters);
        log.info("AlgorithmIdentifier : "+idRsaOaep.toString());
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    encrypter.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCertificate, idRsaOaep).setProvider("BC"));
    return encrypter.generate(message, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC, 256).setProvider("BC").build());
}

Clone this wiki locally