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, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.commons.crypto.cipher; 19 20 import java.nio.ByteBuffer; 21 import java.security.GeneralSecurityException; 22 import java.security.InvalidAlgorithmParameterException; 23 import java.security.InvalidKeyException; 24 import java.security.Key; 25 import java.security.spec.AlgorithmParameterSpec; 26 import java.util.Objects; 27 import java.util.Properties; 28 29 import javax.crypto.BadPaddingException; 30 import javax.crypto.Cipher; 31 import javax.crypto.IllegalBlockSizeException; 32 import javax.crypto.ShortBufferException; 33 34 /** 35 * Implements the {@link CryptoCipher} using JCE provider. 36 * <p> 37 * This class is not public/protected so does not appear in the main Javadoc. Please ensure that property use is documented in the enum 38 * CryptoRandomFactory.RandomProvider 39 * </p> 40 */ 41 class JceCipher implements CryptoCipher { 42 private final Cipher cipher; 43 44 /** 45 * Constructs a {@link CryptoCipher} based on JCE Cipher {@link Cipher}. 46 * 47 * @param props properties for JCE cipher (only uses {@link CryptoCipherFactory#JCE_PROVIDER_KEY}) 48 * @param transformation transformation for JCE cipher (algorithm/mode/padding) 49 * @throws GeneralSecurityException if JCE cipher initialize failed 50 */ 51 public JceCipher(final Properties props, final String transformation) 52 throws GeneralSecurityException { 53 final String provider = props.getProperty(CryptoCipherFactory.JCE_PROVIDER_KEY, ""); 54 cipher = provider.isEmpty() ? Cipher.getInstance(transformation) : Cipher.getInstance(transformation, provider); 55 } 56 57 /** 58 * Closes Jce cipher. 59 */ 60 @Override 61 public void close() { 62 // Do nothing 63 } 64 65 /** 66 * Encrypts or decrypts data in a single-part operation, or finishes a 67 * multiple-part operation. 68 * 69 * @param input the input byte array 70 * @param inputOffset the offset in input where the input starts 71 * @param inputLen the input length 72 * @param output the byte array for the result 73 * @param outputOffset the offset in output where the result is stored 74 * @return the number of bytes stored in output 75 * @throws ShortBufferException if the given output byte array is too small 76 * to hold the result 77 * @throws BadPaddingException if this cipher is in decryption mode, and 78 * (un)padding has been requested, but the decrypted data is not 79 * bounded by the appropriate padding bytes 80 * @throws IllegalBlockSizeException if this cipher is a block cipher, no 81 * padding has been requested (only in encryption mode), and the 82 * total input length of the data processed by this cipher is not a 83 * multiple of block size; or if this encryption algorithm is unable 84 * to process the input data provided. 85 */ 86 @Override 87 public int doFinal(final byte[] input, final int inputOffset, final int inputLen, 88 final byte[] output, final int outputOffset) throws ShortBufferException, 89 IllegalBlockSizeException, BadPaddingException { 90 return cipher.doFinal(input, inputOffset, inputLen, output, 91 outputOffset); 92 } 93 94 /** 95 * Encrypts or decrypts data in a single-part operation, or finishes a 96 * multiple-part operation. The data is encrypted or decrypted, depending on 97 * how this cipher was initialized. 98 * 99 * @param inBuffer the input ByteBuffer 100 * @param outBuffer the output ByteBuffer 101 * @return int number of bytes stored in {@code output} 102 * @throws BadPaddingException if this cipher is in decryption mode, and 103 * (un)padding has been requested, but the decrypted data is not 104 * bounded by the appropriate padding bytes 105 * @throws IllegalBlockSizeException if this cipher is a block cipher, no 106 * padding has been requested (only in encryption mode), and the 107 * total input length of the data processed by this cipher is not a 108 * multiple of block size; or if this encryption algorithm is unable 109 * to process the input data provided. 110 * @throws ShortBufferException if the given output buffer is too small to 111 * hold the result 112 */ 113 @Override 114 public int doFinal(final ByteBuffer inBuffer, final ByteBuffer outBuffer) 115 throws ShortBufferException, IllegalBlockSizeException, 116 BadPaddingException { 117 return cipher.doFinal(inBuffer, outBuffer); 118 } 119 120 /** 121 * Returns the algorithm name of this {@code CryptoCipher} object. 122 * 123 * <p> 124 * This is the same name that was specified in one of the 125 * {@code CryptoCipherFactory#getInstance} calls that created this 126 * {@code CryptoCipher} object.. 127 * </p> 128 * 129 * @return the algorithm name of this {@code CryptoCipher} object. 130 */ 131 @Override 132 public String getAlgorithm() { 133 return cipher.getAlgorithm(); 134 } 135 136 /** 137 * Returns the block size (in bytes). 138 * 139 * @return the block size (in bytes), or 0 if the underlying algorithm is 140 * not a block cipher 141 */ 142 @Override 143 public final int getBlockSize() { 144 return cipher.getBlockSize(); 145 } 146 147 /** 148 * Initializes the cipher with mode, key and iv. 149 * 150 * @param mode {@link Cipher#ENCRYPT_MODE} or {@link Cipher#DECRYPT_MODE} 151 * @param key crypto key for the cipher 152 * @param params the algorithm parameters 153 * @throws InvalidAlgorithmParameterException if the given algorithm 154 * parameters are inappropriate for this cipher, or this cipher 155 * requires algorithm parameters and {@code params} is null, or 156 * the given algorithm parameters imply a cryptographic strength 157 * that would exceed the legal limits (as determined from the 158 * configured jurisdiction policy files). 159 */ 160 @Override 161 public void init(final int mode, final Key key, final AlgorithmParameterSpec params) 162 throws InvalidKeyException, InvalidAlgorithmParameterException { 163 Objects.requireNonNull(key, "key"); 164 Objects.requireNonNull(params, "params"); 165 166 // Jce uses the javax.crypto.Cipher modes; no need to convert the input 167 cipher.init(mode, key, params); 168 } 169 170 /** 171 * Continues a multiple-part encryption/decryption operation. The data is 172 * encrypted or decrypted, depending on how this cipher was initialized. 173 * 174 * @param input the input byte array 175 * @param inputOffset the offset in input where the input starts 176 * @param inputLen the input length 177 * @param output the byte array for the result 178 * @param outputOffset the offset in output where the result is stored 179 * @return the number of bytes stored in output 180 * @throws ShortBufferException if there is insufficient space in the output 181 * byte array 182 */ 183 @Override 184 public int update(final byte[] input, final int inputOffset, final int inputLen, 185 final byte[] output, final int outputOffset) throws ShortBufferException { 186 return cipher 187 .update(input, inputOffset, inputLen, output, outputOffset); 188 } 189 190 191 /** 192 * Continues a multiple-part encryption/decryption operation. The data is 193 * encrypted or decrypted, depending on how this cipher was initialized. 194 * 195 * @param inBuffer the input ByteBuffer 196 * @param outBuffer the output ByteBuffer 197 * @return int number of bytes stored in {@code output} 198 * @throws ShortBufferException if there is insufficient space in the output 199 * buffer 200 */ 201 @Override 202 public int update(final ByteBuffer inBuffer, final ByteBuffer outBuffer) 203 throws ShortBufferException { 204 return cipher.update(inBuffer, outBuffer); 205 } 206 207 /** 208 * Continues a multi-part update of the Additional Authentication 209 * Data (AAD). 210 * <p> 211 * Calls to this method provide AAD to the cipher when operating in 212 * modes such as AEAD (GCM/CCM). If this cipher is operating in 213 * either GCM or CCM mode, all AAD must be supplied before beginning 214 * operations on the ciphertext (via the {@code update} and 215 * {@code doFinal} methods). 216 * </p> 217 * 218 * @param aad the buffer containing the Additional Authentication Data 219 * 220 * @throws IllegalArgumentException if the {@code aad} 221 * byte array is null 222 * @throws IllegalStateException if this cipher is in a wrong state 223 * (e.g., has not been initialized), does not accept AAD, or if 224 * operating in either GCM or CCM mode and one of the {@code update} 225 * methods has already been called for the active 226 * encryption/decryption operation 227 * @throws UnsupportedOperationException if JCE's implementation does not 228 * support such operation 229 */ 230 @Override 231 public void updateAAD(final byte[] aad) { 232 cipher.updateAAD(aad); 233 } 234 235 236 /** 237 * Continues a multi-part update of the Additional Authentication 238 * Data (AAD). 239 * <p> 240 * Calls to this method provide AAD to the cipher when operating in 241 * modes such as AEAD (GCM/CCM). If this cipher is operating in 242 * either GCM or CCM mode, all AAD must be supplied before beginning 243 * operations on the ciphertext (via the {@code update} and 244 * {@code doFinal} methods). 245 * </p> 246 * 247 * @param aad the buffer containing the Additional Authentication Data 248 * 249 * @throws IllegalArgumentException if the {@code aad} 250 * byte array is null 251 * @throws IllegalStateException if this cipher is in a wrong state 252 * (e.g., has not been initialized), does not accept AAD, or if 253 * operating in either GCM or CCM mode and one of the {@code update} 254 * methods has already been called for the active 255 * encryption/decryption operation 256 * @throws UnsupportedOperationException if JCE's implementation does not 257 * support such operation 258 */ 259 @Override 260 public void updateAAD(final ByteBuffer aad) { 261 cipher.updateAAD(aad); 262 } 263 }