1 /* 2 * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.crypto.provider; 27 28 import java.util.Arrays; 29 import java.security.*; 30 import java.security.spec.*; 31 import javax.crypto.*; 32 import javax.crypto.spec.*; 33 34 /** 35 * This class implements the AES KeyWrap algorithm as defined 36 * in <a href=http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap> 37 * "XML Encryption Syntax and Processing" section 5.6.3 "AES Key Wrap". 38 * Note: only <code>ECB</code> mode and <code>NoPadding</code> padding 39 * can be used for this algorithm. 40 * 41 * @author Valerie Peng 42 * 43 * 44 * @see AESCipher 45 */ 46 abstract class AESWrapCipher extends CipherSpi { 47 public static final class General extends AESWrapCipher { 48 public General() { 49 super(-1); 50 } 51 } 52 public static final class AES128 extends AESWrapCipher { 53 public AES128() { 54 super(16); 55 } 56 } 57 public static final class AES192 extends AESWrapCipher { 58 public AES192() { 59 super(24); 60 } 61 } 62 public static final class AES256 extends AESWrapCipher { 63 public AES256() { 64 super(32); 65 } 66 } 67 private static final byte[] IV = { 68 (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, 69 (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6 70 }; 71 72 private static final int blksize = AESConstants.AES_BLOCK_SIZE; 73 74 /* 75 * internal cipher object which does the real work. 76 */ 77 private AESCrypt cipher; 78 79 /* 80 * are we encrypting or decrypting? 81 */ 82 private boolean decrypting = false; 83 84 /* 85 * needed to support AES oids which associates a fixed key size 86 * to the cipher object. 87 */ 88 private final int fixedKeySize; // in bytes, -1 if no restriction 89 90 /** 91 * Creates an instance of AES KeyWrap cipher with default 92 * mode, i.e. "ECB" and padding scheme, i.e. "NoPadding". 93 */ 94 public AESWrapCipher(int keySize) { 95 cipher = new AESCrypt(); 96 fixedKeySize = keySize; 97 98 } 99 100 /** 101 * Sets the mode of this cipher. Only "ECB" mode is accepted for this 102 * cipher. 103 * 104 * @param mode the cipher mode 105 * 106 * @exception NoSuchAlgorithmException if the requested cipher mode 107 * is not "ECB". 108 */ 109 protected void engineSetMode(String mode) 110 throws NoSuchAlgorithmException { 111 if (!mode.equalsIgnoreCase("ECB")) { 112 throw new NoSuchAlgorithmException(mode + " cannot be used"); 113 } 114 } 115 116 /** 117 * Sets the padding mechanism of this cipher. Only "NoPadding" schmem 118 * is accepted for this cipher. 119 * 120 * @param padding the padding mechanism 121 * 122 * @exception NoSuchPaddingException if the requested padding mechanism 123 * is not "NoPadding". 124 */ 125 protected void engineSetPadding(String padding) 126 throws NoSuchPaddingException { 127 if (!padding.equalsIgnoreCase("NoPadding")) { 128 throw new NoSuchPaddingException(padding + " cannot be used"); 129 } 130 } 131 132 /** 133 * Returns the block size (in bytes). i.e. 16 bytes. 134 * 135 * @return the block size (in bytes), i.e. 16 bytes. 136 */ 137 protected int engineGetBlockSize() { 138 return blksize; 139 } 140 141 /** 142 * Returns the length in bytes that an output buffer would need to be 143 * given the input length <code>inputLen</code> (in bytes). 144 * 145 * <p>The actual output length of the next <code>update</code> or 146 * <code>doFinal</code> call may be smaller than the length returned 147 * by this method. 148 * 149 * @param inputLen the input length (in bytes) 150 * 151 * @return the required output buffer size (in bytes) 152 */ 153 protected int engineGetOutputSize(int inputLen) { 154 // can only return an upper-limit if not initialized yet. 155 int result = 0; 156 if (decrypting) { 157 result = inputLen - 8; 158 } else { 159 result = Math.addExact(inputLen, 8); 160 } 161 return (result < 0? 0:result); 162 } 163 164 /** 165 * Returns the initialization vector (IV) which is null for this cipher. 166 * 167 * @return null for this cipher. 168 */ 169 protected byte[] engineGetIV() { 170 return null; 171 } 172 173 /** 174 * Initializes this cipher with a key and a source of randomness. 175 * 176 * <p>The cipher only supports the following two operation modes:<b> 177 * Cipher.WRAP_MODE, and <b> 178 * Cipher.UNWRAP_MODE. 179 * <p>For modes other than the above two, UnsupportedOperationException 180 * will be thrown. 181 * 182 * @param opmode the operation mode of this cipher. Only 183 * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) are accepted. 184 * @param key the secret key. 185 * @param random the source of randomness. 186 * 187 * @exception InvalidKeyException if the given key is inappropriate for 188 * initializing this cipher. 189 */ 190 protected void engineInit(int opmode, Key key, SecureRandom random) 191 throws InvalidKeyException { 192 if (opmode == Cipher.WRAP_MODE) { 193 decrypting = false; 194 } else if (opmode == Cipher.UNWRAP_MODE) { 195 decrypting = true; 196 } else { 197 throw new UnsupportedOperationException("This cipher can " + 198 "only be used for key wrapping and unwrapping"); 199 } 200 AESCipher.checkKeySize(key, fixedKeySize); 201 cipher.init(decrypting, key.getAlgorithm(), key.getEncoded()); 202 } 203 204 /** 205 * Initializes this cipher with a key, a set of algorithm parameters, 206 * and a source of randomness. 207 * 208 * <p>The cipher only supports the following two operation modes:<b> 209 * Cipher.WRAP_MODE, and <b> 210 * Cipher.UNWRAP_MODE. 211 * <p>For modes other than the above two, UnsupportedOperationException 212 * will be thrown. 213 * 214 * @param opmode the operation mode of this cipher. Only 215 * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) are accepted. 216 * @param key the secret key. 217 * @param params the algorithm parameters; must be null for this cipher. 218 * @param random the source of randomness. 219 * 220 * @exception InvalidKeyException if the given key is inappropriate for 221 * initializing this cipher 222 * @exception InvalidAlgorithmParameterException if the given algorithm 223 * parameters is not null. 224 */ 225 protected void engineInit(int opmode, Key key, 226 AlgorithmParameterSpec params, 227 SecureRandom random) 228 throws InvalidKeyException, InvalidAlgorithmParameterException { 229 if (params != null) { 230 throw new InvalidAlgorithmParameterException("This cipher " + 231 "does not accept any parameters"); 232 } 233 engineInit(opmode, key, random); 234 } 235 236 /** 237 * Initializes this cipher with a key, a set of algorithm parameters, 238 * and a source of randomness. 239 * 240 * <p>The cipher only supports the following two operation modes:<b> 241 * Cipher.WRAP_MODE, and <b> 242 * Cipher.UNWRAP_MODE. 243 * <p>For modes other than the above two, UnsupportedOperationException 244 * will be thrown. 245 * 246 * @param opmode the operation mode of this cipher. Only 247 * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) are accepted. 248 * @param key the secret key. 249 * @param params the algorithm parameters; must be null for this cipher. 250 * @param random the source of randomness. 251 * 252 * @exception InvalidKeyException if the given key is inappropriate. 253 * @exception InvalidAlgorithmParameterException if the given algorithm 254 * parameters is not null. 255 */ 256 protected void engineInit(int opmode, Key key, 257 AlgorithmParameters params, 258 SecureRandom random) 259 throws InvalidKeyException, InvalidAlgorithmParameterException { 260 if (params != null) { 261 throw new InvalidAlgorithmParameterException("This cipher " + 262 "does not accept any parameters"); 263 } 264 engineInit(opmode, key, random); 265 } 266 267 /** 268 * This operation is not supported by this cipher. 269 * Since it's impossible to initialize this cipher given the 270 * current Cipher.engineInit(...) implementation, 271 * IllegalStateException will always be thrown upon invocation. 272 * 273 * @param in the input buffer. 274 * @param inOffset the offset in <code>in</code> where the input 275 * starts. 276 * @param inLen the input length. 277 * 278 * @return n/a. 279 * 280 * @exception IllegalStateException upon invocation of this method. 281 */ 282 protected byte[] engineUpdate(byte[] in, int inOffset, int inLen) { 283 throw new IllegalStateException("Cipher has not been initialized"); 284 } 285 286 /** 287 * This operation is not supported by this cipher. 288 * Since it's impossible to initialize this cipher given the 289 * current Cipher.engineInit(...) implementation, 290 * IllegalStateException will always be thrown upon invocation. 291 * 292 * @param in the input buffer. 293 * @param inOffset the offset in <code>in</code> where the input 294 * starts. 295 * @param inLen the input length. 296 * @param out the buffer for the result. 297 * @param outOffset the offset in <code>out</code> where the result 298 * is stored. 299 * 300 * @return n/a. 301 * 302 * @exception IllegalStateException upon invocation of this method. 303 */ 304 protected int engineUpdate(byte[] in, int inOffset, int inLen, 305 byte[] out, int outOffset) 306 throws ShortBufferException { 307 throw new IllegalStateException("Cipher has not been initialized"); 308 } 309 310 /** 311 * This operation is not supported by this cipher. 312 * Since it's impossible to initialize this cipher given the 313 * current Cipher.engineInit(...) implementation, 314 * IllegalStateException will always be thrown upon invocation. 315 * 316 * @param in the input buffer 317 * @param inOffset the offset in <code>in</code> where the input 318 * starts 319 * @param inLen the input length. 320 * 321 * @return n/a. 322 * 323 * @exception IllegalStateException upon invocation of this method. 324 */ 325 protected byte[] engineDoFinal(byte[] input, int inputOffset, 326 int inputLen) 327 throws IllegalBlockSizeException, BadPaddingException { 328 throw new IllegalStateException("Cipher has not been initialized"); 329 } 330 331 /** 332 * This operation is not supported by this cipher. 333 * Since it's impossible to initialize this cipher given the 334 * current Cipher.engineInit(...) implementation, 335 * IllegalStateException will always be thrown upon invocation. 336 * 337 * @param in the input buffer. 338 * @param inOffset the offset in <code>in</code> where the input 339 * starts. 340 * @param inLen the input length. 341 * @param out the buffer for the result. 342 * @param outOffset the ofset in <code>out</code> where the result 343 * is stored. 344 * 345 * @return n/a. 346 * 347 * @exception IllegalStateException upon invocation of this method. 348 */ 349 protected int engineDoFinal(byte[] in, int inOffset, int inLen, 350 byte[] out, int outOffset) 351 throws IllegalBlockSizeException, ShortBufferException, 352 BadPaddingException { 353 throw new IllegalStateException("Cipher has not been initialized"); 354 } 355 356 /** 357 * Returns the parameters used with this cipher which is always null 358 * for this cipher. 359 * 360 * @return null since this cipher does not use any parameters. 361 */ 362 protected AlgorithmParameters engineGetParameters() { 363 return null; 364 } 365 366 /** 367 * Returns the key size of the given key object in number of bits. 368 * 369 * @param key the key object. 370 * 371 * @return the "effective" key size of the given key object. 372 * 373 * @exception InvalidKeyException if <code>key</code> is invalid. 374 */ 375 protected int engineGetKeySize(Key key) throws InvalidKeyException { 376 byte[] encoded = key.getEncoded(); 377 if (!AESCrypt.isKeySizeValid(encoded.length)) { 378 throw new InvalidKeyException("Invalid key length: " + 379 encoded.length + " bytes"); 380 } 381 return Math.multiplyExact(encoded.length, 8); 382 } 383 384 /** 385 * Wrap a key. 386 * 387 * @param key the key to be wrapped. 388 * 389 * @return the wrapped key. 390 * 391 * @exception IllegalBlockSizeException if this cipher is a block 392 * cipher, no padding has been requested, and the length of the 393 * encoding of the key to be wrapped is not a 394 * multiple of the block size. 395 * 396 * @exception InvalidKeyException if it is impossible or unsafe to 397 * wrap the key with this cipher (e.g., a hardware protected key is 398 * being passed to a software only cipher). 399 */ 400 protected byte[] engineWrap(Key key) 401 throws IllegalBlockSizeException, InvalidKeyException { 402 byte[] keyVal = key.getEncoded(); 403 if ((keyVal == null) || (keyVal.length == 0)) { 404 throw new InvalidKeyException("Cannot get an encoding of " + 405 "the key to be wrapped"); 406 } 407 byte[] out = new byte[Math.addExact(keyVal.length, 8)]; 408 409 if (keyVal.length == 8) { 410 System.arraycopy(IV, 0, out, 0, IV.length); 411 System.arraycopy(keyVal, 0, out, IV.length, 8); 412 cipher.encryptBlock(out, 0, out, 0); 413 } else { 414 if (keyVal.length % 8 != 0) { 415 throw new IllegalBlockSizeException("length of the " + 416 "to be wrapped key should be multiples of 8 bytes"); 417 } 418 System.arraycopy(IV, 0, out, 0, IV.length); 419 System.arraycopy(keyVal, 0, out, IV.length, keyVal.length); 420 int N = keyVal.length/8; 421 byte[] buffer = new byte[blksize]; 422 for (int j = 0; j < 6; j++) { 423 for (int i = 1; i <= N; i++) { 424 int T = i + j*N; 425 System.arraycopy(out, 0, buffer, 0, IV.length); 426 System.arraycopy(out, i*8, buffer, IV.length, 8); 427 cipher.encryptBlock(buffer, 0, buffer, 0); 428 for (int k = 1; T != 0; k++) { 429 byte v = (byte) T; 430 buffer[IV.length - k] ^= v; 431 T >>>= 8; 432 } 433 System.arraycopy(buffer, 0, out, 0, IV.length); 434 System.arraycopy(buffer, 8, out, 8*i, 8); 435 } 436 } 437 } 438 return out; 439 } 440 441 /** 442 * Unwrap a previously wrapped key. 443 * 444 * @param wrappedKey the key to be unwrapped. 445 * 446 * @param wrappedKeyAlgorithm the algorithm the wrapped key is for. 447 * 448 * @param wrappedKeyType the type of the wrapped key. 449 * This is one of <code>Cipher.SECRET_KEY</code>, 450 * <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>. 451 * 452 * @return the unwrapped key. 453 * 454 * @exception NoSuchAlgorithmException if no installed providers 455 * can create keys of type <code>wrappedKeyType</code> for the 456 * <code>wrappedKeyAlgorithm</code>. 457 * 458 * @exception InvalidKeyException if <code>wrappedKey</code> does not 459 * represent a wrapped key of type <code>wrappedKeyType</code> for 460 * the <code>wrappedKeyAlgorithm</code>. 461 */ 462 protected Key engineUnwrap(byte[] wrappedKey, 463 String wrappedKeyAlgorithm, 464 int wrappedKeyType) 465 throws InvalidKeyException, NoSuchAlgorithmException { 466 int wrappedKeyLen = wrappedKey.length; 467 // ensure the wrappedKey length is multiples of 8 bytes and non-zero 468 if (wrappedKeyLen == 0) { 469 throw new InvalidKeyException("The wrapped key is empty"); 470 } 471 if (wrappedKeyLen % 8 != 0) { 472 throw new InvalidKeyException 473 ("The wrapped key has invalid key length"); 474 } 475 byte[] out = new byte[wrappedKeyLen - 8]; 476 byte[] buffer = new byte[blksize]; 477 if (wrappedKeyLen == 16) { 478 cipher.decryptBlock(wrappedKey, 0, buffer, 0); 479 for (int i = 0; i < IV.length; i++) { 480 if (IV[i] != buffer[i]) { 481 throw new InvalidKeyException("Integrity check failed"); 482 } 483 } 484 System.arraycopy(buffer, IV.length, out, 0, out.length); 485 } else { 486 System.arraycopy(wrappedKey, 0, buffer, 0, IV.length); 487 System.arraycopy(wrappedKey, IV.length, out, 0, out.length); 488 int N = out.length/8; 489 for (int j = 5; j >= 0; j--) { 490 for (int i = N; i > 0; i--) { 491 int T = i + j*N; 492 System.arraycopy(out, 8*(i-1), buffer, IV.length, 8); 493 for (int k = 1; T != 0; k++) { 494 byte v = (byte) T; 495 buffer[IV.length - k] ^= v; 496 T >>>= 8; 497 } 498 cipher.decryptBlock(buffer, 0, buffer, 0); 499 System.arraycopy(buffer, IV.length, out, 8*(i-1), 8); 500 } 501 } 502 for (int i = 0; i < IV.length; i++) { 503 if (IV[i] != buffer[i]) { 504 throw new InvalidKeyException("Integrity check failed"); 505 } 506 } 507 } 508 return ConstructKeys.constructKey(out, wrappedKeyAlgorithm, 509 wrappedKeyType); 510 } 511 }