1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package javax.crypto.spec; 19 20 import java.security.InvalidKeyException; 21 import java.security.spec.KeySpec; 22 23 /** 24 * The key specification for a DES key. 25 */ 26 public class DESKeySpec implements KeySpec { 27 28 /** 29 * The length of a DES key in bytes. 30 */ 31 public static final int DES_KEY_LEN = 8; 32 33 private final byte[] key; 34 35 // DES weak and semi-weak keys 36 // Got from: 37 // FIP PUB 74 38 // FEDERAL INFORMATION PROCESSING STANDARDS PUBLICATION 1981 39 // GUIDELINES FOR IMPLEMENTING AND USING THE NBS DATA ENCRYPTION STANDARD 40 // http://www.dice.ucl.ac.be/crypto/standards/fips/fip74/fip74-1.pdf 41 private static final byte[][] SEMIWEAKS = { 42 {(byte) 0xE0, (byte) 0x01, (byte) 0xE0, (byte) 0x01, 43 (byte) 0xF1, (byte) 0x01, (byte) 0xF1, (byte) 0x01}, 44 45 {(byte) 0x01, (byte) 0xE0, (byte) 0x01, (byte) 0xE0, 46 (byte) 0x01, (byte) 0xF1, (byte) 0x01, (byte) 0xF1}, 47 48 {(byte) 0xFE, (byte) 0x1F, (byte) 0xFE, (byte) 0x1F, 49 (byte) 0xFE, (byte) 0x0E, (byte) 0xFE, (byte) 0x0E}, 50 51 {(byte) 0x1F, (byte) 0xFE, (byte) 0x1F, (byte) 0xFE, 52 (byte) 0x0E, (byte) 0xFE, (byte) 0x0E, (byte) 0xFE}, 53 54 {(byte) 0xE0, (byte) 0x1F, (byte) 0xE0, (byte) 0x1F, 55 (byte) 0xF1, (byte) 0x0E, (byte) 0xF1, (byte) 0x0E}, 56 57 {(byte) 0x1F, (byte) 0xE0, (byte) 0x1F, (byte) 0xE0, 58 (byte) 0x0E, (byte) 0xF1, (byte) 0x0E, (byte) 0xF1}, 59 60 {(byte) 0x01, (byte) 0xFE, (byte) 0x01, (byte) 0xFE, 61 (byte) 0x01, (byte) 0xFE, (byte) 0x01, (byte) 0xFE}, 62 63 {(byte) 0xFE, (byte) 0x01, (byte) 0xFE, (byte) 0x01, 64 (byte) 0xFE, (byte) 0x01, (byte) 0xFE, (byte) 0x01}, 65 66 {(byte) 0x01, (byte) 0x1F, (byte) 0x01, (byte) 0x1F, 67 (byte) 0x01, (byte) 0x0E, (byte) 0x01, (byte) 0x0E}, 68 69 {(byte) 0x1F, (byte) 0x01, (byte) 0x1F, (byte) 0x01, 70 (byte) 0x0E, (byte) 0x01, (byte) 0x0E, (byte) 0x01}, 71 72 {(byte) 0xE0, (byte) 0xFE, (byte) 0xE0, (byte) 0xFE, 73 (byte) 0xF1, (byte) 0xFE, (byte) 0xF1, (byte) 0xFE}, 74 75 {(byte) 0xFE, (byte) 0xE0, (byte) 0xFE, (byte) 0xE0, 76 (byte) 0xFE, (byte) 0xF1, (byte) 0xFE, (byte) 0xF1}, 77 78 {(byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, 79 (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01}, 80 81 {(byte) 0xFE, (byte) 0xFE, (byte) 0xFE, (byte) 0xFE, 82 (byte) 0xFE, (byte) 0xFE, (byte) 0xFE, (byte) 0xFE}, 83 84 {(byte) 0xE0, (byte) 0xE0, (byte) 0xE0, (byte) 0xE0, 85 (byte) 0xF1, (byte) 0xF1, (byte) 0xF1, (byte) 0xF1}, 86 87 {(byte) 0x1F, (byte) 0x1F, (byte) 0x1F, (byte) 0x1F, 88 (byte) 0x0E, (byte) 0x0E, (byte) 0x0E, (byte) 0x0E}, 89 90 }; 91 92 /** 93 * Creates a new <code>DESKeySpec</code> from the first 8 bytes of the 94 * specified key data. 95 * 96 * @param key 97 * the key data. 98 * @throws InvalidKeyException 99 * if the length of the specified key data is less than 8. 100 */ 101 public DESKeySpec(byte[] key) throws InvalidKeyException { 102 this(key, 0); 103 } 104 105 /** 106 * Creates a new <code>DESKeySpec</code> from the first 8 bytes of the 107 * specified key data starting at <code>offset</code>. 108 * 109 * @param key 110 * the key data 111 * @param offset 112 * the offset to start at. 113 * @throws InvalidKeyException 114 * if the length of the specified key data starting at offset is 115 * less than 8. 116 */ 117 public DESKeySpec(byte[] key, int offset) throws InvalidKeyException { 118 if (key == null) { 119 throw new NullPointerException("key == null"); 120 } 121 if (key.length - offset < DES_KEY_LEN) { 122 throw new InvalidKeyException("key too short"); 123 } 124 this.key = new byte[DES_KEY_LEN]; 125 System.arraycopy(key, offset, this.key, 0, DES_KEY_LEN); 126 } 127 128 /** 129 * Returns a copy of the key. 130 * 131 * @return a copy of the key. 132 */ 133 public byte[] getKey() { 134 byte[] result = new byte[DES_KEY_LEN]; 135 System.arraycopy(this.key, 0, result, 0, DES_KEY_LEN); 136 return result; 137 } 138 139 /** 140 * Returns whether the specified key data starting at <code>offset</code> is 141 * <i>parity-adjusted</i>. 142 * 143 * @param key 144 * the key data. 145 * @param offset 146 * the offset to start checking at. 147 * @return {@code true} if the specified key data is parity-adjusted, 148 * {@code false} otherwise. 149 * @throws InvalidKeyException 150 * if the length of the key data starting at offset is less than 151 * 8, or the key is null. 152 */ 153 public static boolean isParityAdjusted(byte[] key, int offset) throws InvalidKeyException { 154 if (key == null) { 155 throw new InvalidKeyException("key == null"); 156 } 157 if (key.length - offset < DES_KEY_LEN) { 158 throw new InvalidKeyException("key too short"); 159 } 160 161 int byteKey = 0; 162 163 for (int i = offset; i < DES_KEY_LEN; i++) { 164 byteKey = key[i]; 165 166 byteKey ^= byteKey >> 1; 167 byteKey ^= byteKey >> 2; 168 byteKey ^= byteKey >> 4; 169 170 if ((byteKey & 1) == 0) { 171 return false; 172 } 173 } 174 return true; 175 } 176 177 /** 178 * Returns whether the specified key data starting at <code>offset</code> is 179 * weak or semi-weak. 180 * 181 * @param key 182 * the key data. 183 * @param offset 184 * the offset to start checking at. 185 * @return {@code true} if the specified key data is weak or semi-weak. 186 * @throws InvalidKeyException 187 * if the length of the key data starting at offset is less than 188 * 8, or it is null. 189 */ 190 public static boolean isWeak(byte[] key, int offset) throws InvalidKeyException { 191 if (key == null) { 192 throw new InvalidKeyException("key == null"); 193 } 194 if (key.length - offset < DES_KEY_LEN) { 195 throw new InvalidKeyException("key too short"); 196 } 197 I: 198 for (int i=0; i<SEMIWEAKS.length; i++) { 199 for (int j=0; j<DES_KEY_LEN; j++) { 200 if (SEMIWEAKS[i][j] != key[offset+j]) { 201 continue I; 202 } 203 } 204 return true; 205 } 206 return false; 207 } 208 } 209