com.gs.api.accelrx.crypto.bouncycastle.BouncyCastleGCMObfuscation Maven / Gradle / Ivy
The newest version!
package com.gs.api.accelrx.crypto.bouncycastle;
import com.gs.api.accelrx.crypto.messagedigest.BlockingMessageDigestSha512HashingProvider;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.io.CipherOutputStream;
import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class BouncyCastleGCMObfuscation {
private static final int BASE_HEADER_SIZE = (Long.SIZE / Byte.SIZE) + (Integer.SIZE / Byte.SIZE);
private static final long VERSION = 1L;
private final byte[][] salts;
private final int keyLength;
private final int ivLength;
private final int masterKeyIndex;
private final byte[] masterKey;
private byte[] masterKeyIV;
private byte[] otkey;
private byte[] otkiv;
private BouncyCastleGCMObfuscation(byte[][] masterKeys, byte[][] salts, int keyLength, int ivLength) {
this.masterKey = masterKeys[0];
this.masterKeyIndex = 0;
this.salts = salts;
this.keyLength = keyLength;
this.ivLength = ivLength;
}
public static BouncyCastleGCMObfuscation create(byte[][] masterKeys, byte[][] salts, int keyLength, int ivLength) {
return new BouncyCastleGCMObfuscation(masterKeys, salts, keyLength, ivLength);
}
public byte[] obfuscate(byte[] message) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
writeObfuscationHeaderFields(baos, message);
AEADBlockCipher messageCipher = getCipher(otkey, otkiv, true);
encryptBytesToStream(baos, message, messageCipher);
baos.flush();
return baos.toByteArray();
}
private void writeObfuscationHeaderFields(ByteArrayOutputStream baos, byte[] message) throws IOException {
this.masterKeyIV = deterministicBytes(message, salts[0], ivLength);
this.otkey = deterministicBytes(message, salts[1], keyLength);
this.otkiv = deterministicBytes(message, salts[2], ivLength);
AEADBlockCipher headerCipher = getCipher(masterKey, masterKeyIV, true);
baos.write(header(headerCipher));
}
private byte[] header(AEADBlockCipher cipher) throws IOException {
ByteBuffer bb = ByteBuffer.allocate(BASE_HEADER_SIZE + (keyLength + 16) + (ivLength * 2));
bb.putLong(VERSION);
bb.putInt(masterKeyIndex);
bb.put(masterKeyIV);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
encryptBytesToStream(baos, otkey, cipher);
byte[] encryptedKey = baos.toByteArray();
bb.put(encryptedKey);
bb.put(otkiv);
return bb.array();
}
private void encryptBytesToStream(OutputStream outputStream, byte[] bytes, AEADBlockCipher cipher) throws IOException {
try (CipherOutputStream cipherStream = new CipherOutputStream(outputStream, cipher)) {
cipherStream.write(bytes);
}
}
private AEADBlockCipher getCipher(byte[] key, byte[] iv, boolean forEncryption) {
AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
cipher.init(forEncryption, new AEADParameters(new KeyParameter(key), 128, iv));
return cipher;
}
private byte[] deterministicBytes(byte[] message, byte[] salt, int length) {
BlockingMessageDigestSha512HashingProvider hashingProvider = BlockingMessageDigestSha512HashingProvider.create(salt);
String hash = hashingProvider.hash(message);
return Arrays.copyOfRange(hash.getBytes(StandardCharsets.UTF_8), 0, length);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy