001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.core.util.crypt; 018 019import org.apache.wicket.core.random.ISecureRandomSupplier; 020import org.apache.wicket.util.crypt.ICrypt; 021import org.apache.wicket.util.lang.Args; 022 023import java.security.InvalidAlgorithmParameterException; 024import java.security.InvalidKeyException; 025import java.security.NoSuchAlgorithmException; 026 027import javax.crypto.BadPaddingException; 028import javax.crypto.Cipher; 029import javax.crypto.IllegalBlockSizeException; 030import javax.crypto.NoSuchPaddingException; 031import javax.crypto.SecretKey; 032import javax.crypto.spec.IvParameterSpec; 033 034/** 035 * AES based {@link ICrypt} encrypt and decrypt strings such as passwords or URL segments. 036 * Based on http://stackoverflow.com/a/992413 037 * 038 * @see ICrypt 039 */ 040public class AESCrypt extends AbstractJceCrypt 041{ 042 043 private final SecretKey secretKey; 044 private final String algorithm; 045 private final ISecureRandomSupplier randomSupplier; 046 047 048 /** 049 * Constructor 050 * 051 * @param secretKey 052 * The {@link SecretKey} to use to initialize the {@link Cipher}. 053 * @param randomSupplier 054 * The {@link ISecureRandomSupplier} to use to generate random values. 055 */ 056 public AESCrypt(SecretKey secretKey, ISecureRandomSupplier randomSupplier) 057 { 058 this(secretKey, "AES/CBC/PKCS5Padding", randomSupplier); 059 } 060 061 /** 062 * Constructor 063 * 064 * @param secretKey 065 * The {@link SecretKey} to use to initialize the {@link Cipher}. 066 * @param algorithm 067 * The cipher algorithm to use, for example "AES/CBC/PKCS5Padding". 068 * @param randomSupplier 069 * The {@link ISecureRandomSupplier} to use to generate random values. 070 */ 071 public AESCrypt(SecretKey secretKey, String algorithm, 072 ISecureRandomSupplier randomSupplier) 073 { 074 Args.notNull(secretKey, "secretKey"); 075 Args.notNull(algorithm, "algorithm"); 076 Args.notNull(randomSupplier, "randomSupplier"); 077 078 this.secretKey = secretKey; 079 this.algorithm = algorithm; 080 this.randomSupplier = randomSupplier; 081 } 082 083 @Override 084 protected byte[] decrypt(byte[] encrypted) 085 { 086 try 087 { 088 Cipher cipher = Cipher.getInstance(algorithm); 089 090 int ivSize = cipher.getBlockSize(); 091 byte[] iv = new byte[ivSize]; 092 byte[] ciphertext = new byte[encrypted.length - ivSize]; 093 094 System.arraycopy(encrypted, 0, iv, 0, ivSize); 095 System.arraycopy(encrypted, ivSize, ciphertext, 0, ciphertext.length); 096 097 cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); 098 return cipher.doFinal(ciphertext); 099 } 100 catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchPaddingException 101 | InvalidKeyException | InvalidAlgorithmParameterException e) 102 { 103 throw new RuntimeException(e); 104 } 105 } 106 107 @Override 108 protected byte[] encrypt(byte[] plainBytes) 109 { 110 try 111 { 112 Cipher cipher = Cipher.getInstance(algorithm); 113 int ivSize = cipher.getBlockSize(); 114 byte[] iv = randomSupplier.getRandomBytes(ivSize); 115 cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); 116 117 byte[] ciphertext = cipher.doFinal(plainBytes); 118 byte[] finalRes = new byte[ciphertext.length + ivSize]; 119 120 System.arraycopy(iv, 0, finalRes, 0, ivSize); 121 System.arraycopy(ciphertext, 0, finalRes, ivSize, ciphertext.length); 122 123 return finalRes; 124 } 125 catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchPaddingException 126 | InvalidKeyException | InvalidAlgorithmParameterException e) 127 { 128 throw new RuntimeException(e); 129 } 130 131 } 132}