/*
* Copyright (c) 2013-2017 Cinchapi Inc.
*
* 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 com.cinchapi.concourse.security;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import com.cinchapi.concourse.util.ByteBuffers;
import com.google.common.base.Throwables;
/**
* A collection of tools to deal with security on the client. <strong>These
* functions are not suitable for server side security!!!</strong>
*
* @author Jeff Nelson
*/
public class ClientSecurity {
/**
* Decrpyt the specified {@code data} buffer. This method returns a byte
* buffer instead of a string so that the caller can set the buffer to
* {@code null} once it is not longer in useful scope. Doing so will help to
* narrow the window in which vulnerable information resides in memory.
*
* @param data
* @return a byte buffer with the encrypted data.
*/
public static ByteBuffer decrypt(ByteBuffer data) {
return decrypt(data, DEFAULT_KEY);
}
/**
* Decrpyt the specified {@code data} buffer. This method returns a byte
* buffer instead of a string so that the caller can set the buffer to
* {@code null} once it is not longer in useful scope. Doing so will help to
* narrow the window in which vulnerable information resides in memory.
*
* @param data
* @return a byte buffer with the encrypted data.
*/
public static ByteBuffer decrypt(ByteBuffer data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return ByteBuffer
.wrap(cipher.doFinal(ByteBuffers.toByteArray(data)));
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
/**
* Encrypt the {@code data} using the {@code key}
*
* @param data
* @param key
* @return the encrypted payload
*/
public static ByteBuffer encrypt(byte[] data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return ByteBuffer.wrap(cipher.doFinal(data));
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
/**
* Encrypt the {@code data} using the {@code key}
*
* @param data
* @param key
* @return the encrypted payload
*/
public static ByteBuffer encrypt(ByteBuffer data, byte[] key) {
return encrypt(ByteBuffers.toByteArray(data), key);
}
/**
* Encrypt the specified {@code data} string.
*
* @param data
* @return a byte buffer with the encrypted data
*/
public static ByteBuffer encrypt(String data) {
return encrypt(data, DEFAULT_KEY);
}
/**
* Encrypt the {@code data} string using the {@code key}
*
* @param data
* @param key
* @return the encrypted payload
*/
public static ByteBuffer encrypt(String data, byte[] key) {
return encrypt(data.getBytes(), key);
}
/**
* The source of secure randomness.
*/
private static final SecureRandom srand = new SecureRandom();
/**
* Generate a random secret key that can be used for encryption and
* decryption.
*
* @return the key
*/
public static byte[] generateSecretKey() {
byte[] key = new byte[16];
srand.nextBytes(key);
return key;
}
/**
* The client specific key that is used to encrypt/decrypt data. This key is
* valid for the duration of the client JVM's lifetime.
*/
private static final byte[] DEFAULT_KEY = generateSecretKey();
}