Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
H64 |
|
| 4.0;4 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | /* | |
20 | * The apr_md5_encode() routine in the APR project's apr_md5.c file uses much | |
21 | * code obtained from the FreeBSD 3.0 MD5 crypt() function, which is licenced | |
22 | * as follows: | |
23 | * ---------------------------------------------------------------------------- | |
24 | * "THE BEER-WARE LICENSE" (Revision 42): | |
25 | * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you | |
26 | * can do whatever you want with this stuff. If we meet some day, and you think | |
27 | * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp | |
28 | * ---------------------------------------------------------------------------- | |
29 | */ | |
30 | package org.apache.shiro.codec; | |
31 | ||
32 | import java.io.IOException; | |
33 | ||
34 | /** | |
35 | * Codec for <a href="http://en.wikipedia.org/wiki/Crypt_(Unix)">Unix Crypt</a>-style encoding. While similar to | |
36 | * Base64, it is not compatible with Base64. | |
37 | * <p/> | |
38 | * This implementation is based on encoding algorithms found in the Apache Portable Runtime library's | |
39 | * <a href="http://svn.apache.org/viewvc/apr/apr/trunk/crypto/apr_md5.c?revision=HEAD&view=markup">apr_md5.c</a> | |
40 | * implementation for its {@code crypt}-style support. The APR team in turn received inspiration for its encoding | |
41 | * implementation based on FreeBSD 3.0's {@code /usr/src/lib/libcrypt/crypt.c} implementation. The | |
42 | * accompanying license headers have been retained at the top of this source file. | |
43 | * <p/> | |
44 | * This file and all that it contains is ASL 2.0 compatible. | |
45 | * | |
46 | * @since 1.2 | |
47 | */ | |
48 | 0 | public class H64 { |
49 | ||
50 | 1 | private static final char[] itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); |
51 | ||
52 | private static short toShort(byte b) { | |
53 | 6 | return (short) (b & 0xff); |
54 | } | |
55 | ||
56 | private static int toInt(byte[] bytes, int offset, int numBytes) { | |
57 | 2 | if (numBytes < 1 || numBytes > 4) { |
58 | 0 | throw new IllegalArgumentException("numBytes must be between 1 and 4."); |
59 | } | |
60 | 2 | int val = toShort(bytes[offset]); //1st byte |
61 | 6 | for (int i = 1; i < numBytes; i++) { //any remaining bytes: |
62 | 4 | short s = toShort(bytes[offset + i]); |
63 | 4 | switch (i) { |
64 | 2 | case 1: val |= s << 8; break; |
65 | 2 | case 2: val |= s << 16; break; |
66 | 0 | case 3: val |= s << 24; break; |
67 | } | |
68 | } | |
69 | 2 | return val; |
70 | } | |
71 | ||
72 | /** | |
73 | * Appends the specified character into the buffer, rethrowing any encountered | |
74 | * {@link IOException} as an {@link IllegalStateException} (since this method is used for internal | |
75 | * implementation needs and we only ever use StringBuilders, we should never encounter an IOException). | |
76 | * | |
77 | * @param buf the buffer to append to | |
78 | * @param c the character to append. | |
79 | */ | |
80 | private static void append(Appendable buf, char c) { | |
81 | try { | |
82 | 8 | buf.append(c); |
83 | 0 | } catch (IOException e) { |
84 | 0 | throw new IllegalStateException("Unable to append character to internal buffer.", e); |
85 | 8 | } |
86 | 8 | } |
87 | ||
88 | /** | |
89 | * Encodes the specified integer to {@code numChars} H64-compatible characters and appends them into {@code buf}. | |
90 | * | |
91 | * @param value the integer to encode to H64-compatible characters | |
92 | * @param buf the output buffer | |
93 | * @param numChars the number of characters the value should be converted to. 3, 2 or 1. | |
94 | */ | |
95 | private static void encodeAndAppend(int value, Appendable buf, int numChars) { | |
96 | 10 | for (int i = 0; i < numChars; i++) { |
97 | 8 | append(buf, itoa64[value & 0x3f]); |
98 | 8 | value >>= 6; |
99 | } | |
100 | 2 | } |
101 | ||
102 | /** | |
103 | * Encodes the specified bytes to an {@code H64}-encoded String. | |
104 | * | |
105 | * @param bytes | |
106 | * @return | |
107 | */ | |
108 | public static String encodeToString(byte[] bytes) { | |
109 | 1 | if (bytes == null || bytes.length == 0) return null; |
110 | ||
111 | 1 | StringBuilder buf = new StringBuilder(); |
112 | ||
113 | 1 | int length = bytes.length; |
114 | 1 | int remainder = length % 3; |
115 | 1 | int i = 0; //starting byte |
116 | 1 | int last3ByteIndex = length - remainder; //last byte whose index is a multiple of 3 |
117 | ||
118 | 5 | for(; i < last3ByteIndex; i += 3) { |
119 | 2 | int twentyFourBit = toInt(bytes, i, 3); |
120 | 2 | encodeAndAppend(twentyFourBit, buf, 4); |
121 | } | |
122 | 1 | if (remainder > 0) { |
123 | //one or two bytes that we still need to encode: | |
124 | 0 | int a = toInt(bytes, i, remainder); |
125 | 0 | encodeAndAppend(a, buf, remainder + 1); |
126 | } | |
127 | 1 | return buf.toString(); |
128 | } | |
129 | } |