Coverage Report - org.apache.shiro.codec.H64
 
Classes in this File Line Coverage Branch Coverage Complexity
H64
80%
28/35
70%
14/20
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  
 }