1 /* 2 * Copyright 2012 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package io.netty.handler.codec.http.websocketx; 17 18 import io.netty.util.concurrent.FastThreadLocal; 19 20 import java.security.MessageDigest; 21 import java.security.NoSuchAlgorithmException; 22 import java.util.Base64; 23 import java.util.concurrent.ThreadLocalRandom; 24 25 /** 26 * A utility class mainly for use by web sockets 27 */ 28 final class WebSocketUtil { 29 30 private static final FastThreadLocal<MessageDigest> MD5 = new FastThreadLocal<MessageDigest>() { 31 @Override 32 protected MessageDigest initialValue() throws Exception { 33 try { 34 //Try to get a MessageDigest that uses MD5 35 //Suppress a warning about weak hash algorithm 36 //since it's defined in draft-ietf-hybi-thewebsocketprotocol-00 37 return MessageDigest.getInstance("MD5"); 38 } catch (NoSuchAlgorithmException e) { 39 //This shouldn't happen! How old is the computer? 40 throw new InternalError("MD5 not supported on this platform - Outdated?"); 41 } 42 } 43 }; 44 45 private static final FastThreadLocal<MessageDigest> SHA1 = new FastThreadLocal<MessageDigest>() { 46 @Override 47 protected MessageDigest initialValue() throws Exception { 48 try { 49 //Try to get a MessageDigest that uses SHA1 50 //Suppress a warning about weak hash algorithm 51 //since it's defined in draft-ietf-hybi-thewebsocketprotocol-00 52 return MessageDigest.getInstance("SHA1"); 53 } catch (NoSuchAlgorithmException e) { 54 //This shouldn't happen! How old is the computer? 55 throw new InternalError("SHA-1 not supported on this platform - Outdated?"); 56 } 57 } 58 }; 59 60 /** 61 * Performs a MD5 hash on the specified data 62 * 63 * @param data The data to hash 64 * @return The hashed data 65 */ 66 static byte[] md5(byte[] data) { 67 // TODO(normanmaurer): Create md5 method that not need MessageDigest. 68 return digest(MD5, data); 69 } 70 71 /** 72 * Performs a SHA-1 hash on the specified data 73 * 74 * @param data The data to hash 75 * @return The hashed data 76 */ 77 static byte[] sha1(byte[] data) { 78 // TODO(normanmaurer): Create sha1 method that not need MessageDigest. 79 return digest(SHA1, data); 80 } 81 82 private static byte[] digest(FastThreadLocal<MessageDigest> digestFastThreadLocal, byte[] data) { 83 MessageDigest digest = digestFastThreadLocal.get(); 84 digest.reset(); 85 return digest.digest(data); 86 } 87 88 /** 89 * Performs base64 encoding on the specified data 90 * 91 * @param data The data to encode 92 * @return An encoded string containing the data 93 */ 94 static String base64(byte[] data) { 95 return Base64.getEncoder().encodeToString(data); 96 } 97 98 /** 99 * Creates an arbitrary number of random bytes 100 * 101 * @param size the number of random bytes to create 102 * @return An array of random bytes 103 */ 104 static byte[] randomBytes(int size) { 105 byte[] bytes = new byte[size]; 106 ThreadLocalRandom.current().nextBytes(bytes); 107 return bytes; 108 } 109 110 /** 111 * Generates a pseudo-random number 112 * 113 * @param minimum The minimum allowable value 114 * @param maximum The maximum allowable value 115 * @return A pseudo-random number 116 */ 117 static int randomNumber(int minimum, int maximum) { 118 assert minimum < maximum; 119 double fraction = ThreadLocalRandom.current().nextDouble(); 120 121 // the idea here is that nextDouble gives us a random value 122 // 123 // 0 <= fraction <= 1 124 // 125 // the distance from min to max declared as 126 // 127 // dist = max - min 128 // 129 // satisfies the following 130 // 131 // min + dist = max 132 // 133 // taking into account 134 // 135 // 0 <= fraction * dist <= dist 136 // 137 // we've got 138 // 139 // min <= min + fraction * dist <= max 140 return (int) (minimum + fraction * (maximum - minimum)); 141 } 142 143 static int byteAtIndex(int mask, int index) { 144 return (mask >> 8 * (3 - index)) & 0xFF; 145 } 146 147 /** 148 * A private constructor to ensure that instances of this class cannot be made 149 */ 150 private WebSocketUtil() { 151 // Unused 152 } 153 }