// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.mime.smime;

import java.util.Random;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import java.util.TreeSet;
import java.util.Iterator;
import java.util.List;
import org.bouncycastle.cms.SignerInfoGenerator;
import org.bouncycastle.util.Store;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cert.X509CertificateHolder;
import java.util.LinkedHashMap;
import java.util.Collections;
import org.bouncycastle.cms.CMSAlgorithm;
import java.util.HashMap;
import java.io.IOException;
import org.bouncycastle.mime.encoding.Base64OutputStream;
import java.io.ByteArrayOutputStream;
import org.bouncycastle.util.Strings;
import org.bouncycastle.mime.Headers;
import java.io.OutputStream;
import org.bouncycastle.cms.CMSSignedDataStreamGenerator;
import java.util.Map;
import org.bouncycastle.mime.MimeWriter;

public class SMIMESignedWriter extends MimeWriter
{
    public static final Map RFC3851_MICALGS;
    public static final Map RFC5751_MICALGS;
    public static final Map STANDARD_MICALGS;
    private final CMSSignedDataStreamGenerator sigGen;
    private final String boundary;
    private final OutputStream mimeOut;
    private final String contentTransferEncoding;
    
    private SMIMESignedWriter(final Builder builder, final Map<String, String> map, final String boundary, final OutputStream mimeOut) {
        super(new Headers(MimeWriter.mapToLines(map), builder.contentTransferEncoding));
        this.sigGen = builder.sigGen;
        this.contentTransferEncoding = builder.contentTransferEncoding;
        this.boundary = boundary;
        this.mimeOut = mimeOut;
    }
    
    @Override
    public OutputStream getContentStream() throws IOException {
        this.headers.dumpHeaders(this.mimeOut);
        this.mimeOut.write(Strings.toByteArray("\r\n"));
        if (this.boundary == null) {
            return null;
        }
        this.mimeOut.write(Strings.toByteArray("This is an S/MIME signed message\r\n"));
        this.mimeOut.write(Strings.toByteArray("\r\n--"));
        this.mimeOut.write(Strings.toByteArray(this.boundary));
        this.mimeOut.write(Strings.toByteArray("\r\n"));
        final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        final Base64OutputStream base64OutputStream = new Base64OutputStream(byteArrayOutputStream);
        return new ContentOutputStream(this.sigGen.open(base64OutputStream, false, SMimeUtils.createUnclosable(this.mimeOut)), this.mimeOut, byteArrayOutputStream, base64OutputStream);
    }
    
    static {
        final HashMap m = new HashMap();
        m.put(CMSAlgorithm.MD5, "md5");
        m.put(CMSAlgorithm.SHA1, "sha-1");
        m.put(CMSAlgorithm.SHA224, "sha-224");
        m.put(CMSAlgorithm.SHA256, "sha-256");
        m.put(CMSAlgorithm.SHA384, "sha-384");
        m.put(CMSAlgorithm.SHA512, "sha-512");
        m.put(CMSAlgorithm.GOST3411, "gostr3411-94");
        m.put(CMSAlgorithm.GOST3411_2012_256, "gostr3411-2012-256");
        m.put(CMSAlgorithm.GOST3411_2012_512, "gostr3411-2012-512");
        RFC5751_MICALGS = Collections.unmodifiableMap((Map<?, ?>)m);
        final HashMap i = new HashMap();
        i.put(CMSAlgorithm.MD5, "md5");
        i.put(CMSAlgorithm.SHA1, "sha1");
        i.put(CMSAlgorithm.SHA224, "sha224");
        i.put(CMSAlgorithm.SHA256, "sha256");
        i.put(CMSAlgorithm.SHA384, "sha384");
        i.put(CMSAlgorithm.SHA512, "sha512");
        i.put(CMSAlgorithm.GOST3411, "gostr3411-94");
        i.put(CMSAlgorithm.GOST3411_2012_256, "gostr3411-2012-256");
        i.put(CMSAlgorithm.GOST3411_2012_512, "gostr3411-2012-512");
        RFC3851_MICALGS = Collections.unmodifiableMap((Map<?, ?>)i);
        STANDARD_MICALGS = SMIMESignedWriter.RFC5751_MICALGS;
    }
    
    public static class Builder
    {
        private static final String[] detHeaders;
        private static final String[] detValues;
        private static final String[] encHeaders;
        private static final String[] encValues;
        private final CMSSignedDataStreamGenerator sigGen;
        private final Map<String, String> extraHeaders;
        private final boolean encapsulated;
        private final Map micAlgs;
        String contentTransferEncoding;
        
        public Builder() {
            this(false);
        }
        
        public Builder(final boolean encapsulated) {
            this.sigGen = new CMSSignedDataStreamGenerator();
            this.extraHeaders = new LinkedHashMap<String, String>();
            this.micAlgs = SMIMESignedWriter.STANDARD_MICALGS;
            this.contentTransferEncoding = "base64";
            this.encapsulated = encapsulated;
        }
        
        public Builder withHeader(final String s, final String s2) {
            this.extraHeaders.put(s, s2);
            return this;
        }
        
        public Builder addCertificate(final X509CertificateHolder x509CertificateHolder) throws CMSException {
            this.sigGen.addCertificate(x509CertificateHolder);
            return this;
        }
        
