Package net.sourceforge.javautil.database.encryption

Source Code of net.sourceforge.javautil.database.encryption.EncryptionCallBackListener

package net.sourceforge.javautil.database.encryption;

import java.lang.ref.SoftReference;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.Embeddable;
import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;

import net.sourceforge.javautil.common.ByteUtil;
import net.sourceforge.javautil.common.ReflectionUtil;
import net.sourceforge.javautil.common.encode.Base64EncodingAlgorithm;
import net.sourceforge.javautil.common.encryption.IEncryptionProvider;
import net.sourceforge.javautil.common.encryption.impl.SimpleEncryptionKey;
import net.sourceforge.javautil.common.encryption.impl.SimpleEncryptionProvider;
import net.sourceforge.javautil.common.encryption.impl.SimpleEncryptionKey.Strength;
import net.sourceforge.javautil.common.exception.ThrowableManagerRegistry;
import net.sourceforge.javautil.common.password.IPassword;
import net.sourceforge.javautil.common.password.PasswordContext;
import net.sourceforge.javautil.common.reflection.cache.ClassCache;
import net.sourceforge.javautil.common.reflection.cache.ClassDescriptor;
import net.sourceforge.javautil.common.reflection.cache.ClassProperty;
import net.sourceforge.javautil.database.encryption.annotation.Encrypted;
import net.sourceforge.javautil.database.encryption.annotation.EncryptedFields;
import net.sourceforge.javautil.database.encryption.annotation.EncryptionConfig;
import net.sourceforge.javautil.database.encryption.annotation.EncryptionKey;
import net.sourceforge.javautil.database.encryption.annotation.EncryptionConfig.Source;

/**
* This allows easy declaration of entities that desire encryption support for one or more fields.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class EncryptionCallBackListener {
 
  protected static Map<String, SoftReference<IEncryptionProvider>> cache = new HashMap<String, SoftReference<IEncryptionProvider>>();
  protected static final byte[] emptyString = "".getBytes();
 
  protected IEncryptionProvider provider;
  protected Base64EncodingAlgorithm base64 = new Base64EncodingAlgorithm();
 
  public EncryptionCallBackListener () {}
 
  @PrePersist @PreUpdate
  public <T> void encrypt (T entity) { this.encrypt(entity, ClassCache.getFor((Class<T>)entity.getClass())); }
 
  protected <T> void encrypt (T entity, ClassDescriptor<T> desc) {
    IEncryptionProvider provider = this.getProvider(desc, entity);
    this.encrypt(entity, desc, provider);
  }
 
  protected <T> void encrypt (T entity, ClassDescriptor<?> desc, IEncryptionProvider provider) {
    for (ClassProperty property : desc.getProperties(Encrypted.class)) {
      this.encrypt(entity, provider, property);
    }
   
    EncryptedFields fields = desc.getAnnotation(EncryptedFields.class);
    if (fields != null) {
      for (String name : fields.value()) {
        this.encrypt(entity, provider, desc.getProperty(name));
      }
    }
  }
 
  protected <T> void encrypt (T entity, IEncryptionProvider provider, ClassProperty property) {
    Object value = property.getValue(entity);
    if (value == null) return;
   
    if (property.getTypeDescriptor().getAnnotation(Embeddable.class) != null) {
      this.encrypt(value, ClassCache.getFor(value.getClass()), provider);
      return;
    }
   
    byte[] data = ReflectionUtil.coerce(byte[].class, value);
    if (ByteUtil.equals(data, emptyString)) return;
   
    try {
      property.setValue(entity, ReflectionUtil.coerce(property.getType(), base64.encode( provider.encrypt(data) )));
    } catch (Exception e) {
      ThrowableManagerRegistry.caught(e);
    }
  }
 
  @PostPersist @PostUpdate public <T> void decryptLoad (T entity) {
    this.decrypt(entity);
  }
 
  @PostLoad public <T> void decrypt (T entity) {
    this.decrypt(entity, ClassCache.getFor((Class<T>)entity.getClass()));
  }
 
  protected <T> void decrypt (T entity, ClassDescriptor<T> desc) {
    IEncryptionProvider provider = this.getProvider(desc, entity);
    this.decrypt(entity, desc, provider);
  }
 
  protected <T> void decrypt (T entity, ClassDescriptor<?> desc, IEncryptionProvider provider) {
    for (ClassProperty property : desc.getProperties(Encrypted.class)) {
      this.decrypt(entity, provider, property);
    }
 
    EncryptedFields fields = desc.getAnnotation(EncryptedFields.class);
    if (fields != null) {
      for (String name : fields.value()) {
        this.decrypt(entity, provider, desc.getProperty(name));
      }
    }
  }
 
  protected <T> void decrypt (T entity, IEncryptionProvider provider, ClassProperty property) {
    Object value = property.getValue(entity);
    if (value == null) return;
   
    if (property.getTypeDescriptor().getAnnotation(Embeddable.class) != null) {
      this.decrypt(value, ClassCache.getFor(value.getClass()), provider);
      return;
    }
   
    byte[] data = ReflectionUtil.coerce(byte[].class, value);
    if (ByteUtil.equals(data, emptyString)) return;
   
    try {
      property.setValue(entity, ReflectionUtil.coerce(property.getType(), provider.decrypt(base64.decode( data ))));
    } catch (Throwable t) {
      ThrowableManagerRegistry.caught(t);
    }
  }
 
  private <T> IEncryptionProvider getProvider (ClassDescriptor<T> clazz, T instance) {
    if (cache.containsKey(clazz.getDescribedClass().getName())) {
      IEncryptionProvider provider = cache.get(clazz.getDescribedClass().getName()).get();
      if (provider != null) return provider;
    }
   
    EncryptionConfig config = clazz.getAnnotation(EncryptionConfig.class);
    byte[] key = null;
    if (config != null && config.source() == Source.PASSWORD_LOCKER) {
      if ("".equals( config.sourceName() )) throw new IllegalArgumentException("Password locker source name must be provider for: " + clazz);
      if (PasswordContext.get() == null) throw new IllegalStateException("No password locker available for the current context");
     
      IPassword pw = PasswordContext.get().getPassword(config.sourceName());
      if (pw == null) throw new IllegalArgumentException("No such password in current context locker: " + config.sourceName());
     
      key = pw.getPassword();
    } else {
      ClassProperty property = clazz.getProperty(EncryptionKey.class);
      if (property == null) throw new IllegalStateException("No encryption key property available for: " + clazz);
     
      key = ReflectionUtil.coerce(byte[].class, property.getValue(instance));
    }
   
    try {
      IEncryptionProvider provider = new SimpleEncryptionProvider(SimpleEncryptionKey.createUsing(Strength.STRONG, config == null ? "AES" : config.algorithm(), key));
      cache.put(clazz.getDescribedClass().getName(), new SoftReference<IEncryptionProvider>(provider));
      return provider;
    } catch (InvalidKeyException e) {
      throw ThrowableManagerRegistry.caught(e);
    }
  }

}
TOP

Related Classes of net.sourceforge.javautil.database.encryption.EncryptionCallBackListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.