Communardo Software GmbH, Kleiststraße 10 a, D-01129 Dresden
+49 (0) 351/850 33-0

S/MIME mit BouncyCastle 1.46

Mit dem Ende Februar veröffentlichten BouncyCastle 1.46 wurden die APIs für die Ver- und Entschlüsselung von Nachrichten nach dem S/MIME-Standard teils stark verändert. Dies erhöht auf der einen Seite die Flexibilität, erfordert aber auf der anderen Seite eine Umstellung von bestehendem Code, wenn dieser nicht mehr die nun als „deprecated“ gekennzeichneten APIs nutzen soll.

Ein Beispiel für die Verschlüsselung einer S/MIME-Nachricht sieht jetzt folgendermaßen aus:

    public MimeMessage encryptMessage(MimeMessage message) throws Exception {
        SMIMEEnvelopedGenerator smeg = new SMIMEEnvelopedGenerator();
        for (Address recipient : message.getAllRecipients()) {
            Collection certificates = getCertificates((InternetAddress) recipient);
            for (Certificate cert : certificates) {
                RecipientInfoGenerator recipientInfoGen = new JceKeyTransRecipientInfoGenerator(
                        (X509Certificate) cert);
                smeg.addRecipientInfoGenerator(recipientInfoGen);
            }
        }
        OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(
                CMSAlgorithm.AES256_CBC).build();
        MimeBodyPart encryptedContent = smeg.generate(message, encryptor);
        MimeMessage result = new MimeMessage(message);
        result.setContent(encryptedContent.getContent(), encryptedContent
                .getContentType());
        result.saveChanges();
        return result;
    }

Auf dem Rückweg, also für die Entschlüsselung, kann folgender Code verwendet werden:

    public MimeMessage decryptMessage(MimeMessage encrypted)
            throws MessagingException, Exception {
        SMIMEEnveloped message = new SMIMEEnveloped(encrypted);

        RecipientInformationStore recinfos = message.getRecipientInfos();
        Enumeration aliases = this.keystore.aliases();
        RecipientInformation recid = null;
        String alias = null;
        while ((recid == null) && aliases.hasMoreElements()) {
            alias = aliases.nextElement();
            if (this.keystore.isKeyEntry(alias)) {
                recid = recinfos.get(new JceKeyTransRecipientId(
                        (X509Certificate) this.keystore.getCertificate(alias)));
            }
        }
        if (recid == null) {
            throw new RuntimeException("No decryption key found");
        }

        JceKeyTransEnvelopedRecipient recipient = new JceKeyTransEnvelopedRecipient(
                (PrivateKey) this.keystore.getKey(alias, "changeit"
                        .toCharArray()));

        byte[] content = recid.getContent(recipient);

        MimeMessage decrypted = new MimeMessage(Session
                .getDefaultInstance(System.getProperties()),
                new ByteArrayInputStream(content));
        decrypted.saveChanges();
        return decrypted;
    }

Ein komplettes Codebeispiel für die BouncyCastle 1.46
S/MIME-Funktionalität befindet sich in diesem Zip-Archiv.

Nachtrag: Die kompletten Zertifikate sind in verschlüsselten Nachrichten nicht enthalten. BouncyCastle packt die Empfängerinformationen in RecipientInformation-Instanzen. Mit folgendem Codefragment kann man diese Informationen ausgeben lassen:

public MimeMessage decryptMessage(final MimeMessage encrypted)
        throws MessagingException, Exception {
    SMIMEEnveloped message = new SMIMEEnveloped(encrypted);
    RecipientInformationStore recinfos = message.getRecipientInfos();
    printRecInfos(recinfos);
    ...

private void printRecInfos(final RecipientInformationStore recinfos) {
    for (Object info : recinfos.getRecipients()) {
        if (info instanceof RecipientInformation) {
            System.out.println(((RecipientInformation) info).getRID());
        }
    }
}

Wunderbar das Sie mal zusammengetragen haben, was sich wie bei dem Update verändert hat. Wo haben Sie die Informationen her? Ich tu mich sehr schwer aus der Webseite schlau zu werden. Gibt es nicht viel offzielle Dokumentation, oder suche ich an den falschen Stelle?

Ein paar Sachen befinden sich in den mit BouncyCastle mitgelieferten Code-Beispielen, den Rest habe ich durch Analyse der API-Dokumentation, insbesondere der Deprecation-Hinweise rausgefunden.

Koennten Sie bitte ein Beispiel posten, mit welchem ich aus einer s/mime verschluesselten Nachricht das/die verwendeten Zertifikate und deren Attribute extrahieren kann? Besten Dank!

Kommentar hinterlassen


Pin It on Pinterest