summary refs log tree commit diff
path: root/crypto/src/crmf/EncryptedValueBuilder.cs
blob: 37f38df1cff179b56abc2bb504c6ca2e26a3ade3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
using System;
using System.IO;

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Crmf;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.IO;
using Org.BouncyCastle.X509;

namespace Org.BouncyCastle.Crmf
{
    public class EncryptedValueBuilder
    {
        private readonly IKeyWrapper wrapper;
        private readonly ICipherBuilderWithKey encryptor;
        private readonly IEncryptedValuePadder padder;

        ///
        /// Create a builder that makes EncryptedValue structures.
        ///
        /// <param name="wrapper">wrapper a wrapper for key used to encrypt the actual data contained in the EncryptedValue.</param>
        /// <param name="encryptor">encryptor  an output encryptor to encrypt the actual data contained in the EncryptedValue. </param>
        ///
        public EncryptedValueBuilder(IKeyWrapper wrapper, ICipherBuilderWithKey encryptor)
            : this(wrapper, encryptor, null)
        {
        }

        ///
        /// Create a builder that makes EncryptedValue structures with fixed length blocks padded using the passed in padder.
        ///
        /// <param name="wrapper">a wrapper for key used to encrypt the actual data contained in the EncryptedValue.</param>
        /// <param name="encryptor">encryptor  an output encryptor to encrypt the actual data contained in the EncryptedValue.</param>
        /// <param name="padder">padder a padder to ensure that the EncryptedValue created will always be a constant length.</param>
        ///
        public EncryptedValueBuilder(IKeyWrapper wrapper, ICipherBuilderWithKey encryptor, IEncryptedValuePadder padder)
        {
            this.wrapper = wrapper;
            this.encryptor = encryptor;
            this.padder = padder;
        }

        ///
        /// Build an EncryptedValue structure containing the passed in pass phrase.
        ///
        /// <param name="revocationPassphrase">a revocation pass phrase.</param>
        ///<returns>an EncryptedValue containing the encrypted pass phrase.</returns>       
        ///
        public EncryptedValue Build(char[] revocationPassphrase)
        {
            return EncryptData(PadData(Strings.ToUtf8ByteArray(revocationPassphrase)));
        }

        ///<summary>
        /// Build an EncryptedValue structure containing the certificate contained in
        /// the passed in holder.
        ///</summary>
        /// <param name="holder">a holder containing a certificate.</param>
        ///  <returns>an EncryptedValue containing the encrypted certificate.</returns>
        /// <exception cref="CrmfException">on a failure to encrypt the data, or wrap the symmetric key for this value.</exception>
        ///
        public EncryptedValue Build(X509Certificate holder)
        {
            try
            {
                return EncryptData(PadData(holder.GetEncoded()));
            }
            catch (IOException e)
            {
                throw new CrmfException("cannot encode certificate: " + e.Message, e);
            }
        }

        ///<summary>
        /// Build an EncryptedValue structure containing the private key contained in
        /// the passed info structure.
        ///</summary>
        /// <param name="privateKeyInfo">a PKCS#8 private key info structure.</param>
        /// <returns>an EncryptedValue containing an EncryptedPrivateKeyInfo structure.</returns>
        /// <exception cref="CrmfException">on a failure to encrypt the data, or wrap the symmetric key for this value.</exception>
        ///
        public EncryptedValue Build(PrivateKeyInfo privateKeyInfo)
        {
            Pkcs8EncryptedPrivateKeyInfoBuilder encInfoBldr = new Pkcs8EncryptedPrivateKeyInfoBuilder(privateKeyInfo);

            AlgorithmIdentifier intendedAlg = privateKeyInfo.PrivateKeyAlgorithm;
            AlgorithmIdentifier symmAlg = (AlgorithmIdentifier)encryptor.AlgorithmDetails;
            DerBitString encSymmKey;

            try
            {
                Pkcs8EncryptedPrivateKeyInfo encInfo = encInfoBldr.Build(encryptor);

                encSymmKey = new DerBitString(wrapper.Wrap(((KeyParameter)encryptor.Key).GetKey()).Collect());

                AlgorithmIdentifier keyAlg = (AlgorithmIdentifier)wrapper.AlgorithmDetails;
                Asn1OctetString valueHint = null;

                return new EncryptedValue(intendedAlg, symmAlg, encSymmKey, keyAlg, valueHint, new DerBitString(encInfo.GetEncryptedData()));
            }
            catch (Exception e)
            {
                throw new CrmfException("cannot wrap key: " + e.Message, e);
            }
        }

        private EncryptedValue EncryptData(byte[] data)
        {
            MemoryOutputStream bOut = new MemoryOutputStream();
            var cipher = encryptor.BuildCipher(bOut);

            try
            {
                using (var eOut = cipher.Stream)
                {
                    eOut.Write(data, 0, data.Length);
                }
            }
            catch (IOException e)
            {
                throw new CrmfException("cannot process data: " + e.Message, e);
            }

            AlgorithmIdentifier intendedAlg = null;
            AlgorithmIdentifier symmAlg = (AlgorithmIdentifier)encryptor.AlgorithmDetails;

            DerBitString encSymmKey;
            try
            {
                encSymmKey = new DerBitString(wrapper.Wrap(((KeyParameter)encryptor.Key).GetKey()).Collect());
            }
            catch (Exception e)
            {
                throw new CrmfException("cannot wrap key: " + e.Message, e);
            }

            AlgorithmIdentifier keyAlg = (AlgorithmIdentifier)wrapper.AlgorithmDetails;
            Asn1OctetString valueHint = null;
            DerBitString encValue = new DerBitString(bOut.ToArray());

            return new EncryptedValue(intendedAlg, symmAlg, encSymmKey, keyAlg, valueHint, encValue);
        }

        private byte[] PadData(byte[] data)
        {
            if (padder != null)
            {
                return padder.GetPaddedData(data);
            }

            return data;
        }
    }
}