GordianCoreKeyGenerator.java
/*
* GordianKnot: Security Suite
* Copyright 2012-2026. Tony Washer
*
* 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 io.github.tonywasher.joceanus.gordianknot.impl.core.key;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianKeySpec;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianLength;
import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestSpec;
import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestType;
import io.github.tonywasher.joceanus.gordianknot.api.key.GordianKey;
import io.github.tonywasher.joceanus.gordianknot.api.key.GordianKeyGenerator;
import io.github.tonywasher.joceanus.gordianknot.api.mac.GordianMac;
import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianDataConverter;
import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianRandomSource;
import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianDataException;
import io.github.tonywasher.joceanus.gordianknot.impl.core.kdf.GordianHKDFMulti;
import io.github.tonywasher.joceanus.gordianknot.impl.core.kdf.GordianHKDFParams;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Random;
/**
* GordianKnot interface for Key Generators.
*
* @param <T> the keyType
*/
public abstract class GordianCoreKeyGenerator<T extends GordianKeySpec>
implements GordianKeyGenerator<T> {
/**
* The Key Type.
*/
private final T theKeyType;
/**
* The Key Length.
*/
private final int theKeyLength;
/**
* The Security Factory.
*/
private final GordianBaseFactory theFactory;
/**
* The Random Source.
*/
private final GordianRandomSource theRandom;
/**
* Constructor.
*
* @param pFactory the Security Factory
* @param pKeyType the keyType
*/
protected GordianCoreKeyGenerator(final GordianBaseFactory pFactory,
final T pKeyType) {
/* Store parameters */
theKeyType = pKeyType;
theFactory = pFactory;
/* Cache some values */
theKeyLength = pKeyType.getKeyLength().getLength();
theRandom = pFactory.getRandomSource();
}
@Override
public T getKeyType() {
return theKeyType;
}
/**
* Obtain random generator.
*
* @return the generator
*/
protected SecureRandom getRandom() {
return theRandom.getRandom();
}
/**
* Obtain factory.
*
* @return the factory
*/
protected GordianBaseFactory getFactory() {
return theFactory;
}
/**
* Generate a new Key.
*
* @param pBytes the bytes for the key.
* @return the new Key
*/
public abstract GordianKey<T> buildKeyFromBytes(byte[] pBytes);
/**
* Generate a Key from a Secret.
*
* @param pSecret the derived Secret
* @param pSeededRandom the deterministic random
* @return the new Secret Key
* @throws GordianException on error
*/
public GordianKey<T> generateKeyFromSecret(final byte[] pSecret,
final Random pSeededRandom) throws GordianException {
/* Determine the key length in bytes */
final int myKeyLen = theKeyLength
/ Byte.SIZE;
/* Create data that will be cleared */
byte[] myKeyBytes = null;
GordianHKDFParams myParams = null;
/* Derive the two digestTypes from the seededRandom */
final GordianDigestType[] myDigestTypes = theFactory.getIdManager().deriveKeyGenDigestTypesFromSeed(pSeededRandom, 2);
/* Determine info bytes */
final byte[] myAlgo = GordianDataConverter.stringToByteArray(theKeyType.toString());
final byte[] myKeyLenBytes = GordianDataConverter.integerToByteArray(theKeyLength);
final byte[] mySeed = new byte[Long.BYTES];
pSeededRandom.nextBytes(mySeed);
/* Protect against exceptions */
try {
/* Create the HKDF and parameters */
final GordianHKDFMulti myEngine = new GordianHKDFMulti(theFactory,
new GordianDigestSpec(myDigestTypes[0], GordianLength.LEN_512),
new GordianDigestSpec(myDigestTypes[1], GordianLength.LEN_512));
myParams = GordianHKDFParams.expandOnly(pSecret, myKeyLen)
.withInfo(myAlgo).withInfo(myKeyLenBytes).withInfo(mySeed);
theFactory.getPersonalisation().updateInfo(myParams);
myKeyBytes = myEngine.deriveBytes(myParams);
/* Return the new key */
return buildKeyFromBytes(myKeyBytes);
/* Clear build buffer */
} finally {
if (myKeyBytes != null) {
Arrays.fill(myKeyBytes, (byte) 0);
}
if (myParams != null) {
myParams.clearParameters();
}
}
}
@Override
public <X extends GordianKeySpec> GordianKey<T> translateKey(final GordianKey<X> pSource) throws GordianException {
/* Check that the keyLengths are compatible */
if (pSource.getKeyType().getKeyLength() != theKeyType.getKeyLength()) {
throw new GordianDataException("Incorrect length for key");
}
/* Build the key */
final GordianCoreKey<X> mySource = (GordianCoreKey<X>) pSource;
return buildKeyFromBytes(mySource.getKeyBytes());
}
/**
* Init Mac keyBytes.
*
* @param pMac the Mac.
* @param pKeyBytes the keyBytes
* @throws GordianException on error
*/
public abstract void initMacKeyBytes(GordianMac pMac, byte[] pKeyBytes) throws GordianException;
}