All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.akeyless.crypto.utils.AkeylessCiphertext Maven / Gradle / Ivy
package com.akeyless.crypto.utils;
import com.akeyless.crypto.exceptions.BadCiphertextException;
import com.akeyless.exceptions.AkeylessCryptoException;
import com.akeyless.exceptions.AkeylessRuntimeException;
import org.apache.commons.codec.binary.Base64;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class AkeylessCiphertext {
private static final int AKEYLESS_VERSION = 1;
private static final int AKEYLESS_VERSION_BYTES_LEN = 1;
private static final int KEY_VERSION_BYTES_LEN = 4;
private static final int HEADER_DD_LEN = 2;
private CryptoAlgorithm alg;
private byte akeylessVersion = -1;
private Integer keyVersion = -1;
private ArrayList derivationsData;
private byte[] encryptedData;
private byte[] finalCipher;
public AkeylessCiphertext(final CryptoAlgorithm alg, final Integer keyVersion,
final ArrayList derivationsData, final byte[] encryptedData) {
this.alg = alg;
this.akeylessVersion = AKEYLESS_VERSION;
this.keyVersion = keyVersion;
setDerivationsDataByAlg(alg, derivationsData);
this.encryptedData = encryptedData;
this.finalCipher = serialize();
}
public AkeylessCiphertext(final CryptoAlgorithm alg, final byte[] cipher) throws BadCiphertextException {
this.alg = alg;
this.finalCipher = cipher;
deserialize(finalCipher);
}
public AkeylessCiphertext(final CryptoAlgorithm alg, final String cipherBase64) throws BadCiphertextException {
this.alg = alg;
this.finalCipher = Base64.decodeBase64(cipherBase64);
deserialize(this.finalCipher);
}
public byte getAkeylessVersion() {
return akeylessVersion;
}
public Integer getKeyVersion() {
return keyVersion;
}
public ArrayList getDerivationsData(int numOfFragments) throws AkeylessCryptoException {
if(!alg.isDeterministic() && derivationsData.size() == 1) {
return new ArrayList<>(Collections.nCopies(numOfFragments, derivationsData.get(0)));
}
if(derivationsData.size() != numOfFragments) {
throw new AkeylessCryptoException("The number of derivations data does not match the number of the key fragments");
}
return derivationsData;
}
public byte[] getEncryptedData() {
return encryptedData;
}
public byte[] toByteArray() {
return finalCipher;
}
public String toString() {
return new String(Base64.encodeBase64(finalCipher));
}
public static Integer extractKeyVersionFromCipher(final byte[] cipher) throws BadCiphertextException {
byte[] keyVersionBytes = parseBytes(cipher,AKEYLESS_VERSION_BYTES_LEN,KEY_VERSION_BYTES_LEN,"key version");
ByteBuffer buf = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).put(keyVersionBytes);
buf.flip();
Integer version = buf.getInt();
if(version < 1) {
throw new BadCiphertextException("Invalid key version");
}
return version;
}
private void setDerivationsDataByAlg(final CryptoAlgorithm alg, final ArrayList derivationsData) {
if(derivationsData == null || derivationsData.size() == 0) {
throw new AkeylessRuntimeException("No derivation data was provided");
}
if(alg.isDeterministic()) {
this.derivationsData = derivationsData;
return;
}
this.derivationsData = new ArrayList<>(Collections.nCopies(1, derivationsData.get(0)));
}
private byte[] serialize() {
byte[] combinedDD = serializeDerivationsData();
assert combinedDD != null;
ByteBuffer bb = ByteBuffer.allocate(AKEYLESS_VERSION_BYTES_LEN + KEY_VERSION_BYTES_LEN +
combinedDD.length+encryptedData.length);
bb.put((byte) AKEYLESS_VERSION_BYTES_LEN);
bb.put(ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(keyVersion).array());
bb.put(combinedDD);
bb.put(encryptedData);
return bb.array();
}
private byte[] serializeDerivationsData() {
if(alg.isDeterministic()){
return null; //TODO
}
return serializeDDForNondeterministicAlg();
}
private byte[] serializeDDForNondeterministicAlg() {
if(derivationsData == null || derivationsData.size() == 0) {
throw new AkeylessRuntimeException("No derivation data was provided");
}
for (int i = 1; i < derivationsData.size(); i++) {
if(!Arrays.equals(derivationsData.get(i-1), derivationsData.get(i))) {
throw new AkeylessRuntimeException("For a non-deterministic algorithm, all the derivations data should be identical");
}
}
byte[] derivationData = derivationsData.get(0);
byte numOfDD = 1;
ByteBuffer bb = ByteBuffer.allocate(2+derivationData.length);
bb.put((byte) derivationData.length);
bb.put(numOfDD);
bb.put(derivationData);
return bb.array();
}
private int deserialize(final byte[] finalCipher) throws BadCiphertextException {
if(finalCipher == null || finalCipher.length == 0) {
throw new BadCiphertextException("Empty ciphertext");
}
int parsedBytes = 0;
parsedBytes += parseAkeylessVersion(finalCipher, parsedBytes);
parsedBytes += parseKeyVersion(finalCipher, parsedBytes);
parsedBytes += parseDerivationsData(finalCipher, parsedBytes);
parsedBytes += parseEncryptedData(finalCipher, parsedBytes);
return parsedBytes;
}
private int parseAkeylessVersion(final byte[] b, final int off) throws BadCiphertextException {
akeylessVersion = parseBytes(b,off,AKEYLESS_VERSION_BYTES_LEN,"cipher version")[0];
if(akeylessVersion < 1) {
throw new BadCiphertextException("Invalid cipher version");
}
return AKEYLESS_VERSION_BYTES_LEN;
}
private int parseKeyVersion(final byte[] b, final int off) throws BadCiphertextException {
byte[] keyVersionBytes = parseBytes(b,off,KEY_VERSION_BYTES_LEN,"key version");
ByteBuffer buf = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).put(keyVersionBytes);
buf.flip();
keyVersion = buf.getInt();
if(keyVersion < 1) {
throw new BadCiphertextException("Invalid key version");
}
return KEY_VERSION_BYTES_LEN;
}
private int parseDerivationsData(final byte[] b, final int off) throws BadCiphertextException {
if(alg.isDeterministic()){
return parseDerivationsDataForDeterministicAlg(b, off);
}
return parseDerivationsDataForNondeterministicAlg(b, off);
}
private int parseDerivationsDataForDeterministicAlg(final byte[] b, final int off) throws BadCiphertextException {
if(b == null || b.length - off < HEADER_DD_LEN) {
throw new BadCiphertextException("No derivation data was provided");
}
int derivationDataLen = b[off];
int numOfDD = b[off +1];
if(numOfDD < 1){
throw new BadCiphertextException("Invalid number of derivations data");
}
if(b.length - off < derivationDataLen*numOfDD + HEADER_DD_LEN) {
throw new BadCiphertextException("Invalid serialized derivations data length");
}
derivationsData = new ArrayList<>(Collections.nCopies(numOfDD, new byte[0]));
int indx = off+HEADER_DD_LEN;
for (int i = 0; i < numOfDD; i++) {
derivationsData.set(i,Arrays.copyOfRange(b, indx, indx + derivationDataLen));
indx = indx + derivationDataLen;
}
return indx - off;
}
private int parseDerivationsDataForNondeterministicAlg(final byte[] b, final int off) throws BadCiphertextException {
if(b == null || b.length - off < HEADER_DD_LEN) {
throw new BadCiphertextException("No derivation data was provided");
}
int derivationDataLen = b[off];
int numOfDD = b[off +1];
if(numOfDD != 1){
throw new BadCiphertextException("Invalid number of derivations data for non-deterministic algorithm");
}
if(b.length - off < derivationDataLen*numOfDD + HEADER_DD_LEN) {
throw new BadCiphertextException("Invalid serialized derivations data length");
}
int ddStIndx = off+HEADER_DD_LEN;
byte[] dd = Arrays.copyOfRange(b, ddStIndx, ddStIndx + derivationDataLen);
derivationsData = new ArrayList<>(Collections.nCopies(numOfDD, dd));
return HEADER_DD_LEN + derivationDataLen;
}
private int parseEncryptedData(final byte[] b, final int off) {
encryptedData = Arrays.copyOfRange(b, off, b.length);
return b.length - off;
}
private static byte[] parseBytes(final byte[] b,
final int off,
final int size,
final String name) throws BadCiphertextException {
final int len = b.length - off;
if (len < size) {
throw new BadCiphertextException("Not enough bytes to parse "+name);
}
return Arrays.copyOfRange(b, off, off+size);
}
}