All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.internet2.middleware.morphString.Crypto Maven / Gradle / Ivy

There is a newer version: 5.12.2
Show newest version
/**
 * Copyright 2014 Internet2
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.internet2.middleware.morphString;

import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import edu.internet2.middleware.grouperClient.util.GrouperClientUtils;
import edu.internet2.middleware.grouperClientExt.org.apache.commons.codec.binary.Base64;


/**
 * The purpose of this class is to provide encryption 
 * and decryption using standard Java libraries, for potentially 
 * large amounts of data.
 * 

* This class provides default encryption using AES with a constant * 128 bit key. If you want something more secure feel free to * override the defaults however you please. *

* This class works in one of two ways, (1) in memory using Strings, or (2) via * I/O streams (preferred for large amounts of data). *

* Crypo objects, or more specifically the default ciphers they create, are not * threadsafe and are not computationally cheap, so a threadlocal factory * method is provided for convenience. This is the preferred means of usage, * but feel free to create these objects however you please. *

* Note that you can encrypt BLOB fields by specifying encryption in the * configurator (Crypto is the default encryption mechanism for that). *

*/ public class Crypto { /** threadlocal provided for conveniency */ private static final ThreadLocal threadLocalCrypto = new ThreadLocal(); /** @return a non-null thread-safe crypto object from a ThreadLocal */ public static Crypto getThreadLocalCrypto() { Crypto crypto = threadLocalCrypto.get(); if (crypto == null) { crypto = new Crypto(); threadLocalCrypto.set(crypto); } return crypto; } /** * Generate a key. * @param cipherName the name of the cipher, if null will default to "AES" * @param keybits the number of bits in the key, if null will default to 128 * @return the bytes comprising the key */ public static byte[] generateKeyBytes(String cipherName, Integer keybits) { KeyGenerator keyGenerator = null; cipherName = cipherName == null ? "AES" : cipherName; try { keyGenerator = KeyGenerator.getInstance(cipherName); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Failed to create KeyGenerator for cipherName="+cipherName, e); } keyGenerator.init(keybits == null ? 128 : keybits); // 192 and 256 bits may not be available // Generate the secret key specs. SecretKey secretKey = keyGenerator.generateKey(); byte[] keyBytes = secretKey.getEncoded(); return keyBytes; } /** SecretKeySpec */ private SecretKeySpec key; /** lazily constructed cipher */ private Cipher cipher = null; /** * Create the default cipher * @return the default cipher */ public Cipher createDefaultCipher() { try { return Cipher.getInstance("AES"); } catch(Exception x) { throw new RuntimeException("Failed to create the default cipher!", x); } } /** Default crypto object */ public Crypto() { this(Morph.key()); } /** Default crypto object * @param theKey used to encrypt/decrypt */ public Crypto(String theKey) { super(); init(theKey); } /** only warn once */ private static boolean warned = false; /** initialize the key and cipher * @param secret */ protected void init(String secret) { if (GrouperClientUtils.isBlank(secret)) { throw new NullPointerException("Must supply a non blank encrypt.key"); } StringBuilder secretBuilder = new StringBuilder(secret); if (!warned && secret.length() < 8) { //note we dont have a logger System.out.println("morphString warning: secret.key in morphString.properties should be at least 8 chars"); warned = true; } //secret must be length 16 or 32. pad if not while (secretBuilder.length() < 16) { secretBuilder.append("x"); } if (secretBuilder.length() > 16) { while (secretBuilder.length() < 32) { secretBuilder.append("x"); } } if (secretBuilder.length() > 32) { secretBuilder.delete(32, secretBuilder.length()); } secret = secretBuilder.toString(); this.key = new SecretKeySpec(secret.getBytes(), "AES"); this.cipher = this.createDefaultCipher(); } /** * Encrypt the string * @param clearText * @return the encrypted String */ public String encrypt(String clearText) { byte[] input = clearText.getBytes(); try { this.initCipher(true); byte[] output = this.cipher.doFinal(input); byte[] encoded = Base64.encodeBase64(output); return new String(encoded); } catch(Exception x) { throw new RuntimeException("Failed to encrypt string", x); } } /** * Decrypt the string * @param cipherText * @return the decrypted string */ public String decrypt(String cipherText) { try { byte[] cipherBytes = cipherText.getBytes(); byte[] decodedBytes = Base64.decodeBase64(cipherBytes); this.initCipher(false); byte[] clearBytes = this.cipher.doFinal(decodedBytes); return new String(clearBytes); } catch(Exception x) { throw new RuntimeException("Failed to decrypt the cipherText", x); } } /** * Initialize the cipher for encryption or decryption * @param encrypt true to encrypt, false to decrypt */ private void initCipher(boolean encrypt) { try { if ( encrypt ) { this.cipher.init(Cipher.ENCRYPT_MODE, this.key); } else { this.cipher.init(Cipher.DECRYPT_MODE, this.key); } } catch(Exception x) { throw new RuntimeException("Failed to init cipher for "+(encrypt ? "encrypt" : "decrypt"), x); } } /** * Get the encrypted input stream * @param in * @return the encrypted input stream */ public InputStream encrypt(InputStream in) { this.initCipher(true); return new CipherInputStream(in, this.cipher); } /** * the decrypted input stream * @param in * @return the decrypted input stream */ public InputStream decrypt(InputStream in) { this.initCipher(false); return new CipherInputStream(in, this.cipher); } /** * the encrypted output stream * @param out * @return the encrypted output stream */ public OutputStream encrypt(OutputStream out) { this.initCipher(true); return new CipherOutputStream(out, this.cipher); } /** * the decrypted output stream * @param out * @return the decrypted output stream */ public OutputStream decrypt(OutputStream out) { this.initCipher(false); return new CipherOutputStream(out, this.cipher); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy