GordianKeySetLockImpl.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.keyset.GordianKeySet;
import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianKeySetLock;
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.keyset.GordianCoreKeySet;
import java.util.Arrays;
import java.util.Objects;
/**
* Factory Lock implementation.
*/
public class GordianKeySetLockImpl
implements GordianKeySetLock {
/**
* The keySet.
*/
private final GordianCoreKeySet theKeySet;
/**
* The lockASN1.
*/
private final GordianPasswordLockASN1 theLockASN1;
/**
* The lockBytes.
*/
private final byte[] theLockBytes;
/**
* Locking constructor.
*
* @param pLockingFactory the locking factory
* @param pKeySetToLock the keySet to lock
* @param pLockSpec the passwordLockSpec
* @param pPassword the password
* @throws GordianException on error
*/
public GordianKeySetLockImpl(final GordianBaseFactory pLockingFactory,
final GordianCoreKeySet pKeySetToLock,
final GordianPasswordLockSpec pLockSpec,
final char[] pPassword) throws GordianException {
/* Protect from exceptions */
byte[] myPassword = null;
try {
/* Store the KeySet */
theKeySet = pKeySetToLock;
/* Create a recipe */
final GordianPasswordLockRecipe myRecipe = new GordianPasswordLockRecipe(pLockingFactory, pLockSpec);
/* Generate the hash */
myPassword = GordianDataConverter.charsToByteArray(pPassword);
final GordianCoreKeySet myKeySet = myRecipe.processPassword(pLockingFactory, myPassword);
final byte[] myPayload = myKeySet.secureKeySet(pKeySetToLock);
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 GordianKeySetLockImpl(final GordianBaseFactory pLockingFactory,
final byte[] pLockBytes,
final char[] pPassword) throws GordianException {
this(pLockingFactory, GordianPasswordLockASN1.getInstance(pLockBytes), pLockBytes, pPassword);
}
/**
* UnLocking constructor.
*
* @param pLockingFactory the locking factory
* @param pLockASN1 the lockASN1
* @param pPassword the password
* @throws GordianException on error
*/
public GordianKeySetLockImpl(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 GordianKeySetLockImpl(final GordianBaseFactory pLockingFactory,
final GordianPasswordLockASN1 pLockASN1,
final byte[] pLockBytes,
final char[] pPassword) throws GordianException {
/* Protect from exceptions */
byte[] myPassword = null;
try {
/* Store the LockBytes */
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);
theKeySet = myKeySet.deriveKeySet(myRecipe.getPayload());
} finally {
if (myPassword != null) {
Arrays.fill(myPassword, (byte) 0);
}
}
}
@Override
public GordianKeySet getLockedObject() {
return theKeySet;
}
@Override
public GordianPasswordLockASN1 getLockASN1() {
return theLockASN1;
}
@Override
public byte[] getLockBytes() {
return theLockBytes;
}
@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 GordianKeySetLockImpl)) {
return false;
}
/* Access the target field */
final GordianKeySetLockImpl myThat = (GordianKeySetLockImpl) pThat;
/* Check differences */
return theKeySet.equals(myThat.getLockedObject())
&& Arrays.equals(theLockBytes, myThat.getLockBytes());
}
@Override
public int hashCode() {
return Objects.hash(theKeySet, Arrays.hashCode(theLockBytes));
}
}