package com.kryptnostic.kodex.v1.crypto.ciphers;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.kryptnostic.kodex.v1.constants.Names;
import com.kryptnostic.kodex.v1.exceptions.types.SecurityConfigurationException;
public class AesCryptoService extends AbstractCryptoService {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private byte[] key;
public AesCryptoService( Cypher cypher ) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
this( cypher, Cyphers.generateSecretKey( cypher ) );
}
public AesCryptoService( Cypher cypher, SecretKey secretKey ) {
this( cypher, secretKey.getEncoded() );
}
public AesCryptoService( Cypher cypher, byte[] secretKey ) {
super( cypher );
this.key = secretKey;
}
@JsonCreator
public AesCryptoService(
@JsonProperty( Names.CYPHER_FIELD ) CipherDescription cipher,
@JsonProperty( Names.KEY_FIELD ) byte[] secretKey ) {
this( Cypher.createCipher( cipher ), secretKey );
}
@Override
@JsonProperty( Names.CYPHER_FIELD )
public Cypher getCypher() {
return super.getCypher();
}
@JsonProperty( Names.KEY_FIELD )
public byte[] getSecretKey() {
try {
lock.readLock().lock();
return key;
} finally {
lock.readLock().unlock();
}
}
public BlockCiphertext encrypt( byte[] plaintext ) throws SecurityConfigurationException {
return encrypt( plaintext, new byte[ 0 ] );
}
@Override
protected SecretKeySpec getSecretKeySpec( byte[] salt ) throws NoSuchAlgorithmException, InvalidKeySpecException {
try {
lock.readLock().lock();
return new SecretKeySpec( key, cypher.getName() );
} finally {
lock.readLock().unlock();
}
}
public void destroy() {
try {
lock.writeLock().lock();
Arrays.fill( key, (byte) 0 );
key = null;
} finally {
lock.writeLock().unlock();
}
}
public void reinit( byte[] newKey ) {
try {
lock.writeLock().lock();
this.key = Arrays.copyOf( newKey, newKey.length );
} finally {
lock.writeLock().unlock();
}
}
@Override
protected void finalize() throws Throwable {
Arrays.fill( key, (byte) 0 );
super.finalize();
}
}