Communardo Software GmbH, Kleiststraße 10 a, D-01129 Dresden
0800 1 255 255

S/MIME mit BouncyCastle 1.46

Mit dem Ende Februar ver­öf­fent­lich­ten BouncyCastle 1.46 wur­den die APIs für die Ver- und Entschlüsselung von Nachrichten nach dem S/MIME-Standard teils stark ver­än­dert. Dies erhöht auf der einen Seite die Flexibilität, erfor­dert aber auf der ande­ren Seite eine Umstellung von bestehen­dem Code, wenn die­ser nicht mehr die nun als "depre­ca­ted" gekenn­zeich­ne­ten APIs nut­zen soll.

Ein Beispiel für die Verschlüsselung einer S/MIME-Nachricht sieht jetzt fol­gen­der­ma­ß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 fol­gen­der Code ver­wen­det wer­den:

    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 kom­plet­tes Codebeispiel für die BouncyCastle 1.46
S/MIME-Funktionalität befin­det sich in die­sem Zip-Archiv.

Nachtrag: Die kom­plet­ten Zertifikate sind in ver­schlüs­sel­ten Nachrichten nicht ent­hal­ten. BouncyCastle packt die Empfängerinformationen in RecipientInformation-Instanzen. Mit fol­gen­dem Codefragment kann man diese Informationen aus­ge­ben las­sen:

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());
        }
    }
}

Related Posts

Wunderbar das Sie mal zusam­men­ge­tra­gen haben, was sich wie bei dem Update ver­än­dert hat. Wo haben Sie die Informationen her? Ich tu mich sehr schwer aus der Webseite schlau zu wer­den. Gibt es nicht viel off­zi­elle Dokumentation, oder suche ich an den fal­schen Stelle?

Ein paar Sachen befin­den sich in den mit BouncyCastle mit­ge­lie­fer­ten Code-Beispielen, den Rest habe ich durch Analyse der API-Dokumentation, ins­be­son­dere der Deprecation-Hinweise raus­ge­fun­den.

Koennten Sie bitte ein Beispiel pos­ten, mit wel­chem ich aus einer s/mime ver­schlues­sel­ten Nachricht das/die ver­wen­de­ten Zertifikate und deren Attribute extra­hie­ren kann? Besten Dank!

Comments are closed.

Pin It on Pinterest