Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,7 @@

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.*;

/**
* Helper class with step for getting activation status.
Expand Down Expand Up @@ -221,7 +218,7 @@ public void processResponse(StepContext<GetStatusStepModel, Object> stepContext)
}


final Map<String, Object> objectMap = new HashMap<>();
final Map<String, Object> objectMap = new LinkedHashMap<>();
objectMap.put("activationId", resultStatusObject.getActivationId());
objectMap.put("statusBlob", statusBlobInfo);
objectMap.put("customObject", customObject);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -102,7 +103,7 @@ public StepContext<PrepareActivationStepModel, EncryptedResponse> prepareStepCon
}
final String activationCode = model.getActivationCode();

final Map<String, Object> objectMap = new HashMap<>();
final Map<String, Object> objectMap = new LinkedHashMap<>();
objectMap.put("activationCode", activationCode);
stepLogger.writeItem(
getStep().id() + "-activation-code",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
Expand Down Expand Up @@ -112,7 +112,7 @@ public StepContext<RemoveStepModel, ObjectResponse<ActivationRemoveResponse>> pr
@Override
public void processResponse(StepContext<RemoveStepModel, ObjectResponse<ActivationRemoveResponse>> stepContext) {
final String activationId = stepContext.getModel().getResultStatus().getActivationId();
final Map<String, Object> objectMap = new HashMap<>();
final Map<String, Object> objectMap = new LinkedHashMap<>();
objectMap.put("activationId", activationId);

stepContext.getStepLogger().writeItem(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
package com.wultra.security.powerauth.lib.cmd.steps;

import com.wultra.security.powerauth.crypto.client.keyfactory.PowerAuthClientKeyFactory;
import com.wultra.security.powerauth.crypto.client.vault.PowerAuthClientVault;
import com.wultra.security.powerauth.crypto.lib.encryptor.model.EncryptedResponse;
import com.wultra.security.powerauth.crypto.lib.encryptor.model.EncryptorId;
import com.wultra.security.powerauth.crypto.lib.encryptor.model.EncryptorScope;
import com.wultra.security.powerauth.crypto.lib.util.KeyConvertor;
import com.wultra.security.powerauth.crypto.lib.v4.api.PqcDsaKeyConvertor;
import com.wultra.security.powerauth.crypto.lib.v4.ml.MlDsaKeyConvertor;
import com.wultra.security.powerauth.lib.cmd.consts.BackwardCompatibilityConst;
import com.wultra.security.powerauth.lib.cmd.consts.PowerAuthStep;
import com.wultra.security.powerauth.lib.cmd.consts.PowerAuthVersion;
Expand All @@ -42,7 +43,7 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
Expand All @@ -65,10 +66,14 @@ public class VaultUnlockStep extends AbstractBaseStep<VaultUnlockStepModel, Encr

private final PowerAuthHeaderFactory powerAuthHeaderFactory;

private static final KeyConvertor KEY_CONVERTOR = new KeyConvertor();
private static final KeyConvertor KEY_CONVERTOR_EC = new KeyConvertor();
private static final PqcDsaKeyConvertor KEY_CONVERTOR_PQC = new MlDsaKeyConvertor();

private static final PowerAuthClientKeyFactory KEY_FACTORY = new PowerAuthClientKeyFactory();

private static final com.wultra.security.powerauth.crypto.client.vault.PowerAuthClientVault VAULT_V3 = new com.wultra.security.powerauth.crypto.client.vault.PowerAuthClientVault();
private static final com.wultra.security.powerauth.crypto.client.v4.vault.PowerAuthClientVault VAULT_V4 = new com.wultra.security.powerauth.crypto.client.v4.vault.PowerAuthClientVault();

/**
* Constructor
* @param powerAuthHeaderFactory PowerAuth header factory
Expand Down Expand Up @@ -165,7 +170,7 @@ public StepContext<VaultUnlockStepModel, EncryptedResponse> prepareStepContext(S
public void processResponse(StepContext<VaultUnlockStepModel, EncryptedResponse> stepContext) throws Exception {
final int majorVersion = stepContext.getModel().getVersion().getMajorVersion();

final Map<String, Object> objectMap = new HashMap<>();
final Map<String, Object> objectMap = new LinkedHashMap<>();
switch (majorVersion) {
case 3 -> {
final com.wultra.security.powerauth.rest.api.model.response.v3.VaultUnlockResponsePayload responsePayload = decryptResponse(stepContext, com.wultra.security.powerauth.rest.api.model.response.v3.VaultUnlockResponsePayload.class);
Expand All @@ -180,29 +185,42 @@ public void processResponse(StepContext<VaultUnlockStepModel, EncryptedResponse>
return;
}

final byte[] encryptedDevicePrivateKeyBytes = resultStatusObject.getEncryptedDevicePrivateKeyBytes();
final byte[] encryptedDevicePrivateKeyBytes = resultStatusObject.getEncryptedEcDevicePrivateKeyBytes();
final byte[] encryptedVaultEncryptionKey = Base64.getDecoder().decode(responsePayload.getEncryptedVaultEncryptionKey());

final PowerAuthClientVault vault = new PowerAuthClientVault();
final SecretKey vaultEncryptionKey = vault.decryptVaultEncryptionKey(encryptedVaultEncryptionKey, transportMasterKey);
final PrivateKey devicePrivateKey = vault.decryptDevicePrivateKey(encryptedDevicePrivateKeyBytes, vaultEncryptionKey);
final SecretKey vaultEncryptionKey = VAULT_V3.decryptVaultEncryptionKey(encryptedVaultEncryptionKey, transportMasterKey);
final PrivateKey devicePrivateKey = VAULT_V3.decryptDevicePrivateKey(encryptedDevicePrivateKeyBytes, vaultEncryptionKey);
final PublicKey serverPublicKey = resultStatusObject.getEcServerPublicKeyObject();

final SecretKey masterSecretKey = KEY_FACTORY.generateClientMasterSecretKey(devicePrivateKey, serverPublicKey);
final SecretKey transportKeyDeduced = KEY_FACTORY.generateServerTransportKey(masterSecretKey);
final boolean equal = transportKeyDeduced.equals(transportMasterKey);
objectMap.put("activationId", resultStatusObject.getActivationId());
objectMap.put("encryptedVaultEncryptionKey", Base64.getEncoder().encodeToString(encryptedVaultEncryptionKey));
objectMap.put("transportMasterKey", Base64.getEncoder().encodeToString(KEY_CONVERTOR.convertSharedSecretKeyToBytes(transportMasterKey)));
objectMap.put("vaultEncryptionKey", Base64.getEncoder().encodeToString(KEY_CONVERTOR.convertSharedSecretKeyToBytes(vaultEncryptionKey)));
objectMap.put("devicePrivateKey", Base64.getEncoder().encodeToString(KEY_CONVERTOR.convertPrivateKeyToBytes(devicePrivateKey)));
objectMap.put("transportMasterKey", Base64.getEncoder().encodeToString(KEY_CONVERTOR_EC.convertSharedSecretKeyToBytes(transportMasterKey)));
objectMap.put("vaultEncryptionKey", Base64.getEncoder().encodeToString(KEY_CONVERTOR_EC.convertSharedSecretKeyToBytes(vaultEncryptionKey)));
objectMap.put("devicePrivateKey", Base64.getEncoder().encodeToString(KEY_CONVERTOR_EC.convertPrivateKeyToBytes(devicePrivateKey)));
objectMap.put("privateKeyDecryptionSuccessful", (equal ? "true" : "false"));
}
case 4 -> {
final com.wultra.security.powerauth.rest.api.model.response.v4.VaultUnlockResponsePayload responsePayload = decryptResponse(stepContext, com.wultra.security.powerauth.rest.api.model.response.v4.VaultUnlockResponsePayload.class);
final ResultStatusObject resultStatusObject = stepContext.getModel().getResultStatus();
objectMap.put("activationId", resultStatusObject.getActivationId());
objectMap.put("vaultEncryptionKey", responsePayload.getVaultEncryptionKey());

// Decrypt and show device private keys in case key identifier is KEK_DEVICE_PRIVATE
if ("KEK_DEVICE_PRIVATE".equals(stepContext.getModel().getKeyIdentifier())) {
final byte[] vaultUnlockKekDevicePrivateBytes = Base64.getDecoder().decode(responsePayload.getVaultEncryptionKey());
final SecretKey vaultUnlockKekDevicePrivate = KEY_CONVERTOR_EC.convertBytesToSharedSecretKey(vaultUnlockKekDevicePrivateBytes);
final byte[] encryptedEcDevicePrivateKeyBytes = resultStatusObject.getEncryptedEcDevicePrivateKeyBytes();
final PrivateKey ecDevicePrivateKey = VAULT_V4.decryptEcDevicePrivateKey(encryptedEcDevicePrivateKeyBytes, vaultUnlockKekDevicePrivate);
objectMap.put("deviceEcPrivateKey", Base64.getEncoder().encodeToString(KEY_CONVERTOR_EC.convertPrivateKeyToBytes(ecDevicePrivateKey)));
if (resultStatusObject.getEncryptedPqcDevicePrivateKey() != null) {
final byte[] encryptedPqcDevicePrivateKeyBytes = resultStatusObject.getEncryptedPqcDevicePrivateKeyBytes();
final PrivateKey pqcDevicePrivateKey = VAULT_V4.decryptPqcDevicePrivateKey(encryptedPqcDevicePrivateKeyBytes, vaultUnlockKekDevicePrivate);
objectMap.put("devicePqcPrivateKey", Base64.getEncoder().encodeToString(KEY_CONVERTOR_PQC.convertPrivateKeyToBytes(pqcDevicePrivateKey)));
}
}
}
default -> throw new IllegalArgumentException("Unsupported version: " + stepContext.getModel().getVersion());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package com.wultra.security.powerauth.lib.cmd.steps.base;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wultra.security.powerauth.crypto.client.vault.PowerAuthClientVault;
import com.wultra.security.powerauth.crypto.lib.encryptor.ClientEncryptor;
import com.wultra.security.powerauth.crypto.lib.encryptor.EncryptorFactory;
import com.wultra.security.powerauth.crypto.lib.encryptor.model.*;
Expand Down Expand Up @@ -89,7 +88,8 @@ public abstract class AbstractActivationStep<M extends ActivationData> extends A

private static final KeyGenerator KEY_GENERATOR = new KeyGenerator();

private static final PowerAuthClientVault VAULT = new PowerAuthClientVault();
private static final com.wultra.security.powerauth.crypto.client.vault.PowerAuthClientVault VAULT_V3 = new com.wultra.security.powerauth.crypto.client.vault.PowerAuthClientVault();
private static final com.wultra.security.powerauth.crypto.client.v4.vault.PowerAuthClientVault VAULT_V4 = new com.wultra.security.powerauth.crypto.client.v4.vault.PowerAuthClientVault();

private static final ObjectMapper MAPPER = RestClientConfiguration.defaultMapper();

Expand Down Expand Up @@ -128,7 +128,7 @@ public void processResponse(StepContext<M, EncryptedResponse> stepContext) throw

resultStatusService.save(model);

final Map<String, Object> objectMap = new HashMap<>();
final Map<String, Object> objectMap = new LinkedHashMap<>();
objectMap.put("activationId", resultStatusObject.getActivationId());
objectMap.put("activationStatusFile", model.getStatusFileName());
objectMap.put("activationStatusFileContent", model.getResultStatus());
Expand Down Expand Up @@ -220,7 +220,7 @@ private ResultStatusObject processActivationResponseV3(EncryptedResponse encrypt
final SecretKey vaultUnlockMasterKey = KEY_FACTORY_V3.generateServerEncryptedVaultKey(masterSecretKey);

// Encrypt the original device private key using the vault unlock key
final byte[] encryptedDevicePrivateKey = VAULT.encryptDevicePrivateKey(securityContext.getEcDeviceKeyPair().getPrivate(), vaultUnlockMasterKey);
final byte[] encryptedDevicePrivateKey = VAULT_V3.encryptDevicePrivateKey(securityContext.getEcDeviceKeyPair().getPrivate(), vaultUnlockMasterKey);

final char[] password;
if (model.getPassword() == null) {
Expand All @@ -240,7 +240,7 @@ private ResultStatusObject processActivationResponseV3(EncryptedResponse encrypt
resultStatusObject.setActivationId(activationId);
resultStatusObject.setCounter(0L);
resultStatusObject.setCtrData(ctrDataBase64);
resultStatusObject.setEncryptedDevicePrivateKeyBytes(encryptedDevicePrivateKey);
resultStatusObject.setEncryptedEcDevicePrivateKeyBytes(encryptedDevicePrivateKey);
resultStatusObject.setEcServerPublicKeyObject(serverPublicKey);
resultStatusObject.setBiometryFactorKeyObject(biometryFactorKey);
resultStatusObject.setKnowledgeFactorKeyEncryptedBytes(cKnowledgeFactorSecretKey);
Expand Down Expand Up @@ -314,6 +314,7 @@ private ResultStatusObject processActivationResponseV4(EncryptedResponse encrypt
final SecretKey authenticationCodePossessionSecretKey = KEY_FACTORY_V4.generatePossessionFactorKey(activationSharedSecret);
final SecretKey authenticationCodeKnowledgeSecretKey = KEY_FACTORY_V4.generateKnowledgeFactorKey(activationSharedSecret);
final SecretKey authenticationCodeBiometrySecretKey = KEY_FACTORY_V4.generateBiometryFactorKey(activationSharedSecret);
final SecretKey vaultUnlockKekDevicePrivate = KEY_FACTORY_V4.generateKeyKekDevicePrivate(activationSharedSecret);

final char[] password;
if (model.getPassword() == null) {
Expand All @@ -331,6 +332,15 @@ private ResultStatusObject processActivationResponseV4(EncryptedResponse encrypt
final PublicKey ecDevicePublicKey = securityContext.getEcDeviceKeyPair().getPublic();
final PublicKey pqcDevicePublicKey = securityContext.getPqcDeviceKeyPair() != null ? securityContext.getPqcDeviceKeyPair().getPublic() : null;

// Encrypt device private keys
final byte[] encryptedEcDevicePrivateKey = VAULT_V4.encryptEcDevicePrivateKey(securityContext.getEcDeviceKeyPair().getPrivate(), vaultUnlockKekDevicePrivate);
final byte[] encryptedPqcDevicePrivateKey;
if (securityContext.getPqcDeviceKeyPair() != null) {
encryptedPqcDevicePrivateKey = VAULT_V4.encryptPqcDevicePrivateKey(securityContext.getPqcDeviceKeyPair().getPrivate(), vaultUnlockKekDevicePrivate);
} else {
encryptedPqcDevicePrivateKey = null;
}

resultStatusObject.setVersion((long) model.getVersion().getMajorVersion());
resultStatusObject.setActivationId(activationId);
resultStatusObject.setCounter(0L);
Expand All @@ -342,7 +352,10 @@ private ResultStatusObject processActivationResponseV4(EncryptedResponse encrypt
if (serverPublicKeys.getMldsa() != null) {
resultStatusObject.setPqcServerPublicKey(serverPublicKeys.getMldsa());
}
// TODO - store encrypted crypto 4 private keys using updated vault mechanism
resultStatusObject.setEncryptedEcDevicePrivateKeyBytes(encryptedEcDevicePrivateKey);
if (encryptedPqcDevicePrivateKey != null) {
resultStatusObject.setEncryptedPqcDevicePrivateKeyBytes(encryptedPqcDevicePrivateKey);
}
resultStatusObject.setBiometryFactorKeyObject(authenticationCodeBiometrySecretKey);
resultStatusObject.setKnowledgeFactorKeyEncryptedBytes(encryptedKnowledgeSecretKey);
resultStatusObject.setKnowledgeFactorKeySaltBytes(salt);
Expand Down
Loading