        public Builder addCertificates(final Store store) throws CMSException {
            this.sigGen.addCertificates(store);
            return this;
        }
        
        public Builder addSignerInfoGenerator(final SignerInfoGenerator signerInfoGenerator) {
            this.sigGen.addSignerInfoGenerator(signerInfoGenerator);
            return this;
        }
        
        public SMIMESignedWriter build(final OutputStream outputStream) {
            final LinkedHashMap linkedHashMap = new LinkedHashMap();
            String generateBoundary;
            if (this.encapsulated) {
                generateBoundary = null;
                for (int i = 0; i != Builder.encHeaders.length; ++i) {
                    linkedHashMap.put(Builder.encHeaders[i], Builder.encValues[i]);
                }
            }
            else {
                generateBoundary = this.generateBoundary();
                final StringBuilder sb = new StringBuilder(Builder.detValues[0]);
                this.addHashHeader(sb, this.sigGen.getDigestAlgorithms());
                this.addBoundary(sb, generateBoundary);
                linkedHashMap.put(Builder.detHeaders[0], sb.toString());
                for (int j = 1; j < Builder.detHeaders.length; ++j) {
                    linkedHashMap.put(Builder.detHeaders[j], Builder.detValues[j]);
                }
            }
            for (final Map.Entry entry : this.extraHeaders.entrySet()) {
                linkedHashMap.put(entry.getKey(), entry.getValue());
            }
            return new SMIMESignedWriter(this, linkedHashMap, generateBoundary, SMimeUtils.autoBuffer(outputStream), null);
        }
        
        private void addHashHeader(final StringBuilder sb, final List list) {
            int n = 0;
            final Iterator iterator = list.iterator();
            final TreeSet set = new TreeSet();
            while (iterator.hasNext()) {
                final String s = this.micAlgs.get(((AlgorithmIdentifier)iterator.next()).getAlgorithm());
                if (s == null) {
                    set.add("unknown");
                }
                else {
                    set.add(s);
                }
            }
            for (final String str : set) {
                if (n == 0) {
                    if (set.size() != 1) {
                        sb.append("; micalg=\"");
                    }
                    else {
                        sb.append("; micalg=");
                    }
                }
                else {
                    sb.append(',');
                }
                sb.append(str);
                ++n;
            }
            if (n != 0 && set.size() != 1) {
                sb.append('\"');
            }
        }
        
        private void addBoundary(final StringBuilder sb, final String str) {
            sb.append(";\r\n\tboundary=\"");
            sb.append(str);
            sb.append("\"");
        }
        
        private String generateBoundary() {
            return "==" + new BigInteger(180, new SecureRandom()).setBit(179).toString(16) + "=";
        }
        
        static {
            detHeaders = new String[] { "Content-Type" };
            detValues = new String[] { "multipart/signed; protocol=\"application/pkcs7-signature\"" };
            encHeaders = new String[] { "Content-Type", "Content-Disposition", "Content-Transfer-Encoding", "Content-Description" };
            encValues = new String[] { "application/pkcs7-mime; name=\"smime.p7m\"; smime-type=enveloped-data", "attachment; filename=\"smime.p7m\"", "base64", "S/MIME Signed Message" };
        }
    }
    
    private class ContentOutputStream extends OutputStream
    {
        private final OutputStream main;
        private final OutputStream backing;
        private final ByteArrayOutputStream sigStream;
        private final OutputStream sigBase;
        
        ContentOutputStream(final OutputStream main, final OutputStream backing, final ByteArrayOutputStream sigStream, final OutputStream sigBase) {
            this.main = main;
            this.backing = backing;
            this.sigStream = sigStream;
            this.sigBase = sigBase;
        }
        
        @Override
        public void write(final byte[] b) throws IOException {
            this.main.write(b);
        }
        
        @Override
        public void write(final byte[] b, final int off, final int len) throws IOException {
            this.main.write(b, off, len);
        }
        
        @Override
        public void write(final int n) throws IOException {
            this.main.write(n);
        }
        
        @Override
        public void close() throws IOException {
            if (SMIMESignedWriter.this.boundary != null) {
                this.main.close();
                this.backing.write(Strings.toByteArray("\r\n--"));
                this.backing.write(Strings.toByteArray(SMIMESignedWriter.this.boundary));
                this.backing.write(Strings.toByteArray("\r\n"));
                this.backing.write(Strings.toByteArray("Content-Type: application/pkcs7-signature; name=\"smime.p7s\"\r\n"));
                this.backing.write(Strings.toByteArray("Content-Transfer-Encoding: base64\r\n"));
                this.backing.write(Strings.toByteArray("Content-Disposition: attachment; filename=\"smime.p7s\"\r\n"));
                this.backing.write(Strings.toByteArray("\r\n"));
                if (this.sigBase != null) {
                    this.sigBase.close();
                }
                this.backing.write(this.sigStream.toByteArray());
                this.backing.write(Strings.toByteArray("\r\n--"));
                this.backing.write(Strings.toByteArray(SMIMESignedWriter.this.boundary));
                this.backing.write(Strings.toByteArray("--\r\n"));
            }
            if (this.backing != null) {
                this.backing.close();
            }
        }
    }
}
