All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.mosip.authentication.common.service.transaction.manager.IdAuthSecurityManager Maven / Gradle / Ivy

package io.mosip.authentication.common.service.transaction.manager;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.crypto.SecretKey;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import io.mosip.authentication.common.service.repository.IdaUinHashSaltRepo;
import io.mosip.authentication.common.service.util.EnvUtil;
import io.mosip.authentication.core.constant.IdAuthConfigKeyConstants;
import io.mosip.authentication.core.constant.IdAuthenticationErrorConstants;
import io.mosip.authentication.core.exception.IdAuthUncheckedException;
import io.mosip.authentication.core.exception.IdAuthenticationBusinessException;
import io.mosip.authentication.core.logger.IdaLogger;
import io.mosip.authentication.core.util.CryptoUtil;
import io.mosip.idrepository.core.util.SaltUtil;
import io.mosip.kernel.core.exception.ExceptionUtils;
import io.mosip.kernel.core.logger.spi.Logger;
import io.mosip.kernel.core.retry.WithRetry;
import io.mosip.kernel.core.util.DateUtils;
import io.mosip.kernel.core.util.HMACUtils2;
import io.mosip.kernel.crypto.jce.core.CryptoCore;
import io.mosip.kernel.cryptomanager.dto.CryptomanagerRequestDto;
import io.mosip.kernel.cryptomanager.service.CryptomanagerService;
import io.mosip.kernel.cryptomanager.util.CryptomanagerUtils;
import io.mosip.kernel.keygenerator.bouncycastle.KeyGenerator;
import io.mosip.kernel.keymanagerservice.entity.DataEncryptKeystore;
import io.mosip.kernel.keymanagerservice.exception.NoUniqueAliasException;
import io.mosip.kernel.keymanagerservice.repository.DataEncryptKeystoreRepository;
import io.mosip.kernel.signature.constant.SignatureConstant;
import io.mosip.kernel.signature.dto.JWTSignatureRequestDto;
import io.mosip.kernel.signature.dto.JWTSignatureVerifyRequestDto;
import io.mosip.kernel.signature.dto.JWTSignatureVerifyResponseDto;
import io.mosip.kernel.signature.service.SignatureService;
import io.mosip.kernel.zkcryptoservice.constant.ZKCryptoManagerConstants;
import io.mosip.kernel.zkcryptoservice.dto.CryptoDataDto;
import io.mosip.kernel.zkcryptoservice.dto.ReEncryptRandomKeyResponseDto;
import io.mosip.kernel.zkcryptoservice.dto.ZKCryptoRequestDto;
import io.mosip.kernel.zkcryptoservice.dto.ZKCryptoResponseDto;
import io.mosip.kernel.zkcryptoservice.service.spi.ZKCryptoManagerService;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuple3;
import reactor.util.function.Tuples;

/**
 * The Class IdAuthSecurityManager.
 *
 * @author Manoj SP
 */
@Component
public class IdAuthSecurityManager {

	/** The Constant SALT_FOR_THE_GIVEN_ID. */
	private static final String SALT_FOR_THE_GIVEN_ID = "Salt for the given ID";

	/** The application id. */
	@Value("${application.id}")
	private String applicationId;

	/** The reference id. */
	@Value("${identity-cache.reference.id}")
	private String referenceId;

	/** The Constant ENCRYPT_DECRYPT_DATA. */
	private static final String ENCRYPT_DECRYPT_DATA = "encryptDecryptData";

	/** The Constant ID_AUTH_TRANSACTION_MANAGER. */
	private static final String ID_AUTH_TRANSACTION_MANAGER = "IdAuthSecurityManager";

	/** The mosip logger. */
	private Logger mosipLogger = IdaLogger.getLogger(IdAuthSecurityManager.class);

	/** The cryptomanager service. */
	@Autowired
	private CryptomanagerService cryptomanagerService;

	/** The key manager. */
	@Autowired
	private SignatureService signatureService;

	/** The sign applicationid. */
	@Value("${mosip.sign.applicationid:KERNEL}")
	private String signApplicationid;

	/** The sign refid. */
	@Value("${mosip.sign.refid:SIGN}")
	private String signRefid;

