001    package com.nimbusds.jose.util;
002    
003    
004    import java.io.UnsupportedEncodingException;
005    import java.math.BigInteger;
006    
007    import net.jcip.annotations.Immutable;
008    
009    import net.minidev.json.JSONAware;
010    import net.minidev.json.JSONValue;
011    
012    
013    /**
014     * Base64URL-encoded object.
015     *
016     * <p>Related specifications:
017     *
018     * <ul>
019     *     <li>RFC 4648.
020     * </ul>
021     *
022     * @author Vladimir Dzhuvinov
023     * @version $version$ (2013-03-20)
024     */
025    @Immutable
026    public class Base64URL implements JSONAware {
027    
028    
029            /**
030             * The Base64URL value.
031             */
032            private final String value;
033    
034    
035            /**
036             * Creates a new Base64URL-encoded object.
037             *
038             * @param base64URL The Base64URL-encoded object value. The value is 
039             *                  not validated for having characters from the 
040             *                  Base64URL alphabet. Must not be {@code null}.
041             */
042            public Base64URL(final String base64URL) {
043    
044                    if (base64URL == null) {
045    
046                            throw new IllegalArgumentException("The Base64URL value must not be null");
047                    }
048    
049                    value = base64URL;
050            }
051    
052    
053            /**
054             * Decodes this Base64URL object to a byte array.
055             *
056             * @return The resulting byte array.
057             */
058            public byte[] decode() {
059    
060                    return org.apache.commons.codec.binary.Base64.decodeBase64(value);
061            }
062    
063    
064            /**
065             * Decodes this Base64URL object to an unsigned big integer.
066             *
067             * <p>Same as {@code new BigInteger(1, base64url.decode())}.
068             *
069             * @return The resulting big integer.
070             */
071            public BigInteger decodeToBigInteger() {
072    
073                    return new BigInteger(1, decode());
074            }
075    
076    
077            /**
078             * Decodes this Base64URL object to a string.
079             *
080             * @return The resulting string, in the UTF-8 character set.
081             */
082            public String decodeToString() {
083    
084                    try {
085                            return new String(decode(), Base64.CHARSET);
086    
087                    } catch (UnsupportedEncodingException e) {
088    
089                            // UTF-8 should always be supported
090                            return "";
091                    }
092            }
093    
094    
095            /**
096             * Returns a JSON string representation of this object.
097             *
098             * @return The JSON string representation of this object.
099             */
100            @Override
101            public String toJSONString() {
102    
103                    return "\"" + JSONValue.escape(value) + "\"";
104            }
105    
106    
107            /**
108             * Returns a Base64URL string representation of this object.
109             *
110             * @return The Base64URL string representation.
111             */
112            @Override
113            public String toString() {
114    
115                    return value;
116            }
117    
118    
119            /**
120             * Overrides {@code Object.hashCode()}.
121             *
122             * @return The object hash code.
123             */
124            @Override
125            public int hashCode() {
126    
127                    return value.hashCode();
128            }
129    
130    
131            /**
132             * Overrides {@code Object.equals()}.
133             *
134             * @param object The object to compare to.
135             *
136             * @return {@code true} if the objects have the same value, otherwise
137             *         {@code false}.
138             */
139            @Override
140            public boolean equals(final Object object) {
141    
142                    return object != null && 
143                           object instanceof Base64URL && 
144                           this.toString().equals(object.toString());
145            }
146    
147    
148            /**
149             * Base64URL-encodes the specified byte array.
150             *
151             * @param bytes The byte array to encode. Must not be {@code null}.
152             *
153             * @return The resulting Base64URL object.
154             */
155            public static Base64URL encode(final byte[] bytes) {
156    
157                    return new Base64URL(org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(bytes));
158            }
159    
160    
161            /**
162             * Base64URL-encodes the specified big integer, without the sign bit.
163             *
164             * @param bigInt The big integer to encode. Must not be {@code null}.
165             *
166             * @return The resulting Base64URL object.
167             */
168            public static Base64URL encode(final BigInteger bigInt) {
169    
170                    return encode(BigIntegerUtils.toBytesUnsigned(bigInt));
171            }
172    
173    
174            /**
175             * Base64URL-encodes the specified string.
176             *
177             * @param text The string to encode. Must be in the UTF-8 character set
178             *             and not {@code null}.
179             *
180             * @return The resulting Base64URL object.
181             */
182            public static Base64URL encode(final String text) {
183    
184                    try {
185                            return encode(text.getBytes(Base64.CHARSET));
186    
187                    } catch (UnsupportedEncodingException e) {
188    
189                            // UTF-8 should always be supported
190                            return null;
191                    }
192            }
193    }