1   package com.atlassian.seraph.cookie;
2   
3   /**
4    * Insecure cooking encoder that uses an XOR mask with character offsets to "encode" the username and password
5    *
6    * @deprecated replaced by the {@link com.atlassian.seraph.service.rememberme.RememberMeService} code
7    */
8   public class InsecureCookieEncoder implements CookieEncoder
9   {
10      // Character used to separate username and password in persistent cookies.
11      // 0x13 == "Device Control 3" non-printing ASCII char. Unlikely to appear in a username
12      private static final char DELIMITER = 0x13;
13  
14      // "Tweakable" parameters for the cookie encoding. NOTE: changing these
15      // and recompiling this class will essentially invalidate old cookies.
16      private final static int ENCODE_XORMASK = 0x5A;
17      private final static char ENCODE_CHAR_OFFSET1 = 'C';
18      private final static char ENCODE_CHAR_OFFSET2 = 'i';
19  
20      public String encodePasswordCookie(final String username, final String password, final String encoding)
21      {
22          final StringBuffer buf = new StringBuffer();
23          if ((username != null) && (password != null))
24          {
25              final char offset1 = ((encoding != null) && (encoding.length() > 1)) ? encoding.charAt(1) : InsecureCookieEncoder.ENCODE_CHAR_OFFSET1;
26              final char offset2 = ((encoding != null) && (encoding.length() > 2)) ? encoding.charAt(2) : InsecureCookieEncoder.ENCODE_CHAR_OFFSET2;
27  
28              final byte[] bytes = (username + InsecureCookieEncoder.DELIMITER + password).getBytes();
29              int b;
30  
31              for (int n = 0; n < bytes.length; n++)
32              {
33                  b = bytes[n] ^ (InsecureCookieEncoder.ENCODE_XORMASK + n);
34                  buf.append((char) (offset1 + (b & 0x0F)));
35                  buf.append((char) (offset2 + ((b >> 4) & 0x0F)));
36              }
37          }
38          return buf.toString();
39      }
40  
41      public String[] decodePasswordCookie(String cookieVal, final String encoding)
42      {
43          // check that the cookie value isn't null or zero-length
44          if ((cookieVal == null) || (cookieVal.length() <= 0))
45          {
46              return null;
47          }
48  
49          final char offset1 = ((encoding != null) && (encoding.length() > 1)) ? encoding.charAt(1) : InsecureCookieEncoder.ENCODE_CHAR_OFFSET1;
50          final char offset2 = ((encoding != null) && (encoding.length() > 2)) ? encoding.charAt(2) : InsecureCookieEncoder.ENCODE_CHAR_OFFSET2;
51  
52          // decode the cookie value
53          final char[] chars = cookieVal.toCharArray();
54          final byte[] bytes = new byte[chars.length / 2];
55          int b;
56          for (int n = 0, m = 0; n < bytes.length; n++)
57          {
58              b = chars[m++] - offset1;
59              b |= (chars[m++] - offset2) << 4;
60              bytes[n] = (byte) (b ^ (InsecureCookieEncoder.ENCODE_XORMASK + n));
61          }
62          cookieVal = new String(bytes);
63          final int pos = cookieVal.indexOf(InsecureCookieEncoder.DELIMITER);
64          final String username = (pos < 0) ? "" : cookieVal.substring(0, pos);
65          final String password = (pos < 0) ? "" : cookieVal.substring(pos + 1);
66  
67          return new String[] { username, password };
68      }
69  
70      /**
71       * Builds a cookie string containing a username and password.
72       * <p>
73       * Note: with open source this is not really secure, but it prevents users from snooping the cookie file of others and by changing the XOR mask
74       * and character offsets, you can easily tweak results.
75       * 
76       * @param username
77       *            The username.
78       * @param password
79       *            The password.
80       * @return String encoding the input parameters, an empty string if one of the arguments equals <code>null</code>.
81       * @deprecated only here to support {@link com.atlassian.seraph.util.CookieUtils#encodePasswordCookie(String, String)}
82       */
83      public String encodePasswordCookie(final String username, final String password)
84      {
85          return encodePasswordCookie(username, password, new String(new char[] { InsecureCookieEncoder.DELIMITER, InsecureCookieEncoder.ENCODE_CHAR_OFFSET1, InsecureCookieEncoder.ENCODE_CHAR_OFFSET2 }));
86      }
87  
88      /**
89       * Decodes a cookie string containing a username and password.
90       * 
91       * @param cookieVal
92       *            The cookie value.
93       * @return String[] containing the username at index 0 and the password at index 1, or <code>{ null, null }</code> if cookieVal equals
94       *         <code>null</code> or the empty string.
95       * @deprecated only here to support {@link com.atlassian.seraph.util.CookieUtils#decodePasswordCookie(String)}
96       */
97      public String[] decodePasswordCookie(final String cookieVal)
98      {
99          return decodePasswordCookie(cookieVal, new String(new char[] { InsecureCookieEncoder.DELIMITER, InsecureCookieEncoder.ENCODE_CHAR_OFFSET1, InsecureCookieEncoder.ENCODE_CHAR_OFFSET2 }));
100     }
101 }