	/** The uin hash salt repo. */
	@Autowired
	private IdaUinHashSaltRepo uinHashSaltRepo;

	/** The repo. */
	@Autowired
	private DataEncryptKeystoreRepository repo;

	/** The zk crypto manager service. */
	@Autowired
	private ZKCryptoManagerService zkCryptoManagerService;

	/** The crypto core. */
	@Autowired
	private CryptoCore cryptoCore;

	/** The key generator. */
	@Autowired
	private KeyGenerator keyGenerator;

	/** The token ID length. */
	@Value("${mosip.kernel.tokenid.length}")
	private int tokenIDLength;

	/** KeySplitter. */
	@Value("${" + IdAuthConfigKeyConstants.KEY_SPLITTER + "}")
	private String keySplitter;
	
	/** The cryptomanager utils. */
	@Autowired
	private CryptomanagerUtils cryptomanagerUtils;
	/**
	 * Gets the user.
	 *
	 * @return the user
	 */
	public String getUser() {
		return EnvUtil.getIdaAuthClientId();
	}

	/**
	 * Encrypt.
	 *
	 * @param dataToEncrypt the data to encrypt
	 * @param refId         the ref id
	 * @param aad           the aad
	 * @param saltToEncrypt the salt to encrypt
	 * @return the byte[]
	 * @throws IdAuthenticationBusinessException the id authentication business
	 *                                           exception
	 */
	@WithRetry
	public byte[] encrypt(String dataToEncrypt, String refId, String aad, String saltToEncrypt)
			throws IdAuthenticationBusinessException {
		try {
			CryptomanagerRequestDto request = new CryptomanagerRequestDto();
			request.setApplicationId(EnvUtil.getAppId());
			request.setTimeStamp(DateUtils.getUTCCurrentDateTime());
			request.setData(dataToEncrypt);
			request.setReferenceId(refId);
			request.setAad(aad);
			request.setSalt(saltToEncrypt);
			return CryptoUtil.decodeBase64Url(cryptomanagerService.encrypt(request).getData());
		} catch (NoUniqueAliasException e) {
			// TODO: check whether PUBLICKEY_EXPIRED to be thrown for NoUniqueAliasException
			mosipLogger.error(getUser(), ID_AUTH_TRANSACTION_MANAGER, ENCRYPT_DECRYPT_DATA,
					ExceptionUtils.getStackTrace(e));
			throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.PUBLICKEY_EXPIRED, e);
		} catch (Exception e) {
			mosipLogger.error(getUser(), ID_AUTH_TRANSACTION_MANAGER, ENCRYPT_DECRYPT_DATA,
					ExceptionUtils.getStackTrace(e));
			throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.FAILED_TO_ENCRYPT, e);
		}
	}

	/**
	 * Decrypt.
	 *
	 * @param dataToDecrypt the data to decrypt
	 * @param refId         the ref id
	 * @param aad           the aad
	 * @param saltToDecrypt the salt to decrypt
	 * @param isThumbprintEnabled the is thumbprint enabled
	 * @return the byte[]
	 * @throws IdAuthenticationBusinessException the id authentication business
	 *                                           exception
	 */
	@WithRetry
	public byte[] decrypt(String dataToDecrypt, String refId, String aad, String saltToDecrypt,
			Boolean isThumbprintEnabled) throws IdAuthenticationBusinessException {
		try {
			CryptomanagerRequestDto request = new CryptomanagerRequestDto();
			request.setApplicationId(EnvUtil.getAppId());
			request.setTimeStamp(DateUtils.getUTCCurrentDateTime());
			request.setData(dataToDecrypt);
			request.setReferenceId(refId);
			request.setAad(aad);
			request.setSalt(saltToDecrypt);
			//request.setPrependThumbprint(isThumbprintEnabled);
			return CryptoUtil.decodeBase64Url(cryptomanagerService.decrypt(request).getData());
		} catch (NoUniqueAliasException e) {
			// TODO: check whether PUBLICKEY_EXPIRED to be thrown for NoUniqueAliasException
			mosipLogger.error(getUser(), ID_AUTH_TRANSACTION_MANAGER, ENCRYPT_DECRYPT_DATA,
					ExceptionUtils.getStackTrace(e));
			throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.PUBLICKEY_EXPIRED, e);
		} catch (Exception e) {
			mosipLogger.error(getUser(), ID_AUTH_TRANSACTION_MANAGER, ENCRYPT_DECRYPT_DATA,
					ExceptionUtils.getStackTrace(e));
			throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.INVALID_ENCRYPTION, e);
		}
	}

	/**
	 * Re encrypt random key.
	 *
	 * @param encryptedKey the encrypted key
	 * @return the string
	 */
	@WithRetry
	public String reEncryptRandomKey(String encryptedKey) {
		ReEncryptRandomKeyResponseDto zkReEncryptRandomKeyRespDto = zkCryptoManagerService
				.zkReEncryptRandomKey(encryptedKey);
		return zkReEncryptRandomKeyRespDto.getEncryptedKey();
	}

	/**
	 * Re encrypt and store random key.
	 *
	 * @param index the index
	 * @param key the key
	 */
	public void reEncryptAndStoreRandomKey(String index, String key) {
		Integer indexInt = Integer.valueOf(index);
		if (repo.findKeyById(indexInt) == null) {
			String reEncryptedKey = reEncryptRandomKey(key);
			DataEncryptKeystore randomKeyEntity = new DataEncryptKeystore();
			randomKeyEntity.setId(indexInt);
			randomKeyEntity.setKey(reEncryptedKey);
			randomKeyEntity.setCrBy("IDA");
			randomKeyEntity.setCrDTimes(DateUtils.getUTCCurrentDateTime());
			repo.save(randomKeyEntity);
		}
	}

	/**
	 * Zk decrypt.
	 *
	 * @param id the id
	 * @param encryptedAttributes the encrypted attributes
	 * @return the map
	 * @throws IdAuthenticationBusinessException the id authentication business exception
	 */
	@WithRetry
	public Map zkDecrypt(String id, Map encryptedAttributes)
			throws IdAuthenticationBusinessException {
		ZKCryptoRequestDto cryptoRequestDto = new ZKCryptoRequestDto();
		cryptoRequestDto.setId(id);
		List zkDataAttributes = encryptedAttributes.entrySet().stream()
				.map(entry -> new CryptoDataDto(entry.getKey(), entry.getValue())).collect(Collectors.toList());
		cryptoRequestDto.setZkDataAttributes(zkDataAttributes);
		ZKCryptoResponseDto zkDecryptResponse = zkCryptoManagerService.zkDecrypt(cryptoRequestDto);
		return zkDecryptResponse.getZkDataAttributes().stream()
				.collect(Collectors.toMap(CryptoDataDto::getIdentifier, CryptoDataDto::getValue));

	}

	/**
	 * Creates the random token.
	 *
	 * @param dataToEncrypt the data to encrypt
	 * @return the string
	 * @throws IdAuthenticationBusinessException the id authentication business exception
	 */
	public String createRandomToken(byte[] dataToEncrypt) throws IdAuthenticationBusinessException {
		SecretKey key = keyGenerator.getSymmetricKey();
		SecureRandom sRandom = new SecureRandom();
		byte[] nonce = new byte[ZKCryptoManagerConstants.GCM_NONCE_LENGTH];
		byte[] aad = new byte[ZKCryptoManagerConstants.GCM_AAD_LENGTH];

		sRandom.nextBytes(nonce);
		sRandom.nextBytes(aad);
		byte[] encryptedData = cryptoCore.symmetricEncrypt(key, dataToEncrypt, nonce, aad);
		String hash;
		hash = IdAuthSecurityManager.generateHashAndDigestAsPlainText(encryptedData);
		return new BigInteger(hash.getBytes()).toString().substring(0, tokenIDLength);
	}

	/**
	 * Sign.
	 *
	 * @param data the data
	 * @return the string
	 */
	@WithRetry
	public String sign(String data) {
		// TODO: check whether any exception will be thrown
		JWTSignatureRequestDto request = new JWTSignatureRequestDto();
		request.setApplicationId(signApplicationid);
		request.setDataToSign(CryptoUtil.encodeBase64Url(data.getBytes()));
		request.setIncludeCertHash(true);
		request.setIncludeCertificate(true);
		request.setIncludePayload(false);
		request.setReferenceId(signRefid);
		return signatureService.jwtSign(request).getJwtSignedData();
	}

	/**
	 * Verify signature.
	 *
	 * @param signature the signature
	 * @param domain the domain
	 * @param requestData the request data
	 * @param isTrustValidationRequired the is trust validation required
	 * @return true, if successful
	 */
	public boolean verifySignature(String signature, String domain, String requestData,
			Boolean isTrustValidationRequired) {
		JWTSignatureVerifyRequestDto jwtSignatureVerifyRequestDto = new JWTSignatureVerifyRequestDto();
		jwtSignatureVerifyRequestDto.setApplicationId(signApplicationid);
		jwtSignatureVerifyRequestDto.setReferenceId(signRefid);
		if (Objects.nonNull(requestData)) {
			jwtSignatureVerifyRequestDto.setActualData(CryptoUtil.encodeBase64Url(requestData.getBytes()));
		}
		jwtSignatureVerifyRequestDto.setJwtSignatureData(signature);
		jwtSignatureVerifyRequestDto.setValidateTrust(isTrustValidationRequired);
		jwtSignatureVerifyRequestDto.setDomain(domain);
		JWTSignatureVerifyResponseDto jwtResponse = signatureService.jwtVerify(jwtSignatureVerifyRequestDto);
		mosipLogger.info(getUser(), ID_AUTH_TRANSACTION_MANAGER, "verifySignature",
				"SIGNATURE VALID : " + jwtResponse.isSignatureValid() + " - TRUST VALID : "
						+ jwtResponse.getTrustValid().contentEquals(SignatureConstant.TRUST_VALID));
		return isTrustValidationRequired
				? jwtResponse.isSignatureValid()
						&& jwtResponse.getTrustValid().contentEquals(SignatureConstant.TRUST_VALID)
				: jwtResponse.isSignatureValid();
	}

	/**
	 * Hash.
	 *
	 * @param id the id
	 * @return the string
	 * @throws IdAuthenticationBusinessException the id authentication business exception
	 */
	public String hash(String id) throws IdAuthenticationBusinessException {
		Integer idModulo = getSaltKeyForHashOfId(id);
		String hashSaltValue = uinHashSaltRepo.retrieveSaltById(idModulo);
		if (hashSaltValue != null) {
			try {
				return HMACUtils2.digestAsPlainTextWithSalt(id.getBytes(), hashSaltValue.getBytes());
			} catch (NoSuchAlgorithmException e) {
				throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.UNABLE_TO_PROCESS, e);
			}
		} else {
			throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.ID_NOT_AVAILABLE.getErrorCode(),
					String.format(IdAuthenticationErrorConstants.ID_NOT_AVAILABLE.getErrorMessage(),
							SALT_FOR_THE_GIVEN_ID));
		}
	}

	/**
	 * Gets the x 509 certificate.
	 *
	 * @param partnerCertificate the partner certificate
	 * @return the x 509 certificate
	 * @throws IdAuthenticationBusinessException the id authentication business exception
	 */
	private X509Certificate getX509Certificate(String partnerCertificate) throws IdAuthenticationBusinessException {
		try {
			String certificate = IdAuthSecurityManager.trimBeginEnd(partnerCertificate);
			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			X509Certificate x509cert = (X509Certificate) cf
					.generateCertificate(new ByteArrayInputStream(java.util.Base64.getDecoder().decode(certificate)));
			return x509cert;
		} catch (CertificateException e) {
			throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.UNABLE_TO_PROCESS, e);
		}
	}

	/**
	 * Encrypt data.
	 *
	 * @param data the data
	 * @param partnerCertificate the partner certificate
	 * @return the tuple 2
	 * @throws IdAuthenticationBusinessException the id authentication business exception
	 */
	public Tuple3 encryptData(byte[] data, String partnerCertificate) throws IdAuthenticationBusinessException {
		X509Certificate x509Certificate = getX509Certificate(partnerCertificate);
		PublicKey publicKey = x509Certificate.getPublicKey();
		Tuple2 encryptedData = encrypt(publicKey, data);
		byte[] certificateThumbprint = cryptomanagerUtils.getCertificateThumbprint(x509Certificate);
		return Tuples.of(CryptoUtil.encodeBase64Url(encryptedData.getT1()), CryptoUtil.encodeBase64Url(encryptedData.getT2()), digestAsPlainText(certificateThumbprint));
	}

	/**
	 * Encrypt.
	 *
	 * @param publicKey the public key
	 * @param dataToEncrypt the data to encrypt
	 * @return the byte[]
	 */
	public Tuple2 encrypt(PublicKey publicKey, byte[] dataToEncrypt) {
		SecretKey secretKey = keyGenerator.getSymmetricKey();
		byte[] encryptedData = cryptoCore.symmetricEncrypt(secretKey, dataToEncrypt, null);
		byte[] encryptedSymmetricKey = cryptoCore.asymmetricEncrypt(publicKey, secretKey.getEncoded());
		return Tuples.of(encryptedSymmetricKey,encryptedData);
	}

	/**
	 * Combine data to encrypt.
	 *
	 * @param encryptedData the encrypted data
	 * @param encryptedSymmetricKey the encrypted symmetric key
	 * @return the byte[]
	 */
	public byte[] combineDataToEncrypt(byte[] encryptedData, byte[] encryptedSymmetricKey) {
		return CryptoUtil.combineByteArray(encryptedData, encryptedSymmetricKey, keySplitter);
	}

	/**
	 * Trim begin end.
	 *
	 * @param pKey the key
	 * @return the string
	 */
	public static String trimBeginEnd(String pKey) {
		pKey = pKey.replaceAll("-{0,30}BEGIN([^-]{0,30})-{0,30}(\r?\n)?", "");
		pKey = pKey.replaceAll("-{0,30}END([^-]{0,30})-{0,30}(\r?\n)?", "");
		pKey = pKey.replaceAll("\\s", "");
		return pKey;
	}

	/**
	 * Digest as plain text.
	 *
	 * @param data the data
	 * @return the string
	 */
	public static String digestAsPlainText(byte[] data) {
		return toHex(data);
	}

	/**
	 * Generate hash and digest as plain text.
	 *
	 * @param data the data
	 * @return the string
	 */
	public static String generateHashAndDigestAsPlainText(byte[] data) {
		try {
			return digestAsPlainText(generateHash(data));
		} catch (NoSuchAlgorithmException e) {
			throw new IdAuthUncheckedException(IdAuthenticationErrorConstants.UNABLE_TO_PROCESS, e);
		}
	}
	
	/**
	 * Generate hash.
	 *
	 * @param data the data
	 * @return the byte[]
	 * @throws NoSuchAlgorithmException the no such algorithm exception
	 */
	public static byte[] generateHash(final byte[] data) throws NoSuchAlgorithmException {
		try {
			return HMACUtils2.generateHash(data);
		} catch (NoSuchAlgorithmException e) {
			throw new IdAuthUncheckedException(IdAuthenticationErrorConstants.UNABLE_TO_PROCESS, e);
		}
	}
	
	/**
	 * Decode hex.
	 *
	 * @param hexData the hex data
	 * @return the byte[]
	 * @throws DecoderException the decoder exception
	 */
	public static byte[] decodeHex(String hexData) throws DecoderException{
        return Hex.decodeHex(hexData);
    }
	
	/**
	 * To hex.
	 *
	 * @param bytes the bytes
	 * @return the string
	 */
	public static String toHex(byte[] bytes) {
        return Hex.encodeHexString(bytes).toUpperCase();
    }
	
	/**
	 * Gets the bytes from thumbprint.
	 *
	 * @param thumbprint the thumbprint
	 * @return the bytes from thumbprint
	 */
	public static byte[] getBytesFromThumbprint(String thumbprint) {
		try {
			//First try decoding with hex
			return decodeHex(thumbprint);
		} catch (DecoderException e) {
			try {
				//Then try decoding with base64
				return CryptoUtil.decodeBase64Url(thumbprint);
			} catch (Exception ex) {
				throw new IdAuthUncheckedException(IdAuthenticationErrorConstants.UNABLE_TO_PROCESS, ex);
			}
		}
	}
	
	private int getSaltKeyForHashOfId(String id) {
		Integer saltKeyLength = EnvUtil.getSaltKeyLength();
		return SaltUtil.getIdvidHashModulo(id, saltKeyLength);
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy