1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.util.encoders;
2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.ByteArrayOutputStream;
4b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.IOException;
5b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.OutputStream;
6b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
7a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstromimport org.bouncycastle.util.Strings;
8a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
9b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic class Base64
10b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{
11b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static final Encoder encoder = new Base64Encoder();
12b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
13a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    public static String toBase64String(
14a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        byte[] data)
15a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    {
16a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        return toBase64String(data, 0, data.length);
17a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    }
18a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
19a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    public static String toBase64String(
20a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        byte[] data,
21a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        int    off,
22a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        int    length)
23a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    {
24a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        byte[] encoded = encode(data, off, length);
25a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        return Strings.fromByteArray(encoded);
26a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    }
27a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
29b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * encode the input data producing a base 64 encoded byte array.
30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
31b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return a byte array containing the base 64 encoded data.
32b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
33b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public static byte[] encode(
34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]    data)
35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
36a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        return encode(data, 0, data.length);
37a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    }
38a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
39a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    /**
40a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom     * encode the input data producing a base 64 encoded byte array.
41a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom     *
42a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom     * @return a byte array containing the base 64 encoded data.
43a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom     */
44a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    public static byte[] encode(
45a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        byte[] data,
46a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        int    off,
47a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        int    length)
48a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    {
49a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        int len = (length + 2) / 3 * 4;
50c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
51a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        try
53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
54a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            encoder.encode(data, off, length, bOut);
55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
56e1142c149e244797ce73b0e7fad40816e447a817Brian Carlstrom        catch (Exception e)
57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
58e1142c149e244797ce73b0e7fad40816e447a817Brian Carlstrom            throw new EncoderException("exception encoding base64 string: " + e.getMessage(), e);
59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return bOut.toByteArray();
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Encode the byte data to base 64 writing it to the given output stream.
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes produced.
68b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public static int encode(
70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]                data,
71b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        OutputStream    out)
72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
73b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
74b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return encoder.encode(data, 0, data.length, out);
75b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Encode the byte data to base 64 writing it to the given output stream.
79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
80b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes produced.
81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
82b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public static int encode(
83b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]                data,
84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int                    off,
85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int                    length,
86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        OutputStream    out)
87b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
88b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
89b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return encoder.encode(data, off, length, out);
90b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
91b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * decode the base 64 encoded input data. It is assumed the input data is valid.
94b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
95b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return a byte array representing the decoded data.
96b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
97b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public static byte[] decode(
98b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]    data)
99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
100c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int len = data.length / 4 * 3;
101c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        try
104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            encoder.decode(data, 0, data.length, bOut);
106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
107e1142c149e244797ce73b0e7fad40816e447a817Brian Carlstrom        catch (Exception e)
108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
109e1142c149e244797ce73b0e7fad40816e447a817Brian Carlstrom            throw new DecoderException("unable to decode base64 data: " + e.getMessage(), e);
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
112b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return bOut.toByteArray();
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * decode the base 64 encoded String data - whitespace will be ignored.
117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return a byte array representing the decoded data.
119b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public static byte[] decode(
121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String    data)
122b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
123c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int len = data.length() / 4 * 3;
124c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        try
127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            encoder.decode(data, bOut);
129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
130e1142c149e244797ce73b0e7fad40816e447a817Brian Carlstrom        catch (Exception e)
131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
132e1142c149e244797ce73b0e7fad40816e447a817Brian Carlstrom            throw new DecoderException("unable to decode base64 string: " + e.getMessage(), e);
133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return bOut.toByteArray();
136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * decode the base 64 encoded String data writing it to the given output stream,
140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * whitespace characters will be ignored.
141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes produced.
143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public static int decode(
145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String                data,
146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        OutputStream    out)
147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return encoder.decode(data, out);
150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam}
152