GordianFactoryLockImpl.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.lock;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory;
import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory.GordianFactoryLock;
import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianPasswordLockSpec;
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.GordianParameters;
import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianDataException;
import io.github.tonywasher.joceanus.gordianknot.impl.core.keyset.GordianCoreKeySet;
import io.github.tonywasher.joceanus.gordianknot.impl.core.keyset.GordianKeySetData;
import java.util.Arrays;
import java.util.Objects;
/**
* Factory Lock implementation.
*/
public class GordianFactoryLockImpl
implements GordianFactoryLock {
/**
* The factory.
*/
private final GordianBaseFactory theFactory;
/**
* The lockASN1.
*/
private final GordianPasswordLockASN1 theLockASN1;
/**
* The lockBytes.
*/
private final byte[] theLockBytes;
/**
* Locking constructor.
*
* @param pLockingFactory the locking factory
* @param pFactoryToLock the factory to lock
* @param pLockSpec the passwordLockSpec
* @param pPassword the password
* @throws GordianException on error
*/
public GordianFactoryLockImpl(final GordianBaseFactory pLockingFactory,
final GordianBaseFactory pFactoryToLock,
final GordianPasswordLockSpec pLockSpec,
final char[] pPassword) throws GordianException {
/* Protect from exceptions */
byte[] myPassword = null;
try {
/* Store the Factory */
theFactory = pFactoryToLock;
/* Reject the operation if not a random factory */
if (!pFactoryToLock.isRandom()) {
throw new GordianDataException("attempt to lock non-Random factory");
}
/* Create a recipe */
final GordianPasswordLockRecipe myRecipe = new GordianPasswordLockRecipe(pLockingFactory, pLockSpec);
/* Generate the lockBytes */
myPassword = GordianDataConverter.charsToByteArray(pPassword);
final GordianCoreKeySet myKeySet = myRecipe.processPassword(pLockingFactory, myPassword);
final byte[] myPayload = myKeySet.secureFactory(pFactoryToLock);
theLockASN1 = myRecipe.buildLockASN1(myPassword.length, myPayload);
theLockBytes = theLockASN1.getEncodedBytes();
} finally {
if (myPassword != null) {
Arrays.fill(myPassword, (byte) 0);
}
}
}
/**
* UnLocking constructor.
*
* @param pLockingFactory the locking factory
* @param pLockBytes the lockBytes
* @param pPassword the password
* @throws GordianException on error
*/
public GordianFactoryLockImpl(final GordianBaseFactory pLockingFactory,
final byte[] pLockBytes,
final char[] pPassword) throws GordianException {
this(pLockingFactory, GordianPasswordLockASN1.getInstance(pLockBytes), pPassword);
}
/**
* UnLocking constructor.
*
* @param pLockingFactory the locking factory
* @param pLockASN1 the lockASN1
* @param pPassword the password
* @throws GordianException on error
*/
public GordianFactoryLockImpl(final GordianBaseFactory pLockingFactory,
final GordianPasswordLockASN1 pLockASN1,
final char[] pPassword) throws GordianException {
this(pLockingFactory, pLockASN1, pLockASN1.getEncodedBytes(), pPassword);
}
/**
* UnLocking constructor.
*
* @param pLockingFactory the locking factory
* @param pLockASN1 the lockASN1
* @param pLockBytes the lockBytes
* @param pPassword the password
* @throws GordianException on error
*/
public GordianFactoryLockImpl(final GordianBaseFactory pLockingFactory,
final GordianPasswordLockASN1 pLockASN1,
final byte[] pLockBytes,
final char[] pPassword) throws GordianException {
/* Protect from exceptions */
byte[] myPassword = null;
try {
/* Store the Lock */
theLockBytes = pLockBytes;
theLockASN1 = pLockASN1;
/* Resolve the recipe */
myPassword = GordianDataConverter.charsToByteArray(pPassword);
final GordianPasswordLockRecipe myRecipe = new GordianPasswordLockRecipe(pLockingFactory, myPassword.length, theLockASN1);
/* Process the password, create parameters and factory */
final GordianCoreKeySet myKeySet = myRecipe.processPassword(pLockingFactory, myPassword);
theFactory = (GordianBaseFactory) myKeySet.deriveFactory(myRecipe.getPayload());
} finally {
if (myPassword != null) {
Arrays.fill(myPassword, (byte) 0);
}
}
}
@Override
public GordianFactory getLockedObject() {
return theFactory;
}
@Override
public GordianPasswordLockASN1 getLockASN1() {
return theLockASN1;
}
@Override
public byte[] getLockBytes() {
return theLockBytes;
}
/**
* Obtain the byte length of the encoded sequence.
*
* @return the byte length
*/
public static int getEncodedLength() {
return GordianPasswordLockASN1.getEncodedLength(GordianKeySetData.getEncryptionLength(GordianParameters.SEED_LEN.getByteLength()));
}
@Override
public boolean equals(final Object pThat) {
/* Handle the trivial cases */
if (pThat == this) {
return true;
}
if (pThat == null) {
return false;
}
/* Make sure that the object is the same class */
if (!(pThat instanceof GordianFactoryLockImpl)) {
return false;
}
/* Access the target field */
final GordianFactoryLockImpl myThat = (GordianFactoryLockImpl) pThat;
/* Check differences */
return theFactory.equals(myThat.getLockedObject())
&& Arrays.equals(theLockBytes, myThat.getLockBytes());
}
@Override
public int hashCode() {
return Objects.hash(theFactory, Arrays.hashCode(theLockBytes));
}
}